├── .gitattributes ├── .gitignore ├── LICENSE ├── Osu!Bot V2.sln ├── Osu!Bot V2 ├── ConfigurationFile.h ├── CursorMovement.h ├── DrawTextToWindow.h ├── GlobalVariables.h ├── HitObject.h ├── Osu!Bot V2.vcxproj ├── Osu!Bot V2.vcxproj.filters ├── OsuBot.cpp ├── OsuBot.h ├── OsuBotV2.ico ├── OsuBotV2.rc ├── SendInput.h ├── SongsReading.h ├── bitmap1.bmp ├── resource.h ├── small.ico ├── split_string.h ├── stdafx.cpp ├── stdafx.h ├── targetver.h ├── timeAddress.h └── vec2f.h └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # Osu!Bot Data files 5 | Data/ 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | # NUNIT 38 | *.VisualState.xml 39 | TestResult.xml 40 | 41 | # Build Results of an ATL Project 42 | [Dd]ebugPS/ 43 | [Rr]eleasePS/ 44 | dlldata.c 45 | 46 | # DNX 47 | project.lock.json 48 | project.fragment.lock.json 49 | artifacts/ 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # NCrunch 117 | _NCrunch_* 118 | .*crunch*.local.xml 119 | nCrunchTemp_* 120 | 121 | # MightyMoose 122 | *.mm.* 123 | AutoTest.Net/ 124 | 125 | # Web workbench (sass) 126 | .sass-cache/ 127 | 128 | # Installshield output folder 129 | [Ee]xpress/ 130 | 131 | # DocProject is a documentation generator add-in 132 | DocProject/buildhelp/ 133 | DocProject/Help/*.HxT 134 | DocProject/Help/*.HxC 135 | DocProject/Help/*.hhc 136 | DocProject/Help/*.hhk 137 | DocProject/Help/*.hhp 138 | DocProject/Help/Html2 139 | DocProject/Help/html 140 | 141 | # Click-Once directory 142 | publish/ 143 | 144 | # Publish Web Output 145 | *.[Pp]ublish.xml 146 | *.azurePubxml 147 | # TODO: Comment the next line if you want to checkin your web deploy settings 148 | # but database connection strings (with potential passwords) will be unencrypted 149 | #*.pubxml 150 | *.publishproj 151 | 152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 153 | # checkin your Azure Web App publish settings, but sensitive information contained 154 | # in these scripts will be unencrypted 155 | PublishScripts/ 156 | 157 | # NuGet Packages 158 | *.nupkg 159 | # The packages folder can be ignored because of Package Restore 160 | **/packages/* 161 | # except build/, which is used as an MSBuild target. 162 | !**/packages/build/ 163 | # Uncomment if necessary however generally it will be regenerated when needed 164 | #!**/packages/repositories.config 165 | # NuGet v3's project.json files produces more ignoreable files 166 | *.nuget.props 167 | *.nuget.targets 168 | 169 | # Microsoft Azure Build Output 170 | csx/ 171 | *.build.csdef 172 | 173 | # Microsoft Azure Emulator 174 | ecf/ 175 | rcf/ 176 | 177 | # Windows Store app package directories and files 178 | AppPackages/ 179 | BundleArtifacts/ 180 | Package.StoreAssociation.xml 181 | _pkginfo.txt 182 | 183 | # Visual Studio cache files 184 | # files ending in .cache can be ignored 185 | *.[Cc]ache 186 | # but keep track of directories ending in .cache 187 | !*.[Cc]ache/ 188 | 189 | # Others 190 | ClientBin/ 191 | ~$* 192 | *~ 193 | *.dbmdl 194 | *.dbproj.schemaview 195 | *.jfm 196 | *.pfx 197 | *.publishsettings 198 | node_modules/ 199 | orleans.codegen.cs 200 | 201 | # Since there are multiple workflows, uncomment next line to ignore bower_components 202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 203 | #bower_components/ 204 | 205 | # RIA/Silverlight projects 206 | Generated_Code/ 207 | 208 | # Backup & report files from converting an old project file 209 | # to a newer Visual Studio version. Backup files are not needed, 210 | # because we have git ;-) 211 | _UpgradeReport_Files/ 212 | Backup*/ 213 | UpgradeLog*.XML 214 | UpgradeLog*.htm 215 | 216 | # SQL Server files 217 | *.mdf 218 | *.ldf 219 | 220 | # Business Intelligence projects 221 | *.rdl.data 222 | *.bim.layout 223 | *.bim_*.settings 224 | 225 | # Microsoft Fakes 226 | FakesAssemblies/ 227 | 228 | # GhostDoc plugin setting file 229 | *.GhostDoc.xml 230 | 231 | # Node.js Tools for Visual Studio 232 | .ntvs_analysis.dat 233 | 234 | # Visual Studio 6 build log 235 | *.plg 236 | 237 | # Visual Studio 6 workspace options file 238 | *.opt 239 | 240 | # Visual Studio LightSwitch build output 241 | **/*.HTMLClient/GeneratedArtifacts 242 | **/*.DesktopClient/GeneratedArtifacts 243 | **/*.DesktopClient/ModelManifest.xml 244 | **/*.Server/GeneratedArtifacts 245 | **/*.Server/ModelManifest.xml 246 | _Pvt_Extensions 247 | 248 | # Paket dependency manager 249 | .paket/paket.exe 250 | paket-files/ 251 | 252 | # FAKE - F# Make 253 | .fake/ 254 | 255 | # JetBrains Rider 256 | .idea/ 257 | *.sln.iml 258 | 259 | # CodeRush 260 | .cr/ 261 | 262 | # Python Tools for Visual Studio (PTVS) 263 | __pycache__/ 264 | *.pyc 265 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Damian Braat 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Osu!Bot V2.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2010 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Osu!Bot V2", "Osu!Bot V2\Osu!Bot V2.vcxproj", "{4A39DBAF-D7B0-454F-9C13-03A75985CB3E}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {4A39DBAF-D7B0-454F-9C13-03A75985CB3E}.Debug|x64.ActiveCfg = Debug|Win32 17 | {4A39DBAF-D7B0-454F-9C13-03A75985CB3E}.Debug|x64.Build.0 = Debug|Win32 18 | {4A39DBAF-D7B0-454F-9C13-03A75985CB3E}.Debug|x86.ActiveCfg = Debug|Win32 19 | {4A39DBAF-D7B0-454F-9C13-03A75985CB3E}.Debug|x86.Build.0 = Debug|Win32 20 | {4A39DBAF-D7B0-454F-9C13-03A75985CB3E}.Release|x64.ActiveCfg = Release|x64 21 | {4A39DBAF-D7B0-454F-9C13-03A75985CB3E}.Release|x64.Build.0 = Release|x64 22 | {4A39DBAF-D7B0-454F-9C13-03A75985CB3E}.Release|x86.ActiveCfg = Release|Win32 23 | {4A39DBAF-D7B0-454F-9C13-03A75985CB3E}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {B9653817-60BB-4F6B-8824-D080A775611B} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Osu!Bot V2/ConfigurationFile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stdafx.h" 4 | 5 | #include "GlobalVariables.h" 6 | #include 7 | 8 | 9 | using namespace std; 10 | 11 | 12 | enum configurationSettings: wchar_t { 13 | songsFolderPath = L's', 14 | inputKeys = L'k', 15 | inputMethod = L'b', 16 | timerPointer = L'h', 17 | danceSettings = L'i' 18 | }; 19 | 20 | 21 | bool WriteToConfigFile(vector configStrings) { 22 | try { 23 | FILE *wConfigFile = _wfopen(L"Data\\configFile.cfg", L"w"); 24 | 25 | for (wstring configString : configStrings) { 26 | fwprintf(wConfigFile, (configString + L"\n").c_str()); 27 | } 28 | 29 | fclose(wConfigFile); 30 | 31 | return TRUE; 32 | } 33 | catch (const exception &e) { 34 | wstringstream ss; ss << e.what(); 35 | 36 | /* EventLog */ fwprintf(wEventLog, (L"[ERROR] Couldn't write to configuration file!\n with error: " + ss.str() + L"\n").c_str()); 37 | fflush(wEventLog); 38 | return FALSE; 39 | } 40 | return FALSE; 41 | } 42 | 43 | 44 | bool FillMap(map &configValues, wstring &configString, const configurationSettings configurationSetting) { 45 | switch (configurationSetting) { 46 | case timerPointer: 47 | configString = L"[Timer Pointer]"; 48 | configValues[L"ThreadOffset"] = &threadOffset; 49 | configValues[L"Offset0"] = &(offsets[0]); 50 | configValues[L"Offset1"] = &(offsets[1]); 51 | configValues[L"Offset2"] = &(offsets[2]); 52 | configValues[L"Offset3"] = &(offsets[3]); 53 | configValues[L"Offset4"] = &(offsets[4]); 54 | break; 55 | 56 | case songsFolderPath: 57 | configString = L"[Songs Folder Path]"; 58 | configValues[L"FolderPath"] = &songsPath; 59 | break; 60 | 61 | case inputMethod: 62 | configString = L"[Input Method]"; 63 | configValues[L"UseKeyboard"] = &inputKeyBoard; 64 | break; 65 | 66 | case inputKeys: 67 | configString = L"[Input Keys]"; 68 | configValues[L"MainKey"] = &inputMainKey; 69 | configValues[L"AltKey"] = &inputAltKey; 70 | break; 71 | 72 | case danceSettings: 73 | configString = L"[Dance Settings]"; 74 | configValues[L"Amplifier"] = &trackBarPos; 75 | configValues[L"ModeMoveTo"] = &modeMoveTo; 76 | configValues[L"ModeSlider"] = &modeSlider; 77 | configValues[L"ModeSpinner"] = &modeSpinner; 78 | 79 | default: 80 | return FALSE; 81 | } 82 | 83 | return TRUE; 84 | } 85 | 86 | 87 | bool CreateNewConfigFile() { 88 | try { 89 | vector configStrings = { 90 | L"[Songs Folder Path]", 91 | L"FolderPath : ", 92 | L"", 93 | L"[Timer Pointer]", 94 | L"Offset0 : 0", 95 | L"Offset1 : 1F0", 96 | L"Offset2 : 22C", 97 | L"Offset3 : 2D8", 98 | L"Offset4 : 514", 99 | L"ThreadOffset : -32C", 100 | L"", 101 | L"[Input Method]", 102 | L"UseKeyboard : True", 103 | L"", 104 | L"[Input Keys] //Currently only works with ASCII convertible keys!", 105 | L"MainKey : Z", 106 | L"AltKey : X", 107 | L"", 108 | L"[Dance Settings]", 109 | L"Amplifier : 100", 110 | L"ModeMoveTo : 3", 111 | L"ModeSlider : 3", 112 | L"ModeSpinner : 1", 113 | L"" 114 | }; 115 | 116 | WriteToConfigFile(configStrings); 117 | return TRUE; 118 | } 119 | catch (const exception &e) { 120 | wstringstream ss; ss << e.what(); 121 | 122 | /* EventLog */ fwprintf(wEventLog, (L"[ERROR] Couldn't create a configuration file!\n with error: " + ss.str() + L"\n").c_str()); 123 | fflush(wEventLog); 124 | return FALSE; 125 | } 126 | } 127 | 128 | 129 | bool AddSettingString(wstring &settingString, const wstring configSetting, const LPVOID configValue, const configurationSettings configurationSetting) { 130 | switch (configurationSetting) { 131 | case L'i': 132 | { 133 | int* settingValue = (int*)configValue; 134 | settingString = configSetting + L" : " + to_wstring(*settingValue); 135 | 136 | break; 137 | } 138 | case L'h': 139 | { 140 | wstringstream ss; 141 | int* settingValue = (int*)configValue; 142 | int hexValue = *settingValue; 143 | 144 | if (*settingValue < 0) { 145 | hexValue *= -1; 146 | ss << hex << hexValue; 147 | settingString = configSetting + L" : -" + wstring(ss.str()); 148 | } 149 | else { 150 | ss << hex << hexValue; 151 | settingString = configSetting + L" : " + wstring(ss.str()); 152 | } 153 | 154 | break; 155 | } 156 | case L's': 157 | { 158 | wstring* settingValue = (wstring*)configValue; 159 | wstring wValue = *settingValue; 160 | settingString = configSetting + L" : " + wValue; 161 | 162 | break; 163 | } 164 | case L'k': 165 | { 166 | WORD* settingValue = (WORD*)configValue; 167 | TCHAR* keyText = new TCHAR[MAXCHAR]; 168 | if (GetKeyNameText(*settingValue << 16, keyText, MAXCHAR)) { 169 | settingString = configSetting + L" : " + keyText; 170 | } 171 | delete keyText; 172 | 173 | break; 174 | } 175 | case L'b': 176 | { 177 | bool* settingValue = (bool*)configValue; 178 | bool boolValue = *settingValue; 179 | wstring boolString = (boolValue ? L"true" : L"false"); 180 | settingString = configSetting + L" : " + boolString; 181 | 182 | break; 183 | } 184 | default: 185 | return FALSE; 186 | } 187 | return TRUE; 188 | } 189 | 190 | bool UpdateConfigFile(const vector settingsList) { 191 | try { 192 | wstring readLine; 193 | vector allConfigStrings; 194 | 195 | for (configurationSettings configurationSetting : settingsList) { 196 | wstring configString; 197 | vector configStrings; 198 | map configValues; 199 | 200 | FillMap(configValues, configString, configurationSetting); 201 | 202 | wfstream configFile; 203 | configFile.open(L"Data\\configFile.cfg", wfstream::in | wfstream::out); 204 | 205 | while (!configFile.eof()) { 206 | getline(configFile, readLine, configFile.widen('\n')); 207 | 208 | if (readLine.find(configString) != wstring::npos) { 209 | configStrings.push_back(configString); 210 | while (configValues.size() > 0 && (readLine.compare(L"") != 0 || readLine[0] == L'[')) { 211 | getline(configFile, readLine); 212 | 213 | wstring configSetting = readLine.substr(0, 214 | MIN(readLine.find_first_of(L":"), readLine.find_first_of(L" "))); 215 | 216 | wstring settingString; 217 | auto settingFinder = configValues.find(configSetting); 218 | if (settingFinder != configValues.end()) { 219 | AddSettingString(settingString, configSetting, settingFinder->second, configurationSetting); 220 | 221 | configValues.erase(settingFinder); 222 | } 223 | else { 224 | settingString = readLine; 225 | } 226 | configStrings.push_back(settingString); 227 | } 228 | for (auto& configValue : configValues) { 229 | wstring settingString; 230 | AddSettingString(settingString, configValue.first, configValue.second, configurationSetting); 231 | 232 | configStrings.push_back(settingString); 233 | } 234 | 235 | configValues.clear(); 236 | } 237 | else { 238 | configStrings.push_back(readLine); 239 | } 240 | } 241 | 242 | if (configValues.size() > 0) { 243 | configStrings.push_back(configString); 244 | for (auto& configValue : configValues) { 245 | wstring settingString; 246 | 247 | AddSettingString(settingString, configValue.first, configValue.second, configurationSetting); 248 | 249 | configStrings.push_back(settingString); 250 | } 251 | } 252 | 253 | configFile.close(); 254 | 255 | while (configStrings.at(0) == L"") 256 | configStrings.erase(configStrings.begin()); 257 | while (configStrings.at(configStrings.size() - 1) == L"") 258 | configStrings.pop_back(); 259 | 260 | configStrings.push_back(L""); 261 | 262 | allConfigStrings.reserve(allConfigStrings.size() + configStrings.size()); 263 | allConfigStrings.insert(allConfigStrings.end(), configStrings.begin(), configStrings.end()); 264 | 265 | allConfigStrings.pop_back(); 266 | 267 | WriteToConfigFile(allConfigStrings); 268 | 269 | allConfigStrings.clear(); 270 | } 271 | 272 | return TRUE; 273 | } 274 | catch (const exception &e) { 275 | wstringstream ss; ss << e.what(); 276 | 277 | /* EventLog */ fwprintf(wEventLog, (L"[ERROR] Couldn't update a configuration file!\n with error: " + ss.str() + L"\n").c_str()); 278 | fflush(wEventLog); 279 | return FALSE; 280 | } 281 | } 282 | 283 | bool UpdateConfigFile(const configurationSettings &setting) { 284 | return UpdateConfigFile(vector { setting }); 285 | } 286 | 287 | bool ReadFromConfigFile(const configurationSettings &setting) { 288 | try { 289 | wstring readLine; 290 | 291 | wstring configString; 292 | map configValues; 293 | 294 | FillMap(configValues, configString, setting); 295 | 296 | wfstream configFile; 297 | configFile.open(L"Data\\configFile.cfg", wfstream::in); 298 | 299 | while (!configFile.eof() && readLine.find(configString) == wstring::npos) { 300 | getline(configFile, readLine, configFile.widen(L'\n')); 301 | } 302 | 303 | if (readLine.empty() && configFile.eof()) 304 | return FALSE; 305 | 306 | 307 | for (unsigned int i = 0; i < configValues.size(); i++) { 308 | getline(configFile, readLine); 309 | wstring configSetting = readLine.substr(0, 310 | MIN(readLine.find_first_of(L" "), readLine.find_first_of(L":")) - 1); 311 | 312 | UINT pos = UINT(readLine.find_first_of(L":")) + 1U; 313 | UINT valuePos = readLine.at(pos) == L' ' ? pos + 1U : pos; 314 | 315 | switch (setting) { 316 | case L'i': 317 | { 318 | int intValue; 319 | if (readLine.at(valuePos) == L'-') { 320 | intValue = stoi(readLine.substr(valuePos + 1)); 321 | intValue *= -1; 322 | } 323 | else 324 | intValue = stoi(readLine.substr(valuePos)); 325 | 326 | int* configValue = (int*)(configValues.at(configSetting)); 327 | *configValue = intValue; 328 | 329 | break; 330 | } 331 | case L'h': 332 | { 333 | wstringstream ss; 334 | int hexValue; 335 | if (readLine.at(valuePos) == L'-') { 336 | ss << hex << nouppercase << readLine.substr(valuePos + 1); 337 | ss >> hexValue; 338 | hexValue *= -1; 339 | } 340 | else { 341 | ss << hex << nouppercase << readLine.substr(valuePos); 342 | ss >> hexValue; 343 | } 344 | 345 | int* configValue = (int*)(configValues.at(configSetting)); 346 | *configValue = hexValue; 347 | 348 | break; 349 | } 350 | case L's': 351 | { 352 | wstring stringValue = readLine.substr(valuePos); 353 | 354 | wstring* configValue = (wstring*)(configValues.at(configSetting)); 355 | *configValue = stringValue; 356 | 357 | break; 358 | } 359 | case L'k': 360 | { 361 | TCHAR charValue = readLine.substr(valuePos)[0]; 362 | WORD KeyValue = LOWORD(OemKeyScan(charValue)); 363 | 364 | WORD* configValue = (WORD*)(configValues.at(configSetting)); 365 | *configValue = KeyValue; 366 | 367 | break; 368 | } 369 | case L'b': 370 | { 371 | wstring stringValue = readLine.substr(valuePos); 372 | 373 | bool boolValue; 374 | if (stringValue[0] == L't' || stringValue[0] == L'T') 375 | boolValue = TRUE; 376 | else if (stringValue[0] == L'f' || stringValue[0] == L'F') 377 | boolValue = FALSE; 378 | else 379 | boolValue = FALSE; 380 | 381 | bool* configValue = (bool*)(configValues.at(configSetting)); 382 | *configValue = boolValue; 383 | 384 | break; 385 | } 386 | default: 387 | configFile.close(); 388 | return FALSE; 389 | } 390 | } 391 | 392 | configFile.close(); 393 | 394 | return TRUE; 395 | } 396 | catch (const exception &e) { 397 | wstringstream ss; ss << e.what(); 398 | 399 | /* EventLog */ fwprintf(wEventLog, (L"[ERROR] Couldn't read from configuration file!\n with error: " + ss.str() + L"\n").c_str()); 400 | fflush(wEventLog); 401 | return FALSE; 402 | } 403 | } 404 | 405 | bool ReadAllConfigSettings() { 406 | try { 407 | if (ReadFromConfigFile(timerPointer)) 408 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] TimerPointer get successful.\n"); 409 | else 410 | /* EventLog */ fwprintf(wEventLog, L"[WARNING] TimerPointer not specified!\n"); 411 | 412 | if (ReadFromConfigFile(songsFolderPath)) { 413 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] SongsFolderPath get successful.\n"); 414 | if (songsPath.compare(L"") != 0) 415 | pathSet = TRUE; 416 | else 417 | pathSet = FALSE; 418 | } 419 | else { 420 | /* EventLog */ fwprintf(wEventLog, L"[WARNING] SongsFolderPath not specified!\n"); 421 | pathSet = FALSE; 422 | } 423 | 424 | if (ReadFromConfigFile(inputKeys)) 425 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] InputKeys get successful.\n"); 426 | else 427 | /* EventLog */ fwprintf(wEventLog, L"[WARNING] InputKeys not specified!\n"); 428 | 429 | if (ReadFromConfigFile(inputMethod)) 430 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] InputMethod get successful.\n"); 431 | else 432 | /* EventLog */ fwprintf(wEventLog, L"[WARNING] InputMethod not specified!\n"); 433 | 434 | if (ReadFromConfigFile(danceSettings)) { 435 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] DanceSettings get successful.\n"); 436 | SendMessage(hwndTrackBarDanceAmplifier, TBM_SETPOS, TRUE, trackBarPos); 437 | SendMessage(hwndComboBoxDanceModeMoveTo, CB_SETCURSEL, (WPARAM)modeMoveTo, NULL); 438 | SendMessage(hwndComboBoxDanceModeSlider, CB_SETCURSEL, (WPARAM)modeSlider, NULL); 439 | SendMessage(hwndComboBoxDanceModeSpinner, CB_SETCURSEL, (WPARAM)modeSpinner, NULL); 440 | } 441 | else 442 | /* EventLog */ fwprintf(wEventLog, L"[WARNING] DanceSettings not specified!\n"); 443 | 444 | return TRUE; 445 | } 446 | catch (const exception &e) { 447 | wstringstream ss; ss << e.what(); 448 | 449 | /* EventLog */ fwprintf(wEventLog, (L"[ERROR] Couldn't read from configuration file!\n with error: " + ss.str()).c_str()); 450 | fflush(wEventLog); 451 | return FALSE; 452 | } 453 | } -------------------------------------------------------------------------------- /Osu!Bot V2/CursorMovement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stdafx.h" 4 | 5 | #include "OsuBot.h" 6 | 7 | 8 | float HermiteInterp(float _X) { 9 | float _Y0 = 0.1f, // In target 10 | _Y1 = 0.0f, // Start 11 | _Y2 = 1.0f, // End 12 | _Y3 = 1.1f; // Out target 13 | 14 | float tension = -0.2f, // 1 : high, 0 : normal, -1 : low 15 | bias = 0.3f; // >0 : first segment, 0 : mid, <0 : next segment 16 | 17 | float a0, a1, a2, a3; 18 | float m0, m1; 19 | 20 | float _X2 = _X * _X; 21 | float _X3 = _X2 * _X; 22 | 23 | m0 = (_Y1 - _Y0) * (1.f + bias) * (1.f - tension) / 2.f; 24 | m0 += (_Y2 - _Y1) * (1.f - bias) * (1.f - tension) / 2.f; 25 | m1 = (_Y2 - _Y1) * (1.f + bias) * (1.f - tension) / 2.f; 26 | m1 += (_Y3 - _Y2) * (1.f - bias) * (1.f - tension) / 2.f; 27 | 28 | a0 = 2.f * _X3 - 3.f * _X2 + 1.f; 29 | a1 = _X3 - 2.f * _X2 + _X; 30 | a2 = _X3 - _X2; 31 | a3 = -2.f * _X3 + 3.f * _X2; 32 | 33 | float _Y = (a0 * _Y1 + a1 * m0 + a2 * m1 + a3 * _Y2); 34 | 35 | return CLAMP(0.f, _Y, 1.f); 36 | } 37 | 38 | 39 | vector FindControlPoints(vec2f vpP, vec2f vpB, vec2f vpE, vec2f vpN, int index) { 40 | vec2f 41 | d0 = vpP.cpy().sub(vpB), 42 | d1 = vpB.cpy().sub(vpE), 43 | d2 = vpE.cpy().sub(vpN); 44 | 45 | float 46 | l0 = d0.length(), 47 | l1 = d1.length(), 48 | l2 = d2.length(); 49 | 50 | vec2f 51 | m0 = vpP.midPoint(pB), 52 | m1 = vpB.midPoint(pE), 53 | m2 = vpE.midPoint(pN); 54 | 55 | float 56 | amplifier0 = (atan2f(l2 / 480.f, 1.85f * (l2 / 960.f)) / ((40000.f / Amplifier) / l1)) + 1.f, 57 | amplifier1 = (atan2f(l1 / 480.f, 1.85f * (l1 / 960.f)) / ((40000.f / Amplifier) / l1)) + 1.f; 58 | 59 | vec2f 60 | cp0 = m1 + (pB - (m1 + (m0 - m1) * ((l1 * amplifier1) / (l0 + l1)))), 61 | cp1 = m0 + (pB - (m1 + (m0 - m1) * ((l1 * amplifier1) / (l0 + l1)))), 62 | cp2 = m2 + (pE - (m2 + (m1 - m2) * ((l2 * amplifier0) / (l1 + l2)))), 63 | cp3 = m1 + (pE - (m2 + (m1 - m2) * ((l2 * amplifier0) / (l1 + l2)))); 64 | 65 | return index == 1 ? vector{ cp2, cp3 } : vector { cp0, cp1 }; 66 | } 67 | 68 | 69 | vec2f FlowVectorPoint(vec2f vpP, vec2f vpB, vec2f vpE, vec2f vpN, vec2f unreferencedVec2f, int index) { 70 | UNREFERENCED_PARAMETER(unreferencedVec2f); 71 | return FindControlPoints(vpP, vpB, vpE, vpN, index).at(index); 72 | } 73 | 74 | vec2f PredictionVectorPoint(vec2f vpP, vec2f vpB, vec2f vpE, vec2f vpN, vec2f cp1, int unreferencedInt) { 75 | UNREFERENCED_PARAMETER(vpP); 76 | UNREFERENCED_PARAMETER(unreferencedInt); 77 | return vpN.midPoint(vpE).sub(vpN).mult((vpB - vpE).length() / (860.0f / Amplifier)).add(vpE).midPoint(cp1); 78 | } 79 | 80 | 81 | void MoveToCircle(vector *objects, const int nObject, function VectorPoint) { 82 | if (nObject == 0) { 83 | GetCursorPos(&cursorPoint); 84 | 85 | pBack = pP = pB = vec2f(static_cast(cursorPoint.x), static_cast(cursorPoint.y)); 86 | } 87 | else { 88 | if (objects->at(nObject - 1).getHitType() == HIT_SLIDER) { 89 | float tP = (objects->at(nObject - 1).getSliderTickCount() - 1.f) / objects->at(nObject - 1).getSliderTickCount(); 90 | pP = vec2f((objects->at(nObject - 1).getPointByT(tP).x - stackOffset * objects->at(nObject - 1).getStack()) * multiplierX + osuWindowX, (objects->at(nObject - 1).getPointByT(tP).y - stackOffset * objects->at(nObject - 1).getStack()) * multiplierY + osuWindowY); 91 | } 92 | else if (nObject != 1) { 93 | pP = vec2f((objects->at(nObject - 2).getEndPos().x - stackOffset * objects->at(nObject - 2).getStack()) * multiplierX + osuWindowX, (objects->at(nObject - 2).getEndPos().y - stackOffset * objects->at(nObject - 2).getStack()) * multiplierY + osuWindowY); 94 | } 95 | 96 | GetCursorPos(&cursorPoint); 97 | pB = vec2f(static_cast(cursorPoint.x), static_cast(cursorPoint.y)); 98 | } 99 | 100 | pE = vec2f((objects->at(nObject).getStartPos().x - stackOffset * objects->at(nObject).getStack()) * multiplierX + osuWindowX, (objects->at(nObject).getStartPos().y - stackOffset * objects->at(nObject).getStack()) * multiplierY + osuWindowY); 101 | 102 | if (static_cast(nObject + 1) >= objects->size()) { 103 | pN = vec2f(320.f * multiplierX + osuWindowX, 240.f * multiplierY + osuWindowY); 104 | } 105 | else if (objects->at(nObject).getHitType() == HIT_SLIDER) { 106 | float tickCount = ceilf(objects->at(nObject).getSliderTickCount()); 107 | float tN = 1.f / (tickCount == 0.f ? 1.f : tickCount); 108 | 109 | vec2f pNT = objects->at(nObject).getPointByT(tN); 110 | pN = vec2f((pNT.x - stackOffset * objects->at(nObject).getStack()) * multiplierX + osuWindowX, (pNT.y - stackOffset * objects->at(nObject).getStack()) * multiplierY + osuWindowY); 111 | } 112 | else { 113 | pN = vec2f((objects->at(nObject + 1).getStartPos().x - stackOffset * objects->at(nObject + 1).getStack()) * multiplierX + osuWindowX, (objects->at(nObject + 1).getStartPos().y - stackOffset * objects->at(nObject + 1).getStack()) * multiplierY + osuWindowY); 114 | } 115 | 116 | 117 | bool interpBool = true; 118 | 119 | vec2f p1 = (pB - pBack).add(pB); 120 | 121 | vec2f p2; 122 | if ((pE - pB).length() < (1.f / circleSize) * 400.f) { 123 | p2 = FindControlPoints(pP, pB, pE, pN, 1).at(1); 124 | p1 = (pB - pBack).normalize().mult((pE - pB).length() / 2.f).add(pB); 125 | interpBool = false; 126 | } 127 | else if (objects->at(nObject).getHitType() == HIT_SLIDER) { 128 | p2 = FindControlPoints(pP, pB, pE, pN, 1).at(1); 129 | } 130 | else { 131 | p2 = VectorPoint(pP, pB, pE, pN, p1, 1); 132 | } 133 | 134 | vector pts { 135 | pB, p1, p2, pE 136 | }; 137 | 138 | 139 | float dt = static_cast(objects->at(nObject).getStartTime() - songTime); 140 | while (songTime <= objects->at(nObject).getStartTime() && songStarted) { 141 | float t = (dt - static_cast(objects->at(nObject).getStartTime() - songTime)) / dt; 142 | t = interpBool ? HermiteInterp(t) : t; 143 | t = CLAMP(0.f, t, 1.f); 144 | 145 | pCursor = PolyBezier(pts, INT(pts.size()) - 1, 0, t); 146 | 147 | SetCursorPos(static_cast(pCursor.x), static_cast(pCursor.y)); 148 | 149 | this_thread::sleep_for(chrono::milliseconds(1)); 150 | } 151 | 152 | pBack = pts.at(pts.size() - 2); 153 | } 154 | 155 | void MoveToStandard(HitObject *objects) { 156 | GetCursorPos(&cursorPoint); 157 | 158 | pB = vec2f(static_cast(cursorPoint.x), static_cast(cursorPoint.y)); 159 | pE = vec2f((objects->getStartPos().x - stackOffset * objects->getStack()) * multiplierX + osuWindowX, 160 | (objects->getStartPos().y - stackOffset * objects->getStack()) * multiplierY + osuWindowY); 161 | 162 | float dt = static_cast(objects->getStartTime() - songTime); 163 | 164 | while (songTime < objects->getStartTime() && songStarted) { 165 | float t = (dt - static_cast(objects->getStartTime() - songTime)) / dt; 166 | pCursor = pB + t * (pE - pB); 167 | 168 | SetCursorPos(static_cast(pCursor.x), static_cast(pCursor.y)); 169 | this_thread::sleep_for(chrono::milliseconds(1)); 170 | } 171 | } 172 | 173 | void SliderStandard(HitObject *objects) { 174 | SendKeyPress(objects); 175 | 176 | while (songTime <= objects->getEndTime() && songStarted) { 177 | auto t = static_cast(songTime - objects->getStartTime()) / objects->getSliderTime(); 178 | 179 | vec2f vec = objects->getPointByT(t); 180 | pCursor = vec2f((((vec.x - objects->getStack() * stackOffset) * multiplierX) + osuWindowX), 181 | ((vec.y - objects->getStack() * stackOffset) * multiplierY) + osuWindowY); 182 | 183 | SetCursorPos(static_cast(pCursor.x), static_cast(pCursor.y)); 184 | 185 | this_thread::sleep_for(chrono::milliseconds(1)); 186 | } 187 | 188 | SendKeyRelease(objects); 189 | } 190 | 191 | void SliderFlowing(vector *objects, const int nObject) { 192 | GetCursorPos(&cursorPoint); 193 | 194 | int cpCount = 3; 195 | 196 | int nPolyCount = 0; 197 | int nPolyCountReverse; 198 | int nPoly = 0; 199 | vector pts; 200 | pts.resize(static_cast(ceilf(objects->at(nObject).getSliderTickCount()) * objects->at(nObject).getSliderRepeatCount() * static_cast(cpCount)) + (UINT)1); 201 | 202 | vec2f pPBack = pP; 203 | vec2f pNBack = pN; 204 | 205 | if (objects->at(nObject).getSliderRepeatCount() == 1.f) { 206 | for (float i = 0.f; i < objects->at(nObject).getSliderTickCount(); i++) { 207 | float tB = i / objects->at(nObject).getSliderTickCount(); 208 | float tE = (i + 1.f) > objects->at(nObject).getSliderTickCount() ? 1.f : (i + 1.f) / objects->at(nObject).getSliderTickCount(); 209 | float tN = (i + 2.f) / objects->at(nObject).getSliderTickCount(); 210 | 211 | pN = pNBack; 212 | if (tN < 1.f) { 213 | pN = vec2f(((objects->at(nObject).getPointByT(tN).x - objects->at(nObject).getStack() * stackOffset) * multiplierX) + osuWindowX, 214 | ((objects->at(nObject).getPointByT(tN).y - objects->at(nObject).getStack() * stackOffset) * multiplierY) + osuWindowY); 215 | } 216 | 217 | if (nPolyCount != 0) { 218 | pts.at(nPolyCount + 1) = vec2f((pE - pts.at(nPolyCount - cpCount + 2)) + pE); 219 | } 220 | 221 | pE = vec2f(((objects->at(nObject).getPointByT(tE).x - objects->at(nObject).getStack() * stackOffset) * multiplierX) + osuWindowX, 222 | ((objects->at(nObject).getPointByT(tE).y - objects->at(nObject).getStack() * stackOffset) * multiplierY) + osuWindowY); 223 | 224 | if (nPolyCount == 0) { 225 | pB = vec2f(((objects->at(nObject).getPointByT(tB).x - objects->at(nObject).getStack() * stackOffset) * multiplierX) + osuWindowX, 226 | ((objects->at(nObject).getPointByT(tB).y - objects->at(nObject).getStack() * stackOffset) * multiplierY) + osuWindowY); 227 | pts.at(nPolyCount) = pB; 228 | 229 | //pts.at(nPolyCount + 1) = FindControlPoints(pP, pts.at(nPolyCount), pE).at(0); 230 | pts.at(nPolyCount + 1) = vec2f((pts.at(nPolyCount) - pBack) + pts.at(nPolyCount)); 231 | } 232 | 233 | //pts.at(nPolyCount + 1) = FindControlPoints(pP, pts.at(nPolyCount), pE).at(0); 234 | pts.at(nPolyCount + 2) = pN.midPoint(pE).sub(pN).mult((pB - pE).length() / 860.0f).add(pE).midPoint(pts.at(nPolyCount + 1)); //FindControlPoints(pts.at(nPolyCount), pE, pN).at(1); 235 | pts.at(nPolyCount + cpCount) = pE; 236 | 237 | pP = pts.at(nPolyCount); 238 | nPolyCount += cpCount; 239 | } 240 | } 241 | else { 242 | for (int repeated = 0; static_cast(repeated) < objects->at(nObject).getSliderRepeatCount(); repeated++) { 243 | if (repeated % 2 == 0) { 244 | for (float i = 0.f; i < objects->at(nObject).getSliderTickCount(); i++) { 245 | float tB = i / objects->at(nObject).getSliderTickCount(); 246 | float tE = (i + 1.f) > objects->at(nObject).getSliderTickCount() ? 1.f : (i + 1.f) / objects->at(nObject).getSliderTickCount(); 247 | float tN = (i + 2.f) / objects->at(nObject).getSliderTickCount(); 248 | 249 | pN = pNBack; 250 | if (tN < objects->at(nObject).getSliderRepeatCount()) { 251 | pN = vec2f(((objects->at(nObject).getPointByT(tN).x - objects->at(nObject).getStack() * stackOffset) * multiplierX) + osuWindowX, 252 | ((objects->at(nObject).getPointByT(tN).y - objects->at(nObject).getStack() * stackOffset) * multiplierY) + osuWindowY); 253 | } 254 | 255 | if (nPolyCount != 0) { 256 | pts.at(nPolyCount + 1) = vec2f((pE - pts.at(nPolyCount - cpCount + 2)) + pE); 257 | } 258 | 259 | pE = vec2f(((objects->at(nObject).getPointByT(tE).x - objects->at(nObject).getStack() * stackOffset) * multiplierX) + osuWindowX, 260 | ((objects->at(nObject).getPointByT(tE).y - objects->at(nObject).getStack() * stackOffset) * multiplierY) + osuWindowY); 261 | 262 | if (nPolyCount == 0) { 263 | pB = vec2f(((objects->at(nObject).getPointByT(tB).x - objects->at(nObject).getStack() * stackOffset) * multiplierX) + osuWindowX, 264 | ((objects->at(nObject).getPointByT(tB).y - objects->at(nObject).getStack() * stackOffset) * multiplierY) + osuWindowY); 265 | pts.at(nPolyCount) = pB; 266 | 267 | //pts.at(nPolyCount + 1) = FindControlPoints(pP, pts.at(nPolyCount), pE).at(0); 268 | pts.at(nPolyCount + 1) = vec2f((pts.at(nPolyCount) - pBack) + pts.at(nPolyCount)); 269 | } 270 | 271 | //pts.at(nPolyCount + 1) = FindControlPoints(pP, pts.at(nPolyCount), pE).at(0); 272 | pts.at(nPolyCount + 2) = pN.midPoint(pE).sub(pN).mult((pB - pE).length() / 860.0f).add(pE).midPoint(pts.at(nPolyCount + 1)); //FindControlPoints(pts.at(nPolyCount), pE, pN).at(1); 273 | pts.at(nPolyCount + cpCount) = pE; 274 | 275 | pP = pts.at(nPolyCount); 276 | nPolyCount += cpCount; 277 | } 278 | } 279 | if (repeated % 2 != 0) { 280 | nPolyCountReverse = nPolyCount; 281 | for (float i = 0.f; i < objects->at(nObject).getSliderTickCount(); i++) { 282 | nPolyCountReverse -= cpCount; 283 | 284 | pts.at(nPolyCount + 1) = vec2f((pE - pts.at(nPolyCount - cpCount + 2)) + pE); 285 | 286 | pP = pts.at(nPolyCount); 287 | pE = pts.at(nPolyCountReverse); 288 | 289 | if ((i + 1.f) / objects->at(nObject).getSliderTickCount() >= objects->at(nObject).getSliderRepeatCount()) { 290 | pN = pNBack; 291 | } 292 | else if (nPolyCountReverse - cpCount > 0) { 293 | pN = pts.at(nPolyCountReverse - cpCount); 294 | } 295 | else { 296 | pN = pPBack; 297 | } 298 | 299 | //pts.at(nPolyCount + 1) = FindControlPoints(pP, pts.at(nPolyCount), pE).at(0); 300 | pts.at(nPolyCount + 2) = pN.midPoint(pE).sub(pN).mult((pB - pE).length() / 860.0f).add(pE).midPoint(pts.at(nPolyCount + 1)); //FindControlPoints(pts.at(nPolyCount), pE, pN).at(1); 301 | pts.at(nPolyCount + cpCount) = pE; 302 | 303 | pP = pts.at(nPolyCount); 304 | nPolyCount += cpCount; 305 | } 306 | } 307 | } 308 | } 309 | 310 | SendKeyPress(&objects->at(nObject)); 311 | 312 | while (songTime < objects->at(nObject).getEndTime() && songStarted) { 313 | float tickCount = ceilf(objects->at(nObject).getSliderTickCount()); 314 | 315 | float t = static_cast(songTime - objects->at(nObject).getStartTime()) / static_cast(objects->at(nObject).getSliderTime()); 316 | 317 | float T = t * tickCount - nPoly; 318 | if (T > 1.f && static_cast(nPoly + 1) < objects->at(nObject).getSliderRepeatCount() * tickCount) { 319 | ++nPoly; 320 | T = t * tickCount - nPoly; 321 | } 322 | T = CLAMP(0.f, HermiteInterp(T), 1.f); 323 | 324 | pCursor = PolyBezier(pts, cpCount, nPoly, T); 325 | 326 | SetCursorPos(static_cast(pCursor.x), static_cast(pCursor.y)); 327 | 328 | this_thread::sleep_for(chrono::milliseconds(1)); 329 | } 330 | 331 | SendKeyRelease(&objects->at(nObject)); 332 | 333 | pBack = pts.at(pts.size() - 2); 334 | pP = pts.at(pts.size() - 1 - cpCount); 335 | } 336 | 337 | void SpinnerStandard(HitObject *objects) { 338 | vec2f center(objects->getStartPos().x * multiplierX + osuWindowX, 339 | (objects->getStartPos().y + 6.f) * multiplierY + osuWindowY); 340 | float angle = TWO_PI; 341 | float radius = (1.f / circleSize) * 450.f; 342 | 343 | SendKeyPress(objects); 344 | 345 | while (songTime < objects->getEndTime() && songStarted) { 346 | float t = static_cast(songTime - objects->getStartTime()) / static_cast(objects->getEndTime() - objects->getStartTime()); 347 | t *= 3.f; if (t >= 1.f) t = 1.f; 348 | float radiusT = radius * t; 349 | 350 | pCursor = CirclePoint(center, radiusT, angle); 351 | 352 | SetCursorPos(static_cast(pCursor.x), static_cast(pCursor.y)); 353 | 354 | angle -= static_cast(M_PI / 20.f); 355 | 356 | this_thread::sleep_for(chrono::milliseconds(1)); 357 | } 358 | 359 | SendKeyRelease(objects); 360 | } 361 | -------------------------------------------------------------------------------- /Osu!Bot V2/DrawTextToWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // 3 | // FUNCTION: DrawTextToWindow(HWND, wstring, RECT) 4 | // 5 | // PURPOSE: Draw and Re-draw Text to the given HWND. 6 | // 7 | // COMMENTS: 8 | // 9 | // In this function, we draw or re-draw the text given in a 10 | // RECT selected by the message in the given HWND. 11 | // 12 | static void DrawTextToWindow(HDC hdc, std::wstring str, RECT rect) { 13 | FillRect(hdc, &rect, HBRUSH(GetStockObject(WHITE_BRUSH))); 14 | 15 | DrawText( 16 | hdc, 17 | str.c_str(), 18 | (UINT)str.size(), 19 | &rect, 20 | DT_LEFT | DT_WORDBREAK 21 | ); 22 | } 23 | static void DrawTextToWindow(HWND hWnd, std::wstring str, RECT rect) { 24 | HDC hdc = GetDC(hWnd); 25 | DrawTextToWindow(hdc, str, rect); 26 | } 27 | -------------------------------------------------------------------------------- /Osu!Bot V2/GlobalVariables.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #define MIN(X, Y) X < Y ? X : Y 5 | #define MAX(X, Y) X > Y ? X : Y 6 | #define CLAMP(minValue, value, maxValue) value > maxValue ? maxValue : value < minValue ? minValue : value 7 | #define TWO_PI static_cast(M_PI * 2.f) 8 | #define HALF_PI static_cast(M_PI / 2.f) 9 | 10 | #define HIT_SLIDER 2 11 | #define HIT_SPINNER 8 12 | #define HIT_CIRCLE 1 13 | 14 | #define STACK_LENIENCE 3 15 | 16 | #define MODE_NONE 0 17 | #define MODE_STANDARD 1 18 | #define MODE_FLOWING 2 19 | #define MODE_PREDICTING 3 20 | 21 | 22 | #include "stdafx.h" 23 | 24 | #include "vec2f.h" 25 | #include "HitObject.h" 26 | 27 | using namespace std; 28 | 29 | 30 | #pragma region GlobalVariables 31 | FILE *wEventLog; 32 | 33 | vector timingPoints; 34 | vector hitObjects; 35 | vector offsets(5); 36 | 37 | wstring 38 | beatmapPath, 39 | displayBeatmapPath, 40 | songsPath, 41 | statusText = L"Start up...", 42 | songsFolderText = L"Select \"osu!\" Songs Folder.", 43 | songFileText = L"Select an \"osu! beatmap\"", 44 | userSelect = L"user.\n", 45 | autoSelect = L"Osu!Bot.\n"; 46 | 47 | HWND 48 | hWnd, 49 | osuWindow, 50 | hwndButtonOpenSongFolder, 51 | hwndButtonOpenSongFile, 52 | hwndCheckBoxAutoOpenSong, 53 | hwndCheckBoxHardrockFlip, 54 | hwndTrackBarDanceAmplifier, 55 | hwndComboBoxDanceModeMoveTo, 56 | hwndComboBoxDanceModeSlider, 57 | hwndComboBoxDanceModeSpinner, 58 | hwndProgressBar; 59 | 60 | HANDLE osuProcessHandle; 61 | LPVOID timeAddress; 62 | 63 | IFileDialog *pfd, *pfd2; 64 | IShellItem *psi, *psi2; 65 | 66 | vec2f pBack; 67 | vec2f pCursor, pP, pB, pE, pN; 68 | POINT cursorPoint; 69 | 70 | INPUT input; 71 | 72 | WCHAR inputMainKey = 45; 73 | WCHAR inputAltKey = 44; 74 | 75 | int 76 | nHeight = 290, 77 | nWidth = 585; 78 | 79 | int 80 | objectNumber = 0, 81 | trackBarPos = 100; 82 | 83 | int threadOffset = 0x0; 84 | 85 | int osuWindowX, osuWindowY; 86 | int songTime, prevTime, prevInputTime; 87 | 88 | int 89 | modeMoveTo = MODE_NONE, 90 | modeSlider = MODE_NONE, 91 | modeSpinner = MODE_NONE; 92 | 93 | float 94 | multiplierX, multiplierY, 95 | stackLeniency, 96 | beatMapDivider, 97 | overallDifficulty, 98 | circleSize, 99 | sliderMultiplier, 100 | sliderTickRate, 101 | stackOffset, 102 | Amplifier = 1.f; 103 | 104 | bool 105 | songStarted, 106 | pathSet, 107 | autoOpenSong = true, 108 | hardrockFlip, 109 | altKey, 110 | inputFlip = true, 111 | inputKeyBoard = true, 112 | firstStart = true; 113 | 114 | RECT rectSongsFolder = { 10, 10, nWidth - 140, 50 }; 115 | RECT rectSongFile = { 10, 80, nWidth - 140, 120 }; 116 | RECT rectStatus = { 15, nHeight - 65, nWidth - 30, rectStatus.top + 18 }; 117 | 118 | #pragma endregion 119 | -------------------------------------------------------------------------------- /Osu!Bot V2/HitObject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "stdafx.h" 5 | 6 | #include "GlobalVariables.h" 7 | 8 | 9 | using namespace std; 10 | 11 | 12 | extern FILE *wEventLog; 13 | extern bool hardrockFlip; 14 | 15 | 16 | inline bool isIn(float a, float b, float c) { 17 | return (b > a && b < c) || (b < a && b > c); 18 | } 19 | 20 | inline float lerp(float a, float b, float t) { 21 | return a * (1.f - t) + b * t; 22 | } 23 | 24 | inline long BinomialCoefficient(const int &n, int k) { 25 | if (k < 0 || k > n) { return 0; } 26 | if (k == 0 || k == n) { return 1; } 27 | k = MIN(k, n - k); 28 | long c = 1; 29 | for (int i = 0; i < k; i++) { 30 | c = c * (n - i) / (i + 1); 31 | } return c; 32 | } 33 | 34 | inline float Bernstein(const int &i, const int &n, const float &t) { 35 | return BinomialCoefficient(n, i) * powf(t, static_cast(i)) * powf(1.f - t, static_cast(n) - static_cast(i)); 36 | } 37 | 38 | inline vec2f PolyBezier(const vector &pts, const int &cp, const int &r, const float &t) { 39 | vec2f c; 40 | for (int i = 0; i <= cp; i++) { 41 | float b = Bernstein(i, cp, t); 42 | c.y += pts.at(i + (r * cp)).y * b; 43 | c.x += pts.at(i + (r * cp)).x * b; 44 | } return c; 45 | } 46 | 47 | inline vec2f Intersect(vec2f a, vec2f ta, vec2f b, vec2f tb) { 48 | float des = tb.x * ta.y - tb.y * ta.x; 49 | if (abs(des) < 0.00001f) { /* EventLog */ fwprintf(wEventLog, L"[ERROR] Intersect --> Vectors are parallel.\n"); fflush(wEventLog); } 50 | float u = ((b.y - a.y) * ta.x + (a.x - b.x) * ta.y) / des; 51 | return b.cpy().add(tb.x * u, tb.y * u); 52 | } 53 | 54 | 55 | inline vec2f CirclePoint(vec2f center, float radius, float angle) { 56 | float x = cosf(angle) * radius; 57 | float y = sinf(angle) * radius; 58 | return vec2f(x, y) + center; 59 | } 60 | 61 | 62 | class Segment { 63 | public: vector points; 64 | 65 | ~Segment() {} 66 | }; 67 | 68 | class TimingPoint { 69 | int TimingTime; 70 | float BPM; 71 | public: 72 | explicit TimingPoint(wstring TimingString) { 73 | vector tokens = split_string(TimingString, L","); 74 | TimingTime = stoi(tokens.at(0)); 75 | try { 76 | BPM = stof(tokens.at(1)); 77 | } 78 | catch (...) { 79 | wstring bpm = tokens.at(1); 80 | wstring newBpm; 81 | if (bpm.find('-') != string::npos) { 82 | newBpm = L"MIN_FLOAT"; 83 | BPM = 0.f; 84 | } 85 | else { 86 | newBpm = L"MAX_FLOAT"; 87 | BPM = FLT_MAX; 88 | } 89 | 90 | /* EventLog */ fwprintf(wEventLog, (L"[ERROR] BPM out of Range --> " + bpm + L".\n" + L" Setting BPM to " + newBpm + L" value.\n").c_str()); 91 | fflush(wEventLog); 92 | } 93 | } 94 | 95 | float getBPM() const { 96 | return BPM; 97 | } 98 | int getTime() const { 99 | return TimingTime; 100 | } 101 | 102 | ~TimingPoint() {} 103 | }; 104 | 105 | class HitObject { 106 | public: 107 | vector sliderPoints; 108 | vector sliderSegments; 109 | vec2f startPosition, 110 | circleCenter, 111 | centerP; 112 | int startTime, 113 | endTime = 0, 114 | sliderTime, 115 | hitType, 116 | stackId = 0; 117 | float radius, 118 | radiusP, 119 | startAng, 120 | midAng, 121 | endAng, 122 | pixelLength, 123 | beatLength, 124 | beatLengthBase, 125 | repeatCount, 126 | sliderTickCount, 127 | timingPointMultiplier; 128 | wchar_t sliderType; 129 | 130 | int getHitType() { 131 | if ((hitType & 2) > 0) 132 | return HIT_SLIDER; 133 | else if ((hitType & 8) > 0) 134 | return HIT_SPINNER; 135 | else 136 | return HIT_CIRCLE; 137 | } 138 | 139 | int getStartTime() { 140 | return startTime; 141 | } 142 | 143 | int getEndTime() { 144 | return endTime; 145 | } 146 | 147 | int getStack() { 148 | return stackId; 149 | } 150 | 151 | float getSliderTickCount() { 152 | return sliderTickCount; 153 | } 154 | 155 | float getSliderRepeatCount() { 156 | return repeatCount; 157 | } 158 | 159 | float getSliderTime() { 160 | return static_cast(sliderTime); 161 | } 162 | 163 | float getBPM() { 164 | return beatLength; 165 | } 166 | 167 | void setStack(int stack) { 168 | stackId = stack; 169 | } 170 | 171 | vec2f getStartPos() { 172 | return startPosition; 173 | } 174 | vec2f getEndPos() { 175 | if (getHitType() != HIT_SLIDER) 176 | return getStartPos(); 177 | 178 | static float t = getSliderRepeatCount(); 179 | return getPointByT(t); 180 | } 181 | 182 | vec2f getPointByT(float &t) { 183 | float floor = floorf(t); 184 | t = static_cast(floor) % 2 == 0 ? t - floor : floor + 1.f - t; 185 | 186 | if (sliderType == 'P') { 187 | float ang = lerp(startAng, endAng, t); 188 | if (hardrockFlip) 189 | return { circleCenter.x + radius * cosf(ang), 384.f - (circleCenter.y + radius * sinf(ang)) }; 190 | return { circleCenter.x + radius * cosf(ang), circleCenter.y + radius * sinf(ang) }; 191 | } 192 | 193 | float dist = pixelLength * t; 194 | float currDist = 0.f; 195 | 196 | vec2f oldPoint; 197 | try { oldPoint = sliderSegments.at(0).points.at(0); } 198 | catch (...) { 199 | /* EventLog */ fwprintf(wEventLog, L"[ERROR] getPointByT --> oldPoint\n"); 200 | fflush(wEventLog); 201 | 202 | if (hardrockFlip) 203 | return vec2f(oldPoint.x, 384.f - oldPoint.y); 204 | return oldPoint; 205 | } 206 | 207 | for (unsigned int i = 0; i < sliderSegments.size(); i++) { 208 | auto seg = sliderSegments.at(i); 209 | if (i == sliderSegments.size() - 1) { 210 | float ct = 0.f; 211 | while (currDist < pixelLength) { 212 | vec2f p = PolyBezier(seg.points, INT(seg.points.size()) - 1, 0, ct); 213 | currDist += (oldPoint - p).length(); 214 | 215 | if (currDist > dist) { 216 | if (hardrockFlip) 217 | return vec2f(oldPoint.x, 384.f - oldPoint.y); 218 | return oldPoint; 219 | } 220 | 221 | oldPoint = p; 222 | ct += 1.f / (seg.points.size() * 50 - 1); 223 | } 224 | } 225 | 226 | for (float ct = 0.f; ct < 1.f + (1.f / (seg.points.size() * 50.f - 1.f)); ct += 1.f / (seg.points.size() * 50.f - 1.f)) { 227 | vec2f p = PolyBezier(seg.points, INT(seg.points.size()) - 1, 0, ct); 228 | 229 | currDist += (oldPoint - p).length(); 230 | if (currDist > dist) { 231 | if (hardrockFlip) 232 | return vec2f(oldPoint.x, 384.f - oldPoint.y); 233 | return oldPoint; 234 | } 235 | oldPoint = p; 236 | } 237 | } 238 | 239 | if (hardrockFlip) 240 | return vec2f(oldPoint.x, 384.f - oldPoint.y); 241 | return oldPoint; 242 | } 243 | 244 | HitObject(wstring hitstring, vector *timingPoints, float mapSliderMultiplier, float mapSliderTickRate) { 245 | auto tokens = split_string(hitstring, L","); 246 | startPosition = vec2f(stof(tokens.at(0)), stof(tokens.at(1))); 247 | startTime = stoi(tokens.at(2)); 248 | hitType = _wtoi(tokens.at(3).c_str()); 249 | 250 | if (getHitType() == HIT_SLIDER) { 251 | beatLengthBase = timingPoints->at(0).getBPM(); 252 | float BPM = beatLengthBase; 253 | repeatCount = stof(tokens.at(6)); 254 | pixelLength = stof(tokens.at(7)); 255 | 256 | for (auto point : *timingPoints) { 257 | if (point.getTime() <= startTime) { 258 | if (point.getBPM() >= 0.f) { beatLengthBase = point.getBPM(); } 259 | BPM = point.getBPM(); 260 | } 261 | } 262 | 263 | if (BPM < 0.f) { float newMulti = BPM / -100.f; BPM = beatLengthBase * newMulti; } 264 | beatLength = BPM; 265 | timingPointMultiplier = beatLength / beatLengthBase; 266 | 267 | sliderTime = static_cast(BPM * (pixelLength / mapSliderMultiplier) / 100.f); 268 | endTime = static_cast(static_cast(sliderTime) * repeatCount) + startTime; 269 | 270 | sliderTickCount = pixelLength / (100.f * mapSliderMultiplier / mapSliderTickRate / timingPointMultiplier); 271 | if (sliderTickCount < 1.f) sliderTickCount = 1.f; 272 | 273 | sliderPoints.push_back(startPosition); 274 | 275 | auto sliderTokens = split_string(tokens.at(5), L"|"); 276 | for (int i = 1; i < static_cast(sliderTokens.size()); i++) { 277 | auto p = split_string(sliderTokens.at(i), L":"); 278 | vec2f point(stof(p.at(0)), stof(p.at(1))); 279 | sliderPoints.push_back(point); 280 | } 281 | 282 | if (sliderPoints.at(sliderPoints.size() - 1) == sliderPoints.at(sliderPoints.size() - 2)) 283 | sliderPoints.resize(sliderPoints.size() - 1); 284 | 285 | sliderType = sliderTokens[0].c_str()[0]; 286 | 287 | if (sliderType == L'L' || sliderType == L'C') { 288 | for (int i = 1; i < static_cast(sliderPoints.size()); i++) { 289 | Segment seg; 290 | seg.points = { sliderPoints.at(i - 1), sliderPoints.at(i) }; 291 | 292 | sliderSegments.push_back(seg); 293 | } 294 | } 295 | else if (sliderType == L'P' && sliderPoints.size() == 3) { 296 | vec2f start = sliderPoints.at(0); 297 | vec2f mid = sliderPoints.at(1); 298 | vec2f end = sliderPoints.at(2); 299 | 300 | vec2f mida = start.midPoint(mid); 301 | vec2f midb = end.midPoint(mid); 302 | vec2f nora = mid.cpy().sub(start).nor(); 303 | vec2f norb = mid.cpy().sub(end).nor(); 304 | 305 | circleCenter = Intersect(mida, nora, midb, norb); 306 | 307 | vec2f startAngPoint = start.cpy().sub(circleCenter); 308 | vec2f midAngPoint = mid.sub(circleCenter); 309 | vec2f endAngPoint = end.cpy().sub(circleCenter); 310 | 311 | startAng = atan2(startAngPoint.y, startAngPoint.x); 312 | midAng = atan2(midAngPoint.y, midAngPoint.x); 313 | endAng = atan2(endAngPoint.y, endAngPoint.x); 314 | 315 | radius = startAngPoint.length(); 316 | 317 | if (!isIn(startAng, midAng, endAng)) { 318 | if (abs(startAng + TWO_PI - endAng) < TWO_PI && isIn(startAng + TWO_PI, midAng, endAng)) 319 | startAng += TWO_PI; 320 | else if (abs(startAng - (endAng + TWO_PI)) < TWO_PI && isIn(startAng, midAng, endAng + TWO_PI)) 321 | endAng += TWO_PI; 322 | else if (abs(startAng - TWO_PI - endAng) < TWO_PI && isIn(startAng - TWO_PI, midAng, endAng)) 323 | startAng -= TWO_PI; 324 | else if (abs(startAng - (endAng - TWO_PI)) < TWO_PI && isIn(startAng, midAng, endAng - TWO_PI)) 325 | endAng -= TWO_PI; 326 | else { 327 | /* EventLog */ fwprintf(wEventLog, (L"[ERROR] Angle error: (" + to_wstring(startAng) + L", " + to_wstring(midAng) + L", " + to_wstring(endAng) + L")\n").c_str()); 328 | fflush(wEventLog); 329 | } 330 | } 331 | float arcAng = pixelLength / radius; 332 | if (endAng > startAng) endAng = startAng + arcAng; 333 | else endAng = startAng - arcAng; 334 | 335 | centerP = circleCenter; 336 | radiusP = radius; 337 | } 338 | else { 339 | sliderType = L'B'; 340 | vector> curveList; 341 | vector curve; 342 | 343 | for (auto point : sliderPoints) { 344 | if (curve.size() > 1) { 345 | if (point == curve.at(curve.size() - 1)) { 346 | curveList.push_back(curve); 347 | curve.clear(); 348 | } 349 | } curve.push_back(point); 350 | } 351 | curveList.push_back(curve); 352 | curve.clear(); 353 | 354 | for (auto plot : curveList) { 355 | Segment seg; seg.points = plot; 356 | sliderSegments.push_back(seg); 357 | } 358 | } 359 | } 360 | else if (getHitType() == HIT_SPINNER) endTime = _wtoi(tokens.at(5).c_str()); 361 | } 362 | 363 | ~HitObject() {} 364 | }; 365 | -------------------------------------------------------------------------------- /Osu!Bot V2/Osu!Bot V2.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {4A39DBAF-D7B0-454F-9C13-03A75985CB3E} 24 | Win32Proj 25 | OsuBotV20 26 | 10.0.16299.0 27 | Osu!Bot V2 28 | 29 | 30 | 31 | Application 32 | true 33 | v141 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v141 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v141 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | false 75 | 76 | 77 | false 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Create 88 | Level4 89 | MaxSpeed 90 | true 91 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 92 | false 93 | Speed 94 | true 95 | Default 96 | ProgramDatabase 97 | stdcpplatest 98 | CompileAsCpp 99 | false 100 | true 101 | true 102 | 103 | 104 | Windows 105 | DebugFastLink 106 | Default 107 | true 108 | 109 | 110 | 111 | 112 | Create 113 | Level4 114 | MaxSpeed 115 | true 116 | _WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 117 | false 118 | false 119 | Speed 120 | Default 121 | true 122 | stdcpplatest 123 | CompileAsCpp 124 | ProgramDatabase 125 | false 126 | true 127 | true 128 | 129 | 130 | Windows 131 | DebugFastLink 132 | Default 133 | true 134 | 135 | 136 | 137 | 138 | Level4 139 | true 140 | true 141 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 142 | ProgramDatabase 143 | stdcpplatest 144 | true 145 | CompileAsCpp 146 | MaxSpeed 147 | Speed 148 | Create 149 | false 150 | false 151 | true 152 | 153 | 154 | Windows 155 | true 156 | true 157 | DebugFastLink 158 | Default 159 | 160 | 161 | 162 | 163 | Create 164 | Level4 165 | MaxSpeed 166 | true 167 | false 168 | true 169 | _WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 170 | false 171 | false 172 | stdcpplatest 173 | true 174 | Default 175 | Speed 176 | false 177 | false 178 | CompileAsCpp 179 | true 180 | 181 | 182 | Windows 183 | true 184 | true 185 | DebugFastLink 186 | Default 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | Create 209 | Create 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | -------------------------------------------------------------------------------- /Osu!Bot V2/Osu!Bot V2.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {a12ea123-11cb-464d-9f89-22337794502d} 18 | 19 | 20 | {f5fdf684-24b8-45d2-aa9e-f6732554f8e4} 21 | 22 | 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files\OsuBot 44 | 45 | 46 | Header Files\OsuBot 47 | 48 | 49 | Header Files\OsuBot 50 | 51 | 52 | Header Files\OsuBot 53 | 54 | 55 | Header Files\OsuBot 56 | 57 | 58 | Header Files\OsuBot 59 | 60 | 61 | Header Files\OsuBot 62 | 63 | 64 | Header Files\OsuBot 65 | 66 | 67 | 68 | 69 | Source Files 70 | 71 | 72 | Source Files 73 | 74 | 75 | 76 | 77 | Resource Files 78 | 79 | 80 | Resource Files 81 | 82 | 83 | Resource Files 84 | 85 | 86 | 87 | 88 | Resource Files 89 | 90 | 91 | 92 | 93 | Project Files 94 | 95 | 96 | -------------------------------------------------------------------------------- /Osu!Bot V2/OsuBot.cpp: -------------------------------------------------------------------------------- 1 | // OsuBot.cpp : Defines the entry point for the application. 2 | // 3 | 4 | #define _CRT_SECURE_NO_WARNINGS 5 | 6 | #define MAX_LOADSTRING 100 7 | #define BTN_ButtonOpenSongFolder 3001 8 | #define BTN_ButtonOpenSongFile 3002 9 | #define CB_CheckBoxAutoOpenSong 3003 10 | #define CB_CheckBoxHardrockFlip 3004 11 | #define TB_TrackBarDanceAmplifier 3005 12 | #define CB_ComboBoxDanceModeMoveTo 3006 13 | #define CB_ComboBoxDanceModeSlider 3007 14 | #define CB_ComboBoxDanceModeSpinner 3008 15 | 16 | #include "stdafx.h" 17 | 18 | #include "GlobalVariables.h" 19 | #include "DrawTextToWindow.h" 20 | #include "ConfigurationFile.h" 21 | #include "OsuBot.h" 22 | 23 | using namespace std; 24 | 25 | // Global Variables: 26 | HINSTANCE hInst; // current instance 27 | WCHAR szTitle[MAX_LOADSTRING]; // The title bar text 28 | WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name 29 | 30 | 31 | // User Global Variables: 32 | bool songFileCheck; 33 | 34 | // Standard Variables for UI: 35 | RECT rectOsuBotWindow; 36 | RECT rectDanceAmplifier = { 15, 150, 200, 170 }; 37 | RECT rectDanceModeMoveTo = { 210, 150, 320, 175 }; 38 | RECT rectDanceModeSlider = { 330, 150, 440, 175 }; 39 | RECT rectDanceModeSpinner = { 450, 150, 560, 175 }; 40 | // User Global Variables END; 41 | 42 | // Forward declarations of functions included in this code module: 43 | ATOM MyRegisterClass(HINSTANCE hInstance); 44 | BOOL InitInstance(HINSTANCE, int); 45 | LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 46 | INT_PTR CALLBACK Settings(HWND, UINT, WPARAM, LPARAM); 47 | INT_PTR CALLBACK ErrorBox(HWND, UINT, WPARAM, LPARAM); 48 | INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); 49 | 50 | int APIENTRY wWinMain(_In_ HINSTANCE hInstance, 51 | _In_opt_ HINSTANCE hPrevInstance, 52 | _In_ LPWSTR lpCmdLine, 53 | _In_ int nCmdShow) { 54 | UNREFERENCED_PARAMETER(hPrevInstance); 55 | UNREFERENCED_PARAMETER(lpCmdLine); 56 | 57 | // TODO: Place user added startup code here. 58 | CreateDirectory(LPCTSTR(L"Data"), NULL); 59 | CreateDirectory(LPCTSTR(L"Data\\Logs"), NULL); 60 | 61 | 62 | FILE* rEventLog = _wfopen(L"Data\\Logs\\Events.log", L"r"); 63 | if (rEventLog != NULL) { 64 | TCHAR buff[MAX_LOADSTRING]; 65 | fgetws(buff, MAX_LOADSTRING, rEventLog); 66 | 67 | wstring timestamp(buff); 68 | timestamp.assign(timestamp.begin() + 22U, timestamp.end() - 1U); 69 | 70 | for (unsigned int i = 0; i < timestamp.size() - 1; i++) 71 | if (timestamp.at(i) == L':') 72 | timestamp.at(i) = L'.'; 73 | 74 | wstring backupLog = (L"Data\\Logs\\Events (" + timestamp + L").log"); 75 | 76 | FILE* bEventLog = _wfopen(&backupLog[0], L"w"); 77 | 78 | fputws(buff, bEventLog); 79 | while (!feof(rEventLog)) 80 | if (fgetws(buff, MAX_LOADSTRING, rEventLog) != NULL) 81 | fputws(buff, bEventLog); 82 | fflush(bEventLog); 83 | fclose(bEventLog); 84 | } 85 | 86 | wEventLog = _wfopen(L"Data\\Logs\\Events.log", L"w"); 87 | if (wEventLog == NULL) { DialogBox(hInst, MAKEINTRESOURCE(IDD_ERRORBOX), hWnd, ErrorBox); } 88 | 89 | time_t timeStamp = time(nullptr); 90 | wstring timeString = _wasctime(localtime(&timeStamp)); 91 | timeString.erase(timeString.end() - 1, timeString.end()); 92 | wstring logString = L"Events.log created at " + timeString; 93 | 94 | /* EventLog */ fwprintf(wEventLog, (logString + L"\n").c_str()); 95 | fflush(wEventLog); 96 | 97 | 98 | if (_wfopen(L"Data\\configFile.cfg", L"r")) { 99 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] ConfigFile found.\n"); 100 | 101 | ReadAllConfigSettings(); 102 | } 103 | else { 104 | /* EventLog */ fwprintf(wEventLog, L"[WARNING] ConfigFile not found!\n"); 105 | 106 | int configMB = MessageBox(hWnd, 107 | L"No configFile was found!\nDo you want to generate a new configFile?\n\nIf this doesn't work try manualy creating an empty file named \"configFile.cfg\" under the \"Data\" folder.", 108 | L"ConfigFile not found!", 109 | MB_ICONWARNING | MB_YESNO | MB_APPLMODAL); 110 | 111 | if (configMB == IDYES) { 112 | CreateNewConfigFile(); 113 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] ConfigFile generated successful.\n"); 114 | 115 | ReadAllConfigSettings(); 116 | } 117 | else 118 | /* EventLog */ fwprintf(wEventLog, L"[WARNING] ConfigFile was not auto generated.\n"); 119 | } 120 | fflush(wEventLog); 121 | 122 | 123 | thread findGameThread(FindGame); 124 | findGameThread.detach(); 125 | // TODO END; 126 | 127 | // Initialize global strings 128 | LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 129 | LoadStringW(hInstance, IDC_OSUBOTV2, szWindowClass, MAX_LOADSTRING); 130 | MyRegisterClass(hInstance); 131 | 132 | // Perform application initialization: 133 | if (!InitInstance(hInstance, nCmdShow)) { 134 | return FALSE; 135 | } 136 | 137 | HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_OSUBOTV2)); 138 | 139 | MSG msg; 140 | 141 | // Main message loop: 142 | while (GetMessage(&msg, nullptr, 0, 0)) { 143 | if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { 144 | TranslateMessage(&msg); 145 | DispatchMessage(&msg); 146 | } 147 | } 148 | 149 | return (int)msg.wParam; 150 | } 151 | 152 | // 153 | // FUNCTION: MyRegisterClass() 154 | // 155 | // PURPOSE: Registers the window class. 156 | // 157 | ATOM MyRegisterClass(HINSTANCE hInstance) { 158 | WNDCLASSEXW wcex; 159 | 160 | wcex.cbSize = sizeof(WNDCLASSEX); 161 | 162 | wcex.style = CS_HREDRAW | CS_VREDRAW; 163 | wcex.lpfnWndProc = WndProc; 164 | wcex.cbClsExtra = 0; 165 | wcex.cbWndExtra = 0; 166 | wcex.hInstance = hInstance; 167 | wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_OSUBOTV2)); 168 | wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); 169 | wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 170 | wcex.lpszMenuName = MAKEINTRESOURCE(IDC_OSUBOTV2); 171 | wcex.lpszClassName = szWindowClass; 172 | wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); 173 | 174 | return RegisterClassExW(&wcex); 175 | } 176 | 177 | // 178 | // FUNCTION: InitInstance(HINSTANCE, int) 179 | // 180 | // PURPOSE: Saves instance handle and creates main window 181 | // 182 | // COMMENTS: 183 | // 184 | // In this function, we save the instance handle in a global variable and 185 | // create and display the main program window. 186 | // 187 | BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { 188 | hInst = hInstance; // Store instance handle in our global variable 189 | 190 | hWnd = CreateWindow( 191 | szWindowClass, 192 | szTitle, 193 | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | 194 | CS_VREDRAW | CS_HREDRAW, 195 | CW_USEDEFAULT, CW_USEDEFAULT, 196 | nWidth, nHeight, 197 | nullptr, 198 | nullptr, 199 | hInstance, 200 | nullptr); 201 | 202 | if (!hWnd) { 203 | return FALSE; 204 | } 205 | 206 | ShowWindow(hWnd, nCmdShow); 207 | UpdateWindow(hWnd); 208 | 209 | return TRUE; 210 | } 211 | 212 | // 213 | // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) 214 | // 215 | // PURPOSE: Processes messages for the main window. 216 | // 217 | // WM_COMMAND - process the application menu 218 | // WM_PAINT - Paint the main window 219 | // WM_DESTROY - post a quit message and return 220 | // 221 | // 222 | LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { 223 | 224 | switch (message) { 225 | case WM_GETMINMAXINFO: 226 | { 227 | LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; 228 | lpMMI->ptMinTrackSize.x = 600; 229 | lpMMI->ptMinTrackSize.y = 350; 230 | break; 231 | } 232 | case WM_CTLCOLORSTATIC: 233 | { 234 | SetBkColor((HDC)wParam, RGB(255, 255, 255)); 235 | return (LRESULT)GetStockObject(WHITE_BRUSH); 236 | } 237 | case WM_HSCROLL: 238 | { 239 | switch (LOWORD(wParam)) { 240 | case TB_ENDTRACK: 241 | ULONG dwPos = (ULONG)SendMessage(hwndTrackBarDanceAmplifier, TBM_GETPOS, NULL, NULL); 242 | 243 | trackBarPos = (INT)dwPos; 244 | Amplifier = static_cast(dwPos) / 80.f; 245 | 246 | UpdateConfigFile(danceSettings); 247 | } 248 | } 249 | case WM_COMMAND: 250 | { 251 | int wmId = LOWORD(wParam); 252 | switch (wmId) { 253 | case BTN_ButtonOpenSongFolder: 254 | { 255 | SendMessage(hwndButtonOpenSongFolder, WM_SETTEXT, 0, LPARAM(L"...")); 256 | 257 | statusText = L"Selecting Songs Folder..."; 258 | DrawTextToWindow(hwnd, statusText, rectStatus); 259 | 260 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] User selecting/changing Songs Folder.\n"); 261 | fflush(wEventLog); 262 | 263 | pathSet = OpenSongFolder(); 264 | 265 | if (!pathSet) { 266 | statusText = L"No Songs Folder Selected!"; 267 | DrawTextToWindow(hwnd, statusText, rectStatus); 268 | 269 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] No Songs folder Selected.\n"); 270 | } 271 | else { 272 | DrawTextToWindow(hwnd, songsPath.c_str(), rectSongsFolder); 273 | statusText = L"Songs Folder Successfully Selected!"; 274 | DrawTextToWindow(hwnd, statusText, rectStatus); 275 | 276 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] Songs Folder Successfully Selected.\n or not changed.\n"); 277 | 278 | UpdateConfigFile(songsFolderPath); 279 | } 280 | fflush(wEventLog); 281 | 282 | SendMessage(hwndButtonOpenSongFolder, WM_SETTEXT, 0, ((pathSet) ? (LPARAM(L"Change")) : (LPARAM(L"Select")))); 283 | break; 284 | } 285 | case BTN_ButtonOpenSongFile: 286 | { 287 | SendMessage(hwndButtonOpenSongFile, WM_SETTEXT, 0, LPARAM(L"...")); 288 | 289 | statusText = L"Selecting a Beatmap..."; 290 | DrawTextToWindow(hwnd, statusText, rectStatus); 291 | 292 | songFileCheck = OpenSongManual(); 293 | SongFileCheck(songFileCheck, userSelect); 294 | 295 | SendMessage(hwndButtonOpenSongFile, WM_SETTEXT, 0, ((songFileCheck) ? (LPARAM(L"Change")) : (LPARAM(L"Select")))); 296 | break; 297 | } 298 | case CB_CheckBoxAutoOpenSong: 299 | { 300 | if (autoOpenSong) 301 | autoOpenSong = FALSE; 302 | else autoOpenSong = TRUE; 303 | 304 | wstring autoState = (autoOpenSong ? L"Enabled" : L"Disabled"); 305 | /* EventLog */ fwprintf(wEventLog, (L"[EVENT] Auto opening of beatmap: " + autoState + L"\n").c_str()); 306 | fflush(wEventLog); 307 | 308 | if (autoOpenSong && !pathSet) { 309 | statusText = L"Please select \"osu!\" Songs Folder for Osu!Bot to autosearch in for the beatmaps!"; 310 | DrawTextToWindow(hwnd, statusText, rectStatus); 311 | } 312 | 313 | break; 314 | } 315 | case CB_CheckBoxHardrockFlip: 316 | { 317 | if (hardrockFlip) 318 | hardrockFlip = FALSE; 319 | else hardrockFlip = TRUE; 320 | 321 | wstring hardrockState = (hardrockFlip ? L"Enabled" : L"Disabled"); 322 | /* EventLog */ fwprintf(wEventLog, (L"[EVENT] Hardrock mod: " + hardrockState + L"\n").c_str()); 323 | fflush(wEventLog); 324 | 325 | break; 326 | } 327 | case CB_ComboBoxDanceModeMoveTo: 328 | { 329 | if (HIWORD(wParam) == CBN_SELCHANGE) { 330 | int index = (INT)SendMessage(hwndComboBoxDanceModeMoveTo, CB_GETCURSEL, NULL, NULL); 331 | 332 | modeMoveTo = index; 333 | if (index < MODE_STANDARD || index > MODE_PREDICTING) { 334 | modeMoveTo = MODE_NONE; 335 | } 336 | } 337 | UpdateConfigFile(danceSettings); 338 | break; 339 | } 340 | case CB_ComboBoxDanceModeSlider: 341 | { 342 | if (HIWORD(wParam) == CBN_SELCHANGE) { 343 | int index = (INT)SendMessage(hwndComboBoxDanceModeSlider, CB_GETCURSEL, NULL, NULL); 344 | 345 | modeSlider = index; 346 | if (index < MODE_STANDARD || index > MODE_PREDICTING) { 347 | modeSlider = MODE_NONE; 348 | } 349 | } 350 | UpdateConfigFile(danceSettings); 351 | break; 352 | } 353 | case CB_ComboBoxDanceModeSpinner: 354 | { 355 | if (HIWORD(wParam) == CBN_SELCHANGE) { 356 | int index = (INT)SendMessage(hwndComboBoxDanceModeSpinner, CB_GETCURSEL, NULL, NULL); 357 | 358 | modeSpinner = index; 359 | if (index < MODE_STANDARD || index > MODE_PREDICTING) { 360 | modeSpinner = MODE_NONE; 361 | } 362 | } 363 | UpdateConfigFile(danceSettings); 364 | break; 365 | } 366 | case ID_DATAFILES_OPENDATAFOLDER: 367 | { 368 | if (PtrToLong(ShellExecute(NULL, LPCTSTR(L"explore"), LPCTSTR(L"Data"), NULL, NULL, SW_SHOW)) == ERROR_FILE_NOT_FOUND) 369 | DialogBox(hInst, MAKEINTRESOURCE(IDD_ERRORBOX), hwnd, ErrorBox); 370 | 371 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] User Opening \"Data\" Folder.\n"); 372 | fflush(wEventLog); 373 | break; 374 | } 375 | case ID_DATAFILES_OPENSONGDATA: 376 | { 377 | if (PtrToLong(ShellExecute(NULL, LPCTSTR(L"open"), LPCTSTR(L"SFData.txt"), NULL, LPCTSTR(L"Data"), SW_SHOW)) == ERROR_FILE_NOT_FOUND) 378 | DialogBox(hInst, MAKEINTRESOURCE(IDD_ERRORBOX), hwnd, ErrorBox); 379 | 380 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] User Opening \"SFData.txt\".\n"); 381 | fflush(wEventLog); 382 | break; 383 | } 384 | case ID_DATAFILES_OPENBEATMAPDATA: 385 | { 386 | if (PtrToLong(ShellExecute(NULL, LPCTSTR(L"open"), LPCTSTR(L"BMData.txt"), NULL, LPCTSTR(L"Data"), SW_SHOW)) == ERROR_FILE_NOT_FOUND) 387 | DialogBox(hInst, MAKEINTRESOURCE(IDD_ERRORBOX), hwnd, ErrorBox); 388 | 389 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] User Opening \"BMData.txt\".\n"); 390 | fflush(wEventLog); 391 | break; 392 | } 393 | case ID_DATAFILES_OPENEVENTLOG: 394 | { 395 | if (PtrToLong(ShellExecute(NULL, LPCTSTR(L"open"), LPCTSTR(L"Events.log"), NULL, LPCTSTR(L"Data\\Logs"), SW_SHOW)) == ERROR_FILE_NOT_FOUND) 396 | DialogBox(hInst, MAKEINTRESOURCE(IDD_ERRORBOX), hwnd, ErrorBox); 397 | 398 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] User Opening \"Events.log\".\n"); 399 | fflush(wEventLog); 400 | break; 401 | } 402 | case IDM_CLEARDATA: 403 | { 404 | int clearDataMB = MessageBox(hwnd, 405 | L"Osu!Bot will clear/clean up all collected data (logs).\nNOTE: this will clear ALL logs (The config file will not be removed!)\n\nAre you sure you want to delete the data files?", 406 | L"Delete Osu!Bot data files?", 407 | MB_ICONWARNING | MB_YESNO | MB_APPLMODAL); 408 | if (clearDataMB == IDNO) 409 | break; 410 | 411 | DeleteFile(L"Data\\SFData.txt"); 412 | DeleteFile(L"Data\\BMData.txt"); 413 | DeleteFile(L"Data\\Logs"); 414 | 415 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] User cleared data Files.\n"); 416 | fflush(wEventLog); 417 | 418 | SendMessage(hwndButtonOpenSongFolder, WM_SETTEXT, 0, LPARAM(L"Select")); 419 | SendMessage(hwndButtonOpenSongFile, WM_SETTEXT, 0, LPARAM(L"Select")); 420 | 421 | DrawTextToWindow(hwnd, songsFolderText, rectSongsFolder); 422 | DrawTextToWindow(hwnd, songFileText, rectSongFile); 423 | break; 424 | } 425 | case IDM_SETTINGS: 426 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] User Opened Settings.\n"); 427 | DialogBox(hInst, MAKEINTRESOURCE(IDD_SETTINGSBOX), hwnd, Settings); 428 | fflush(wEventLog); 429 | break; 430 | 431 | case IDM_ABOUT: 432 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] User opened about box.\n"); 433 | DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, About); 434 | fflush(wEventLog); 435 | break; 436 | 437 | case IDM_EXIT: 438 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] User Exited the program.\n"); 439 | DestroyWindow(hwnd); 440 | fflush(wEventLog); 441 | break; 442 | 443 | default: 444 | return DefWindowProc(hwnd, message, wParam, lParam); 445 | } break; 446 | } 447 | case WM_PAINT: 448 | { 449 | // Dance Settings Strings 450 | LPCTSTR& modeNone = (LPCTSTR&)L"None"; 451 | LPCTSTR& modeStandard = (LPCTSTR&)L"Standard"; 452 | LPCTSTR& modeFlowing = (LPCTSTR&)L"Flowing"; 453 | LPCTSTR& modePredicting = (LPCTSTR&)L"Predicting"; 454 | 455 | // Clean-up before re-draw hwnds 456 | DestroyWindow(hwndButtonOpenSongFile); 457 | DestroyWindow(hwndButtonOpenSongFolder); 458 | DestroyWindow(hwndTrackBarDanceAmplifier); 459 | DestroyWindow(hwndProgressBar); 460 | 461 | 462 | PAINTSTRUCT ps; 463 | HDC hdc = BeginPaint(hwnd, &ps); 464 | 465 | GetClientRect(hwnd, &rectOsuBotWindow); 466 | nHeight = rectOsuBotWindow.bottom > 290 ? rectOsuBotWindow.bottom : 290; 467 | nWidth = rectOsuBotWindow.right > 585 ? rectOsuBotWindow.right : 585; 468 | 469 | rectSongsFolder = { 10, 10, nWidth - 140, 50 }; 470 | rectSongFile = { 10, 80, nWidth - 140, 120 }; 471 | rectStatus = { 15, nHeight - 65, nWidth - 30, rectStatus.top + 18 }; 472 | 473 | 474 | // TODO: Add any drawing code that uses hdc here... 475 | // Status 476 | DrawTextToWindow( 477 | hdc, 478 | statusText, 479 | rectStatus 480 | ); 481 | 482 | // Text 483 | DrawTextToWindow( 484 | hdc, 485 | pathSet ? songsPath : songsFolderText, 486 | rectSongsFolder 487 | ); 488 | 489 | DrawTextToWindow( 490 | hdc, 491 | songFileCheck ? displayBeatmapPath : songFileText, 492 | rectSongFile 493 | ); 494 | 495 | DrawTextToWindow( 496 | hdc, 497 | L"Dance Amplifier", 498 | rectDanceAmplifier 499 | ); 500 | 501 | DrawTextToWindow( 502 | hdc, 503 | L"Mode MoveTo", 504 | rectDanceModeMoveTo 505 | ); 506 | 507 | DrawTextToWindow( 508 | hdc, 509 | L"Mode Slider", 510 | rectDanceModeSlider 511 | ); 512 | 513 | DrawTextToWindow( 514 | hdc, 515 | L"Mode Spinner", 516 | rectDanceModeSpinner 517 | ); 518 | 519 | // Buttons 520 | hwndButtonOpenSongFolder = CreateWindow( 521 | WC_BUTTON, 522 | pathSet ? L"Change" : L"Select", 523 | WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 524 | (nWidth - 110), 10, 525 | 100, 40, 526 | hwnd, 527 | (HMENU)BTN_ButtonOpenSongFolder, 528 | (HINSTANCE)LongToPtr(GetWindowLong(hwnd, GWLP_HINSTANCE)), 529 | nullptr 530 | ); 531 | 532 | hwndButtonOpenSongFile = CreateWindow( 533 | WC_BUTTON, 534 | songFileCheck ? L"Change" : L"Select", 535 | WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 536 | (nWidth - 110), 80, 537 | 100, 40, 538 | hwnd, 539 | (HMENU)BTN_ButtonOpenSongFile, 540 | (HINSTANCE)LongToPtr(GetWindowLong(hwnd, GWLP_HINSTANCE)), 541 | nullptr 542 | ); 543 | 544 | // Check Boxes 545 | hwndCheckBoxAutoOpenSong = CreateWindowEx( 546 | NULL, 547 | WC_BUTTON, 548 | L"Auto Open Song", 549 | WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX, 550 | 10, 60, 551 | 140, 15, 552 | hwnd, 553 | (HMENU)CB_CheckBoxAutoOpenSong, 554 | (HINSTANCE)LongToPtr(GetWindowLong(hwnd, GWLP_HINSTANCE)), 555 | nullptr 556 | ); 557 | 558 | SendMessage(hwndCheckBoxAutoOpenSong, BM_SETCHECK, WPARAM(autoOpenSong), NULL); 559 | 560 | hwndCheckBoxHardrockFlip = CreateWindowEx( 561 | NULL, 562 | WC_BUTTON, 563 | L"Hardrock (flip)", 564 | WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX, 565 | 10, 130, 566 | 140, 15, 567 | hwnd, 568 | (HMENU)CB_CheckBoxHardrockFlip, 569 | (HINSTANCE)LongToPtr(GetWindowLong(hwnd, GWLP_HINSTANCE)), 570 | nullptr 571 | ); 572 | 573 | SendMessage(hwndCheckBoxHardrockFlip, BM_SETCHECK, WPARAM(hardrockFlip), NULL); 574 | 575 | // Dance Settings 576 | hwndTrackBarDanceAmplifier = CreateWindowEx( 577 | NULL, 578 | TRACKBAR_CLASS, 579 | NULL, 580 | WS_VISIBLE | WS_CHILD | TBS_HORZ | TBS_BOTTOM | TBS_DOWNISLEFT | TBS_AUTOTICKS | TBS_TOOLTIPS, 581 | 10, 170, 582 | 180, 30, 583 | hwnd, 584 | (HMENU)TB_TrackBarDanceAmplifier, 585 | (HINSTANCE)LongToPtr(GetWindowLong(hwnd, GWLP_HINSTANCE)), 586 | nullptr 587 | ); 588 | 589 | SendMessage(hwndTrackBarDanceAmplifier, TBM_SETRANGE, FALSE, MAKELPARAM(50, 200)); 590 | SendMessage(hwndTrackBarDanceAmplifier, TBM_SETTICFREQ, (WPARAM)10, NULL); 591 | SendMessage(hwndTrackBarDanceAmplifier, TBM_SETPOS, TRUE, trackBarPos); 592 | 593 | hwndComboBoxDanceModeMoveTo = CreateWindowEx( 594 | NULL, 595 | WC_COMBOBOX, 596 | L"Mode MoveTo", 597 | WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST, 598 | 210, 175, 599 | 110, 100, 600 | hwnd, 601 | (HMENU)CB_ComboBoxDanceModeMoveTo, 602 | (HINSTANCE)LongToPtr(GetWindowLong(hwnd, GWLP_HINSTANCE)), 603 | nullptr 604 | ); 605 | 606 | SendMessage(hwndComboBoxDanceModeMoveTo, CB_ADDSTRING, NULL, (LPARAM)&modeNone); 607 | SendMessage(hwndComboBoxDanceModeMoveTo, CB_ADDSTRING, NULL, (LPARAM)&modeStandard); 608 | SendMessage(hwndComboBoxDanceModeMoveTo, CB_ADDSTRING, NULL, (LPARAM)&modeFlowing); 609 | SendMessage(hwndComboBoxDanceModeMoveTo, CB_ADDSTRING, NULL, (LPARAM)&modePredicting); 610 | SendMessage(hwndComboBoxDanceModeMoveTo, CB_SETCURSEL, (WPARAM)modeMoveTo, NULL); 611 | 612 | hwndComboBoxDanceModeSlider = CreateWindowEx( 613 | NULL, 614 | WC_COMBOBOX, 615 | L"Mode Slider", 616 | WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST, 617 | 330, 175, 618 | 110, 100, 619 | hwnd, 620 | (HMENU)CB_ComboBoxDanceModeSlider, 621 | (HINSTANCE)LongToPtr(GetWindowLong(hwnd, GWLP_HINSTANCE)), 622 | nullptr 623 | ); 624 | 625 | SendMessage(hwndComboBoxDanceModeSlider, CB_ADDSTRING, NULL, (LPARAM)&modeNone); 626 | SendMessage(hwndComboBoxDanceModeSlider, CB_ADDSTRING, NULL, (LPARAM)&modeStandard); 627 | SendMessage(hwndComboBoxDanceModeSlider, CB_ADDSTRING, NULL, (LPARAM)&modeFlowing); 628 | SendMessage(hwndComboBoxDanceModeSlider, CB_ADDSTRING, NULL, (LPARAM)&modePredicting); 629 | SendMessage(hwndComboBoxDanceModeSlider, CB_SETCURSEL, (WPARAM)modeSlider, NULL); 630 | 631 | hwndComboBoxDanceModeSpinner = CreateWindowEx( 632 | NULL, 633 | WC_COMBOBOX, 634 | L"Mode Spinner", 635 | WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST, 636 | 450, 175, 637 | 110, 100, 638 | hwnd, 639 | (HMENU)CB_ComboBoxDanceModeSpinner, 640 | (HINSTANCE)LongToPtr(GetWindowLong(hwnd, GWLP_HINSTANCE)), 641 | nullptr 642 | ); 643 | 644 | SendMessage(hwndComboBoxDanceModeSpinner, CB_ADDSTRING, NULL, (LPARAM)&modeNone); 645 | SendMessage(hwndComboBoxDanceModeSpinner, CB_ADDSTRING, NULL, (LPARAM)&modeStandard); 646 | SendMessage(hwndComboBoxDanceModeSpinner, CB_ADDSTRING, NULL, (LPARAM)&modeFlowing); 647 | SendMessage(hwndComboBoxDanceModeSpinner, CB_ADDSTRING, NULL, (LPARAM)&modePredicting); 648 | SendMessage(hwndComboBoxDanceModeSpinner, CB_SETCURSEL, (WPARAM)modeSpinner, NULL); 649 | 650 | // Utilities 651 | hwndProgressBar = CreateWindowEx( 652 | NULL, 653 | PROGRESS_CLASS, 654 | NULL, 655 | WS_VISIBLE | WS_CHILD | PBS_SMOOTH, 656 | 10, (nHeight - 40), 657 | (nWidth - 20), 30, 658 | hwnd, 659 | nullptr, 660 | hInst, 661 | nullptr 662 | ); 663 | 664 | SendMessage(hwndProgressBar, PBM_SETRANGE, NULL, MAKELPARAM(0, hitObjects.size() + 1)); 665 | SendMessage(hwndProgressBar, PBM_SETSTEP, WPARAM(1), NULL); 666 | SendMessage(hwndProgressBar, PBM_SETPOS, WPARAM(objectNumber), NULL); 667 | 668 | // TODO END; 669 | EndPaint(hwnd, &ps); 670 | break; 671 | } 672 | case WM_DESTROY: 673 | PostQuitMessage(0); 674 | break; 675 | 676 | default: 677 | return DefWindowProc(hwnd, message, wParam, lParam); 678 | } return 0; 679 | } 680 | 681 | // Message handler for settings box. 682 | INT_PTR CALLBACK Settings(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { 683 | UNREFERENCED_PARAMETER(lParam); 684 | switch (message) { 685 | case WM_INITDIALOG: 686 | { 687 | for (int i = 0; i <= 5; i++) { 688 | int intValue; 689 | wstring str = L""; 690 | wstringstream stream; 691 | stream << hex; 692 | 693 | if (i == 0) 694 | intValue = threadOffset; 695 | else 696 | intValue = offsets[i - 1]; 697 | 698 | if (intValue < 0) { 699 | intValue *= -1; 700 | stream << intValue; 701 | str = L"-"; 702 | } 703 | else { 704 | stream << intValue; 705 | } 706 | 707 | str += stream.str(); 708 | 709 | SetDlgItemText(hDlg, IDC_THREADOFFSET + i, LPCTSTR(str.c_str())); 710 | } 711 | 712 | 713 | LPCTSTR& inputKeyboard = (LPCTSTR&)L"Keyboard"; 714 | SendDlgItemMessage(hDlg, IDC_INPUTMETHODE, CB_ADDSTRING, NULL, (LPARAM)&inputKeyboard); 715 | LPCTSTR& inputMouse = (LPCTSTR&)L"Mouse"; 716 | SendDlgItemMessage(hDlg, IDC_INPUTMETHODE, CB_ADDSTRING, NULL, (LPARAM)&inputMouse); 717 | SendDlgItemMessage(hDlg, IDC_INPUTMETHODE, CB_SETCURSEL, NULL, (LPARAM)!inputKeyBoard); 718 | 719 | 720 | TCHAR* keyText = new TCHAR[MAXCHAR]; 721 | if (GetKeyNameText(inputMainKey << 16, keyText, MAXCHAR)) { 722 | SetDlgItemText(hDlg, IDC_INPUTKEYMAIN, keyText); 723 | } 724 | 725 | if (GetKeyNameText(inputAltKey << 16, keyText, MAXCHAR)) { 726 | SetDlgItemText(hDlg, IDC_INPUTKEYALT, keyText); 727 | } 728 | 729 | delete keyText; 730 | 731 | return (INT_PTR)TRUE; 732 | } 733 | case WM_COMMAND: 734 | switch (LOWORD(wParam)) { 735 | case IDOK: 736 | { 737 | TCHAR method[MAXCHAR]; 738 | 739 | GetDlgItemText(hDlg, IDC_INPUTMETHODE, (LPTSTR)method, MAXCHAR); 740 | inputKeyBoard = _tcscmp(method, L"Keyboard") == 0 ? TRUE : FALSE; 741 | 742 | 743 | TCHAR key[MAXCHAR]; 744 | 745 | GetDlgItemText(hDlg, IDC_INPUTKEYMAIN, (LPTSTR)key, MAXCHAR); 746 | inputMainKey = LOWORD(OemKeyScan(key[0])); 747 | 748 | GetDlgItemText(hDlg, IDC_INPUTKEYALT, (LPTSTR)key, MAXCHAR); 749 | inputAltKey = LOWORD(OemKeyScan(key[0])); 750 | 751 | 752 | TCHAR offset[MAXCHAR]; 753 | bool subtrating = FALSE; 754 | 755 | for (int i = 0; i <= 5; i++) { 756 | GetWindowText(GetDlgItem(hDlg, IDC_THREADOFFSET + i), (LPTSTR)offset, MAXCHAR); 757 | wstring wOffset = wstring(offset); 758 | 759 | if (wOffset[0] == '-') { 760 | subtrating = TRUE; 761 | } 762 | 763 | wstring tOffset = wstring(wOffset.begin() + (int)subtrating, wOffset.end()); 764 | wstringstream stream; 765 | stream << hex << tOffset; 766 | 767 | if (i == 0) { 768 | stream >> threadOffset; 769 | if (subtrating) { 770 | threadOffset = -threadOffset; 771 | subtrating = FALSE; 772 | } 773 | } 774 | else { 775 | stream >> offsets[i - 1]; 776 | if (subtrating) { 777 | offsets[i - 1] = -offsets[i - 1]; 778 | subtrating = FALSE; 779 | } 780 | } 781 | } 782 | 783 | 784 | UpdateConfigFile({ inputMethod, inputKeys, timerPointer }); 785 | 786 | 787 | timeAddress = GetTimeAddress(); 788 | 789 | if (timeAddress == nullptr) { 790 | CloseHandle(osuProcessHandle); 791 | 792 | /* EventLog */ fwprintf(wEventLog, L"[WARNING] timeAddress NOT FOUND!\n"); 793 | fflush(wEventLog); 794 | 795 | statusText = L"timeAddress NOT found!"; 796 | DrawTextToWindow(hWnd, statusText, rectStatus); 797 | } 798 | 799 | wstringstream timeAddressString; 800 | timeAddressString << "0x" << hex << PtrToUlong(timeAddress); 801 | 802 | /* EventLog */ fwprintf(wEventLog, (L"[EVENT] \"timeAddress\" UPDATED!\n timeAddress: " + timeAddressString.str() + L"\n").c_str()); 803 | fflush(wEventLog); 804 | 805 | 806 | /* EventLog */ fwprintf(wEventLog, L" Settings are changed!\n"); 807 | EndDialog(hDlg, LOWORD(wParam)); 808 | fflush(wEventLog); 809 | 810 | return (INT_PTR)TRUE; 811 | } 812 | case IDCANCEL: 813 | { 814 | /* EventLog */ fwprintf(wEventLog, L" Nothing was changed.\n"); 815 | fflush(wEventLog); 816 | 817 | EndDialog(hDlg, LOWORD(wParam)); 818 | return (INT_PTR)TRUE; 819 | } 820 | } 821 | } return (INT_PTR)FALSE; 822 | } 823 | 824 | // Message handler for error box. 825 | INT_PTR CALLBACK ErrorBox(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { 826 | UNREFERENCED_PARAMETER(lParam); 827 | switch (message) { 828 | case WM_INITDIALOG: 829 | SetDlgItemTextW(hDlg, IDT_ERRORTEXT, LPCWSTR(L"GENERIC ERROR TEXT")); 830 | return (INT_PTR)TRUE; 831 | 832 | case WM_COMMAND: 833 | if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { 834 | EndDialog(hDlg, LOWORD(wParam)); 835 | return (INT_PTR)TRUE; 836 | } break; 837 | } return (INT_PTR)FALSE; 838 | } 839 | 840 | // Message handler for about box. 841 | INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { 842 | UNREFERENCED_PARAMETER(lParam); 843 | switch (message) { 844 | case WM_INITDIALOG: 845 | return (INT_PTR)TRUE; 846 | 847 | case WM_COMMAND: 848 | if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { 849 | EndDialog(hDlg, LOWORD(wParam)); 850 | return (INT_PTR)TRUE; 851 | } break; 852 | } return (INT_PTR)FALSE; 853 | } 854 | -------------------------------------------------------------------------------- /Osu!Bot V2/OsuBot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stdafx.h" 4 | 5 | #include "GlobalVariables.h" 6 | #include "timeAddress.h" 7 | #include "SendInput.h" 8 | #include "CursorMovement.h" 9 | #include "SongsReading.h" 10 | 11 | 12 | using namespace std; 13 | 14 | 15 | LPVOID GetTimeAddress() { 16 | int pLevel = 5; 17 | 18 | LPVOID osuProcessID = GetProcessID(L"osu!.exe"); 19 | osuProcessHandle = GetHandle(osuProcessID); 20 | 21 | LPVOID thread = GetThreadList(osuProcessID)[0]; 22 | 23 | ULONG threadStack = GetThreadStack(osuProcessHandle, thread); 24 | 25 | LPVOID threadAddress = UlongToPtr(threadStack + (ULONG)threadOffset); 26 | 27 | return GetAddress(osuProcessHandle, threadAddress, pLevel); 28 | } 29 | 30 | 31 | void TimeThread() { 32 | SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); 33 | while (true) { 34 | ReadProcessMemory(osuProcessHandle, timeAddress, &songTime, sizeof(INT), NULL); 35 | this_thread::sleep_for(chrono::milliseconds(1)); 36 | } 37 | } 38 | 39 | 40 | void AutoPlay(wstring nowPlaying) { 41 | SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); 42 | 43 | wstring beatmap(nowPlaying.begin() + 8, nowPlaying.end()); 44 | 45 | if (statusText != L"No New Beatmap Selected! Using The Last Selected Beatmap.") 46 | statusText = L"Now Playing: " + beatmap; 47 | DrawTextToWindow(hWnd, statusText, rectStatus); 48 | 49 | prevInputTime = songTime; 50 | SendMessage(hwndProgressBar, PBM_SETPOS, WPARAM(0), NULL); 51 | 52 | if (hardrockFlip) 53 | for (unsigned int i = 0; i < hitObjects.size(); i++) { 54 | hitObjects.at(i).startPosition.y = 384.f - hitObjects.at(i).startPosition.y; 55 | } 56 | 57 | for (unsigned int nObject = 0; nObject < hitObjects.size(); nObject++) { 58 | HitObject hit = hitObjects.at(nObject); 59 | if (songStarted) { 60 | 61 | // Movement calls: 62 | switch (modeMoveTo) { 63 | case MODE_NONE: 64 | break; 65 | 66 | case MODE_STANDARD: 67 | MoveToStandard(&hit); 68 | break; 69 | 70 | case MODE_FLOWING: 71 | MoveToCircle(&hitObjects, nObject, FlowVectorPoint); 72 | break; 73 | 74 | case MODE_PREDICTING: 75 | MoveToCircle(&hitObjects, nObject, PredictionVectorPoint); 76 | break; 77 | } 78 | 79 | if ((hit.getHitType() == HIT_CIRCLE || modeSlider == MODE_NONE) && modeMoveTo != MODE_NONE && songStarted) { 80 | SendKeyPress(&hit); 81 | 82 | int keyPressTime = MAX(static_cast(hit.getBPM() / 4.f), 5); 83 | this_thread::sleep_for(chrono::milliseconds(keyPressTime)); 84 | 85 | SendKeyRelease(&hit); 86 | } 87 | else if (hit.getHitType() == HIT_SLIDER) { 88 | switch (modeSlider) { 89 | case MODE_NONE: 90 | break; 91 | 92 | case MODE_STANDARD: 93 | SliderStandard(&hit); 94 | break; 95 | 96 | case MODE_FLOWING: 97 | SliderFlowing(&hitObjects, nObject); 98 | break; 99 | 100 | case MODE_PREDICTING: 101 | SliderFlowing(&hitObjects, nObject); 102 | break; 103 | } 104 | } 105 | else if (hit.getHitType() == HIT_SPINNER) { 106 | switch (modeSpinner) { 107 | case MODE_NONE: 108 | break; 109 | 110 | case MODE_STANDARD: 111 | SpinnerStandard(&hit); 112 | break; 113 | 114 | case MODE_FLOWING: 115 | SpinnerStandard(&hit); 116 | break; 117 | 118 | case MODE_PREDICTING: 119 | SpinnerStandard(&hit); 120 | break; 121 | } 122 | } 123 | // Movement calls END; 124 | 125 | SendMessage(hwndProgressBar, PBM_SETPOS, WPARAM(nObject), NULL); 126 | } 127 | else { 128 | while (!songStarted && !firstStart) { 129 | this_thread::sleep_for(chrono::milliseconds(5)); 130 | } 131 | nObject -= (UINT)2; 132 | } 133 | } 134 | 135 | statusText = L"Waiting for user..."; 136 | DrawTextToWindow(hWnd, statusText, rectStatus); 137 | 138 | songStarted = FALSE; 139 | } 140 | 141 | 142 | void GameActiveChecker() { 143 | SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); 144 | while (true) { 145 | RECT rect; 146 | POINT w = { 0, 6 }; 147 | GetClientRect(osuWindow, &rect); 148 | ClientToScreen(osuWindow, &w); 149 | 150 | int x = min(rect.right, GetSystemMetrics(SM_CXSCREEN)), swidth = x, 151 | y = min(rect.bottom, GetSystemMetrics(SM_CXSCREEN)), sheight = y; 152 | 153 | if (swidth * 3 > sheight * 4) swidth = sheight * 4 / 3; 154 | else sheight = swidth * 3 / 4; 155 | multiplierX = swidth / 640.f; 156 | multiplierY = sheight / 480.f; 157 | 158 | int xOffset = static_cast(x - 512.f * multiplierX) / 2, 159 | yOffset = static_cast(y - 384.f * multiplierY) / 2; 160 | 161 | osuWindowX = w.x + xOffset; 162 | osuWindowY = w.y + yOffset; 163 | 164 | TCHAR titleC[MAXCHAR]; 165 | GetWindowText(osuWindow, (LPTSTR)titleC, MAXCHAR); 166 | wstring title(titleC); 167 | 168 | if (title != L"osu!" && title != L"" && pathSet) { 169 | if (firstStart) { 170 | songStarted = TRUE; 171 | 172 | if (autoOpenSong) { 173 | SongFileCheck(OpenSongAuto(title), autoSelect); 174 | } 175 | 176 | thread AutoThread(AutoPlay, title); 177 | AutoThread.detach(); 178 | 179 | firstStart = FALSE; 180 | } 181 | else if (songTime > 0) { 182 | if (songTime == prevTime) { 183 | songStarted = FALSE; 184 | } 185 | else { 186 | songStarted = TRUE; 187 | } 188 | } prevTime = songTime; 189 | } 190 | else if (title == L"osu!" && songStarted) { 191 | firstStart = TRUE; 192 | songStarted = FALSE; 193 | } 194 | else if (title == L"osu!" && !songStarted) { 195 | firstStart = TRUE; 196 | } 197 | else if (title == L"") { 198 | if (!songStarted) { 199 | if (true) /*if Option to close Osu!Bot on osu! exit.*/ 200 | { 201 | TerminateProcess(GetCurrentProcess(), 0); 202 | } 203 | } 204 | } 205 | this_thread::sleep_for(chrono::milliseconds(100)); 206 | } 207 | } 208 | 209 | void FindGame() { 210 | osuWindow = FindWindow(NULL, L"osu!"); 211 | if (osuWindow == NULL) { 212 | /* EventLog */ fwprintf(wEventLog, L"[WARNING] The process \"osu!\" was not found!\n"); 213 | fflush(wEventLog); 214 | 215 | statusText = L"\"osu!\" NOT found! Please start \"osu!\"..."; 216 | DrawTextToWindow(hWnd, statusText, rectStatus); 217 | 218 | while (osuWindow == NULL) { 219 | osuWindow = FindWindow(NULL, L"osu!"); 220 | Sleep(500); 221 | } 222 | } 223 | 224 | /* EventLog */ fwprintf(wEventLog, L"[EVENT] osu!.exe FOUND!\n"); 225 | 226 | if (threadOffset == 0x0) { 227 | /* EventLog */ fwprintf(wEventLog, L"[WARNING] Thread / Pointer Offsets not set!\n"); 228 | fflush(wEventLog); 229 | 230 | statusText = L"Thread / Pointer Offsets not set! Change it under Settings!"; 231 | DrawTextToWindow(hWnd, statusText, rectStatus); 232 | 233 | while (threadOffset == 0x0) { Sleep(500); } 234 | } 235 | 236 | timeAddress = GetTimeAddress(); 237 | 238 | if (timeAddress == nullptr) { 239 | CloseHandle(osuProcessHandle); 240 | 241 | /* EventLog */ fwprintf(wEventLog, L"[WARNING] timeAddress NOT FOUND!\n"); 242 | fflush(wEventLog); 243 | 244 | statusText = L"timeAddress NOT found!"; 245 | DrawTextToWindow(hWnd, statusText, rectStatus); 246 | 247 | FindGame(); 248 | } 249 | 250 | wstringstream timeAddressString; 251 | timeAddressString << "0x" << hex << PtrToUlong(timeAddress); 252 | 253 | /* EventLog */ fwprintf(wEventLog, (L"[EVENT] \"timeAddress\" FOUND! Starting Checker and Time threads!\n timeAddress: " + timeAddressString.str() + L"\n").c_str()); 254 | fflush(wEventLog); 255 | 256 | statusText = L"Waiting for user..."; 257 | DrawTextToWindow(hWnd, statusText, rectStatus); 258 | 259 | thread gameActiveThread(GameActiveChecker); 260 | gameActiveThread.detach(); 261 | thread timeThread(TimeThread); 262 | timeThread.detach(); 263 | } 264 | -------------------------------------------------------------------------------- /Osu!Bot V2/OsuBotV2.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingNina/Osu-Bot/8f2d9ef7743e84e3a9a85e46ad5fbd11145261be/Osu!Bot V2/OsuBotV2.ico -------------------------------------------------------------------------------- /Osu!Bot V2/OsuBotV2.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #ifndef APSTUDIO_INVOKED 11 | #include "targetver.h" 12 | #endif 13 | #define APSTUDIO_HIDDEN_SYMBOLS 14 | #include "windows.h" 15 | #undef APSTUDIO_HIDDEN_SYMBOLS 16 | 17 | ///////////////////////////////////////////////////////////////////////////// 18 | #undef APSTUDIO_READONLY_SYMBOLS 19 | 20 | ///////////////////////////////////////////////////////////////////////////// 21 | // English (United States) resources 22 | 23 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 24 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 25 | #pragma code_page(1252) 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | // 29 | // Icon 30 | // 31 | 32 | // Icon with lowest ID value placed first to ensure application icon 33 | // remains consistent on all systems. 34 | IDI_OSUBOTV2 ICON "OsuBotV2.ico" 35 | 36 | IDI_SMALL ICON "small.ico" 37 | 38 | 39 | ///////////////////////////////////////////////////////////////////////////// 40 | // 41 | // Menu 42 | // 43 | 44 | IDC_OSUBOTV2 MENU 45 | BEGIN 46 | POPUP "&File" 47 | BEGIN 48 | POPUP "Data &Files" 49 | BEGIN 50 | MENUITEM "Open Data &Folder", ID_DATAFILES_OPENDATAFOLDER 51 | MENUITEM SEPARATOR 52 | MENUITEM "Open &Song Folder Data", ID_DATAFILES_OPENSONGDATA 53 | MENUITEM "Open &Beat Map Data", ID_DATAFILES_OPENBEATMAPDATA 54 | MENUITEM "Open &Event Log", ID_DATAFILES_OPENEVENTLOG 55 | MENUITEM SEPARATOR 56 | MENUITEM "&Clear OsuBot Data", IDM_CLEARDATA 57 | END 58 | MENUITEM "E&xit", IDM_EXIT 59 | END 60 | MENUITEM "&Settings", IDM_SETTINGS 61 | POPUP "&Help" 62 | BEGIN 63 | MENUITEM "&About ...", IDM_ABOUT 64 | END 65 | END 66 | 67 | 68 | ///////////////////////////////////////////////////////////////////////////// 69 | // 70 | // Accelerator 71 | // 72 | 73 | IDC_OSUBOTV20 ACCELERATORS 74 | BEGIN 75 | "/", IDM_ABOUT, ASCII, ALT, NOINVERT 76 | "?", IDM_ABOUT, ASCII, ALT, NOINVERT 77 | END 78 | 79 | 80 | ///////////////////////////////////////////////////////////////////////////// 81 | // 82 | // Dialog 83 | // 84 | 85 | IDD_ABOUTBOX DIALOGEX 0, 0, 173, 63 86 | STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU 87 | CAPTION "About Osu!Bot V2" 88 | FONT 8, "MS Shell Dlg", 0, 0, 0x1 89 | BEGIN 90 | ICON IDI_OSUBOTV2,IDC_STATIC,14,14,20,20 91 | LTEXT "Osu!Bot, Version 2.5",IDC_STATIC,42,14,114,8,SS_NOPREFIX 92 | LTEXT "Copyright (C) 2017-2018",IDC_STATIC,42,26,114,8 93 | DEFPUSHBUTTON "OK",IDOK,116,42,50,14,WS_GROUP 94 | END 95 | 96 | IDD_ERRORBOX DIALOGEX 0, 0, 173, 93 97 | STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU 98 | CAPTION "ERROR MESSAGE" 99 | FONT 8, "MS Shell Dlg", 400, 0, 0x0 100 | BEGIN 101 | LTEXT "An ERROR has occured:",IDC_STATIC,48,22,118,12 102 | DEFPUSHBUTTON "OK",IDOK,116,72,50,14,WS_GROUP 103 | LTEXT "Static",IDT_ERRORTEXT,47,44,80,23 104 | CONTROL IDB_BITMAP1,IDB_BITMAP1,"Static",SS_BITMAP | SS_CENTERIMAGE,14,14,29,25,WS_EX_TRANSPARENT 105 | END 106 | 107 | IDD_SETTINGSBOX DIALOGEX 0, 0, 229, 212 108 | STYLE DS_SETFONT | DS_SETFOREGROUND | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU 109 | EXSTYLE WS_EX_TOPMOST 110 | CAPTION "Settings" 111 | FONT 8, "MS Shell Dlg", 400, 0, 0x0 112 | BEGIN 113 | PUSHBUTTON "Cancel",IDCANCEL,167,192,50,14 114 | COMBOBOX IDC_THREADOFFSET,108,78,108,12,CBS_SIMPLE | CBS_SORT | CBS_UPPERCASE | WS_TABSTOP 115 | COMBOBOX IDC_POINTEROFFSET1,108,96,108,12,CBS_SIMPLE | CBS_SORT | CBS_UPPERCASE | WS_TABSTOP 116 | COMBOBOX IDC_POINTEROFFSET2,108,114,108,12,CBS_SIMPLE | CBS_SORT | CBS_UPPERCASE | WS_TABSTOP 117 | COMBOBOX IDC_POINTEROFFSET3,108,132,108,12,CBS_SIMPLE | CBS_SORT | CBS_UPPERCASE | WS_TABSTOP 118 | COMBOBOX IDC_POINTEROFFSET4,108,150,108,12,CBS_SIMPLE | CBS_SORT | CBS_UPPERCASE | WS_TABSTOP 119 | COMBOBOX IDC_POINTEROFFSET5,108,168,108,12,CBS_SIMPLE | CBS_SORT | CBS_UPPERCASE | WS_TABSTOP 120 | LTEXT "ThreadOffset",IDC_STATIC,18,78,75,12,NOT WS_GROUP,WS_EX_TRANSPARENT 121 | LTEXT "PointerOffset0",IDC_STATIC,18,96,75,12,NOT WS_GROUP,WS_EX_TRANSPARENT 122 | LTEXT "PointerOffset1",IDC_STATIC,18,114,75,12,NOT WS_GROUP,WS_EX_TRANSPARENT 123 | LTEXT "PointerOffset2",IDC_STATIC,18,132,75,12,NOT WS_GROUP,WS_EX_TRANSPARENT 124 | LTEXT "PointerOffset3",IDC_STATIC,18,150,75,12,NOT WS_GROUP,WS_EX_TRANSPARENT 125 | LTEXT "PointerOffset4",IDC_STATIC,18,168,75,12,NOT WS_GROUP,WS_EX_TRANSPARENT 126 | LTEXT "Alt Key",IDC_STATIC,18,54,75,12,NOT WS_GROUP,WS_EX_TRANSPARENT 127 | LTEXT "Input methode",IDC_STATIC,18,12,75,12,NOT WS_GROUP,WS_EX_TRANSPARENT 128 | COMBOBOX IDC_INPUTMETHODE,108,12,108,44,CBS_DROPDOWNLIST | CBS_SORT 129 | LTEXT "Main Key",IDC_STATIC,18,36,75,12,NOT WS_GROUP,WS_EX_TRANSPARENT 130 | DEFPUSHBUTTON "Accept",IDOK,108,192,50,14 131 | EDITTEXT IDC_INPUTKEYMAIN,108,36,108,14,ES_UPPERCASE | ES_AUTOHSCROLL | ES_OEMCONVERT | ES_READONLY 132 | EDITTEXT IDC_INPUTKEYALT,108,54,108,14,ES_UPPERCASE | ES_AUTOHSCROLL | ES_OEMCONVERT | ES_READONLY 133 | END 134 | 135 | 136 | ///////////////////////////////////////////////////////////////////////////// 137 | // 138 | // DESIGNINFO 139 | // 140 | 141 | #ifdef APSTUDIO_INVOKED 142 | GUIDELINES DESIGNINFO 143 | BEGIN 144 | IDD_ABOUTBOX, DIALOG 145 | BEGIN 146 | LEFTMARGIN, 7 147 | RIGHTMARGIN, 166 148 | TOPMARGIN, 7 149 | BOTTOMMARGIN, 56 150 | END 151 | 152 | IDD_ERRORBOX, DIALOG 153 | BEGIN 154 | LEFTMARGIN, 7 155 | RIGHTMARGIN, 166 156 | TOPMARGIN, 7 157 | BOTTOMMARGIN, 86 158 | END 159 | 160 | IDD_SETTINGSBOX, DIALOG 161 | BEGIN 162 | END 163 | END 164 | #endif // APSTUDIO_INVOKED 165 | 166 | 167 | #ifdef APSTUDIO_INVOKED 168 | ///////////////////////////////////////////////////////////////////////////// 169 | // 170 | // TEXTINCLUDE 171 | // 172 | 173 | 1 TEXTINCLUDE 174 | BEGIN 175 | "resource.h\0" 176 | END 177 | 178 | 2 TEXTINCLUDE 179 | BEGIN 180 | "#ifndef APSTUDIO_INVOKED\r\n" 181 | "#include ""targetver.h""\r\n" 182 | "#endif\r\n" 183 | "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" 184 | "#include ""windows.h""\r\n" 185 | "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" 186 | "\0" 187 | END 188 | 189 | 3 TEXTINCLUDE 190 | BEGIN 191 | "\r\n" 192 | "\0" 193 | END 194 | 195 | #endif // APSTUDIO_INVOKED 196 | 197 | 198 | ///////////////////////////////////////////////////////////////////////////// 199 | // 200 | // Bitmap 201 | // 202 | 203 | IDB_BITMAP1 BITMAP "bitmap1.bmp" 204 | 205 | 206 | ///////////////////////////////////////////////////////////////////////////// 207 | // 208 | // String Table 209 | // 210 | 211 | STRINGTABLE 212 | BEGIN 213 | IDS_APP_TITLE "Osu!Bot" 214 | IDC_OSUBOTV2 "OSUBOTV2" 215 | END 216 | 217 | #endif // English (United States) resources 218 | ///////////////////////////////////////////////////////////////////////////// 219 | 220 | 221 | 222 | #ifndef APSTUDIO_INVOKED 223 | ///////////////////////////////////////////////////////////////////////////// 224 | // 225 | // Generated from the TEXTINCLUDE 3 resource. 226 | // 227 | 228 | 229 | ///////////////////////////////////////////////////////////////////////////// 230 | #endif // not APSTUDIO_INVOKED 231 | 232 | -------------------------------------------------------------------------------- /Osu!Bot V2/SendInput.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stdafx.h" 4 | 5 | #include "OsuBot.h" 6 | 7 | 8 | void SendKeyPress(HitObject *hitObject) { 9 | if ((static_cast(hitObject->getStartTime() - prevInputTime) > 125.f) || altKey == TRUE) { 10 | if (inputKeyBoard) { 11 | input.type = INPUT_KEYBOARD; 12 | input.ki.dwFlags = NULL; 13 | if (inputFlip) 14 | input.ki.wVk = inputAltKey * 2U; 15 | else 16 | input.ki.wVk = inputMainKey * 2U; 17 | } 18 | else { 19 | input.type = INPUT_MOUSE; 20 | if (inputFlip) 21 | input.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; 22 | else 23 | input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN; 24 | } 25 | altKey = FALSE; 26 | } 27 | else { 28 | if (inputKeyBoard) { 29 | input.type = INPUT_KEYBOARD; 30 | input.ki.dwFlags = NULL; 31 | if (inputFlip) 32 | input.ki.wVk = inputMainKey * 2U; 33 | else 34 | input.ki.wVk = inputAltKey * 2U; 35 | } 36 | else { 37 | input.type = INPUT_MOUSE; 38 | if (inputFlip) 39 | input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN; 40 | else 41 | input.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; 42 | } 43 | altKey = TRUE; 44 | } 45 | 46 | SendInput(1, &input, sizeof(INPUT)); 47 | } 48 | 49 | void SendKeyRelease(HitObject *hitObject) { 50 | if (inputKeyBoard) { 51 | input.type = INPUT_KEYBOARD; 52 | input.ki.dwFlags = KEYEVENTF_KEYUP; 53 | SendInput(1, &input, sizeof(INPUT)); 54 | } 55 | else { 56 | input.type = INPUT_MOUSE; 57 | input.mi.dwFlags = MOUSEEVENTF_LEFTUP; 58 | SendInput(1, &input, sizeof(INPUT)); 59 | input.mi.dwFlags = MOUSEEVENTF_RIGHTUP; 60 | SendInput(1, &input, sizeof(INPUT)); 61 | } 62 | 63 | prevInputTime = hitObject->getStartTime(); 64 | if (hitObject->getEndTime() > hitObject->getStartTime()) 65 | prevInputTime = hitObject->getEndTime(); 66 | } 67 | -------------------------------------------------------------------------------- /Osu!Bot V2/SongsReading.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stdafx.h" 4 | 5 | #include "OsuBot.h" 6 | 7 | 8 | float MapDifficultyRange(float difficulty, float min, float mid, float max) { 9 | if (difficulty > 5.0f) return mid + (max - mid)*(difficulty - 5.0f) / 5.0f; 10 | if (difficulty < 5.0f) return mid - (mid - min)*(5.0f - difficulty) / 5.0f; 11 | return mid; 12 | } 13 | 14 | void ParseSong(LPCTSTR songPath) { 15 | wfstream path; path.open(songPath, wfstream::in); 16 | bool general = false; 17 | bool difficulty = false; 18 | bool timing = false; 19 | bool hits = false; 20 | bool beatDivisor = false; 21 | while (!path.eof()) { 22 | wstring str; 23 | getline(path, str, path.widen(L'\n')); 24 | if (str.find(L"[General]") != wstring::npos) { 25 | general = true; 26 | } 27 | else if (general) { 28 | if (str.find(L"StackLeniency") != wstring::npos) { 29 | stackLeniency = stof(str.substr(str.find(L':') + 1U)); 30 | } 31 | else if (str.find(L':') == wstring::npos) { 32 | general = false; 33 | } 34 | } 35 | else if (str.find(L"[Editor]") != wstring::npos) { 36 | beatDivisor = true; 37 | } 38 | else if (beatDivisor) { 39 | if (str.find(L"BeatDivisor") != wstring::npos) { 40 | beatMapDivider = stof(str.substr(str.find(L':') + 1U)); 41 | } 42 | else if (str.find(L':') == wstring::npos) { 43 | beatDivisor = false; 44 | } 45 | } 46 | else if (str.find(L"[Difficulty]") != wstring::npos) { 47 | difficulty = true; 48 | } 49 | else if (difficulty) { 50 | if (str.find(L"OverallDifficulty") != wstring::npos) { 51 | overallDifficulty = stof(str.substr(str.find(L':') + 1U)); 52 | } 53 | else if (str.find(L"CircleSize") != wstring::npos) { 54 | circleSize = stof(str.substr(str.find(L':') + 1U)); 55 | } 56 | else if (str.find(L"SliderMultiplier") != wstring::npos) { 57 | sliderMultiplier = stof(str.substr(str.find(L':') + 1U)); 58 | } 59 | else if (str.find(L"SliderTickRate") != wstring::npos) { 60 | sliderTickRate = stof(str.substr(str.find(L':') + 1U)); 61 | } 62 | else if (str.find(L':') == wstring::npos) { 63 | difficulty = false; 64 | } 65 | } 66 | else if (str.find(L"[TimingPoints]") != wstring::npos) { 67 | timing = true; 68 | } 69 | else if (timing) { 70 | if (str.find(L',') == wstring::npos) { 71 | timing = false; 72 | } 73 | else { 74 | TimingPoint TP = TimingPoint(str); 75 | timingPoints.push_back(TP); 76 | } 77 | } 78 | else if (str.find(L"[HitObjects]") != wstring::npos) { 79 | hits = true; 80 | } 81 | else if (hits) { 82 | if (str.find(L',') == wstring::npos) { 83 | hits = false; 84 | } 85 | else { 86 | HitObject HO = HitObject(str, &timingPoints, sliderMultiplier, sliderTickRate); 87 | hitObjects.push_back(HO); 88 | } 89 | } 90 | } 91 | path.close(); 92 | 93 | float preEmpt = MapDifficultyRange(overallDifficulty, 1800.0f, 1200.0f, 450.0f); 94 | 95 | stackOffset = ((512.0f / 16.0f) * (1.0f - 0.7f * (circleSize - 5.0f) / 5.0f) / 10.0f) / circleSize; 96 | 97 | for (int i = INT(hitObjects.size()) - 1; i > 0; i--) { 98 | HitObject* hitObjectI = &hitObjects[i]; 99 | if (hitObjectI->getStack() != 0 || hitObjectI->getHitType() == HIT_SPINNER) { 100 | continue; 101 | } 102 | 103 | for (int n = i - 1; n >= 0; n--) { 104 | HitObject* hitObjectN = &hitObjects[n]; 105 | if (hitObjectN->getHitType() == HIT_SPINNER) { 106 | continue; 107 | } 108 | 109 | // check if in range stack calculation 110 | float timeI = hitObjectI->startTime - preEmpt * stackLeniency; 111 | float timeN = float(hitObjectN->getHitType() == HIT_SLIDER ? hitObjects[n].endTime : hitObjectN->startTime); 112 | if (timeI > timeN) 113 | break; 114 | 115 | if (hitObjectN->getHitType() == HIT_SLIDER) { 116 | vec2f p1 = hitObjects[i].getStartPos(); 117 | vec2f p2 = hitObjects[n].getEndPos(); 118 | float distance = (p2 - p1).length(); 119 | 120 | // check if hit object part of this stack 121 | if (stackLeniency > 0.0f) { 122 | float circleRadius = pow(circleSize, -1) * 200.0f; 123 | if (distance < circleRadius) { 124 | int offset = hitObjectI->getStack() - hitObjectN->getStack() + 1; 125 | for (int j = n + 1; j <= i; j++) { 126 | HitObject* hitObjectJ = &hitObjects[j]; 127 | p1 = hitObjectJ->getStartPos(); 128 | distance = (p2 - p1).length(); 129 | //cout << offset; 130 | // hit object below slider end 131 | if (distance < circleRadius) 132 | hitObjectJ->setStack(hitObjectJ->getStack() - offset); 133 | } 134 | break; // slider end always start of the stack: reset calculation 135 | } 136 | } 137 | else { 138 | break; 139 | } 140 | } 141 | auto distance = ( 142 | hitObjectN->getStartPos() - 143 | hitObjectI->getStartPos() 144 | ).length(); 145 | if (distance < stackLeniency) { 146 | hitObjectN->setStack(hitObjectI->getStack() + 1); 147 | hitObjectI = hitObjectN; 148 | } 149 | } 150 | } 151 | for (int i = INT(hitObjects.size()) - 1; i > 0; i--) { 152 | int n = i; 153 | /* We should check every note which has not yet got a stack. 154 | * Consider the case we have two interwound stacks and this will make sense. 155 | * 156 | * o <-1 o <-2 157 | * o <-3 o <-4 158 | * 159 | * We first process starting from 4 and handle 2, 160 | * then we come backwards on the i loop iteration until we reach 3 and handle 1. 161 | * 2 and 1 will be ignored in the i loop because they already have a stack value. 162 | */ 163 | 164 | HitObject *objectI = &hitObjects[i]; 165 | 166 | if (objectI->stackId != 0 || objectI->getHitType() == HIT_SPINNER) continue; 167 | 168 | /* If this object is a hitcircle, then we enter this "special" case. 169 | * It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider. 170 | * Any other case is handled by the "is Slider" code below this. 171 | */ 172 | if (objectI->endTime == 0) { 173 | while (--n >= 0) { 174 | HitObject* objectN = &hitObjects[n]; 175 | 176 | if (objectN->getHitType() == HIT_SPINNER) continue; 177 | 178 | //HitObjectSpannable spanN = objectN as HitObjectSpannable; 179 | float timeI = objectI->startTime - preEmpt * stackLeniency; 180 | float timeN = static_cast(objectN->getHitType() == HIT_SLIDER ? objectN->endTime : objectN->startTime); 181 | if (timeI > timeN) 182 | break; 183 | 184 | /* This is a special case where hticircles are moved DOWN and RIGHT (negative stacking) if they are under the *last* slider in a stacked pattern. 185 | * o==o <- slider is at original location 186 | * o <- hitCircle has stack of -1 187 | * o <- hitCircle has stack of -2 188 | */ 189 | if (objectN->endTime != 0 && (objectI->getEndPos() - objectN->startPosition).length() < STACK_LENIENCE) { 190 | int offset = objectI->stackId - objectN->stackId + 1; 191 | for (int j = n + 1; j <= i; j++) { 192 | //For each object which was declared under this slider, we will offset it to appear *below* the slider end (rather than above). 193 | if ((hitObjects[j].startPosition - objectN->getEndPos()).length() < STACK_LENIENCE) 194 | hitObjects[j].stackId -= offset; 195 | } 196 | 197 | //We have hit a slider. We should restart calculation using this as the new base. 198 | //Breaking here will mean that the slider still has StackCount of 0, so will be handled in the i-outer-loop. 199 | break; 200 | } 201 | 202 | if ((objectI->startPosition - objectN->startPosition).length() < STACK_LENIENCE) { 203 | //Keep processing as if there are no sliders. If we come across a slider, this gets cancelled out. 204 | //NOTE: Sliders with start positions stacking are a special case that is also handled here. 205 | 206 | objectN->stackId = objectI->stackId + 1; 207 | objectI = objectN; 208 | } 209 | } 210 | } 211 | else if (objectI->getHitType() == HIT_SLIDER) { 212 | /* We have hit the first slider in a possible stack. 213 | * From this point on, we ALWAYS stack positive regardless. 214 | */ 215 | while (--n >= 0) { 216 | HitObject* objectN = &hitObjects[n]; 217 | 218 | if (objectN->getHitType() == HIT_SPINNER) continue; 219 | 220 | //HitObjectSpannable spanN = objectN as HitObjectSpannable; 221 | 222 | if (objectI->startTime - (preEmpt * stackLeniency) > objectN->startTime) 223 | break; 224 | 225 | if ((objectI->startPosition - (objectN->endTime != 0 ? objectN->getEndPos() : objectN->startPosition)).length() < STACK_LENIENCE) { 226 | objectN->stackId = objectI->stackId + 1; 227 | objectI = objectN; 228 | } 229 | } 230 | } 231 | } 232 | } 233 | 234 | 235 | bool OpenSongAuto(wstring title) { 236 | wchar_t charsToRemove[] = { L"?.\"" }; 237 | wchar_t charsToRemoveDiff[] = { L"?<>" }; 238 | wstring beatmapName; 239 | wstring difficultyName; 240 | vector beatmapSets; 241 | int beatmapSetCount = 0; 242 | 243 | 244 | if (title.find(L"[") != wstring::npos) { 245 | difficultyName = title.substr(title.find_last_of(L"[")); 246 | } 247 | 248 | beatmapName = title.substr(8U, title.find_last_of(L"[") - 1U - 8U); 249 | 250 | if (beatmapName.at(beatmapName.length() - 1U) == L' ') 251 | beatmapName.pop_back(); 252 | 253 | for (unsigned int i = 0; i < beatmapName.size() - 1; i++) { 254 | switch (beatmapName.at(i)) { 255 | case L'<': 256 | beatmapName.at(i) = L'-'; 257 | case L'>': 258 | beatmapName.at(i) = L'-'; 259 | case L'*': 260 | beatmapName.at(i) = L'-'; 261 | case L':': 262 | beatmapName.at(i) = L'_'; 263 | } 264 | } 265 | 266 | for (unsigned int i = 0; i < wcslen(charsToRemove); i++) { 267 | beatmapName.erase(remove(beatmapName.begin(), beatmapName.end(), charsToRemove[i]), beatmapName.end()); 268 | } 269 | 270 | for (unsigned int i = 0; i < difficultyName.size() - 1U; i++) { 271 | switch (difficultyName.at(i)) { 272 | case L'*': 273 | difficultyName.at(i) = L'_'; 274 | case L':': 275 | difficultyName.at(i) = L'_'; 276 | } 277 | } 278 | 279 | for (unsigned int i = 0; i < wcslen(charsToRemoveDiff); i++) { 280 | difficultyName.erase(remove(difficultyName.begin(), difficultyName.end(), charsToRemoveDiff[i]), difficultyName.end()); 281 | } 282 | 283 | difficultyName += L".osu"; 284 | 285 | 286 | DeleteFile(L"Data\\BMData.txt"); 287 | 288 | 289 | wfstream rSFData; rSFData.open(L"Data\\SFData.txt", wfstream::in); 290 | 291 | wstring readLine; 292 | while (readLine != L"[Songs Folders]") { 293 | getline(rSFData, readLine); 294 | } 295 | 296 | while (rSFData) { 297 | getline(rSFData, readLine); 298 | size_t findPos = readLine.find(beatmapName); 299 | if (findPos != wstring::npos) { 300 | if (readLine.substr(findPos) == beatmapName 301 | || readLine.substr(findPos, readLine.find_last_of('(') - 1U - findPos) == beatmapName) { 302 | wfstream wBMData; wBMData.open(L"Data\\BMData.txt", wfstream::out | wfstream::app); 303 | wBMData << L"[BeatmapDifficulties]\n"; 304 | 305 | wstring directory = wstring(songsPath.begin(), songsPath.end()) + L"\\" + readLine; 306 | 307 | for (auto beatmapFile : experimental::filesystem::directory_iterator(directory)) { 308 | wstringstream sstream; sstream << beatmapFile; 309 | 310 | wstring beatmapString = sstream.str(); 311 | wBMData << wstring((beatmapString.begin() + directory.size() + 1U), beatmapString.end()) << endl; 312 | } 313 | 314 | beatmapSets.push_back(directory); 315 | 316 | wBMData << L"\n"; 317 | 318 | wBMData.close(); 319 | } 320 | } 321 | } 322 | rSFData.close(); 323 | readLine.clear(); 324 | 325 | 326 | wfstream rBMData; rBMData.open("Data\\BMData.txt", wfstream::in); 327 | 328 | getline(rBMData, readLine); 329 | 330 | while (rBMData) { 331 | getline(rBMData, readLine); 332 | if (readLine == L"[BeatmapDifficulties]") { 333 | getline(rBMData, readLine); 334 | beatmapSetCount++; 335 | } 336 | 337 | if (readLine.find(difficultyName) != wstring::npos) { 338 | beatmapPath = beatmapSets.at(beatmapSetCount) + L"\\" + readLine; 339 | displayBeatmapPath = readLine; 340 | 341 | rBMData.close(); 342 | 343 | return TRUE; 344 | } 345 | } 346 | rBMData.close(); 347 | 348 | return FALSE; 349 | } 350 | 351 | bool OpenSongManual() { 352 | if (SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd2)))) { 353 | LPWSTR pathName = NULL; if (CoTaskMemAlloc(NULL) == NULL) return FALSE; 354 | DWORD dwOptions2; 355 | COMDLG_FILTERSPEC rgFilterSpec[] = { { L"osu! Beatmap", L"*.osu" } }; 356 | pfd2->GetOptions(&dwOptions2); 357 | pfd2->SetOptions(dwOptions2 | FOS_STRICTFILETYPES); 358 | pfd2->SetFileTypes(1U, rgFilterSpec); 359 | pfd2->Show(NULL); 360 | try { 361 | if (SUCCEEDED(pfd2->GetResult(&psi2))) { 362 | if (psi2->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &pathName) == S_OK) { beatmapPath = pathName; } 363 | else beatmapPath.clear(); 364 | psi2->Release(); 365 | } 366 | else beatmapPath.clear(); 367 | } 368 | catch (...) {} 369 | pfd2->Release(); 370 | CoTaskMemFree(pathName); 371 | CoUninitialize(); 372 | } 373 | 374 | if (!beatmapPath.empty()) { 375 | displayBeatmapPath = beatmapPath.substr(beatmapPath.find_last_of('\\') + 1U); 376 | return TRUE; 377 | } 378 | else return FALSE; 379 | } 380 | 381 | 382 | bool OpenSongFolder() { 383 | if (SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd)))) { 384 | LPWSTR pathName = NULL; if (CoTaskMemAlloc(NULL) == NULL) return FALSE; 385 | DWORD dwOptions; 386 | pfd->GetOptions(&dwOptions); 387 | pfd->SetOptions(dwOptions | FOS_PICKFOLDERS); 388 | pfd->Show(NULL); 389 | if (SUCCEEDED(pfd->GetResult(&psi))) { 390 | if (psi->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &pathName) == S_OK) { 391 | songsPath = pathName; 392 | 393 | wfstream wSFData; wSFData.open(L"Data\\SFData.txt", wfstream::out); 394 | wSFData << L"[Songs Folders]\n"; 395 | 396 | for (auto beatmapFolder : experimental::filesystem::directory_iterator(pathName)) { 397 | wstringstream sstream; sstream << beatmapFolder; 398 | 399 | wstring beatmapString = sstream.str(); 400 | wSFData << wstring((beatmapString.begin() + songsPath.size() + 1U), beatmapString.end()) << endl; 401 | } 402 | wSFData.close(); 403 | } 404 | else 405 | songsPath.clear(); 406 | 407 | psi->Release(); 408 | } 409 | else 410 | songsPath.clear(); 411 | 412 | pfd->Release(); 413 | CoTaskMemFree(pathName); 414 | CoUninitialize(); 415 | } 416 | 417 | if (_wfopen(L"Data\\SFData.txt", L"r")) 418 | return TRUE; 419 | else if (songsPath.empty()) { 420 | if (ReadFromConfigFile(songsFolderPath)) { 421 | if (songsPath.compare(L"") != 0) 422 | return TRUE; 423 | else 424 | return FALSE; 425 | } 426 | return FALSE; 427 | } 428 | else return FALSE; 429 | } 430 | 431 | 432 | void SongFileCheck(bool songFileCheck, wstring selectedBy) { 433 | if (songFileCheck) { 434 | DrawTextToWindow(hWnd, displayBeatmapPath.c_str(), rectSongFile); 435 | 436 | statusText = L"Beatmap Successfully Selected!"; 437 | DrawTextToWindow(hWnd, statusText, rectStatus); 438 | 439 | /* EventLog */ fwprintf(wEventLog, (L"[EVENT] Beatmap successfully selected by " + selectedBy).c_str()); 440 | 441 | hitObjects.clear(); 442 | timingPoints.clear(); 443 | 444 | ParseSong((beatmapPath.c_str())); 445 | 446 | SendMessage(hwndProgressBar, PBM_SETRANGE, NULL, MAKELPARAM(0, hitObjects.size() + 1)); 447 | SendMessage(hwndProgressBar, PBM_SETSTEP, WPARAM(1), NULL); 448 | SendMessage(hwndProgressBar, PBM_SETPOS, WPARAM(0), NULL); 449 | } 450 | else { 451 | statusText = L"No New Beatmap Selected! Using The Last Selected Beatmap."; 452 | DrawTextToWindow(hWnd, statusText, rectStatus); 453 | 454 | /* EventLog */ fwprintf(wEventLog, (L"[EVENT] No Beatmap was selected by " + selectedBy).c_str()); 455 | } 456 | } 457 | -------------------------------------------------------------------------------- /Osu!Bot V2/bitmap1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingNina/Osu-Bot/8f2d9ef7743e84e3a9a85e46ad5fbd11145261be/Osu!Bot V2/bitmap1.bmp -------------------------------------------------------------------------------- /Osu!Bot V2/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by OsuBotV2.rc 4 | // 5 | #define IDC_MYICON 2 6 | #define IDD_ERRORBOX 101 7 | #define IDD_OSUBOTV2_DIALOG 102 8 | #define IDS_APP_TITLE 103 9 | #define IDD_ABOUTBOX 103 10 | #define IDM_ABOUT 104 11 | #define IDD_SETTINGSBOX 104 12 | #define IDM_EXIT 105 13 | #define IDM_SETTINGS 106 14 | #define IDI_OSUBOTV2 107 15 | #define IDI_SMALL 108 16 | #define IDC_OSUBOTV2 109 17 | #define IDR_MAINFRAME 128 18 | #define IDB_BITMAP1 133 19 | #define IDT_ERRORTEXT 1001 20 | #define IDC_BUTTON_CANCEL 1003 21 | #define IDC_BUTTON_ACCEPT 1004 22 | #define IDC_THREADOFFSET 1005 23 | #define IDC_POINTEROFFSET1 1006 24 | #define IDC_POINTEROFFSET2 1007 25 | #define IDC_POINTEROFFSET3 1008 26 | #define IDC_POINTEROFFSET4 1009 27 | #define IDC_POINTEROFFSET5 1010 28 | #define IDC_INPUTKEYALT 1011 29 | #define IDC_INPUTKEYMAIN 1012 30 | #define IDC_INPUTMETHODE 1013 31 | #define ID_FILE_SETTINGS 32771 32 | #define ID_FILE_DATAFILES 32782 33 | #define ID_DATAFILES_OPENSONGFOLDER 32783 34 | #define ID_DATAFILES_OPENBEATMAPFOLDER 32784 35 | #define IDM_CLEARDATA 32785 36 | #define ID_DATAFILES_OPENSONGDATA 32786 37 | #define ID_DATAFILES_OPENBEATMAPDATA 32787 38 | #define ID_DATAFILES_OPENDATAFOLDER 32788 39 | #define ID_DATAFILES_OPENEVENTLOG 32790 40 | #define IDC_STATIC -1 41 | 42 | // Next default values for new objects 43 | // 44 | #ifdef APSTUDIO_INVOKED 45 | #ifndef APSTUDIO_READONLY_SYMBOLS 46 | #define _APS_NO_MFC 1 47 | #define _APS_NEXT_RESOURCE_VALUE 134 48 | #define _APS_NEXT_COMMAND_VALUE 32794 49 | #define _APS_NEXT_CONTROL_VALUE 1019 50 | #define _APS_NEXT_SYMED_VALUE 110 51 | #endif 52 | #endif 53 | -------------------------------------------------------------------------------- /Osu!Bot V2/small.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingNina/Osu-Bot/8f2d9ef7743e84e3a9a85e46ad5fbd11145261be/Osu!Bot V2/small.ico -------------------------------------------------------------------------------- /Osu!Bot V2/split_string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | inline std::vector split_string(const std::wstring &str, const std::wstring &delim = L" ", size_t pos = 0) { 5 | std::vector out; 6 | if (pos >= str.size()) return out; 7 | 8 | size_t currentPos = 0; 9 | while (str.find(delim, pos + 1) != std::wstring::npos) { 10 | out.push_back(str.substr(currentPos, str.find(delim, pos + 1) - currentPos)); 11 | pos = str.find(delim, pos + 1) + 1; 12 | currentPos = pos; 13 | } 14 | out.push_back(str.substr(pos)); 15 | 16 | return out; 17 | } -------------------------------------------------------------------------------- /Osu!Bot V2/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // $safeprojectname$.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /Osu!Bot V2/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | // C RunTime Header Files 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | // TODO: reference additional headers your program 22 | #define _USE_MATH_DEFINES 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "split_string.h" 39 | #include "DrawTextToWindow.h" 40 | #include "resource.h" -------------------------------------------------------------------------------- /Osu!Bot V2/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /Osu!Bot V2/timeAddress.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stdafx.h" 4 | 5 | #include "OsuBot.h" 6 | 7 | #ifdef _WIN64 // Offsets for _WIN64 compatibility 8 | ULONG xBaseOffset = 8192UL; 9 | ULONG xStackOffset = 90112UL; 10 | #elif _WIN32 // Offsets are not needed (set to 0UL) on _WIN32 11 | ULONG xBaseOffset = 0UL; 12 | ULONG xStackOffset = 0UL; 13 | #endif // Offsets for _WIN64 compatibility 14 | 15 | typedef struct _CLIENT_ID { 16 | LPVOID UniqueProcess; 17 | LPVOID UniqueThread; 18 | } CLIENT_ID, *PCLIENT_ID; 19 | 20 | typedef struct _THREAD_BASIC_INFORMATION { 21 | LONG ExitStatus; 22 | LPVOID TebBaseAddress; 23 | CLIENT_ID ClientId; 24 | KAFFINITY AffinityMask; 25 | ULONG Priority; 26 | ULONG BasePriority; 27 | } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; 28 | 29 | enum THREADINFOCLASS { 30 | ThreadBasicInformation 31 | }; 32 | 33 | 34 | LPVOID GetBaseAddress(HANDLE hProcess, HANDLE hThread) { 35 | LPCTSTR moduleName = L"ntdll.dll"; 36 | bool loadedManually = FALSE; 37 | 38 | HMODULE hModule = GetModuleHandle(moduleName); 39 | 40 | if (!hModule) { 41 | hModule = LoadLibrary(moduleName); 42 | loadedManually = TRUE; 43 | } 44 | 45 | LONG(__stdcall *NtQueryInformationThread)(HANDLE ThreadHandle, THREADINFOCLASS ThreadInformationClass, LPVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength); 46 | NtQueryInformationThread = reinterpret_cast(GetProcAddress(hModule, "NtQueryInformationThread")); 47 | 48 | if (NtQueryInformationThread) { 49 | NT_TIB tib = { NULL }; 50 | THREAD_BASIC_INFORMATION tbi = { NULL }; 51 | 52 | LONG ntStatus = NtQueryInformationThread(hThread, ThreadBasicInformation, &tbi, sizeof(tbi), nullptr); 53 | if (ntStatus >= NULL) { 54 | tbi.TebBaseAddress = UlongToPtr(PtrToUlong(tbi.TebBaseAddress) + xBaseOffset); 55 | 56 | ReadProcessMemory(hProcess, tbi.TebBaseAddress, &tib, sizeof(tib), nullptr); 57 | 58 | if (loadedManually) { 59 | FreeLibrary(hModule); 60 | loadedManually = FALSE; 61 | } 62 | /* EventLog */ fwprintf(wEventLog, (L"[DEBUG] GetBaseAddress / TebBaseAddress = " + to_wstring(PtrToUlong(tbi.TebBaseAddress)) + L"\n").c_str()); 63 | /* EventLog */ fwprintf(wEventLog, (L"[DEBUG] GetBaseAddress / StackBase = " + to_wstring(PtrToUlong(tib.StackBase) + xStackOffset) + L"\n").c_str()); fflush(wEventLog); 64 | 65 | return UlongToPtr(PtrToUlong(tib.StackBase) + xStackOffset); 66 | } 67 | } 68 | 69 | if (loadedManually) { 70 | FreeLibrary(hModule); 71 | loadedManually = FALSE; 72 | } 73 | 74 | return NULL; 75 | } 76 | 77 | ULONG GetThreadStartAddress(HANDLE hProcess, HANDLE hThread) { 78 | ULONG stacktop = NULL; 79 | ULONG result = NULL; 80 | 81 | MODULEINFO mi; 82 | 83 | HMODULE hModule = LoadLibraryEx(L"kernel32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); 84 | 85 | GetModuleInformation(hProcess, hModule, &mi, sizeof(mi)); 86 | stacktop = PtrToUlong(GetBaseAddress(hProcess, hThread)); 87 | 88 | CloseHandle(hThread); 89 | 90 | if (stacktop) { 91 | const LONG buff32size = 4096L; 92 | ULONG* buff32 = new ULONG[buff32size]; 93 | 94 | if (ReadProcessMemory(hProcess, UlongToPtr(stacktop - (ULONG)buff32size), buff32, buff32size, nullptr)) { 95 | for (LONG i = buff32size / 4L - 1L; i >= NULL; --i) { 96 | if (buff32[i] >= PtrToUlong(mi.lpBaseOfDll) && buff32[i] <= PtrToUlong(mi.lpBaseOfDll) + mi.SizeOfImage) { 97 | result = (stacktop - (ULONG)buff32size + i * 4UL); 98 | break; 99 | } 100 | } 101 | } 102 | delete buff32; 103 | } 104 | 105 | FreeModule(hModule); 106 | 107 | /* EventLog */ fwprintf(wEventLog, (L"[DEBUG] GetThreadStartAddress / result = " + to_wstring(result) + L"\n").c_str()); fflush(wEventLog); 108 | 109 | return result; 110 | } 111 | 112 | ULONG GetThreadStack(HANDLE hProcess, LPVOID thread) { 113 | HANDLE hThread = OpenThread(THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, PtrToUlong(thread)); 114 | return GetThreadStartAddress(hProcess, hThread); 115 | } 116 | 117 | vector GetThreadList(LPVOID pid) { 118 | vector threadList; 119 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL); 120 | 121 | if (hSnapshot == INVALID_HANDLE_VALUE) { 122 | return threadList; 123 | } 124 | 125 | THREADENTRY32 te; 126 | te.dwSize = sizeof(te); 127 | 128 | if (Thread32First(hSnapshot, &te)) { 129 | do { 130 | if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID)) { 131 | if ((ULONG)te.th32OwnerProcessID == PtrToUlong(pid)) { 132 | threadList.push_back(ULongToPtr((ULONG)te.th32ThreadID)); 133 | } 134 | } 135 | te.dwSize = sizeof(te); 136 | } while (Thread32Next(hSnapshot, &te)); 137 | } 138 | 139 | return threadList; 140 | } 141 | 142 | HANDLE GetHandle(LPVOID processId) { 143 | return OpenProcess(PROCESS_ALL_ACCESS | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PtrToUlong(processId)); 144 | } 145 | 146 | LPVOID GetProcessID(wstring exe) { 147 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); 148 | 149 | if (hSnapshot == INVALID_HANDLE_VALUE) { 150 | /* EventLog */ fwprintf(wEventLog, L"[ERROR] Could not get a snapshot of the process \"osu!\"!\n"); 151 | fflush(wEventLog); 152 | 153 | statusText = L"Unable to get a Snapshot of the process!"; 154 | DrawTextToWindow(hWnd, statusText, rectStatus); 155 | 156 | return NULL; 157 | } 158 | 159 | PROCESSENTRY32 pe; 160 | pe.dwSize = sizeof(pe); 161 | 162 | if (Process32First(hSnapshot, &pe)) { 163 | do { 164 | if (pe.szExeFile == exe) { 165 | CloseHandle(hSnapshot); 166 | return ULongToPtr((ULONG)pe.th32ProcessID); 167 | } 168 | } while (Process32Next(hSnapshot, &pe)); 169 | } 170 | 171 | CloseHandle(hSnapshot); 172 | return NULL; 173 | } 174 | 175 | LPVOID GetAddress(HANDLE hProcess, LPVOID baseAddress, UINT pLevel) { 176 | ULONG address; 177 | ULONG result; 178 | 179 | ReadProcessMemory(hProcess, baseAddress, &address, sizeof(address), nullptr); 180 | 181 | for (UINT i = 1U; i < pLevel; i++) { 182 | ReadProcessMemory(hProcess, ULongToPtr(address), &result, sizeof(result), nullptr); 183 | address = result + offsets[i]; 184 | } 185 | 186 | return ULongToPtr(address); 187 | } 188 | -------------------------------------------------------------------------------- /Osu!Bot V2/vec2f.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class vec2f { 4 | public: 5 | // Constructor 6 | float x, y; 7 | vec2f(float x, float y) : x(x), y(y) {} 8 | vec2f() : x(0.f), y(0.f) {} 9 | 10 | // Operators: 11 | vec2f nor() { 12 | auto nx = -y, ny = x; 13 | x = nx; 14 | y = ny; 15 | return *this; 16 | } 17 | vec2f midPoint(const vec2f &vec) const { 18 | return vec2f((x + vec.x) / 2.f, (y + vec.y) / 2.f); 19 | } 20 | vec2f add(vec2f vec) { 21 | x += vec.x; 22 | y += vec.y; 23 | return *this; 24 | } 25 | vec2f add(float ax, float ay) { 26 | x += ax; 27 | y += ay; 28 | return *this; 29 | } 30 | vec2f operator+=(const vec2f &alt) { 31 | x += alt.x; 32 | y += alt.y; 33 | return *this; 34 | } 35 | vec2f sub(vec2f vec) { 36 | x -= vec.x; 37 | y -= vec.y; 38 | return *this; 39 | } 40 | vec2f mult(float n) { 41 | x *= n; 42 | y *= n; 43 | return *this; 44 | } 45 | vec2f dev(float n) { 46 | x /= n; 47 | y /= n; 48 | return *this; 49 | } 50 | vec2f cpy() const { 51 | return vec2f(x, y); 52 | } 53 | vec2f rotate(float angle) { 54 | auto nx = x, ny = y; 55 | x = (nx * cos(angle) - ny * sin(angle)); 56 | y = (nx * sin(angle) + ny * cos(angle)); 57 | return *this; 58 | } 59 | float length() const { 60 | return sqrtf(x * x + y * y); 61 | } 62 | vec2f normalize() { 63 | return this->dev(this->length()); 64 | } 65 | // Operators END; 66 | 67 | // Destructor 68 | ~vec2f() {} 69 | }; 70 | 71 | // Inline operators: 72 | inline vec2f operator + (vec2f a, vec2f b) { 73 | return a.add(b); 74 | } 75 | inline vec2f operator - (vec2f a, vec2f b) { 76 | return a.sub(b); 77 | } 78 | inline vec2f operator * (vec2f vec, float n) { 79 | return vec.mult(n); 80 | } 81 | inline vec2f operator * (float n, vec2f vec) { 82 | return vec.mult(n); 83 | } 84 | inline vec2f operator / (vec2f vec, float n) { 85 | return vec.dev(n); 86 | } 87 | inline vec2f rotate(vec2f vec, float angle) { 88 | return vec.rotate(angle); 89 | } 90 | inline float vectorAngle(vec2f vec1, vec2f vec2) { 91 | return abs(atan2(vec1.x * vec2.y - vec2.x * vec1.y, vec1.x * vec2.y + vec1.y * vec2.x)); 92 | } 93 | inline bool operator == (vec2f a, vec2f b) { 94 | return a.x == b.x && a.y == b.y; 95 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Osu!Bot V2 2 | A cursor dancing bot that can, fully autonomous, play the Rhythm game called Osu! (standard mode). 3 | 4 | **NOTICE: Osu!Bot V2 is NOT being supported any more! 5 | Please go to [Osu!Bot V3](https://github.com/DDDinggo22/Osu-Bot-V3) for a continued version.** 6 | 7 | USE THIS WITH RESPONSABLITY!! 8 | I DO NOT, I REPEAT, I DO NOT TAKE RESPONSABILITY IF YOU GET YOUR ACCOUNT BANNED/RESTRICTED ON OSU! 9 | 10 | **PROTIP: It is safer to logout of your account before letting Osu!Bot play any beatmap.** 11 | 12 | ## Video Showcase Playlist 13 | https://www.youtube.com/playlist?list=PLkSZ7HI4dIRgKJmiZ_L2XXK7PqpaEbNSl 14 | 15 | ## Downloadable Executables 16 | https://github.com/DDDinggo22/Osu-Bot/releases/ 17 | 18 | ## Usage Instructions 19 | 0. Unzip anywhere you like. 20 | 1. Execute (Osu!Bot V2.exe). 21 | 2. Select osu! 'songs' folder (default location like: C:\Users\\[USERNAME]\AppData\local\osu!\songs). 22 | (This step only needed on first startup or after deletion of Osu!Bot 'Data' Folder.) 23 | 3. Play any map. 24 | 4. Customize Dance if you like. 25 | 5. Play next map. 26 | 27 | ## Remarks 28 | ### Issues 29 | * If the cursor seems to freeze in place after starting any beatmap and osu! recently had an update, it mostlikely is a outdated 'TimerPointer'. 30 | You can find a working one below here. If that one doesn't seem to work either, you can try to find it yourself with the instructions below that. Or just give me a ping/make an issue with the tag TimerPointer. And I'll update it as soon as possible. 31 | 32 | * Osu!Bot seems to have issues in the 'Release x64' build with finding the 'TimerPointer'. So for the time being, only the x86 will be packed/zipped in the downloadable releases. 33 | 34 | ### Compatibility 35 | * If Osu!Bot can't find the beatmap you can manually select it by pressing the select/change button to the right of the 'Auto Open song'. 36 | 37 | ### Features 38 | * Osu!Bot is able to play with any mod! 39 | BUT if you want it to play with 'Hardrock' You need to manually enable the hardrock by checking 'Hardrock (flip)'. 40 | 41 | * Osu!Bot has a slider that can increase how strong the Dance moves are! 42 | 43 | * Osu!Bot can Dance with multiple styles! Try them out, mix different styles for circles, sliders and spinners! 44 | Not All styles for sliders/spinners are implemented yet, but will fallback to their defaults. 45 | 46 | * Osu!Bot will remember your (Dance) Settings upon restart with its configFile! 47 | Only need to set once and play as much as you want! 48 | 49 | ## Timer Pointer 50 | | Name | Hex Value | 51 | | ------------- | ------------- | 52 | | ThreadOffset | -32C | 53 | | Offset0 | 0 | 54 | | Offset1 | 1F0 | 55 | | Offset2 | 22C | 56 | | Offset3 | 2D8 | 57 | | Offset4 | 514 | 58 | 59 | ### To find this pointer yourself 60 | Search for the time with something like Cheat Engine, this can be done easily in edit mode on osu!, and make a pointer of that address. Then put the pointer as the TimerPointer for Osu!Bot. You can change this via the settings tab or manually in the configFile. 61 | --------------------------------------------------------------------------------