├── icons ├── icon.ico └── icon.png ├── LICENSE ├── FAQ.md ├── main.py └── README.md /icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HGStyle/GD-SaveFileFixer/HEAD/icons/icon.ico -------------------------------------------------------------------------------- /icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HGStyle/GD-SaveFileFixer/HEAD/icons/icon.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 HGStyle 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 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | # FAQ (Frequently Asked Questions) 2 | 3 | A.K.A. "Foire Aux Questions" (FAQ) in French. (useless fact but why not) 4 | 5 | ## it doznt workkkkk helllppp meeeee 6 | 7 | I'm sorry, but I can't help if you just send me this. 8 | At least send me a screenshot or a text transcription of what's on the screen, if a terminal (a black window) is opened, please report what's written on it. 9 | 10 | ## Android tutorial is way too long 11 | 12 | You wanna try to get your GD savefiles back, yes or not? It's the only way, as far as I know. 13 | 14 | ## I use BSD or Ubuntu Touch 15 | 16 | Use Android or Linux instead. I have no idea where are the savefiles saved. Good luck. 17 | If you have the savefiles, ~~use [Wine](https://winehq.org/) to get a Windows environement (to get support fixing for Windows/Android-like savefiles), 18 | or [Darling](https://darlinghq.org/) to get a Darwin (MacOS) environement (to get support for fixing MacOS/iOS-like savefiles)~~ Version 2 now automatically selects the right format even if you're not on the right OS and fixes it in the format it originally was. You won't be able to convert from a format to another using this tool. (Maybe I'll make a future 2.1 update where I will add this functionality...). 19 | 20 | ## I don't wanna cancel my iDevice guarentee 21 | 22 | Firstly, check is the guarentee still available for your device! Because maybe it's not, so you won't cancel anything. 23 | See Apple's website: [Apple Check Coverage](https://checkcoverage.apple.com/). Also, if it's not a guarentee directly given by Apple (example: a guarentee given by your local tech shop), you have to check their terms. Maybe they allow jailbreaking under certain terms, or maybe they allow it if you pay them to do it. I don't know everything, however, searching is the most precious power in the universe. Finding is the second one. 24 | 25 | ## What is this for? 26 | 27 | If you cannot open Geometry Dash, then try this. It is not guarenteed to work, but it may in 50% of time. 28 | It fixes some weird data put by Geometry Dash in it for some reason and that the game can't handle, because 29 | we all know that RobTop is the most unlogical programmer that ever existed. 30 | It works on official versions from Google Play Store, Apple Store/iTunes, Microsoft Store and Steam, but also 31 | for cracked versions and other custom versions such as unofficial versions (ex: unofficial 2.2s) or GDPSes. 32 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | ### DEVELOPER WARNING: THE SYNTAX USED IN THIS PROGRAM MOSTLY DOES NOT RESPECT THE PEP 8 SYNTAX, YOUVE BEEN WARNED ### 4 | # Imports the necessary libraries 5 | import base64 6 | import datetime # Don't forget to write datetime.datetime, and not just datetime ! 7 | import os 8 | import shutil 9 | import sys 10 | import gzip 11 | import platform 12 | import time 13 | import urllib.request # Oh my fckin no. Not this fckin library. 14 | import subprocess 15 | 16 | # Function to clear the screen 17 | def clear_screen() -> None: 18 | if os.name == 'nt': 19 | os.system('cls') 20 | else: 21 | print('\033c', end='') 22 | 23 | # Function to set the terminal title 24 | def set_title(title: str) -> None: 25 | if os.name == 'nt': 26 | os.system(f'title {title}') 27 | else: 28 | print(f"\033]0;{title}\a", end='') 29 | 30 | # Function to exit 31 | def exit(code: int = 0) -> None: 32 | input('Press Enter to exit...') 33 | if not code: 34 | clear_screen() 35 | sys.exit(code) 36 | 37 | # Function to remove KeyboardInterrupt errors on Ctrl+C on input() functions 38 | _input = input 39 | def input(*args, **kwargs): 40 | try: 41 | return _input(*args, **kwargs) 42 | except KeyboardInterrupt: 43 | if "Press Enter to exit..." in args or "Press Enter to exit..." in kwargs.values(): 44 | sys.exit(1) 45 | exit(1) 46 | 47 | IS_COMPILED = "__compiled__" in globals() # Difference between compiled and frozen: 48 | IS_FROZEN = getattr(sys, 'frozen', False) # Frozing is putting Python and the script in an EXE like PyInstaller/Oxidizer 49 | 50 | if not(IS_COMPILED) and not(IS_FROZEN): 51 | # Tries to import PIP (to install other modules) 52 | try: 53 | exec('i m p o r t p i p'.replace(' ', '')) # Little hack so Depency Walkers used by compilers won't detect this import 54 | except ImportError: 55 | print('PIP is not installed. It is needed to download some additional modules to add functionalities.') 56 | choice = input('Would you like to download it? (y/n) -> ') 57 | if "y" in choice.lower(): 58 | print('Installing PIP... This may take some time depending on your internet connection.') 59 | # Download the right installer 60 | pip_ver_dl_url = f"https://bootstrap.pypa.io/pip/{sys.version_info.major}.{sys.version_info.minor}/get-pip.py" 61 | pip_dl_url = "https://bootstrap.pypa.io/pip/get-pip.py" 62 | if urllib.request.urlopen(pip_ver_dl_url).getcode() // 100 == 2: 63 | urllib.request.urlretrieve(pip_ver_dl_url, 'get-pip.py') 64 | else: 65 | urllib.request.urlretrieve(pip_dl_url, 'get-pip.py') 66 | # Run the installer 67 | subprocess.run([sys.executable, "get-pip.py"]) 68 | # Check PIP's installation 69 | try: 70 | exec('i m p o r t p i p'.replace(' ', '')) # Little hack so Depency Walkers used by compilers won't detect this import 71 | print('PIP installation has been successfull.') 72 | except ImportError: 73 | print('PIP installation has failed.') 74 | pip = None 75 | else: 76 | pip = None 77 | # Tries to import PyCryptoDome (to en/decrypt Apple GD savefiles) 78 | try: 79 | exec('f r o m C r y p t o . C i p h e r i m p o r t A E S'.replace(' ', '')) # Little hack so Depency Walkers used by compilers won't detect this import 80 | except ImportError: 81 | print('PyCryptoDome is not installed. It is needed for fixing MacOS/iOS savefiles.') 82 | if pip: 83 | choice = input('Would you like to download it? (y/n) -> ') 84 | if "y" in choice.lower(): 85 | print('Installing PyCryptoDome... This may take some time depending on your internet connection.') 86 | subprocess.run([sys.executable, "-m", "pip", "install", "pycryptodome"]) 87 | try: 88 | exec('f r o m C r y p t o . C i p h e r i m p o r t A E S'.replace(' ', '')) # Little hack so Depency Walkers used by compilers won't detect this import 89 | print('PyCryptoDome installation has been successfull.') 90 | except ImportError: 91 | print('PyCryptoDome installation has failed.') 92 | AES = None 93 | else: 94 | print('PIP is not installed. Installing PyCryptoDome is impossible.') 95 | AES = None 96 | else: 97 | try: 98 | from Crypto.Cipher import AES # This one should stay as-is even when compilling a binary/using a depency walker 99 | except ImportError: 100 | print('MacOS/iOS savefiles will not be fixed since PyCryptoDome is not available.') 101 | AES = None 102 | 103 | # Set some Python variables 104 | __version__ = "2.0.0" 105 | __author__ = "HGStyle" 106 | __original_by__ = "WEGFan" 107 | __program_name__ = "GD-SaveFile-Fixer" 108 | __source__ = "https://github.com/HGStyle/GD-SaveFileFixer" 109 | __license__ = "MIT License" 110 | 111 | # Function to decode a savefile 112 | def decode_savefile(data: bytes, decode_type: str) -> bytes: 113 | if decode_type.lower().strip() in ["windows", "android", "linux"]: 114 | # Decode the savefile using non-Apple GD encoding 115 | data = bytes(c ^ 11 for c in memoryview(data)[:len(data) & -4]) 116 | data = base64.urlsafe_b64decode(data) 117 | data = gzip.decompress(data) 118 | elif decode_type.lower().strip() in ["macos", 'ios']: 119 | if not AES: 120 | print('PyCryptoDome is not installed. Savefile decoding cannot be done.') 121 | return b"" 122 | # Decode the savefile using Apple GD encoding 123 | cipher = AES.new(b'ipu9TUv54yv]isFMh5@;t.5w34E2Ry@{', AES.MODE_ECB) 124 | data = cipher.decrypt(data) 125 | if data[-1] < 16: 126 | data = data[:-data[-1]] 127 | else: 128 | print(f'Cannot decode savefile due to unknown encoding type called {decode_type}.') 129 | return b"" 130 | return data 131 | 132 | # Function to encode a savefile 133 | def encode_savefile(data: bytes, encode_type: str) -> bytes: 134 | if encode_type.lower().strip() in ["windows", "android", "linux"]: 135 | # Encode the savefile using non-Apple GD encoding 136 | data = gzip.compress(data) 137 | data = base64.urlsafe_b64encode(data) 138 | data = bytes(c ^ 11 for c in data) 139 | elif encode_type.lower().strip() in ["macos", 'ios']: 140 | if not AES: 141 | print('PyCryptoDome is not installed. Savefile encoding cannot be done.') 142 | return b"" 143 | # Encode the savefile using Apple GD encoding 144 | len_r = len(data) % 16 145 | if len_r: 146 | data += (16 - len_r).to_bytes(1, "little") * (16 - len_r) 147 | cipher = AES.new(b'ipu9TUv54yv]isFMh5@;t.5w34E2Ry@{', AES.MODE_ECB) 148 | data = cipher.encrypt(data) 149 | else: 150 | print(f'Cannot encode savefile due to unknown encoding type called {encode_type}.') 151 | return data 152 | 153 | # Function to guess which GD encoding is being used 154 | def guess_gd_encoding(data: bytes) -> str: 155 | try: 156 | decode_savefile(data, "windows") 157 | except Exception: 158 | return "macos" 159 | try: 160 | decode_savefile(data, "macos") 161 | except Exception: 162 | if not AES: 163 | return "macos" 164 | return "windows" 165 | return "windows" 166 | 167 | # Function to fix a savefile 168 | def fix_savefile(filepath: str, decode_type: str = "") -> bool: 169 | try: 170 | # Read the data 171 | data = open(filepath, 'rb').read() 172 | # Guess the GD encoding if needed 173 | if not decode_type: 174 | decode_type = guess_gd_encoding(data) 175 | # Decode the savefile 176 | data = decode_savefile(data, decode_type) 177 | if not data: 178 | return False 179 | # Fix the savefile 180 | data = data.replace(b'><', b'> <') 181 | # Encode the savefile 182 | data = encode_savefile(data, decode_type) 183 | if not data: 184 | return False 185 | # Write the data 186 | with open(filepath, 'wb') as f: 187 | f.write(data) 188 | return True 189 | except Exception: 190 | return False 191 | 192 | # Function to ask a question and get a valid response from a set of responses 193 | def ask_for_choice(question: str, responses: list) -> int: 194 | print(question) 195 | choices = "" 196 | valid_keys = [] 197 | x = 1 198 | for response in responses: 199 | choices += f"{x}. {response}\n" 200 | valid_keys.append(str(x)) 201 | x += 1 202 | print(choices) 203 | isfirstatt = True 204 | while True: 205 | if not isfirstatt: 206 | print('Invalid response, please choose the number of the option.') 207 | print(question) 208 | print(choices) 209 | choice = input('Write your choice -> ') 210 | if choice.lower().strip() in valid_keys: 211 | return int(choice.lower().strip()) - 1 212 | else: 213 | if isfirstatt: 214 | isfirstatt = False 215 | clear_screen() 216 | 217 | # Function to ask a question and get a valid filepath 218 | def ask_for_path(question: str) -> None: 219 | print(question) 220 | isfirstatt = True 221 | while True: 222 | if not isfirstatt: 223 | print('Invalid file path, please choose the number of the option.') 224 | print(question) 225 | choice = input('Write the filepath -> ').strip() 226 | if not choice: 227 | return "" 228 | choice = choice.replace('/', os.sep).replace('\\', os.sep) 229 | if os.path.exists(choice): 230 | return choice 231 | else: 232 | if isfirstatt: 233 | isfirstatt = False 234 | clear_screen() 235 | 236 | # Function to create a backup of a file 237 | def backup_file(filepath: str, dirpath: str) -> bool: 238 | output = os.path.join(dirpath, os.path.basename(filepath)) 239 | shutil.copyfile(filepath, output) 240 | return os.path.exists(output) 241 | 242 | # Function to get a backup directory 243 | def get_backup_dir(path: str) -> str: 244 | dirpath = os.path.join(path, "backup_" 245 | + datetime.datetime.now().strftime('Y%Y-M%m-D%d-h%H') 246 | + str(round(time.time())) 247 | ) 248 | if not os.path.exists(dirpath): 249 | os.mkdir(dirpath) 250 | return dirpath 251 | 252 | # Function to check is a file a Geometry Dash savefile (now its a better algorythm) 253 | def is_valid_savefile(filepath: str) -> bool: 254 | if not os.path.basename(filepath).startswith('CC'): 255 | return False # Not a GD savefile filename 256 | if os.path.basename(filepath).startswith('CCBetter'): 257 | return False # GD mod savefile filename 258 | if not filepath.endswith('.dat'): 259 | return False 260 | encoded = open(filepath, 'rb').read() 261 | if not encoded: # Empty savefile 262 | return False 263 | try: 264 | decoded = decode_savefile(encoded, "windows").decode() 265 | except Exception: # Not using non-Apple GD encoding 266 | try: 267 | decoded = decode_savefile(encoded, "macos").decode() 268 | except Exception: # Not using Apple GD encoding 269 | return False 270 | if not decoded: # Decoding failed 271 | return False 272 | if "<" not in decoded or ">" not in decoded: 273 | return False # Not XML data 274 | return True 275 | 276 | # Function to search for savefiles 277 | def search_savefiles(path: str) -> list: 278 | results = [] 279 | for root, dirs, files in os.walk(path, onerror=lambda _: None): 280 | try: 281 | for f in files: 282 | p = os.path.join(root, f) 283 | if p.split(os.sep)[-2].startswith('backup'): 284 | continue 285 | if is_valid_savefile(p): 286 | results.append(p) 287 | print('Found savefile: ' + results[-1]) 288 | except PermissionError: 289 | continue 290 | return results 291 | 292 | # Function to get the system name 293 | def get_system_name() -> str: 294 | systemname = platform.system().lower() 295 | platformname = platform.platform().lower() 296 | if systemname == "windows" or systemname == "cygwin": 297 | return "windows" 298 | elif systemname == "darwin" and "mac" in platformname: 299 | return "macos" 300 | elif systemname == "linux": 301 | return "linux" 302 | elif systemname == "android": 303 | return "android" 304 | elif systemname == "darwin" and "mac" not in platformname: 305 | return "ios" 306 | else: 307 | print(f'Cannot recognise the system name called {systemname} {platformname}.') 308 | return "" 309 | 310 | # Function to get Geometry Dash's data folder depending on the system 311 | def get_game_data_folder(system_name: str) -> str: 312 | if system_name == "windows": # Stored in %localappdata%\GeometryDash 313 | return os.path.join(os.getenv('LOCALAPPDATA'), "GeometryDash") 314 | elif system_name == "macos": # Most likely stored in ~/Library/Application Support/GeometryDash 315 | path = os.path.expanduser("~/Library/Application Support/GeometryDash") 316 | if os.path.exists(path): 317 | return path 318 | elif system_name in ["linux", "macos"]: # TODO: Maybe split these in multiple functions for better understanding 319 | if os.path.exists(os.path.expanduser('~/.local/share/Steam/')) or os.path.exists(os.path.expanduser('~/.steam/')): # Steam 320 | # Get the Steam folder 321 | if os.path.exists(os.path.expanduser('~/.local/share/Steam/')): 322 | steam_path = "~/.local/share/Steam/" 323 | elif os.path.exists(os.path.expanduser('~/.steam/')): 324 | if os.path.exists(os.path.expanduser('~/.steam/steam/')): 325 | steam_path = "~/.steam/steam/" 326 | else: 327 | steam_path = "~/.steam/" 328 | # Get the Geometry Dash data folder 329 | path = os.path.expanduser(steam_path + 330 | "steamapps/compatdata/322170/pfx/drive_c/users/{}/Local Settings/Application Data/GeometryDash") 331 | # Gets the current Steam account username (needed to get the data folder path) 332 | try: 333 | steam_user_dir = os.path.expanduser(steam_path + "userdata") 334 | steam_user_dirs = [os.path.join(steam_user_dir, d) for d in os.listdir(steam_user_dir) 335 | if os.path.isdir(os.path.join(steam_user_dir, d))] 336 | steam_user_account = os.path.basename(max(steam_user_dirs, key=os.path.getmtime)) 337 | except: 338 | steam_user_account = "steamuser" 339 | # Get the final data folder path 340 | if os.path.exists(path.format(steam_user_account)): 341 | return path.format(steam_user_account) 342 | if os.path.exists(os.path.expanduser('~/.local/share/lutris/')) or os.path.exists(os.path.expanduser('~/.lutris/')): # Lutris 343 | # Get the Lutris folder 344 | if os.path.exists(os.path.expanduser('~/.local/share/lutris/')): 345 | lutris_path = "~/.local/share/lutris/" 346 | elif os.path.exists(os.path.expanduser('~/.lutris/')): 347 | if os.path.exists(os.path.expanduser('~/.lutris/lutris/')): 348 | lutris_path = "~/.lutris/lutris/" 349 | else: 350 | lutris_path = "~/.lutris/" 351 | # Get the Geometry Dash data folder 352 | path = os.path.expanduser(lutris_path + 353 | "runners/wine/{}/prefix/drive_c/users/{}/Local Settings/Application Data/GeometryDash") 354 | # Get the session name from the home folder 355 | username = path.split(os.sep)[2] 356 | # Get Lutris's Wine version 357 | wine_vers = [i for i in os.listdir(os.path.expanduser(lutris_path + "runners/wine")) 358 | if os.path.exists(path.format(i, username))] 359 | # Get the final data folder path 360 | if wine_vers: 361 | return path.format(wine_vers[0], username) 362 | if os.path.exists(os.path.expanduser('~/.wine/')) or os.path.exists(os.path.expanduser('~/.local/share/applications/wine/')): # Wine 363 | # Get the Wine folder 364 | if os.path.exists(os.path.expanduser('~/.wine/')): 365 | if os.path.exists(os.path.expanduser('~/.wine/wine/')): 366 | wine_path = "~/.wine/wine/" 367 | else: 368 | wine_path = "~/.wine/" 369 | elif os.path.exists(os.path.expanduser('~/.local/share/applications/wine/')): 370 | wine_path = "~/.local/share/applications/wine/" 371 | # Get the Geometry Dash data folder 372 | path = os.path.expanduser(wine_path + "drive_c/users/{}/Local Settings/Application Data/GeometryDash") 373 | # Get the session name from the home folder 374 | username = path.split(os.sep)[2] 375 | # Get the final data folder path 376 | if os.path.exists(path.format(username)): 377 | return path.format(username) 378 | print('Cannot get the game data folder due to unknown way of launching Geometry Dash under this Linux system.') 379 | elif system_name == "android": # Stored in /data/data/com.robtopx.geometryjump/ 380 | return "/data/data/com.robtopx.geometryjump/" 381 | elif system_name == "ios": # Stored in /var/mobile/Containers/Data/Application/com.robtop.geometryjump/ 382 | return "/var/mobile/Containers/Data/Application/com.robtop.geometryjump/" 383 | else: 384 | print(f'Cannot get the game data folder due to unknown system called {system_name}.') 385 | return "" 386 | 387 | # Function to check if the folder available and show tips to users about it being inaccessible, if its the case 388 | def is_folder_accessible(path: str, system_name: str) -> bool: 389 | if not os.path.exists(path): 390 | print('The data folder cannot be found. Please use annother mode.') 391 | if system_name == "linux": 392 | print('Note that the programm can only get the data folder if you play Geometry Dash using Steam, Lutris or Wine.') 393 | return False 394 | if os.access(path, os.R_OK) and os.access(path, os.W_OK): 395 | return True # Folder is accessible 396 | if system_name == "android": 397 | print('The data folder is inaccessible. Make sure you rooted your phone, or that you modified the app using App Cloner.') 398 | if system_name == "ios": 399 | print('The data folder is inaccessible. Make sure you jailbroken your phone.') 400 | return False 401 | 402 | # Function to check whenether a filename is being known as a savefile 403 | def is_savefile_name(path: str): 404 | return os.path.basename(path) in [ 405 | "CCGameManager.dat", 406 | "CCGameManager.dat.bak", 407 | "CCGameManager2.dat", 408 | "CCGameManager2.dat.bak", 409 | "CCLoaderManager.dat", 410 | "CCLoaderManager.dat.bak", 411 | "CCLoaderManager2.dat", 412 | "CCLoaderManager2.dat.bak", 413 | "CCLocalLevels.dat", 414 | "CCLocalLevels.dat.bak", 415 | "CCLocalLevels2.dat", 416 | "CCLocalLevels2.dat.bak" 417 | ] 418 | 419 | # Function to search for the savefiles from their static names 420 | def search_static_savefiles(path: str) -> list: 421 | results = [] 422 | for root, dirs, files in os.walk(path, onerror=lambda _: None): 423 | try: 424 | for f in files: 425 | p = os.path.join(root, f) 426 | if p.split(os.sep)[-2].startswith('backup'): 427 | continue 428 | if is_savefile_name(p) and is_valid_savefile(p): 429 | results.append(p) 430 | print('Found savefile: ' + results[-1]) 431 | except PermissionError: 432 | continue 433 | return results 434 | 435 | # Function to get the data folder depending on the system 436 | def get_data_folder(system_name: str) -> list: 437 | return { 438 | "windows": [ 439 | os.getenv('LOCALAPPDATA') 440 | ], 441 | "macos": [ 442 | os.path.expanduser("~/Library/Application Support"), 443 | os.path.expanduser("~/.wine"), 444 | os.path.expanduser("~/.lutris"), 445 | os.path.expanduser("~/.steam"), 446 | os.path.expanduser('~/.local/share/lutris/'), 447 | os.path.expanduser('~/.local/share/applications/wine/'), 448 | os.path.expanduser('~/.local/share/Steam/') 449 | ], 450 | "linux": [ 451 | os.path.expanduser("~/.wine"), 452 | os.path.expanduser("~/.lutris"), 453 | os.path.expanduser("~/.steam"), 454 | os.path.expanduser('~/.local/share/lutris/'), 455 | os.path.expanduser('~/.local/share/applications/wine/'), 456 | os.path.expanduser('~/.local/share/Steam/') 457 | ], 458 | "android": [ 459 | "/data/data" 460 | ], 461 | "ios": [ 462 | "/var/mobile/Containers/Data/Application" 463 | ] 464 | }[system_name] 465 | 466 | # Run if not imported 467 | if __name__ == "__main__": 468 | print("""----------------------------------------------------------- 469 | Hello user! READ THIS IF ITS YOUR FIRST USE. (IMPORTANT) 470 | ----------------------------------------------------------- 471 | THIS TOOL IS PROVIDEN WITHOUT ANY GUARANTEE OF SUCCESS, 472 | OR MAY ACCIDENTALY BROKES YOUR SAVEFILES, that's why it 473 | automatically creates a backup before modifying any file! 474 | Rollback this backup manually if you need it. 475 | (TODO: Add a function to rollback backups of savefiles) 476 | ----------------------------------------------------------- 477 | NOTE IF YOU USE AN ANDROID EMULATOR (BlueStacks, Nox, etc): 478 | You must run this program in the emulator using Termux 479 | and follow the Android instructions, else it won't work! 480 | ----------------------------------------------------------- 481 | NOTE IF YOU ARE USING WINE OR SIMILAR SOFTWARE: 482 | On Linux and MacOS, downloading the programm and running it 483 | by double-clicking it should work. 484 | If it doesn't work, or you are not using Linux or MacOS 485 | (example: any BSD system), download the Windows version 486 | and run it in Wine or the program you use to run the game. 487 | ----------------------------------------------------------- 488 | THIS PROGRAM IS FREELY RELEASED UNDER MIT LICENSE. 489 | IF YOU PAID FOR IT, YOU SHOULD ASK FOR REFUND! 490 | ----------------------------------------------------------- 491 | ALWAYS DOWNLOAD THE PROGRAM FROM OUR GITHUB REPO (link below) 492 | TO MAKE SURE YOU DON'T GET MALWARE! 493 | ----------------------------------------------------------- 494 | For more informations/help, check our GitHub at: 495 | https://github.com/HGStyle/GD-SaveFileFixer/""") 496 | input('Press Enter to continue.') 497 | clear_screen() 498 | MODES_RESPONSES = [ 499 | "Static Classic: Will get the game data folder for your OS, and repair only the known savefiles.", 500 | "Dynamic Classic: Will get the game data folder for your OS, and repair all the data files that uses GD encoding.", 501 | "Static Search: Will search for known savefiles recursively in the data folder of your OS.", 502 | "Dynamic Search: Will search for data files that uses GD encoding recursively in the data folder of your OS.", 503 | "Manual: Will ask you for the paths of the savefiles. Don't use if you are not guided or if you're not a technerd." 504 | ] 505 | MODES_QUESTION = """ 506 | Which mode do you want to use? Every mode makes a backup of each file found. 507 | NOTES ABOUT MODES: 508 | - Always try first Classic modes. 509 | - Search modes are a bit long but will work with GDPS while Classics modes can't. 510 | - Search modes are made to try to not corrupt non-GD files, however this is not guaranteed. 511 | - Manual is for you if you know where are your savefiles and what are their paths.""".strip() 512 | modes_choice = ask_for_choice(MODES_QUESTION, MODES_RESPONSES) # decided to not care about this: peps.python.org/pep-8/#constants 513 | # Get the system name 514 | system_name = get_system_name() 515 | clear_screen() 516 | # Launch the selected mode 517 | if modes_choice in [0, 1]: 518 | gamedata_folder = get_game_data_folder(system_name) 519 | if modes_choice == 0: 520 | savefiles = search_static_savefiles(gamedata_folder) 521 | else: 522 | savefiles = search_savefiles(gamedata_folder) 523 | elif modes_choice in [2, 3]: 524 | data_folder = get_data_folder(system_name) 525 | if modes_choice == 2: 526 | savefiles = search_static_savefiles(data_folder) 527 | else: 528 | savefiles = search_savefiles(data_folder) 529 | game_names = [i[len(data_folder):].split(os.sep)[0] for i in savefiles] 530 | print(""" 531 | Which "copy of Geometry Dash" do you want to fix? Write the number of the choice. 532 | You can put multiple ones by separating the numbers of your choice by a slash (/). 533 | Not choosing anything by just pressing Enter will fix them all.""".strip()) 534 | print('\n'.join(game_names)) 535 | selected_game_names = [] 536 | user_choice = input('---> ') 537 | if not user_choice: 538 | selected_game_names = game_names 539 | else: 540 | user_choice = user_choice.split('/') 541 | for selection in user_choice: 542 | if selection.strip() in game_names: 543 | selected_game_names.append(selection.strip()) 544 | else: 545 | print(f'Ignoring "{selection.strip()}" as the name is not recognized.') 546 | if not selected_game_names: 547 | print('Warning: No valid name has been recognized, selecting them all...') 548 | selected_game_names = game_names 549 | savefiles = [i for i in savefiles if i[len(data_folder):].split(os.sep)[0] in selected_game_names] 550 | else: 551 | savefiles = [] 552 | user_input = None 553 | while user_input != "": 554 | user_input = ask_for_path("Which file should be added to savefile list?" + 555 | "\nEnter nothing to start fixing all the selected savefiles.") 556 | is_savefile = is_valid_savefile(user_input) 557 | if user_input and is_savefile: 558 | savefiles.append(user_input) 559 | elif user_input and not is_savefile: 560 | print('This savefile is not seeming valid. Make sure you did put the right file!' + 561 | '\nIf you did, then sorry, everything in it is probably lost forever, and I cannot do anything.') 562 | clear_screen() 563 | clear_screen() 564 | print(f'{len(savefiles)} savefiles selected...') 565 | print('Backing up savefiles...') 566 | errors = 0 567 | for savefile in savefiles: 568 | try: 569 | backup_dir = get_backup_dir(os.path.dirname(savefile)) 570 | backup_file(savefile, backup_dir) 571 | except Exception: 572 | errors += 1 573 | print('An exception occured while backuping file: ' + savefile) 574 | print('Backup done.') 575 | if errors > 0: 576 | if ask_for_choice(['Yes', 'No'], "Error(s) occured. Do you still want to try to fix the savefiles ?") == 1: 577 | exit() 578 | del errors # A bit of cleanup (completely useless, I know) 579 | clear_screen() 580 | print('Fixing the savefiles...') 581 | errors = 0 582 | for savefile in savefiles: 583 | if not fix_savefile(savefile): 584 | errors += 1 585 | print('An exception occurred while fixing file: ' + savefile) 586 | else: 587 | print('Savefile fixed successfully: ' + savefile) 588 | print('Fixing done.') 589 | if errors > 0: 590 | print(f'{errors} number of errors happened while fixing all of them.') 591 | print("Now, you can retry to launch Geometry Dash. If it didn't worked, I'm sorry, but I can't do anything more.") 592 | exit() 593 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Geometry Dash Savefile Fixer 2 | 3 | This tool can fix most problems that make the game unable to open due to the savefiles. (which means that the game will only launch if you move the savefiles to other folders.) 4 | This is an ameliorated version of the [Geometry-Dash-Savefile-Fix](https://github.com/WEGFan/Geometry-Dash-Savefile-Fix) made by [WEGFan](https://github.com/WEGFan) but since he seems inactive now, and there are some issues opened, I wanted to help these people to don't lose their data. This is an entire rewrite of the code, I licensed it under [MIT License](https://hgstyle.mit-license.org/2023) so you can do almost anything you want on this software, including using it in closed-source projects and so on... Only 1 thing: credit me (plz). Thank you all. 5 | 6 | ## Note 7 | 8 | ### 2.2 certainly fixed this bug, so if you are using 2.2 it's very very unlikely this program will fix your game. However, for 2.1 and before, this software is still quite useful, and still working great! 9 | 10 | ## Instructions 11 | 12 | If they seem really long, its because I try to include every cases to make everyone can use this programm. You can skip sections for Linux users (since they are really long) if you aren't using Linux (remember, Ubuntu, Debian, etc... are Linux!). If its so complicated on Linux, it's because there are many different "editions" of Linux (actually called distributions or distros, example: Ubuntu and Debian are Linux distributions) and they have different applications, with different versions, and its sometimes hard to make an operation working on every distribution. 13 | 14 | ## Not working? 15 | 16 | Firstly, check the [project FAQ](https://github.com/HGStyle/GD-SaveFileFixer/blob/master/FAQ.md) If you encounter any problem (unable to fix / doesn't work after fixed), get help by [creating an issue](https://github.com/HGStyle/GD-SaveFileFixer/issues/new) (edit: @superchupu on Discord told me issues are disabled, now they are back - sorry) or [contact me on Discord](https://dsc.gg/hgstyle). 17 | 18 | ### Using prebuilt binaries 19 | 20 | In the [GitHub Releases](https://github.com/HGStyle/GD-SaveFileFixer/releases), I post the source code of the project per version, but also binaries (= executable files) that I build myself on my computer (mostly on live sessions like MX Linux or Hirens BootCD). You can download these and run them on your computer directly without installing the whole [Python programming language](https://python.org/) (if you dont know if your computer is 64bits or 32bits, choose the 32bits version). Note that **I dont post binaries for MacOS, iOS and iPadOS due to the fact that I dont own any Apple device since I hate Apple** (no drama please, its just my opinion. OK, actually I own some iPhones from 2013 but they are so old that I can't even install new apps on them). Even if you download prebuilt binaries, you will still have to install some apps if you are on mobile. 21 | 22 | ### Using the source code 23 | 24 | You may use the source code because there isn't any binary file for you system, or because you dont know which binary file corresponds to your device, or simply because you think that just before compiling binaries I injected a malware in them. (which, I guarrentee it, is false) but if you dont want to risk to be hacked (which is something that I entirelly respect, even me sometimes I prefer running source code that binaries because people reads the code and sees there is no malware in it), you may download the source code in [GitHub Releases](https://github.com/HGStyle/GD-SaveFileFixer/releases), which is the only file that ends with `.py`. You could also download the source code ZIP or TAR file automatically made by GitHub, but you will have to decompress it to get the Python script file. You could also download it from the `master` branch, but I don't recommend that way since I can make changes that makes the someware buggy (since I use online GitHub code editor to edit code of this repository and then I test it on annother PC that have Geometry Dash installed, since my main PC can't support Geometry Dash for the reason that I'm on Linux and when running Geometry Dash with WINE, it says it's a 32 bits program and it can't run it since my PC is 64 bits). 25 | 26 | ### Running on Windows, MacOS or Linux 27 | 28 | If you have downloaded the source code and you are on Windows or MacOS, go to the [Python 3.11.4 downloads](https://www.python.org/downloads/release/python-3117/) which is the latest Python version for now and is tested to be functionnal with my code, scroll down until you see the header "Files", then download and install the version that is right for you (if you dont know if your computer is 64bits or 32bits, choose the 32bits version). Linux users does not have any Python installer on the Python website. Instead, open your package manager (either in graphical UI or in command line) and install the package `python3` and `python3-pip`. After, check the Python version by running the command `python3 --version` in a terminal (don't use `python3 -v` because some old Python versions understands that `-v` means `--verbose` instead of `--version`, if you do it you will get a Python interpreter with lots of weird logs texts for debugging Python, to exit type `exit()` and validate using the Enter key). If your Python version is 3.8 or newer (Python 3.9, 3.10, 3.11, etc...) it should work fine (programm tested on Python 3.8, 3.9 and 3.11). If you get an older version (example: Python 3.6) try to install in your package manager the package called `python3.8` or `python3.10` and then, instead of running the command `python3 --version`, run `[the name of the package you installed] --version` (example for package `python3.8`: `python3.8 --version`). And make sure its Python 3.8 or newer. If the command isn't found, you will have to compile Python yourself from the source code, but don't panic, its pretty easy if you [follow this tutorial](https://ubuntuhandbook.org/index.php/2021/10/compile-install-python-3-10-ubuntu/) (if the commands containing `apt` does not works, try replacing `apt` by `yum`, `pacman` or `dnf`, else try skipping these commands containing `apt` or search Google for annother tutorial, search `How to compile Python 3.10 on [your operating system name, example: Debian]`). 29 | For every OS, after installing Python, you will have to open a terminal (search and run `cmd` on Windows, on MacOS and Linux, search and run `Terminal`) and run the command: `pip install pycryptodome` (its really important if you are fixing MacOS or iOS savefiles, if it fails and you are not fixing MacOS/iOS savefiles its okay, but it should rarely fail). 30 | If you have downloaded a prebuilt binary, you dont have to do anything. 31 | To run the program, on Windows and MacOS, double-click on it. Linux users could try clicking on it (generaly one time) but in most cases it will not work. The solution in that case is to right-click anywhere in the folder on an empty zone, click on "Open terminal here". If this option isn't here, it should be accessible via the options bar at the top of the file manager window, in most cases, under tools, then click on "Open terminal here" or something similar. Then, execute this command in the terminal: `[the name of the python package you installed] [the name of the source code file you downloaded from the github repo]`. In most of case this command will be: `python3 GD-SaveFileFixer-SourceCode.py`. Also, if you downloaded a zip or a tar file, make sure to extract before running the command. You can use [7-zip](https://7-zip.org/) by example (also notice that Windows, MacOS and Linux have a tool installed by default to extract ZIP files, but not TAR files, except on Linux). 32 | 33 | ### Running on Android 34 | 35 | Firstly, you will have to make the Geometry Dash app data accessible to you. By default, to avoid others apps to steal your data, Android has a protection that only allows the installed app to access to his data. Even you, the user, cannot access to it. To bypass this, the most known way is rooting your Android device. This task is dangerous. Really dangerous: do it incorrectly and you may never see your phone starts again. Also, rooting your Android device may cancel the warenty of the device, depending on what you have signed for while getting the warrenty. To avoid users to do this dangerous task and risk to lose all of their data, I found another way, which is still a bit hard to realise but is way much more safer. I'm sorry, but if you have a GDPS (or any Geometry Dash app that has been signed using a test development key like [old App Cloner versions](https://appcloner.blog/2023/01/14/google-play-protect-signing-keys/) or any version of APK Editor with default settings for signing apps) you can do this using only your Android device, but this way is really long to do, and if you have the real Geometry Dash or annother app that hasn't been signed using the test development key (including the Geometry Dash app from the Play Store, every Android mod menus and modified GDPS such as GDPS Editor 2.2) you will need two devices: your Android device and a Windows, MacOS or Linux (they cannot be the same). Here are the steps: 36 | 37 | To know is your Geometry Dash app signed with testkey (so you can use the "is a GDPS" version of the fixer, which requires only your device and is less long): 38 | - Download and install the app [APK Signature Viewer](https://apkpure.com/fr/apk-signature-viewer/com.badzzz.apksigninfoextractor) 39 | - Open the app 40 | - Search for your Geometry Dash 41 | - Click on it 42 | - See if its written somewhere "CN=Android Debug" in the message box that popped up. 43 | - If there is "CN=Android Debug" written, your Geometry Dash is signed with testkey. Else, its not. 44 | 45 | If your Geometry Dash version is a GDPS (or your Geometry Dash is signed using testkey, or has been modified and signed using any version of APK Editor with default signing settings, or [modified using an old version of App Cloner](https://appcloner.blog/2023/01/14/google-play-protect-signing-keys/)) and you aren't on a rooted device: 46 | - Install the app [APK Extractor](https://play.google.com/store/apps/details?id=com.ext.ui) from the Play Store. 47 | - Open the app. Search for your Geometry Dash (or your GDPS, in case it's a GDPS) 48 | - Memorise the package name (which is usually formated like `aaa.bbbbbbb.cccccccccccc`). Since there is many steps, I recommend you to write it on a sticky note. 49 | - Click on the app to extract his APK. We'll need it later. 50 | - Do not uninstall APK Extractor since we'll need it later. 51 | - If the package name you memorised is `com.robtopx.geometryjumq` (notice the `q` at the end !): 52 | - Download and install [APK Editor Pro](https://dl.hgstyle.fr/Apps/AndroidHackerKit/APK_Editor/Clean/APK_Editor_Pro.apk) 53 | - Download the APK of Geometry Dash (but not the one used by GDPSes, and it should be version the same version as the app). I recommend using this one: [Download Geometry Dash 2.111 APK](https://dl.hgstyle.fr/Every_Geometry_Dash_Versions/Android/GeometryDash_Normal_2.111.apk) but if you want other Geometry Dash versions, you can go [here](https://dl.hgstyle.fr/Every_Geometry_Dash_Versions/Android/) to download the right file. 54 | - Open APK Editor Pro, alow storage access, click "Select Apk from App" and click on your Geometry Dash or your GDPS 55 | - Select "Full Edit" and then "Decode All Files", then go to "Files" in the toolbar of APK Editor Pro 56 | - Select the folder `assets` and `lib` and click "Extract", then go to your downloads folder and click "OK" (then wait for it ends and exit the app) 57 | - Make sure to exit the app completely and reopen it, now click "Select an Apk File" and click on the APK file of Geometry Dash 2.111 you downloaded (make sure the APK is stored in your internal storage, not in your SD card !) 58 | - Click "Full Edit" and then "Decode All Files" again and go to files 59 | - Select the folders `assets` and `lib` and click delete 60 | - Click the button with a plus symbol in a folder, and go to "Import Folder" 61 | - Click on the "..." button and browse into the `assets` folder in your downloads folder and click "OK" 62 | - A field will be filled automatically, be sure to see that the last word separated by the "/" is `assets` else click cancel and repeat the two last steps 63 | - Click "OK" and wait for it imports the folder `assets` into the APK 64 | - Again, click the button with a plus symbol in a folder, and go to "Import Folder" 65 | - Click on the "..." button and browse into the `lib` folder in your downloads folder and click "OK" 66 | - A field will be filled automatically, be sure to see that the last word separated by the "/" is `lib` else click cancel and repeat the two last steps 67 | - Click "OK" and wait for it imports the folder `assets` into the APK 68 | - Click on the "Build" button and wait for it builds the APK file 69 | - Open your file manager, go to internal storage, go to the folder "ApkEditor" (if you see multiple files, ignore those that aren't an APK) and move the APK file to the downloas folder in your internal storage 70 | - Optionally, you can delete the "ApkEditor" folder and/or the APK Editor Pro app 71 | - Download an install [App Cloner Pro](https://dl.hgstyle.fr/AndroidHackerKit/Other_apps/App_Cloner_Pro.apk) 72 | - Open App Cloner 73 | - If the package name you memorised is `com.robtopx.geometryjumq` (notice the `q` at the end !): 74 | - Click on the folder icon and click OK when a message box appears 75 | - Click the browse files logo 76 | - Open your downloads folder and click on the APK you just moved here 77 | - Else: 78 | - Search the Geometry Dash app (or your GDPS) and click on it 79 | - Scroll down and go to "Storage options" 80 | - Click on "Redirect external storage" and check the "Enable" box 81 | - Scroll down and enable "Acessible data directory" 82 | - Go back to main options categories 83 | - Scroll up and click on "Clone number" option 84 | - Check the box "Replace original app" and click "OK" 85 | - Click the button with the App Cloner logo on it, click "OK" and wait for it ends 86 | - When you can, click on the "Cancel" button (this will not delete the APK modified by App Cloner) 87 | - Go to the "Cloned APKs" category and hold on the first of the two apps that seems the same, then stop holding 88 | - In the upper toolbar click the diskette logo and save the file to your downloads folder 89 | - Wait for the app to say "Successfully saved file" at the bottom of the app UI 90 | - Close the app and open your file manager 91 | - Go to your downloads folder by going to storage and then in the "Download" folder 92 | - Search for the APK made by App Cloner anc open it/click on it 93 | - It will normally show something like "Do you wanna update this app ?", so click "Install" (or "Update" depending on your Android version) 94 | - If it says "App not installed" it can means two things: you dont have much space free on your device (this normally never happens since the update only adds like 5 mb of code from App Cloner) or (in most of cases) your Geometry Dash hasn't been signed using the test development key, you will have to use the other way with two devices 95 | - If it worked, open your Geometry Dash, and close it. (If it still crashes like before, its not a problem) 96 | - Exit all the apps and go to your browser to download the latest version of the Python programm. There is a binary for Android but I dont recommend it and it may be deleted in the future since Python installation in Termux (the app we'l use to launch the programm) is easy. Download it using [GitHub Releases](https://github.com/HGStyle/GD-SaveFileFixer/releases), download the first file ending with `.py` to your Downloads folder on your internal storage (not SD card ! if its on your SD card you will have to move it to your internal storage download folder). 97 | - Download and install the latest version of [Termux](https://github.com/termux/termux-app/releases/download/v0.118.0/termux-app_v0.118.0+github-debug_universal.apk), then open the app and wait for the loading to finish. Dont use the Google Play Store version since it is no longer updated and broken. You will get a terminal like on Linux, but dont panic, I'll guide you ! 98 | - Open the app when it's installed 99 | - You will have to allow the storage access since [its not enabled by default](https://wiki.termux.com/wiki/Termux-setup-storage). To do that, simply type `termux-setup-storage` and press enter. Now allow storage access and you are ready ! You can enter the next command when you see the dollar symbol back and waiting you for the next command. 100 | - If you are on Android 11 or later (or you dont know which version of Android you have), go to Settings (exit Termux, you can completely close it or not), Applications, Termux, Permissions, disable storage access and re-enable it. [This is due to an Android bug which cannot be fixed by the Termux community.](https://wiki.termux.com/wiki/Termux-setup-storage) Then go back to Termux. 101 | - Now we'll update the Termux programms. Simply type `apt update`, then press enter. After, type `apt upgrade -y` and press enter. After, remove unnecesary software (its automatic and won't break anything) by typing `apt autoremove -y` and press enter. (from now I will no longer say "Press enter", but you will still have to do it after typing a command) 102 | - Now we will install Python. Simply type the command `apt install python3 python-pip -y` and wait. Notice that this can take up to some minutes, depending on your device and internet connection speed. 103 | - Now we need to install Python depencies. This can be done by simply running `python3 -m pip install pycryptodome`. If it fails, it's not really important, just skip this step like if it was done correctly. 104 | - Now you will have to naviguate to your download folder. Firstly, run the command `cd /storage/emulated/0` to go to your internal storage. Then type the command `dir` to list all the files and folders. Find your download folder name and run the command `cd [entire name of your download folder]`. It's usually `cd Download`. 105 | - Now, find the name of the Python script file. Run the command `find . -name "*.py"` (dont forget the dots). You will get the name of every file ending with `.py` (so, for almost every user, only one file: the actual Python script we need to run). 106 | - Run the Python script by doing `python3 [python script full file name]`. It's usually `python3 GD-SaveFileFixer-SourceCode.py`. If the Python script filename contains spaces, run `python3 "[python script full file name]"` (dont forget the two `"`: one at the start, one at the end of the filename). 107 | - If the package name you memorised isn't `com.robtopx.geometryjump`, the second option won't work. That's why it is not recommended, use the recommended option 3 instead. (it should not be long) 108 | - Once the programm has done running (you see the `$` symbol of Termux), close Termux. 109 | - Try opening Geometry Dash (or your GDPS), it should be fixed. BUT DONT QUIT THIS TUTORIAL OR YOU COULD GET HACKED. 110 | - Now we have a problem (not really since I have the solution): every app can access to the game data. Why is this a problem ? They can access your savefiles, so they can access your account, and even, your password. Almost no apps actually steal data from Geometry Dash since they normally can't, but no one knows. To fix this high security issue, go to your file manager, internal storage, then go to the folder called "ApkExtractor", then to the folder called with the same name as your Geometry Dash or GDPS app, then install the only APK in this folder. This will remove the App Cloner changes but not the Python script changes. After this, you are 100% safe. 111 | 112 | If you dont have a rooted phone and the method before this one does not works for you: 113 | - On your Android device, install [Package Name Viewer 2.0](https://play.google.com/store/apps/details?id=com.csdroid.pkg) from the Play Store 114 | - Open the app, and search the Geometry Dash you wanna modify and memorize its package name (which is usually formated like `aaa.bbbbbbb.cccccccccccc`) (write it on a sticky note by example) 115 | - Optionnally, uninstall Package Name Viewer 2.0 116 | - Go to Settings, go to About your device, Informations about the software, and spam the version number box. (Click on it atleast 7 times fastly) 117 | - Confirm your device code/schema if you have one 118 | - Go back to settings menu, scroll down and you will have a new category called "Developers options": go into it. 119 | - WARNING: YOU SHOULD NOT MODIFY A SETTING WITHOUT KNOWING WHAT ARE YOU DOING ! PLAYING WITH THESE SETTINGS MAY MAKE YOUR DEVICE COMPLETELY UNUSABLE AND USELESS, AND YOU MAY LOSE ALL YOUR DATA ! 120 | - Scroll down and enable USB Debugging, so we can use special software to access your device from the other device 121 | - Accept the warning 122 | - Be sure you trust the computer: if it has a malware on it, the malware could steal your Android device data or even infect it ! Also, try to not use a MacOS computer, because I made a mistake in the code so MacOS users will have to install extra software. 123 | - On the computer, download ADB from one of these three links, depending what OS it is running: [Windows version](https://dl.hgstyle.fr/Android_Platform_Tools/PlatformTools_Windows.zip) - [MacOS version](https://dl.hgstyle.fr/Android_Platform_Tools/PlatformTools_MacOS.zip) - [Linux version](https://dl.hgstyle.fr/Android_Platform_Tools/PlatformTools_Linux.zip) 124 | - Decompress the downloaded ZIP file in a folder 125 | - Download the ABE utility by [clicking here](https://github.com/nelenkov/android-backup-extractor/releases/download/master-20221109063121-8fdfc5e/abe.jar) and move it to the folder where are ADB files 126 | - Open the folder in your file manager and to open a terminal: 127 | - On Windows: [Click on the path of the folder and type "cmd" then validate (click to see screenshot)](https://cdn.mos.cms.futurecdn.net/KdeamF4DcfAorSckFR69ZW.jpg) 128 | - On MacOS: [Click Finder, then services and finally "Open terminal at folder" (click to see screenshot)](https://www.maketecheasier.com/assets/uploads/2021/10/launch-any-folder-mac-terminal-new-terminal-at-folder-2.jpg) 129 | - On Linux: Right-click in an empty space and click "Open terminal here". If the option isn't here, in the toolbar click "Tools" and then "Open terminal here" 130 | - In the terminal, type the command `java --version` and press enter. If the `java` command is not found, [install Java by following the instructions here](https://www.java.com/en/download/) or if you are on Linux, search `openjdk` in your package manager and install a version of it (depeding on the package manager, Java can be found as `openjdk-11` by example) then after installing, go back to the terminal and retype the command to see if the command is found (it should be found now) 131 | - Link your Android device and your PC using a charging cable 132 | - In your file manager, make sure you can see that your device is pluged in, else change cable and recheck until you can see it 133 | - In the terminal, type `./adb devices` (or `.\adb.exe devices` if you are on Windows): you should see a list of devices, only one device should be detected: it's yours (you just have to check there is a device detected) 134 | - Now run the command `./adb backup [package name of the geometry dash app]` (on Windows, replace `./adb` by `.\adb.exe`, notice that it's an antislash on Windows, and on other systems its a normal slash) 135 | - On your device, you will have to enter a password: enter a simple password since the encryption for the backup is actually useless for us. The only important thing: make sure you remember it ! Also, make sure it does not contain any special characters, only letters and numbers. Then, validate the backup creation and wait for it finishes. 136 | - While its creating the backup, do not touch your charger to make sure it does not unplug. 137 | - Also (on the PC), Windows 10 users should [enable file extensions in the file manager (click for tutorial)](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/). MacOS users should also do it by [following this tutorial (do it for every files)](https://support.apple.com/guide/mac-help/show-or-hide-filename-extensions-on-mac-mchlp2304/mac). Linux users may see them by default in most cases. 138 | - There is no progress bar, but if you wanna has a proof that it's running, you can right-click on the "backup.ab" file in the folder you previously opened in your file manager, then properties: you can see the file size getting bigger and bigger with time. 139 | - Once the programm in the terminal has stopped, the backup is finished. But since it is encrypted and in an unknown format, we'll use the ABE utility to decrypt it. 140 | - Run the command `java -jar abe.jar unpack backup.ab backup.tar [your password]`. Make sure the password is exactly what you put ! Wait for the programm to end. 141 | - Go back to the folder containing ADB and ABE. Right-click on the file backup.tar and open it with any compatible app (Linux users can open it using their default archiving app, others OSes needs a specific archiving programm to be installed. If you don't have one, download and install [7-zip](https://7-zip.org/)), but only open it, dont extract all the files. (with 7-zip, right-click on the file, 7-zip and finally open archive) 142 | - In the archive manager window to the "apps" folder, then go to the folder called with the same name as the app package name, then go to the folder called "r". 143 | - Select the files that ends with `.dat` (maybe there is 2 files, 3 or 4) and drag-n-drop them to the folder containing the ADB and ABE programms, wait for the archiving programm to decompress the file and close the programm. 144 | - ~~If you are on MacOS, you will have to use [WineBottler](https://winebottler.kronenberg.org/) to run the programm as a Windows programm (because I made a mistake lol). To install WineBottler, go to [their website](https://winebottler.kronenberg.org/) and download and install the version that suits for your MacOS X version. I recommend you [this tutorial](https://www.howtogeek.com/263211/how-to-run-windows-programs-on-a-mac-with-wine/). You dont have to install from WineBottler any apps like Internet Explorer.~~ Fixed since version 2.0 which detects the format and corrects it in the original format, meaning you can fix Android/Windows savefiles on MacOS/iOS with no problem, but you will only be able to use the savefiles under the same original OS, so fixing an Android/Windows savefile won't make you able to use the fixed savefiles under MacOS/iOS. 145 | - Go to the [Python 3.11.4 downloads](https://www.python.org/downloads/release/python-3114/) which is the latest Python version for now and is tested to be functionnal with my code, scroll down until you see the header "Files", then download and install the version that is right for you (if you dont know if your computer is 64bits or 32bits, choose the 32bits version). MacOS users will have to download the 64bits Windows version of [Python 3.8.9](https://www.python.org/downloads/release/python-389/) (not the Python 3.11.4 since it's not compatible with Wine !) and run it directly throught Wine (dont convert it to Mac `.app` file). Linux users does not have any Python installer on the Python website. Instead, open your package manager (either in graphical UI or in command line) and install the package `python3` and `python3-pip`. After, check the Python version by running the command `python3 --version` in a terminal (don't use `python3 -v` because some old Python versions understands that `-v` means `--verbose` instead of `--version`, if you do it you will get a Python interpreter with lots of weird logs texts for debugging Python, to exit type `exit()` and validate using the Enter key). If your Python version is 3.8 or newer (Python 3.9, 3.10, 3.11, etc...) it should work fine (programm testd on Python 3.8, 3.9 and 3.11). If you get an older version (example: Python 3.6) try to install in your package manager the package called `python3.8` or `python3.10` and then, instead of running the command `python3 --version`, run `[the name of the package you installed] --version` (example for package `python3.8`: `python3.8 --version`). And make sure its Python 3.8 or newer. If the command isn't found, you will have to compile Python yourself from the source code, but don't panic, its pretty easy if you [follow this tutorial](https://ubuntuhandbook.org/index.php/2021/10/compile-install-python-3-10-ubuntu/) (if the commands containing `apt` does not works, try replacing `apt` by `yum`, `pacman` or `dnf`, else try skipping these commands containing `apt` or search Google for annother tutorial, search `How to compile Python 3.10 on [your operating system name, example: Debian]`). 146 | - Go back to the same terminal and run the command `pip install pycryptodome` to install a needed library for the programm. MacOS users will have to run `wine py -m pip install pycryptodome` instead. If it fails, it's not important, just skip the command. 147 | - Download the first file you see that ends with `.py` in the [GitHub Releases](https://github.com/HGStyle/GD-SaveFileFixer/releases). Download the file in the folder that has all the stuff such as ADB and ABE programms. 148 | - If you are on Windows: 149 | - In the terminal, run the command: `dir /s /b *.dat` 150 | - In the folder containing all the stuff, run the programm you just downloaded (double-click on it) 151 | - Enter the option 1 of the programm 152 | - Follow the instructions given by the programm: add the paths that were given by the command in the terminal. You can use copy-paste, but add the paths 1 by 1 only ! When you are ready to fix it, enter nothing and it'll start. 153 | - If you are on MacOS: 154 | - In the terminal, run the command: `find "$(pwd)" -name "*.dat"` 155 | - Open annother terminal: [Click Finder, then services and finally "Open terminal at folder" (click to see screenshot)](https://www.maketecheasier.com/assets/uploads/2021/10/launch-any-folder-mac-terminal-new-terminal-at-folder-2.jpg) but keep the old terminal open 156 | - Run the command: `wine py [name of the python file you downloaded]`, usually the Python script file name is `GD-SaveFileFixer-SourceCode.py`. 157 | - Enter the option 1 of the programm 158 | - Follow the instructions given by the programm: add the paths that were given by the command in the terminal. You can use copy-paste, but add the paths 1 by 1 only ! When you are ready to fix it, enter nothing and it'll start. 159 | - If you are on Linux: 160 | - In the terminal, run the command: `find "$(pwd)" -name "*.dat"` 161 | - Open a new terminal: right-click in an empty space and click "Open terminal here". If the option isn't here, in the toolbar click "Tools" and then "Open terminal here" 162 | - Run the command: `python3 [name of the python file you downloaded]`, usually the Python script file name is `GD-SaveFileFixer-SourceCode.py`. 163 | - Enter the option 1 of the programm 164 | - Follow the instructions given by the programm: add the paths that were given by the command in the terminal. You can use copy-paste, but add the paths 1 by 1 only ! When you are ready to fix it, enter nothing and it'll start. 165 | - When the programm is done, open a file manager and go to your Android device, go to your internal memory of your device and copy the fixed files (not the files in the backup folder !) to your Android device. Make sure to move them at the root of the memory, not in a folder and not on your SD card. For all the next steps you won't need a computer. 166 | - Install the app [APK Extractor](https://play.google.com/store/apps/details?id=com.ext.ui) from the Play Store. 167 | - Open the app. Search for your Geometry Dash (or your GDPS, in case it's a GDPS) 168 | - Memorise the package name (which is usually formated like `aaa.bbbbbbb.cccccccccccc`). Since there is many steps, I recommend you to write it on a sticky note. 169 | - Click on the app to extract his APK. We'll need it later. 170 | - Do not uninstall APK Extractor since we'll need it later. 171 | - If the package name you memorised is `com.robtopx.geometryjumq` (notice the `q` at the end !): 172 | - Download and install [APK Editor Pro](https://dl.hgstyle.fr/Apps/AndroidHackerKit/APK_Editor/Clean/APK_Editor_Pro.apk) 173 | - Download the APK of Geometry Dash (but not the one used by GDPSes, and it should be version 2.111). I recommend using this one: [Download Geometry Dash 2.111 APK](https://dl.hgstyle.fr/Geometry_Dash_Versions/Geometry.Dash.ver.2.111.build.33.apk) 174 | - Open APK Editor Pro, alow storage access, click "Select Apk from App" and click on your Geometry Dash or your GDPS 175 | - Select "Full Edit" and then "Decode All Files", then go to "Files" in the toolbar of APK Editor Pro 176 | - Select the folder `assets` and `lib` and click "Extract", then go to your downloads folder and click "OK" (then wait for it ends and exit the app) 177 | - Make sure to exit the app completely and reopen it, now click "Select an Apk File" and click on the APK file of Geometry Dash 2.111 you downloaded (make sure the APK is stored in your internal storage, not in your SD card !) 178 | - Click "Full Edit" and then "Decode All Files" again and go to files 179 | - Select the folders `assets` and `lib` and click delete 180 | - Click the button with a plus symbol in a folder, and go to "Import Folder" 181 | - Click on the "..." button and browse into the `assets` folder in your downloads folder and click "OK" 182 | - A field will be filled automatically, be sure to see that the last word separated by the "/" is `assets` else click cancel and repeat the two last steps 183 | - Click "OK" and wait for it imports the folder `assets` into the APK 184 | - Again, click the button with a plus symbol in a folder, and go to "Import Folder" 185 | - Click on the "..." button and browse into the `lib` folder in your downloads folder and click "OK" 186 | - A field will be filled automatically, be sure to see that the last word separated by the "/" is `lib` else click cancel and repeat the two last steps 187 | - Click "OK" and wait for it imports the folder `assets` into the APK 188 | - Click on the "Build" button and wait for it builds the APK file 189 | - Open your file manager, go to internal storage, go to the folder "ApkEditor" (if you see multiple files, ignore those that aren't an APK) and move the APK file to the downloas folder in your internal storage 190 | - Optionally, you can delete the "ApkEditor" folder and/or the APK Editor Pro app 191 | - Download an install [App Cloner Pro](https://dl.hgstyle.fr/Apps/AndroidHackerKit/Other_apps/App_Cloner_Pro.apk) 192 | - Open App Cloner 193 | - If the package name you memorised is `com.robtopx.geometryjumq` (notice the `q` at the end !): 194 | - Click on the folder icon and click OK when a message box appears 195 | - Click the browse files logo 196 | - Open your downloads folder and click on the APK you just moved here 197 | - Else: 198 | - Search the Geometry Dash app (or your GDPS) and click on it 199 | - Scroll down and go to "Storage options" 200 | - Click on "Redirect external storage" and check the "Enable" box 201 | - Scroll down and enable "Acessible data directory" 202 | - Go back to main options categories 203 | - Scroll up and click on "Clone number" option 204 | - Check the box "Replace original app" and click "OK" 205 | - Click the button with the App Cloner logo on it, click "OK" and wait for it ends 206 | - When you can, click on the "Uninstall app" button (this will uninstall the Geometry Dash, but we got a backup of the data that we fixed so you won't lose anything) 207 | - Go to the "Cloned APKs" category and hold on the first of the two apps that seems the same, then stop holding 208 | - In the upper toolbar click the diskette logo and save the file to your downloads folder 209 | - Wait for the app to say "Successfully saved file" at the bottom of the app UI 210 | - Close the app and open your file manager 211 | - Go to your downloads folder by going to storage and then in the "Download" folder 212 | - Search for the APK made by App Cloner anc open it/click on it 213 | - It will normally show something like "Do you wanna install this app ?", so click "Install" 214 | - When its done, click "Open" to open the game, then close it 215 | - Download and install the latest version of [Termux](https://github.com/termux/termux-app/releases/download/v0.118.0/termux-app_v0.118.0+github-debug_universal.apk), then open the app and wait for the loading to finish. Dont use the Google Play Store version since it is no longer updated and broken. You will get a terminal like on Linux, but dont panic, I'll guide you ! 216 | - Open the app when it's installed 217 | - You will have to allow the storage access since [its not enabled by default](https://wiki.termux.com/wiki/Termux-setup-storage). To do that, simply type `termux-setup-storage` and press enter. Now allow storage access and you are ready ! You can enter the next command when you see the dollar symbol back and waiting you for the next command. 218 | - If you are on Android 11 or later (or you dont know which version of Android you have), go to Settings (exit Termux, you can completely close it or not), Applications, Termux, Permissions, disable storage access and re-enable it. [This is due to an Android bug which cannot be fixed by the Termux community.](https://wiki.termux.com/wiki/Termux-setup-storage) Then go back to Termux. 219 | - Then browse to the Geometry Dash app memory by executing `cd /data/data/aaa.bbbbbbb.cccccccccccc` (replace `aaa.bbbbbbb.cccccccccccc` by the package name you memorized) 220 | - Remove the current savefiles by executing `rm -rf *.dat` 221 | - Move the fixed savefiles of your phone memory by running the command `mv /storage/emulated/0/*.dat ./` (dont forget the dots, else you may get permission error or inexistant path error) 222 | - Try opening Geometry Dash (or your GDPS), it should be fixed. BUT DONT QUIT THIS TUTORIAL OR YOU COULD GET HACKED. 223 | - Now we have a problem (not really since I have the solution): every app can access to the game data. Why is this a problem ? They can access your savefiles, so they can access your account, and even, your password. Almost no apps actually steal data from Geometry Dash since they normally can't, but no one knows. To fix this high security issue, go to your file manager, internal storage, then go to the folder called "ApkExtractor", then to the folder called with the same name as your Geometry Dash or GDPS app, then install the only APK in this folder. This will remove the App Cloner changes but not the savefiles changes. 224 | - Annother "problem": USB debugging is enabled so everyone that has your phone can backup data of any apps of your smartphone. To disable it: 225 | - Go back to settings menu, scroll down and you will have a new category called "Developers options": go into it. 226 | - WARNING: YOU SHOULD NOT MODIFY A SETTING WITHOUT KNOWING WHAT ARE YOU DOING ! PLAYING WITH THESE SETTINGS MAY MAKE YOUR DEVICE COMPLETELY UNUSABLE AND USELESS, AND YOU MAY LOSE ALL YOUR DATA ! 227 | - Scroll down and disable USB Debugging 228 | - Close the Settings app 229 | - After this, you are 100% safe. 230 | - Now you can uninstall all the "temporary" apps we installed (ADB and ABE on the PC, APK Editor Pro, AppCloner and Termux on the phone) 231 | 232 | If your Android device is rooted (its a very lot more fast): 233 | - Go to your browser to download the latest version of the Python programm. There is a binary for Android but I dont recommend it and it may be deleted in the future since Python installation in Termux (the app we'l use to launch the programm) is easy. Download it using [GitHub Releases](https://github.com/HGStyle/GD-SaveFileFixer/releases), download the first file ending with `.py` to your Downloads folder on your internal storage (not SD card ! if its on your SD card you will have to move it to your internal storage download folder). 234 | - Download and install the latest version of [Termux](https://github.com/termux/termux-app/releases/download/v0.118.0/termux-app_v0.118.0+github-debug_universal.apk), then open the app and wait for the loading to finish. Dont use the Google Play Store version since it is no longer updated and broken. You will get a terminal like on Linux, but dont panic, I'll guide you ! 235 | - Open the app when it's installed 236 | - You will have to allow the storage access since [its not enabled by default](https://wiki.termux.com/wiki/Termux-setup-storage). To do that, simply type `termux-setup-storage` and press enter. Now allow storage access and you are ready ! You can enter the next command when you see the dollar symbol back and waiting you for the next command. 237 | - If you are on Android 11 or later (or you dont know which version of Android you have), go to Settings (exit Termux, you can completely close it or not), Applications, Termux, Permissions, disable storage access and re-enable it. [This is due to an Android bug which cannot be fixed by the Termux community.](https://wiki.termux.com/wiki/Termux-setup-storage) Then go back to Termux. 238 | - Now we'll update the Termux programms. Simply type `apt update`, then press enter. After, type `apt upgrade -y` and press enter. After, remove unnecesary software (its automatic and won't break anything) by typing `apt autoremove -y` and press enter. (from now I will no longer say "Press enter", but you will still have to do it after typing a command) 239 | - Now we will install Python. Simply type the command `apt install python3 python-pip -y` and wait. Notice that this can take up to some minutes, depending on your device and internet connection speed. 240 | - Now we need to install Python depencies. This can be done by simply running `python3 -m pip install pycryptodome`. If it fails, it's not really important, just skip this step like if it was done correctly. 241 | - Now you will have to naviguate to your download folder. Firstly, run the command `cd /storage/emulated/0` to go to your internal storage. Then type the command `dir` to list all the files and folders. Find your download folder name and run the command `cd [entire name of your download folder]`. It's usually `cd Download`. 242 | - Now, find the name of the Python script file. Run the command `find . -name "*.py"` (dont forget the dots). You will get the name of every file ending with `.py` (so, for almost every user, only one file: the actual Python script we need to run). 243 | - Now we need to get root access. To do this, we'll use st42's termux-sudo script: 244 | - Install the needed packages by running `pkg install ncurses-utils wget tsu` 245 | - Download the script by running `wget -O "sudo" "https://gitlab.com/st42/termux-sudo/-/raw/master/sudo?ref_type=heads"` 246 | - Run these 2 commands to install termux-sudo completely: `cat sudo > /data/data/com.termux/files/usr/bin/sudo` and then `chmod 700 /data/data/com.termux/files/usr/bin/sudo` 247 | - Run the Python script by doing `sudo python3 [python script full file name]`. It's usually `sudo python3 GD-SaveFileFixer-SourceCode.py`. If the Python script filename contains spaces, run `sudo python3 "[python script full file name]"` (dont forget the two `"`: one at the start, one at the end of the filename). 248 | - If the package name you memorised isn't `com.robtopx.geometryjump`, the second option won't work. That's why it is not recommended, use the recommended option 3 instead. (it should not be long) 249 | - Once the programm has done running (you see the `$` symbol of Termux), close Termux. 250 | - Try opening Geometry Dash (or your GDPS), it should be fixed. 251 | - You can uninstall the Termux app. 252 | 253 | ## Running on iOS or iPadOS 254 | 255 | [READ THIS. You have to extract the game files, run the program ~~on MacOS (Windows won't work until I decide to update)~~ (working fine on any OS since version 2.0 but this doesn't convert the savefile to annother format!), use the manual option, select the savefiles one by one, fix them, but them back into the folder where you got them.](https://www.reddit.com/r/geometrydash/comments/1ak4ssz/tutorial_how_to_access_the_game_files_get_nongs/) (Maybe someday I'll try to make a tutorial about this) 256 | 257 | As I said before, I dont own any iOS or iPadOS devices that are up to date, I can't install apps on them since they are way too old. But here is a way that will probably work that I haven't tested. Firstly, [jailbreak your iDevice, here is a list of tutorials depending on your iOS/iPadOS version and/or iPhone/iPad edition](https://www.idownloadblog.com/jailbreak/). You may (or not) also see these jailbreaking tools: [unc0ver](https://unc0ver.dev/), [checkra1n](https://checkra.in/), [palera1n](https://palera.in/), [Dopamine](https://ellekit.space/dopamine/), [Taurine](https://taurine.app/), [Odyssey](https://theodyssey.dev/), [Chimera](https://chimera.coolstar.org/), [Electra](https://www.coolstar.org/electra/), [H3lix](https://h3lix.tihmstar.net/), [Phoenix](https://phoenixpwn.com/), [EtasonJB](https://etasonjb.tihmstar.net/), [backr00m (french old tutorial)](https://gamergen.com/forums/tutos-membres-ios/backr00m-jailbreak-de-l-apple-tv4-tvos-10-2-2-a-11-1-t736325.html) etc... You can find many more on the Internet but be careful ! [Malwares exists on iOS and iPadOS !](https://www.howtogeek.com/447107/can-my-iphone-or-ipad-get-a-virus/). Then install [iSH](https://ish.app/) and the Python programm, open iSH, install Python, run the Python program and exit iSH and finally open Geometry Dash, It should be fixed. NOTE: I havn't tested this because as I said, I dont own any iDevice that can install apps ! (they are too old, Apple Store refuses to install apps on it). 258 | 259 | ## More info about savefile encoding/decoding 260 | 261 | These pages were useful to me to encrypt/decrypt GD savefiles: 262 | 263 | [Click here to see Savefiles page backup from a GD Wiki user](https://geometry-dash.fandom.com/wiki/User:XBZZZZALT#backup_of_useful_stuff_from_Save_Files_page) 264 | 265 | [Click here to see GD Programming Docs about Savefiles](https://github.com/gd-programming/gd.docs/blob/main/docs/topics/localfiles_encrypt_decrypt.md) 266 | 267 | ## Credits and legality 268 | 269 | Thanks to WEGFan because this would not exist without his GitHub repo. I dont see any license on his GitHub repo, but I credit him anyways, even if its not needed. 270 | Note that **this is an entire rewrite**, actually what was **reused from WEGFan's code** is actually **one single line of code**. And some sentances of the README.md file. But that's all. 271 | Edit: It seems like WEGFan has seen this repo, since he made a modification in his GitHub repo to redirect users from his archived repo to mine! Just thanks bro, I think I can license the software without having problems with him. (it's the first time a known gd coder does that so thx) 272 | 273 | ## Thanks you all! 274 | --------------------------------------------------------------------------------