From 4919300aa6e9134c6882d3b617eb74efa64e1173 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Sat, 3 Aug 2024 16:21:58 -0400 Subject: [PATCH 01/58] support for Classic Marathon Infinity on Steam Squashed commit of the following: commit 1a185af594dc23a0ce93d9498ff1513319eab18d Author: Gregory Smith Date: Sun Jul 21 21:52:09 2024 -0400 macOS build targets for Classic Marathon Infinity Steam commit fc52ca7f021e6801f4b713453e9363689b5b68e8 Author: Gregory Smith Date: Sun Jul 21 21:40:09 2024 -0400 add Windows target for Classic Marathon Infinity Steam commit 99ea3a0effc6dcaee55357bb0d03039107624874 Author: Gregory Smith Date: Sun Jul 21 21:39:47 2024 -0400 fix indentation commit 2648a661fd3fa54e7b54cacea05feb881b4c351b Author: Gregory Smith Date: Sun Jul 21 21:37:20 2024 -0400 correct typo commit f18d30fb84f69a6876c7a0363003e13a40217ca2 Author: Gregory Smith Date: Sun Jul 21 21:19:18 2024 -0400 github and steamcmd tooling for Classic Marathon Infinity commit 690866aea9551a576404261f34d732eac69e19d6 Author: Gregory Smith Date: Sun Jul 21 21:09:22 2024 -0400 add infinity achievements --- .github/workflows/release-steam-mac-os.yml | 11 +- .github/workflows/release-steam-windows.yml | 4 +- PBProjects/AlephOne.xcodeproj/project.pbxproj | 1031 +++++++++++++++++ .../Marathon Infinity/Info-Steam.plist | 558 +++++++++ Source_Files/Misc/Makefile.am | 2 +- Source_Files/Misc/achievements.cpp | 7 + Source_Files/Misc/inf_achievements.lua | 246 ++++ Steam/inf_build.vdf | 49 + Steam/inf_mac.vdf | 33 + VisualStudio/AlephOne.sln | 66 +- VisualStudio/AlephOne/AlephOne.vcxproj | 104 ++ VisualStudio/LibAlephOne/LibAlephOne.vcxproj | 71 ++ 12 files changed, 2155 insertions(+), 27 deletions(-) create mode 100644 PBProjects/AppStore/Marathon Infinity/Info-Steam.plist create mode 100644 Source_Files/Misc/inf_achievements.lua create mode 100644 Steam/inf_build.vdf create mode 100644 Steam/inf_mac.vdf diff --git a/.github/workflows/release-steam-mac-os.yml b/.github/workflows/release-steam-mac-os.yml index 2bb4c3d82..86c363b9d 100644 --- a/.github/workflows/release-steam-mac-os.yml +++ b/.github/workflows/release-steam-mac-os.yml @@ -11,7 +11,7 @@ jobs: - name: Build Steam Marathon uses: ./.github/actions/build-mac-osx with: - xcode_targets: "Marathon Steam, Marathon 2 Steam, Classic Marathon Launcher" + xcode_targets: "Marathon Steam, Marathon 2 Steam, Marathon Infinity Steam, Classic Marathon Launcher" - name: Bootstrap Steamcmd continue-on-error: true #Steamcmd may throw error exit code while bootstrapping that we can ignore, we will see on upload if everything is working fine @@ -53,6 +53,7 @@ jobs: /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --entitlements "$GITHUB_WORKSPACE/PBProjects/Steamshim.entitlements" --options runtime "$GITHUB_WORKSPACE/PBProjects/build/Release/Classic Marathon Launcher" -v /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime "$GITHUB_WORKSPACE/PBProjects/build/Release/Classic Marathon Steam.app" -v /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime "$GITHUB_WORKSPACE/PBProjects/build/Release/Classic Marathon 2 Steam.app" -v + /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime "$GITHUB_WORKSPACE/PBProjects/build/Release/Classic Marathon Infinity Steam.app" -v - name: "Notarize app bundle" # Extract the secrets we defined earlier as environment variables @@ -74,6 +75,7 @@ jobs: echo "Creating temp notarization archives" ditto -c -k --keepParent "$GITHUB_WORKSPACE/PBProjects/build/Release/Classic Marathon Steam.app" "marathon.zip" ditto -c -k --keepParent "$GITHUB_WORKSPACE/PBProjects/build/Release/Classic Marathon 2 Steam.app" "marathon2.zip" + ditto -c -k --keepParent "$GITHUB_WORKSPACE/PBProjects/build/Release/Classic Marathon Infinity Steam.app" "infinity.zip" ditto -c -k --keepParent "$GITHUB_WORKSPACE/PBProjects/build/Release/Classic Marathon Launcher" "launcher.zip" # Here we send the notarization request to the Apple's Notarization service, waiting for the result. @@ -97,5 +99,10 @@ jobs: echo "Attach staple" xcrun stapler staple "$GITHUB_WORKSPACE/PBProjects/build/Release/Classic Marathon 2 Steam.app" + echo "Notarize Classic Marathon Infinity Steam" + xcrun notarytool submit "infinity.zip" --keychain-profile "notarytool-profile" --wait + echo "Attach staple" + xcrun stapler staple "$GITHUB_WORKSPACE/PBProjects/build/Release/Classic Marathon Infinity Steam.app" + - name: Deploy to Steam - run: ./Steam/steamcmd/steamcmd.sh +login alephone_upload +run_app_build ../m1_mac.vdf +run_app_build ../m2_mac.vdf +quit \ No newline at end of file + run: ./Steam/steamcmd/steamcmd.sh +login alephone_upload +run_app_build ../m1_mac.vdf +run_app_build ../m2_mac.vdf +run_app_build ../inf_mac.vdf +quit \ No newline at end of file diff --git a/.github/workflows/release-steam-windows.yml b/.github/workflows/release-steam-windows.yml index 09bb5044f..8c7e7d7f0 100644 --- a/.github/workflows/release-steam-windows.yml +++ b/.github/workflows/release-steam-windows.yml @@ -14,7 +14,7 @@ jobs: uses: ./.github/actions/build-windows with: platform: x64 - configurations: "Steam Marathon, Steam Marathon 2" + configurations: "Steam Marathon, Steam Marathon 2, Steam Marathon Infinity" vcpkg_installed_folder: installed-x64-windows - name: Bootstrap Steamcmd @@ -30,4 +30,4 @@ jobs: shell: bash - name: Deploy to Steam - run: ./Steam/steamcmd/steamcmd.exe +login alephone_upload +run_app_build ../m1_build.vdf +run_app_build ../m2_build.vdf +quit \ No newline at end of file + run: ./Steam/steamcmd/steamcmd.exe +login alephone_upload +run_app_build ../m1_build.vdf +run_app_build ../m2_build.vdf +run_app_build ../inf_build.vdf +quit \ No newline at end of file diff --git a/PBProjects/AlephOne.xcodeproj/project.pbxproj b/PBProjects/AlephOne.xcodeproj/project.pbxproj index 02a7ffd51..4288d27ef 100644 --- a/PBProjects/AlephOne.xcodeproj/project.pbxproj +++ b/PBProjects/AlephOne.xcodeproj/project.pbxproj @@ -2039,6 +2039,460 @@ AEB4A28D14296CAE00537AE7 /* FilmProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27D1A4F112FDF3630085E79C /* FilmProfile.cpp */; }; AEB4A2B314296DC000537AE7 /* Marathon Infinity.icns in Resources */ = {isa = PBXBuildFile; fileRef = AEB4A2B214296DC000537AE7 /* Marathon Infinity.icns */; }; AEB4A2B614296DC700537AE7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = AEB4A2B414296DC700537AE7 /* InfoPlist.strings */; }; + AEBDC50D2C4DF0780026DFF1 /* PlayerName.h in Headers */ = {isa = PBXBuildFile; fileRef = F522120C0136A6FD01000001 /* PlayerName.h */; }; + AEBDC50E2C4DF0780026DFF1 /* Random.h in Headers */ = {isa = PBXBuildFile; fileRef = F52212190136A6FD01000001 /* Random.h */; }; + AEBDC50F2C4DF0780026DFF1 /* game_errors.h in Headers */ = {isa = PBXBuildFile; fileRef = F52211AE0136A6FD01000001 /* game_errors.h */; }; + AEBDC5102C4DF0780026DFF1 /* interface.h in Headers */ = {isa = PBXBuildFile; fileRef = F52211C50136A6FD01000001 /* interface.h */; }; + AEBDC5112C4DF0780026DFF1 /* interface_menus.h in Headers */ = {isa = PBXBuildFile; fileRef = F52211C20136A6FD01000001 /* interface_menus.h */; }; + AEBDC5122C4DF0780026DFF1 /* Decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = AE601F100B927C51009F881C /* Decoder.h */; }; + AEBDC5132C4DF0780026DFF1 /* key_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F52211CB0136A6FD01000001 /* key_definitions.h */; }; + AEBDC5142C4DF0780026DFF1 /* preferences.h in Headers */ = {isa = PBXBuildFile; fileRef = F52212100136A6FD01000001 /* preferences.h */; }; + AEBDC5152C4DF0780026DFF1 /* progress.h in Headers */ = {isa = PBXBuildFile; fileRef = F52212140136A6FD01000001 /* progress.h */; }; + AEBDC5162C4DF0780026DFF1 /* sdl_dialogs.h in Headers */ = {isa = PBXBuildFile; fileRef = F522123B0136A6FD01000001 /* sdl_dialogs.h */; }; + AEBDC5172C4DF0780026DFF1 /* sdl_network.h in Headers */ = {isa = PBXBuildFile; fileRef = F522123E0136A6FD01000001 /* sdl_network.h */; }; + AEBDC5182C4DF0780026DFF1 /* sdl_widgets.h in Headers */ = {isa = PBXBuildFile; fileRef = F52212400136A6FD01000001 /* sdl_widgets.h */; }; + AEBDC5192C4DF0780026DFF1 /* shell.h in Headers */ = {isa = PBXBuildFile; fileRef = F522124C0136A6FD01000001 /* shell.h */; }; + AEBDC51A2C4DF0780026DFF1 /* vbl_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F52212560136A6FD01000001 /* vbl_definitions.h */; }; + AEBDC51B2C4DF0780026DFF1 /* vbl.h in Headers */ = {isa = PBXBuildFile; fileRef = F522125A0136A6FD01000001 /* vbl.h */; }; + AEBDC51C2C4DF0780026DFF1 /* byte_swapping.h in Headers */ = {isa = PBXBuildFile; fileRef = F522111D0136A4DD01000001 /* byte_swapping.h */; }; + AEBDC51D2C4DF0780026DFF1 /* csalerts.h in Headers */ = {isa = PBXBuildFile; fileRef = F522111E0136A4DD01000001 /* csalerts.h */; }; + AEBDC51E2C4DF0780026DFF1 /* cscluts.h in Headers */ = {isa = PBXBuildFile; fileRef = F522111F0136A4DD01000001 /* cscluts.h */; }; + AEBDC51F2C4DF0780026DFF1 /* csdialogs.h in Headers */ = {isa = PBXBuildFile; fileRef = F52211200136A4DD01000001 /* csdialogs.h */; }; + AEBDC5202C4DF0780026DFF1 /* cseries.h in Headers */ = {isa = PBXBuildFile; fileRef = F52211210136A4DD01000001 /* cseries.h */; }; + AEBDC5212C4DF0780026DFF1 /* Scenario.h in Headers */ = {isa = PBXBuildFile; fileRef = AE2A50CF09C6727C007681A4 /* Scenario.h */; }; + AEBDC5222C4DF0780026DFF1 /* csfonts.h in Headers */ = {isa = PBXBuildFile; fileRef = F52211230136A4DD01000001 /* csfonts.h */; }; + AEBDC5232C4DF0780026DFF1 /* csmacros.h in Headers */ = {isa = PBXBuildFile; fileRef = F52211250136A4DD01000001 /* csmacros.h */; }; + AEBDC5242C4DF0780026DFF1 /* csmisc.h in Headers */ = {isa = PBXBuildFile; fileRef = F52211260136A4DD01000001 /* csmisc.h */; }; + AEBDC5252C4DF0780026DFF1 /* CourierPrimeBold.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BED001A846FD900AE52F4 /* CourierPrimeBold.h */; }; + AEBDC5262C4DF0780026DFF1 /* cspixels.h in Headers */ = {isa = PBXBuildFile; fileRef = F52211270136A4DD01000001 /* cspixels.h */; }; + AEBDC5272C4DF0780026DFF1 /* csstrings.h in Headers */ = {isa = PBXBuildFile; fileRef = F52211280136A4DD01000001 /* csstrings.h */; }; + AEBDC5282C4DF0780026DFF1 /* cstypes.h in Headers */ = {isa = PBXBuildFile; fileRef = F52211290136A4DD01000001 /* cstypes.h */; }; + AEBDC5292C4DF0780026DFF1 /* network.h in Headers */ = {isa = PBXBuildFile; fileRef = F52213900136ABAE01000001 /* network.h */; }; + AEBDC52A2C4DF0780026DFF1 /* network_games.h in Headers */ = {isa = PBXBuildFile; fileRef = F52213800136ABAE01000001 /* network_games.h */; }; + AEBDC52B2C4DF0780026DFF1 /* IMG_savepng.h in Headers */ = {isa = PBXBuildFile; fileRef = AEF1AC1410E05826007EE0D5 /* IMG_savepng.h */; }; + AEBDC52C2C4DF0780026DFF1 /* Model3D.h in Headers */ = {isa = PBXBuildFile; fileRef = F5830B4401E77D5701BA387C /* Model3D.h */; }; + AEBDC52D2C4DF0780026DFF1 /* ModelRenderer.h in Headers */ = {isa = PBXBuildFile; fileRef = F5830B4601E77D5701BA387C /* ModelRenderer.h */; }; + AEBDC52E2C4DF0780026DFF1 /* StudioLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = F5830B4B01E77D5701BA387C /* StudioLoader.h */; }; + AEBDC52F2C4DF0780026DFF1 /* WavefrontLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = F5830B4D01E77D5701BA387C /* WavefrontLoader.h */; }; + AEBDC5302C4DF0780026DFF1 /* network_dialog_widgets_sdl.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BECF91A846D2000AE52F4 /* network_dialog_widgets_sdl.h */; }; + AEBDC5312C4DF0780026DFF1 /* Dim3_Loader.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CFAD3A0200F9D201D80110 /* Dim3_Loader.h */; }; + AEBDC5322C4DF0780026DFF1 /* FFmpegDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 27E878F2173202F80010F485 /* FFmpegDecoder.h */; }; + AEBDC5332C4DF0780026DFF1 /* SW_Texture_Extras.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BECF41A846CC800AE52F4 /* SW_Texture_Extras.h */; }; + AEBDC5342C4DF0780026DFF1 /* network_dialogs.h in Headers */ = {isa = PBXBuildFile; fileRef = F53DC61D022179A801A80001 /* network_dialogs.h */; }; + AEBDC5352C4DF0780026DFF1 /* network_lookup_sdl.h in Headers */ = {isa = PBXBuildFile; fileRef = F53DC62002219A3D01A80001 /* network_lookup_sdl.h */; }; + AEBDC5362C4DF0780026DFF1 /* ActionQueues.h in Headers */ = {isa = PBXBuildFile; fileRef = F5A00027023FDA6101A80001 /* ActionQueues.h */; }; + AEBDC5372C4DF0780026DFF1 /* CircularQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = F5A00029023FDA7601A80001 /* CircularQueue.h */; }; + AEBDC5382C4DF0780026DFF1 /* preferences_widgets_sdl.h in Headers */ = {isa = PBXBuildFile; fileRef = F5A0002B023FDAD101A80001 /* preferences_widgets_sdl.h */; }; + AEBDC5392C4DF0780026DFF1 /* network_distribution_types.h in Headers */ = {isa = PBXBuildFile; fileRef = F5A00033023FDBBD01A80001 /* network_distribution_types.h */; }; + AEBDC53A2C4DF0780026DFF1 /* OGL_LoadScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = AEF5025509A8258C004B0179 /* OGL_LoadScreen.h */; }; + AEBDC53B2C4DF0780026DFF1 /* crc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92000240D09B01A80001 /* crc.h */; }; + AEBDC53C2C4DF0780026DFF1 /* extensions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92010240D09B01A80001 /* extensions.h */; }; + AEBDC53D2C4DF0780026DFF1 /* FileHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92020240D09B01A80001 /* FileHandler.h */; }; + AEBDC53E2C4DF0780026DFF1 /* find_files.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92030240D09B01A80001 /* find_files.h */; }; + AEBDC53F2C4DF0780026DFF1 /* game_wad.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92040240D09B01A80001 /* game_wad.h */; }; + AEBDC5402C4DF0780026DFF1 /* Packing.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92050240D09B01A80001 /* Packing.h */; }; + AEBDC5412C4DF0780026DFF1 /* resource_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92060240D09B01A80001 /* resource_manager.h */; }; + AEBDC5422C4DF0780026DFF1 /* preference_dialogs.h in Headers */ = {isa = PBXBuildFile; fileRef = AE2FDED109E9352B00A18ABC /* preference_dialogs.h */; }; + AEBDC5432C4DF0780026DFF1 /* tags.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92070240D09B01A80001 /* tags.h */; }; + AEBDC5442C4DF0780026DFF1 /* wad.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92080240D09B01A80001 /* wad.h */; }; + AEBDC5452C4DF0780026DFF1 /* wad_prefs.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92090240D09B01A80001 /* wad_prefs.h */; }; + AEBDC5462C4DF0780026DFF1 /* dynamic_limits.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92510240D28201A80001 /* dynamic_limits.h */; }; + AEBDC5472C4DF0780026DFF1 /* editor.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92520240D28201A80001 /* editor.h */; }; + AEBDC5482C4DF0780026DFF1 /* effect_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92530240D28201A80001 /* effect_definitions.h */; }; + AEBDC5492C4DF0780026DFF1 /* effects.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92550240D28201A80001 /* effects.h */; }; + AEBDC54A2C4DF0780026DFF1 /* flood_map.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92570240D28201A80001 /* flood_map.h */; }; + AEBDC54B2C4DF0780026DFF1 /* item_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92580240D28201A80001 /* item_definitions.h */; }; + AEBDC54C2C4DF0780026DFF1 /* items.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC925A0240D28201A80001 /* items.h */; }; + AEBDC54D2C4DF0780026DFF1 /* SDL_rwops_ostream.h in Headers */ = {isa = PBXBuildFile; fileRef = 278E0C7C1AA4012600FA93B7 /* SDL_rwops_ostream.h */; }; + AEBDC54E2C4DF0780026DFF1 /* lightsource.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC925C0240D28201A80001 /* lightsource.h */; }; + AEBDC54F2C4DF0780026DFF1 /* map.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC925E0240D28201A80001 /* map.h */; }; + AEBDC5502C4DF0780026DFF1 /* CourierPrimeBoldItalic.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BED011A846FD900AE52F4 /* CourierPrimeBoldItalic.h */; }; + AEBDC5512C4DF0780026DFF1 /* confpaths.h in Headers */ = {isa = PBXBuildFile; fileRef = 27A6DB4F1B9CED1E003DA766 /* confpaths.h */; }; + AEBDC5522C4DF0780026DFF1 /* media.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92620240D28201A80001 /* media.h */; }; + AEBDC5532C4DF0780026DFF1 /* media_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92630240D28201A80001 /* media_definitions.h */; }; + AEBDC5542C4DF0780026DFF1 /* monster_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92640240D28201A80001 /* monster_definitions.h */; }; + AEBDC5552C4DF0780026DFF1 /* monsters.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92660240D28201A80001 /* monsters.h */; }; + AEBDC5562C4DF0780026DFF1 /* physics_models.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92690240D28201A80001 /* physics_models.h */; }; + AEBDC5572C4DF0780026DFF1 /* platform_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC926B0240D28201A80001 /* platform_definitions.h */; }; + AEBDC5582C4DF0780026DFF1 /* mytm.h in Headers */ = {isa = PBXBuildFile; fileRef = F522112D0136A4DD01000001 /* mytm.h */; }; + AEBDC5592C4DF0780026DFF1 /* CourierPrime.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BECFF1A846FD900AE52F4 /* CourierPrime.h */; }; + AEBDC55A2C4DF0780026DFF1 /* InfoTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 27FF26591B6F169200DA0A19 /* InfoTree.h */; }; + AEBDC55B2C4DF0780026DFF1 /* platforms.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC926D0240D28201A80001 /* platforms.h */; }; + AEBDC55C2C4DF0780026DFF1 /* player.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC926F0240D28201A80001 /* player.h */; }; + AEBDC55D2C4DF0780026DFF1 /* projectile_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92700240D28201A80001 /* projectile_definitions.h */; }; + AEBDC55E2C4DF0780026DFF1 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 27A6DB471B9CED02003DA766 /* config.h */; }; + AEBDC55F2C4DF0780026DFF1 /* projectiles.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92720240D28201A80001 /* projectiles.h */; }; + AEBDC5602C4DF0780026DFF1 /* scenery.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92740240D28201A80001 /* scenery.h */; }; + AEBDC5612C4DF0780026DFF1 /* scenery_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92750240D28201A80001 /* scenery_definitions.h */; }; + AEBDC5622C4DF0780026DFF1 /* weapon_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92760240D28201A80001 /* weapon_definitions.h */; }; + AEBDC5632C4DF0780026DFF1 /* weapons.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92780240D28201A80001 /* weapons.h */; }; + AEBDC5642C4DF0780026DFF1 /* world.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC927A0240D28201A80001 /* world.h */; }; + AEBDC5652C4DF0780026DFF1 /* mouse.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92D90240D54401A80001 /* mouse.h */; }; + AEBDC5662C4DF0780026DFF1 /* AnimatedTextures.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92E50240D56101A80001 /* AnimatedTextures.h */; }; + AEBDC5672C4DF0780026DFF1 /* collection_definition.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92E60240D56101A80001 /* collection_definition.h */; }; + AEBDC5682C4DF0780026DFF1 /* Crosshairs.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92E80240D56101A80001 /* Crosshairs.h */; }; + AEBDC5692C4DF0780026DFF1 /* low_level_textures.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92ED0240D56101A80001 /* low_level_textures.h */; }; + AEBDC56A2C4DF0780026DFF1 /* OGL_Faders.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92EF0240D56101A80001 /* OGL_Faders.h */; }; + AEBDC56B2C4DF0780026DFF1 /* OGL_Render.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92F10240D56101A80001 /* OGL_Render.h */; }; + AEBDC56C2C4DF0780026DFF1 /* OGL_Setup.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92F30240D56101A80001 /* OGL_Setup.h */; }; + AEBDC56D2C4DF0780026DFF1 /* OGL_Textures.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92F50240D56101A80001 /* OGL_Textures.h */; }; + AEBDC56E2C4DF0780026DFF1 /* Rasterizer.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92F90240D56101A80001 /* Rasterizer.h */; }; + AEBDC56F2C4DF0780026DFF1 /* Rasterizer_OGL.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92FA0240D56101A80001 /* Rasterizer_OGL.h */; }; + AEBDC5702C4DF0780026DFF1 /* Rasterizer_SW.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92FB0240D56101A80001 /* Rasterizer_SW.h */; }; + AEBDC5712C4DF0780026DFF1 /* render.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92FD0240D56101A80001 /* render.h */; }; + AEBDC5722C4DF0780026DFF1 /* RenderPlaceObjs.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92FF0240D56101A80001 /* RenderPlaceObjs.h */; }; + AEBDC5732C4DF0780026DFF1 /* RenderRasterize.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93010240D56101A80001 /* RenderRasterize.h */; }; + AEBDC5742C4DF0780026DFF1 /* RenderSortPoly.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93030240D56101A80001 /* RenderSortPoly.h */; }; + AEBDC5752C4DF0780026DFF1 /* ProFontAO.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BED031A846FD900AE52F4 /* ProFontAO.h */; }; + AEBDC5762C4DF0780026DFF1 /* RenderVisTree.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93050240D56101A80001 /* RenderVisTree.h */; }; + AEBDC5772C4DF0780026DFF1 /* scottish_textures.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93080240D56101A80001 /* scottish_textures.h */; }; + AEBDC5782C4DF0780026DFF1 /* shape_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC930A0240D56101A80001 /* shape_definitions.h */; }; + AEBDC5792C4DF0780026DFF1 /* achievements.h in Headers */ = {isa = PBXBuildFile; fileRef = AED959B12BC23591008EFCA2 /* achievements.h */; }; + AEBDC57A2C4DF0780026DFF1 /* WadImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 278E0C721AA3CD4500FA93B7 /* WadImageCache.h */; }; + AEBDC57B2C4DF0780026DFF1 /* shape_descriptors.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC930B0240D56101A80001 /* shape_descriptors.h */; }; + AEBDC57C2C4DF0780026DFF1 /* textures.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93100240D56101A80001 /* textures.h */; }; + AEBDC57D2C4DF0780026DFF1 /* ChaseCam.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93700240D85D01A80001 /* ChaseCam.h */; }; + AEBDC57E2C4DF0780026DFF1 /* sdl_resize.h in Headers */ = {isa = PBXBuildFile; fileRef = 27EFC4BD1A7D8CBF00A95592 /* sdl_resize.h */; }; + AEBDC57F2C4DF0780026DFF1 /* computer_interface.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93710240D85D01A80001 /* computer_interface.h */; }; + AEBDC5802C4DF0780026DFF1 /* PlayerImage_sdl.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BED2C1A8470A900AE52F4 /* PlayerImage_sdl.h */; }; + AEBDC5812C4DF0780026DFF1 /* fades.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93720240D85D01A80001 /* fades.h */; }; + AEBDC5822C4DF0780026DFF1 /* FontHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93730240D85D01A80001 /* FontHandler.h */; }; + AEBDC5832C4DF0780026DFF1 /* game_window.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93740240D85D01A80001 /* game_window.h */; }; + AEBDC5842C4DF0780026DFF1 /* HUDRenderer.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93750240D85D01A80001 /* HUDRenderer.h */; }; + AEBDC5852C4DF0780026DFF1 /* HUDRenderer_OGL.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93760240D85D01A80001 /* HUDRenderer_OGL.h */; }; + AEBDC5862C4DF0780026DFF1 /* HUDRenderer_SW.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93770240D85D01A80001 /* HUDRenderer_SW.h */; }; + AEBDC5872C4DF0780026DFF1 /* powered_by_alephone_h.h in Headers */ = {isa = PBXBuildFile; fileRef = AED959AF2BC23591008EFCA2 /* powered_by_alephone_h.h */; }; + AEBDC5882C4DF0780026DFF1 /* OGL_FBO.h in Headers */ = {isa = PBXBuildFile; fileRef = 2710CC601B8F94FC00CE2EAE /* OGL_FBO.h */; }; + AEBDC5892C4DF0780026DFF1 /* images.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93780240D85D01A80001 /* images.h */; }; + AEBDC58A2C4DF0780026DFF1 /* motion_sensor.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93790240D85D01A80001 /* motion_sensor.h */; }; + AEBDC58B2C4DF0780026DFF1 /* powered_by_alephone.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BED211A84701E00AE52F4 /* powered_by_alephone.h */; }; + AEBDC58C2C4DF0780026DFF1 /* overhead_map.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC937A0240D85D01A80001 /* overhead_map.h */; }; + AEBDC58D2C4DF0780026DFF1 /* OverheadMap_OGL.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC937B0240D85D01A80001 /* OverheadMap_OGL.h */; }; + AEBDC58E2C4DF0780026DFF1 /* OverheadMap_SDL.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC938B0240D85D01A80001 /* OverheadMap_SDL.h */; }; + AEBDC58F2C4DF0780026DFF1 /* OverheadMapRenderer.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC937C0240D85D01A80001 /* OverheadMapRenderer.h */; }; + AEBDC5902C4DF0780026DFF1 /* screen.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC937D0240D85D01A80001 /* screen.h */; }; + AEBDC5912C4DF0780026DFF1 /* screen_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC937E0240D85D01A80001 /* screen_definitions.h */; }; + AEBDC5922C4DF0780026DFF1 /* screen_drawing.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC937F0240D85D01A80001 /* screen_drawing.h */; }; + AEBDC5932C4DF0780026DFF1 /* screen_shared.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC939E0240D85D01A80001 /* screen_shared.h */; }; + AEBDC5942C4DF0780026DFF1 /* sdl_fonts.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93A00240D85D01A80001 /* sdl_fonts.h */; }; + AEBDC5952C4DF0780026DFF1 /* CourierPrimeItalic.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BED021A846FD900AE52F4 /* CourierPrimeItalic.h */; }; + AEBDC5962C4DF0780026DFF1 /* TextLayoutHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93A20240D85D01A80001 /* TextLayoutHelper.h */; }; + AEBDC5972C4DF0780026DFF1 /* TextStrings.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93A40240D85D01A80001 /* TextStrings.h */; }; + AEBDC5982C4DF0780026DFF1 /* ViewControl.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC93A60240D85D01A80001 /* ViewControl.h */; }; + AEBDC5992C4DF0780026DFF1 /* song_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC94140240DA4301A80001 /* song_definitions.h */; }; + AEBDC59A2C4DF0780026DFF1 /* OGL_Headers.h in Headers */ = {isa = PBXBuildFile; fileRef = AEF8C4F210AEFEB500ED84AD /* OGL_Headers.h */; }; + AEBDC59B2C4DF0780026DFF1 /* SndfileDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = AE601F120B927C51009F881C /* SndfileDecoder.h */; }; + AEBDC59C2C4DF0780026DFF1 /* sound_definitions.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC94150240DA4301A80001 /* sound_definitions.h */; }; + AEBDC59D2C4DF0780026DFF1 /* DefaultStringSets.h in Headers */ = {isa = PBXBuildFile; fileRef = C13C71E61B3FB4C500F1188D /* DefaultStringSets.h */; }; + AEBDC59E2C4DF0780026DFF1 /* XML_LevelScript.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC94320240DE0E01A80001 /* XML_LevelScript.h */; }; + AEBDC59F2C4DF0780026DFF1 /* XML_ParseTreeRoot.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC94330240DE0E01A80001 /* XML_ParseTreeRoot.h */; }; + AEBDC5A02C4DF0780026DFF1 /* alephversion.h in Headers */ = {isa = PBXBuildFile; fileRef = F5D11AE40326A93E01000105 /* alephversion.h */; }; + AEBDC5A12C4DF0780026DFF1 /* Logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DAC27A703DC9D1C00000104 /* Logging.h */; }; + AEBDC5A22C4DF0780026DFF1 /* steamshim_child.h in Headers */ = {isa = PBXBuildFile; fileRef = AE120D682BC776E7001873DD /* steamshim_child.h */; }; + AEBDC5A32C4DF0780026DFF1 /* OGL_Model_Def.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DF290E6046F5BA900000104 /* OGL_Model_Def.h */; }; + AEBDC5A42C4DF0780026DFF1 /* OGL_Subst_Texture_Def.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DF290E8046F5BED00000104 /* OGL_Subst_Texture_Def.h */; }; + AEBDC5A52C4DF0780026DFF1 /* OGL_Texture_Def.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DF290E9046F5BED00000104 /* OGL_Texture_Def.h */; }; + AEBDC5A62C4DF0780026DFF1 /* network_star.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CA04819BD700A8000D /* network_star.h */; }; + AEBDC5A72C4DF0780026DFF1 /* NetworkGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CC04819BD700A8000D /* NetworkGameProtocol.h */; }; + AEBDC5A82C4DF0780026DFF1 /* RingGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CE04819BD700A8000D /* RingGameProtocol.h */; }; + AEBDC5A92C4DF0780026DFF1 /* StarGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5D004819BD700A8000D /* StarGameProtocol.h */; }; + AEBDC5AA2C4DF0780026DFF1 /* AStream.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E404819EBF00A8000D /* AStream.h */; }; + AEBDC5AB2C4DF0780026DFF1 /* TickBasedCircularQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E904819F2300A8000D /* TickBasedCircularQueue.h */; }; + AEBDC5AC2C4DF0780026DFF1 /* WindowedNthElementFinder.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5EC04819F8400A8000D /* WindowedNthElementFinder.h */; }; + AEBDC5AD2C4DF0780026DFF1 /* thread_priority_sdl.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5F00481A07000A8000D /* thread_priority_sdl.h */; }; + AEBDC5AE2C4DF0780026DFF1 /* network_data_formats.h in Headers */ = {isa = PBXBuildFile; fileRef = EFBAF0140485BEA500A8000D /* network_data_formats.h */; }; + AEBDC5AF2C4DF0780026DFF1 /* QuickSave.h in Headers */ = {isa = PBXBuildFile; fileRef = 276D4E751A2E710F00C16CF5 /* QuickSave.h */; }; + AEBDC5B02C4DF0780026DFF1 /* SDL_netx.h in Headers */ = {isa = PBXBuildFile; fileRef = EFBAF0170485BEA500A8000D /* SDL_netx.h */; }; + AEBDC5B12C4DF0780026DFF1 /* SSLP_API.h in Headers */ = {isa = PBXBuildFile; fileRef = EFBAF0180485BEA500A8000D /* SSLP_API.h */; }; + AEBDC5B22C4DF0780026DFF1 /* SSLP_Protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EFBAF0190485BEA500A8000D /* SSLP_Protocol.h */; }; + AEBDC5B32C4DF0780026DFF1 /* CircularByteBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = EFEF1AC404AF552D00C3A19D /* CircularByteBuffer.h */; }; + AEBDC5B42C4DF0780026DFF1 /* metaserver_dialogs.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D87957E07D11E120078D26B /* metaserver_dialogs.h */; }; + AEBDC5B52C4DF0780026DFF1 /* metaserver_messages.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D87958007D11E120078D26B /* metaserver_messages.h */; }; + AEBDC5B62C4DF0780026DFF1 /* network_metaserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D87958207D11E120078D26B /* network_metaserver.h */; }; + AEBDC5B72C4DF0780026DFF1 /* CommunicationsChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC152410711123100836977 /* CommunicationsChannel.h */; }; + AEBDC5B82C4DF0780026DFF1 /* Message.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC152440711123200836977 /* Message.h */; }; + AEBDC5B92C4DF0780026DFF1 /* MessageDispatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC152460711123200836977 /* MessageDispatcher.h */; }; + AEBDC5BA2C4DF0780026DFF1 /* MessageHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC152480711123200836977 /* MessageHandler.h */; }; + AEBDC5BB2C4DF0780026DFF1 /* AlephSansMono-Bold.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BECFE1A846FD900AE52F4 /* AlephSansMono-Bold.h */; }; + AEBDC5BC2C4DF0780026DFF1 /* MessageInflater.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DC1524A0711123200836977 /* MessageInflater.h */; }; + AEBDC5BD2C4DF0780026DFF1 /* network_capabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = AE5604E0086F6E0D00D9797C /* network_capabilities.h */; }; + AEBDC5BE2C4DF0780026DFF1 /* shared_widgets.h in Headers */ = {isa = PBXBuildFile; fileRef = AE437C8B08779BC900038E30 /* shared_widgets.h */; }; + AEBDC5BF2C4DF0780026DFF1 /* Console.h in Headers */ = {isa = PBXBuildFile; fileRef = AEC6C89E0879A6020055EC57 /* Console.h */; }; + AEBDC5C02C4DF0780026DFF1 /* ImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = F5CC92EA0240D56101A80001 /* ImageLoader.h */; }; + AEBDC5C12C4DF0780026DFF1 /* DDS.h in Headers */ = {isa = PBXBuildFile; fileRef = AE791CF60968E49100350190 /* DDS.h */; }; + AEBDC5C22C4DF0780026DFF1 /* Music.h in Headers */ = {isa = PBXBuildFile; fileRef = AE626E660B878534009CFF2D /* Music.h */; }; + AEBDC5C32C4DF0780026DFF1 /* cspaths.h in Headers */ = {isa = PBXBuildFile; fileRef = 272BA59E1E622438008C5335 /* cspaths.h */; }; + AEBDC5C42C4DF0780026DFF1 /* SoundFile.h in Headers */ = {isa = PBXBuildFile; fileRef = AE626E680B878534009CFF2D /* SoundFile.h */; }; + AEBDC5C52C4DF0780026DFF1 /* SoundManager.h in Headers */ = {isa = PBXBuildFile; fileRef = AE626E6A0B878534009CFF2D /* SoundManager.h */; }; + AEBDC5C62C4DF0780026DFF1 /* binders.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BED2B1A8470A900AE52F4 /* binders.h */; }; + AEBDC5C72C4DF0780026DFF1 /* SoundManagerEnums.h in Headers */ = {isa = PBXBuildFile; fileRef = AE626E6B0B878534009CFF2D /* SoundManagerEnums.h */; }; + AEBDC5C82C4DF0780026DFF1 /* joystick.h in Headers */ = {isa = PBXBuildFile; fileRef = AEAE12FD0FC9AB4900EDA5A6 /* joystick.h */; }; + AEBDC5C92C4DF0780026DFF1 /* lua_serialize.h in Headers */ = {isa = PBXBuildFile; fileRef = AEAE13200FC9C38400EDA5A6 /* lua_serialize.h */; }; + AEBDC5CA2C4DF0780026DFF1 /* BStream.h in Headers */ = {isa = PBXBuildFile; fileRef = AEAE132D0FC9C3C800EDA5A6 /* BStream.h */; }; + AEBDC5CB2C4DF0780026DFF1 /* OGL_Blitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 270D534B0FCB417500482ED4 /* OGL_Blitter.h */; }; + AEBDC5CC2C4DF0780026DFF1 /* HUDRenderer_Lua.h in Headers */ = {isa = PBXBuildFile; fileRef = 27911B23100073460063ACB6 /* HUDRenderer_Lua.h */; }; + AEBDC5CD2C4DF0780026DFF1 /* Image_Blitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 27CE0842100ECDBC00F59FD1 /* Image_Blitter.h */; }; + AEBDC5CE2C4DF0780026DFF1 /* Shape_Blitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2739B491101B862A00CC8098 /* Shape_Blitter.h */; }; + AEBDC5CF2C4DF0780026DFF1 /* OGL_Shader.h in Headers */ = {isa = PBXBuildFile; fileRef = 27DC606F10917F690062003A /* OGL_Shader.h */; }; + AEBDC5D02C4DF0780026DFF1 /* vec3.h in Headers */ = {isa = PBXBuildFile; fileRef = 27DC60C4109218800062003A /* vec3.h */; }; + AEBDC5D12C4DF0780026DFF1 /* Plugins.h in Headers */ = {isa = PBXBuildFile; fileRef = 277AB98010A26B020003402A /* Plugins.h */; }; + AEBDC5D22C4DF0780026DFF1 /* Rasterizer_Shader.h in Headers */ = {isa = PBXBuildFile; fileRef = 277AB6BD109CE2570003402A /* Rasterizer_Shader.h */; }; + AEBDC5D32C4DF0780026DFF1 /* RenderRasterize_Shader.h in Headers */ = {isa = PBXBuildFile; fileRef = 277AB6BF109CE2570003402A /* RenderRasterize_Shader.h */; }; + AEBDC5D42C4DF0780026DFF1 /* SDL_rwops_zzip.h in Headers */ = {isa = PBXBuildFile; fileRef = 2759F31A10D5BC9C000204DD /* SDL_rwops_zzip.h */; }; + AEBDC5D52C4DF0780026DFF1 /* ReplacementSounds.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BECEF1A846BC500AE52F4 /* ReplacementSounds.h */; }; + AEBDC5D62C4DF0780026DFF1 /* FilmProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 27D1A4F212FDF3630085E79C /* FilmProfile.h */; }; + AEBDC5D72C4DF0780026DFF1 /* VecOps.h in Headers */ = {isa = PBXBuildFile; fileRef = 276BED1C1A846FF600AE52F4 /* VecOps.h */; }; + AEBDC5D82C4DF0780026DFF1 /* HTTP.h in Headers */ = {isa = PBXBuildFile; fileRef = AEDF1A121416FE2200183689 /* HTTP.h */; }; + AEBDC5D92C4DF0780026DFF1 /* Statistics.h in Headers */ = {isa = PBXBuildFile; fileRef = AE48F3551421900900051D61 /* Statistics.h */; }; + AEBDC5DA2C4DF0780026DFF1 /* Movie.h in Headers */ = {isa = PBXBuildFile; fileRef = 27ECF2921698DD7700BE9C35 /* Movie.h */; }; + AEBDC5DB2C4DF0780026DFF1 /* SDL_ffmpeg.h in Headers */ = {isa = PBXBuildFile; fileRef = 27ECF2941698DD7700BE9C35 /* SDL_ffmpeg.h */; }; + AEBDC5DC2C4DF0780026DFF1 /* lctype.h in Headers */ = {isa = PBXBuildFile; fileRef = 2792861A170F92DD0005CD56 /* lctype.h */; }; + AEBDC5DE2C4DF0780026DFF1 /* ImagesIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = F56AEB6B01F8AA1201780311 /* ImagesIcon.icns */; }; + AEBDC5DF2C4DF0780026DFF1 /* ShapesIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = F56AEB6C01F8AA1201780311 /* ShapesIcon.icns */; }; + AEBDC5E02C4DF0780026DFF1 /* SoundsIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = F56AEB6D01F8AA1201780311 /* SoundsIcon.icns */; }; + AEBDC5E12C4DF0780026DFF1 /* FilmIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = F5CFAD3D0200FA6B01D80110 /* FilmIcon.icns */; }; + AEBDC5E22C4DF0780026DFF1 /* m1_achievements.lua in Resources */ = {isa = PBXBuildFile; fileRef = AED959B02BC23591008EFCA2 /* m1_achievements.lua */; }; + AEBDC5E32C4DF0780026DFF1 /* MapIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = F5CFAD3E0200FA6B01D80110 /* MapIcon.icns */; }; + AEBDC5E52C4DF0780026DFF1 /* MMLIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = F5CFAD3F0200FA6B01D80110 /* MMLIcon.icns */; }; + AEBDC5E62C4DF0780026DFF1 /* MusakIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = F5CFAD400200FA6B01D80110 /* MusakIcon.icns */; }; + AEBDC5E72C4DF0780026DFF1 /* PhysIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = F5CFAD420200FA6B01D80110 /* PhysIcon.icns */; }; + AEBDC5E82C4DF0780026DFF1 /* SaveIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = F5CFAD430200FA6B01D80110 /* SaveIcon.icns */; }; + AEBDC5E92C4DF0780026DFF1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = AE7A143A141D16D000834C2D /* InfoPlist.strings */; }; + AEBDC5EB2C4DF0780026DFF1 /* byte_swapping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F52211410136A66601000001 /* byte_swapping.cpp */; }; + AEBDC5EC2C4DF0780026DFF1 /* csalerts_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F52211430136A66601000001 /* csalerts_sdl.cpp */; }; + AEBDC5ED2C4DF0780026DFF1 /* PortForward.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE72AA8F269A7E7B001F7675 /* PortForward.cpp */; }; + AEBDC5EE2C4DF0780026DFF1 /* cscluts_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F52211450136A66601000001 /* cscluts_sdl.cpp */; }; + AEBDC5EF2C4DF0780026DFF1 /* csmisc_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F522114B0136A66601000001 /* csmisc_sdl.cpp */; }; + AEBDC5F02C4DF0780026DFF1 /* achievements.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AED959BE2BC235B2008EFCA2 /* achievements.cpp */; }; + AEBDC5F12C4DF0780026DFF1 /* game_errors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F52211970136A6FD01000001 /* game_errors.cpp */; }; + AEBDC5F22C4DF0780026DFF1 /* interface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F52211C40136A6FD01000001 /* interface.cpp */; }; + AEBDC5F32C4DF0780026DFF1 /* PlayerName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F522120B0136A6FD01000001 /* PlayerName.cpp */; }; + AEBDC5F42C4DF0780026DFF1 /* preferences.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F522120F0136A6FD01000001 /* preferences.cpp */; }; + AEBDC5F52C4DF0780026DFF1 /* sdl_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F522123A0136A6FD01000001 /* sdl_dialogs.cpp */; }; + AEBDC5F62C4DF0780026DFF1 /* sdl_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F522123F0136A6FD01000001 /* sdl_widgets.cpp */; }; + AEBDC5F72C4DF0780026DFF1 /* shell_misc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F52212490136A6FD01000001 /* shell_misc.cpp */; }; + AEBDC5F82C4DF0780026DFF1 /* shell.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F522124B0136A6FD01000001 /* shell.cpp */; }; + AEBDC5F92C4DF0780026DFF1 /* vbl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F52212590136A6FD01000001 /* vbl.cpp */; }; + AEBDC5FA2C4DF0780026DFF1 /* network_lookup_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F52213810136ABAE01000001 /* network_lookup_sdl.cpp */; }; + AEBDC5FB2C4DF0780026DFF1 /* network_udp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F522138E0136ABAE01000001 /* network_udp.cpp */; }; + AEBDC5FC2C4DF0780026DFF1 /* network.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F522138F0136ABAE01000001 /* network.cpp */; }; + AEBDC5FD2C4DF0780026DFF1 /* AudioPlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE61F16628615A22003128EE /* AudioPlayer.cpp */; }; + AEBDC5FE2C4DF0780026DFF1 /* cspaths_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 272BA5A21E628212008C5335 /* cspaths_sdl.cpp */; }; + AEBDC5FF2C4DF0780026DFF1 /* network_games.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F522137F0136ABAE01000001 /* network_games.cpp */; }; + AEBDC6002C4DF0780026DFF1 /* Model3D.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5830B4301E77D5701BA387C /* Model3D.cpp */; }; + AEBDC6012C4DF0780026DFF1 /* ModelRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5830B4501E77D5701BA387C /* ModelRenderer.cpp */; }; + AEBDC6022C4DF0780026DFF1 /* StudioLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5830B4A01E77D5701BA387C /* StudioLoader.cpp */; }; + AEBDC6032C4DF0780026DFF1 /* WavefrontLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5830B4C01E77D5701BA387C /* WavefrontLoader.cpp */; }; + AEBDC6042C4DF0780026DFF1 /* csdialogs_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5574EEE01F4EB1E01FEABBD /* csdialogs_sdl.cpp */; }; + AEBDC6052C4DF0780026DFF1 /* SDL_rwops_ostream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 278E0C7B1AA4012600FA93B7 /* SDL_rwops_ostream.cpp */; }; + AEBDC6062C4DF0780026DFF1 /* mytm_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5574EEF01F4EB1E01FEABBD /* mytm_sdl.cpp */; }; + AEBDC6072C4DF0780026DFF1 /* PlayerImage_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5574EF201F4EBD401FEABBD /* PlayerImage_sdl.cpp */; }; + AEBDC6082C4DF0780026DFF1 /* thread_priority_sdl_macosx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5574EF601F4EC8501FEABBD /* thread_priority_sdl_macosx.cpp */; }; + AEBDC6092C4DF0780026DFF1 /* network_data_formats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5574EF801F4ECD701FEABBD /* network_data_formats.cpp */; }; + AEBDC60A2C4DF0780026DFF1 /* network_dialog_widgets_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5574EFA01F4ED0A01FEABBD /* network_dialog_widgets_sdl.cpp */; }; + AEBDC60B2C4DF0780026DFF1 /* SDL_netx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5574EFC01F4ED4801FEABBD /* SDL_netx.cpp */; }; + AEBDC60C2C4DF0780026DFF1 /* SSLP_limited.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5574EFE01F4ED6501FEABBD /* SSLP_limited.cpp */; }; + AEBDC60D2C4DF0780026DFF1 /* network_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F522137D0136ABAE01000001 /* network_dialogs.cpp */; }; + AEBDC60E2C4DF0780026DFF1 /* Dim3_Loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CFAD390200F9D201D80110 /* Dim3_Loader.cpp */; }; + AEBDC60F2C4DF0780026DFF1 /* preferences_widgets_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5A00023023FDA1601A80001 /* preferences_widgets_sdl.cpp */; }; + AEBDC6102C4DF0780026DFF1 /* ActionQueues.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5A00022023FDA1601A80001 /* ActionQueues.cpp */; }; + AEBDC6112C4DF0780026DFF1 /* crc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC920A0240D09B01A80001 /* crc.cpp */; }; + AEBDC6122C4DF0780026DFF1 /* FileHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC920C0240D09B01A80001 /* FileHandler.cpp */; }; + AEBDC6132C4DF0780026DFF1 /* find_files_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC920F0240D09B01A80001 /* find_files_sdl.cpp */; }; + AEBDC6142C4DF0780026DFF1 /* game_wad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92100240D09B01A80001 /* game_wad.cpp */; }; + AEBDC6152C4DF0780026DFF1 /* import_definitions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92110240D09B01A80001 /* import_definitions.cpp */; }; + AEBDC6162C4DF0780026DFF1 /* preprocess_map_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92130240D09B01A80001 /* preprocess_map_sdl.cpp */; }; + AEBDC6172C4DF0780026DFF1 /* resource_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92140240D09B01A80001 /* resource_manager.cpp */; }; + AEBDC6182C4DF0780026DFF1 /* wad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92150240D09B01A80001 /* wad.cpp */; }; + AEBDC6192C4DF0780026DFF1 /* wad_prefs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92170240D09B01A80001 /* wad_prefs.cpp */; }; + AEBDC61A2C4DF0780026DFF1 /* MusicPlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE61F16528615A22003128EE /* MusicPlayer.cpp */; }; + AEBDC61B2C4DF0780026DFF1 /* wad_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92190240D09B01A80001 /* wad_sdl.cpp */; }; + AEBDC61C2C4DF0780026DFF1 /* devices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC924F0240D28201A80001 /* devices.cpp */; }; + AEBDC61D2C4DF0780026DFF1 /* dynamic_limits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92500240D28201A80001 /* dynamic_limits.cpp */; }; + AEBDC61E2C4DF0780026DFF1 /* effects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92540240D28201A80001 /* effects.cpp */; }; + AEBDC61F2C4DF0780026DFF1 /* flood_map.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92560240D28201A80001 /* flood_map.cpp */; }; + AEBDC6202C4DF0780026DFF1 /* items.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92590240D28201A80001 /* items.cpp */; }; + AEBDC6212C4DF0780026DFF1 /* lightsource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC925B0240D28201A80001 /* lightsource.cpp */; }; + AEBDC6222C4DF0780026DFF1 /* map.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC925D0240D28201A80001 /* map.cpp */; }; + AEBDC6232C4DF0780026DFF1 /* map_constructors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC925F0240D28201A80001 /* map_constructors.cpp */; }; + AEBDC6242C4DF0780026DFF1 /* marathon2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92600240D28201A80001 /* marathon2.cpp */; }; + AEBDC6252C4DF0780026DFF1 /* media.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92610240D28201A80001 /* media.cpp */; }; + AEBDC6262C4DF0780026DFF1 /* monsters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92650240D28201A80001 /* monsters.cpp */; }; + AEBDC6272C4DF0780026DFF1 /* pathfinding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92670240D28201A80001 /* pathfinding.cpp */; }; + AEBDC6282C4DF0780026DFF1 /* FFmpegDecoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27E878F1173202F80010F485 /* FFmpegDecoder.cpp */; }; + AEBDC6292C4DF0780026DFF1 /* physics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92680240D28201A80001 /* physics.cpp */; }; + AEBDC62A2C4DF0780026DFF1 /* placement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC926A0240D28201A80001 /* placement.cpp */; }; + AEBDC62B2C4DF0780026DFF1 /* lua_ephemera.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE780E0F2533A4C7002184B5 /* lua_ephemera.cpp */; }; + AEBDC62C2C4DF0780026DFF1 /* OpenALManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE61F16428615A21003128EE /* OpenALManager.cpp */; }; + AEBDC62D2C4DF0780026DFF1 /* platforms.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC926C0240D28201A80001 /* platforms.cpp */; }; + AEBDC62E2C4DF0780026DFF1 /* player.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC926E0240D28201A80001 /* player.cpp */; }; + AEBDC62F2C4DF0780026DFF1 /* projectiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92710240D28201A80001 /* projectiles.cpp */; }; + AEBDC6302C4DF0780026DFF1 /* scenery.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92730240D28201A80001 /* scenery.cpp */; }; + AEBDC6312C4DF0780026DFF1 /* weapons.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92770240D28201A80001 /* weapons.cpp */; }; + AEBDC6322C4DF0780026DFF1 /* world.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92790240D28201A80001 /* world.cpp */; }; + AEBDC6332C4DF0780026DFF1 /* mouse_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92DC0240D54401A80001 /* mouse_sdl.cpp */; }; + AEBDC6342C4DF0780026DFF1 /* interpolated_world.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEA26AD225E3364A008895CC /* interpolated_world.cpp */; }; + AEBDC6352C4DF0780026DFF1 /* AnimatedTextures.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92E40240D56101A80001 /* AnimatedTextures.cpp */; }; + AEBDC6362C4DF0780026DFF1 /* StreamPlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE61F16828615A22003128EE /* StreamPlayer.cpp */; }; + AEBDC6372C4DF0780026DFF1 /* Crosshairs_SDL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92E90240D56101A80001 /* Crosshairs_SDL.cpp */; }; + AEBDC6382C4DF0780026DFF1 /* ImageLoader_SDL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92EC0240D56101A80001 /* ImageLoader_SDL.cpp */; }; + AEBDC6392C4DF0780026DFF1 /* WadImageCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 278E0C711AA3CD4500FA93B7 /* WadImageCache.cpp */; }; + AEBDC63A2C4DF0780026DFF1 /* OGL_Faders.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92EE0240D56101A80001 /* OGL_Faders.cpp */; }; + AEBDC63B2C4DF0780026DFF1 /* OGL_Render.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92F00240D56101A80001 /* OGL_Render.cpp */; }; + AEBDC63C2C4DF0780026DFF1 /* OGL_Setup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92F20240D56101A80001 /* OGL_Setup.cpp */; }; + AEBDC63D2C4DF0780026DFF1 /* OGL_Textures.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92F40240D56101A80001 /* OGL_Textures.cpp */; }; + AEBDC63E2C4DF0780026DFF1 /* render.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92FC0240D56101A80001 /* render.cpp */; }; + AEBDC63F2C4DF0780026DFF1 /* RenderPlaceObjs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC92FE0240D56101A80001 /* RenderPlaceObjs.cpp */; }; + AEBDC6402C4DF0780026DFF1 /* RenderRasterize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93000240D56101A80001 /* RenderRasterize.cpp */; }; + AEBDC6412C4DF0780026DFF1 /* RenderSortPoly.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93020240D56101A80001 /* RenderSortPoly.cpp */; }; + AEBDC6422C4DF0780026DFF1 /* RenderVisTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93040240D56101A80001 /* RenderVisTree.cpp */; }; + AEBDC6432C4DF0780026DFF1 /* scottish_textures.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93070240D56101A80001 /* scottish_textures.cpp */; }; + AEBDC6442C4DF0780026DFF1 /* shapes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC930C0240D56101A80001 /* shapes.cpp */; }; + AEBDC6452C4DF0780026DFF1 /* textures.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC930F0240D56101A80001 /* textures.cpp */; }; + AEBDC6462C4DF0780026DFF1 /* ChaseCam.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC938C0240D85D01A80001 /* ChaseCam.cpp */; }; + AEBDC6472C4DF0780026DFF1 /* computer_interface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC938D0240D85D01A80001 /* computer_interface.cpp */; }; + AEBDC6482C4DF0780026DFF1 /* fades.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC938E0240D85D01A80001 /* fades.cpp */; }; + AEBDC6492C4DF0780026DFF1 /* FontHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC938F0240D85D01A80001 /* FontHandler.cpp */; }; + AEBDC64A2C4DF0780026DFF1 /* game_window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93900240D85D01A80001 /* game_window.cpp */; }; + AEBDC64B2C4DF0780026DFF1 /* HUDRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93910240D85D01A80001 /* HUDRenderer.cpp */; }; + AEBDC64C2C4DF0780026DFF1 /* HUDRenderer_OGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93920240D85D01A80001 /* HUDRenderer_OGL.cpp */; }; + AEBDC64D2C4DF0780026DFF1 /* HUDRenderer_SW.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93930240D85D01A80001 /* HUDRenderer_SW.cpp */; }; + AEBDC64E2C4DF0780026DFF1 /* images.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93940240D85D01A80001 /* images.cpp */; }; + AEBDC64F2C4DF0780026DFF1 /* motion_sensor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93950240D85D01A80001 /* motion_sensor.cpp */; }; + AEBDC6502C4DF0780026DFF1 /* overhead_map.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93960240D85D01A80001 /* overhead_map.cpp */; }; + AEBDC6512C4DF0780026DFF1 /* OverheadMap_OGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93970240D85D01A80001 /* OverheadMap_OGL.cpp */; }; + AEBDC6522C4DF0780026DFF1 /* OverheadMap_SDL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC938A0240D85D01A80001 /* OverheadMap_SDL.cpp */; }; + AEBDC6532C4DF0780026DFF1 /* OverheadMapRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93980240D85D01A80001 /* OverheadMapRenderer.cpp */; }; + AEBDC6542C4DF0780026DFF1 /* screen_drawing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC939A0240D85D01A80001 /* screen_drawing.cpp */; }; + AEBDC6552C4DF0780026DFF1 /* sdl_fonts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC939F0240D85D01A80001 /* sdl_fonts.cpp */; }; + AEBDC6562C4DF0780026DFF1 /* TextLayoutHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93A10240D85D01A80001 /* TextLayoutHelper.cpp */; }; + AEBDC6572C4DF0780026DFF1 /* TextStrings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93A30240D85D01A80001 /* TextStrings.cpp */; }; + AEBDC6582C4DF0780026DFF1 /* ViewControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC93A50240D85D01A80001 /* ViewControl.cpp */; }; + AEBDC6592C4DF0780026DFF1 /* XML_LevelScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC94400240DE0E01A80001 /* XML_LevelScript.cpp */; }; + AEBDC65A2C4DF0780026DFF1 /* QuickSave.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 276D4E761A2E734E00C16CF5 /* QuickSave.cpp */; }; + AEBDC65B2C4DF0780026DFF1 /* XML_MakeRoot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC94410240DE0E01A80001 /* XML_MakeRoot.cpp */; }; + AEBDC65C2C4DF0780026DFF1 /* sdl_resize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27EFC4BC1A7D8CBF00A95592 /* sdl_resize.cpp */; }; + AEBDC65D2C4DF0780026DFF1 /* Pinger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE3C01A32C13DB8B002A3EB2 /* Pinger.cpp */; }; + AEBDC65E2C4DF0780026DFF1 /* steamshim_child.c in Sources */ = {isa = PBXBuildFile; fileRef = AE120D662BC776CE001873DD /* steamshim_child.c */; }; + AEBDC65F2C4DF0780026DFF1 /* Packing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5837191031EEE0201000105 /* Packing.cpp */; }; + AEBDC6602C4DF0780026DFF1 /* DefaultStringSets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DAC27A503DC9D1C00000104 /* DefaultStringSets.cpp */; }; + AEBDC6612C4DF0780026DFF1 /* Logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DAC27A603DC9D1C00000104 /* Logging.cpp */; }; + AEBDC6622C4DF0780026DFF1 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE171BCC2A59F6EE00A4D3FC /* main.cpp */; }; + AEBDC6632C4DF0780026DFF1 /* preprocess_map_shared.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D5F21430403230F00000104 /* preprocess_map_shared.cpp */; }; + AEBDC6642C4DF0780026DFF1 /* OGL_Model_Def.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DF290EF046F5C5B00000104 /* OGL_Model_Def.cpp */; }; + AEBDC6652C4DF0780026DFF1 /* OGL_Subst_Texture_Def.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DF290F0046F5C5B00000104 /* OGL_Subst_Texture_Def.cpp */; }; + AEBDC6662C4DF0780026DFF1 /* network_star_hub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C804819BD700A8000D /* network_star_hub.cpp */; }; + AEBDC6672C4DF0780026DFF1 /* InfoTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27FF265E1B6F170600DA0A19 /* InfoTree.cpp */; }; + AEBDC6682C4DF0780026DFF1 /* network_star_spoke.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C904819BD700A8000D /* network_star_spoke.cpp */; }; + AEBDC6692C4DF0780026DFF1 /* RingGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CD04819BD700A8000D /* RingGameProtocol.cpp */; }; + AEBDC66A2C4DF0780026DFF1 /* StarGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CF04819BD700A8000D /* StarGameProtocol.cpp */; }; + AEBDC66B2C4DF0780026DFF1 /* lua_music.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE96370B2A39578600DE43FF /* lua_music.cpp */; }; + AEBDC66C2C4DF0780026DFF1 /* AStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5E304819EBF00A8000D /* AStream.cpp */; }; + AEBDC66D2C4DF0780026DFF1 /* CircularByteBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EFEF1AC504AF552D00C3A19D /* CircularByteBuffer.cpp */; }; + AEBDC66E2C4DF0780026DFF1 /* lua_script.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F51B058B047AC6DA01C5C930 /* lua_script.cpp */; }; + AEBDC66F2C4DF0780026DFF1 /* metaserver_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D87957D07D11E120078D26B /* metaserver_dialogs.cpp */; }; + AEBDC6702C4DF0780026DFF1 /* metaserver_messages.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D87957F07D11E120078D26B /* metaserver_messages.cpp */; }; + AEBDC6712C4DF0780026DFF1 /* network_metaserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D87958107D11E120078D26B /* network_metaserver.cpp */; }; + AEBDC6722C4DF0780026DFF1 /* CommunicationsChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DC152400711123100836977 /* CommunicationsChannel.cpp */; }; + AEBDC6732C4DF0780026DFF1 /* Message.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DC152430711123200836977 /* Message.cpp */; }; + AEBDC6742C4DF0780026DFF1 /* MessageDispatcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DC152450711123200836977 /* MessageDispatcher.cpp */; }; + AEBDC6752C4DF0780026DFF1 /* MessageHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DC152470711123200836977 /* MessageHandler.cpp */; }; + AEBDC6762C4DF0780026DFF1 /* MessageInflater.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DC152490711123200836977 /* MessageInflater.cpp */; }; + AEBDC6772C4DF0780026DFF1 /* network_messages.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DF154D6080376E100BC3C09 /* network_messages.cpp */; }; + AEBDC6782C4DF0780026DFF1 /* csstrings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F522114C0136A66601000001 /* csstrings.cpp */; }; + AEBDC6792C4DF0780026DFF1 /* SdlMetaserverClientUi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 088809F3084C1A5500DC9E4D /* SdlMetaserverClientUi.cpp */; }; + AEBDC67A2C4DF0780026DFF1 /* network_capabilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE5604DD086F6DF100D9797C /* network_capabilities.cpp */; }; + AEBDC67B2C4DF0780026DFF1 /* shared_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE437C8E08779BE500038E30 /* shared_widgets.cpp */; }; + AEBDC67C2C4DF0780026DFF1 /* Console.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEC6C89B0879A5DE0055EC57 /* Console.cpp */; }; + AEBDC67D2C4DF0780026DFF1 /* ImageLoader_Shared.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE791CD60968E16600350190 /* ImageLoader_Shared.cpp */; }; + AEBDC67E2C4DF0780026DFF1 /* OGL_LoadScreen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEF5025E09A825E2004B0179 /* OGL_LoadScreen.cpp */; }; + AEBDC67F2C4DF0780026DFF1 /* ephemera.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE780E142533A4D8002184B5 /* ephemera.cpp */; }; + AEBDC6802C4DF0780026DFF1 /* Scenario.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE2A50CC09C67253007681A4 /* Scenario.cpp */; }; + AEBDC6812C4DF0780026DFF1 /* preference_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE2FDECA09E934E000A18ABC /* preference_dialogs.cpp */; }; + AEBDC6822C4DF0780026DFF1 /* OGL_Blitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE0053ED0ABE16300038507F /* OGL_Blitter.cpp */; }; + AEBDC6832C4DF0780026DFF1 /* SW_Texture_Extras.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEC02F900B6D8B310095E8C9 /* SW_Texture_Extras.cpp */; }; + AEBDC6842C4DF0780026DFF1 /* Music.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE626E650B878534009CFF2D /* Music.cpp */; }; + AEBDC6852C4DF0780026DFF1 /* shell_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEEA4E7E2544B50B0031363A /* shell_options.cpp */; }; + AEBDC6862C4DF0780026DFF1 /* SoundFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE626E670B878534009CFF2D /* SoundFile.cpp */; }; + AEBDC6872C4DF0780026DFF1 /* SoundManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE626E690B878534009CFF2D /* SoundManager.cpp */; }; + AEBDC6882C4DF0780026DFF1 /* Decoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE601F060B927C25009F881C /* Decoder.cpp */; }; + AEBDC6892C4DF0780026DFF1 /* SndfileDecoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE601F080B927C25009F881C /* SndfileDecoder.cpp */; }; + AEBDC68A2C4DF0780026DFF1 /* ReplacementSounds.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE23F5990BDAC23E00C11385 /* ReplacementSounds.cpp */; }; + AEBDC68B2C4DF0780026DFF1 /* lapi.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21800BFF67B700CE63EC /* lapi.c */; }; + AEBDC68C2C4DF0780026DFF1 /* lauxlib.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21810BFF67B700CE63EC /* lauxlib.c */; }; + AEBDC68D2C4DF0780026DFF1 /* lbaselib.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21820BFF67B700CE63EC /* lbaselib.c */; }; + AEBDC68E2C4DF0780026DFF1 /* lcode.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21830BFF67B700CE63EC /* lcode.c */; }; + AEBDC68F2C4DF0780026DFF1 /* ldblib.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21840BFF67B700CE63EC /* ldblib.c */; }; + AEBDC6902C4DF0780026DFF1 /* ldebug.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21850BFF67B700CE63EC /* ldebug.c */; }; + AEBDC6912C4DF0780026DFF1 /* ldo.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21860BFF67B700CE63EC /* ldo.c */; }; + AEBDC6922C4DF0780026DFF1 /* ldump.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21870BFF67B700CE63EC /* ldump.c */; }; + AEBDC6932C4DF0780026DFF1 /* lfunc.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21880BFF67B700CE63EC /* lfunc.c */; }; + AEBDC6942C4DF0780026DFF1 /* lgc.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21890BFF67B700CE63EC /* lgc.c */; }; + AEBDC6952C4DF0780026DFF1 /* linit.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C218A0BFF67B700CE63EC /* linit.c */; }; + AEBDC6962C4DF0780026DFF1 /* liolib.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C218B0BFF67B700CE63EC /* liolib.c */; }; + AEBDC6972C4DF0780026DFF1 /* llex.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C218C0BFF67B700CE63EC /* llex.c */; }; + AEBDC6982C4DF0780026DFF1 /* lmathlib.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C218D0BFF67B700CE63EC /* lmathlib.c */; }; + AEBDC6992C4DF0780026DFF1 /* lmem.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C218E0BFF67B700CE63EC /* lmem.c */; }; + AEBDC69A2C4DF0780026DFF1 /* lobject.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C218F0BFF67B700CE63EC /* lobject.c */; }; + AEBDC69B2C4DF0780026DFF1 /* lopcodes.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21900BFF67B700CE63EC /* lopcodes.c */; }; + AEBDC69C2C4DF0780026DFF1 /* loslib.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21910BFF67B700CE63EC /* loslib.c */; }; + AEBDC69D2C4DF0780026DFF1 /* lparser.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21920BFF67B700CE63EC /* lparser.c */; }; + AEBDC69E2C4DF0780026DFF1 /* lstate.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21930BFF67B700CE63EC /* lstate.c */; }; + AEBDC69F2C4DF0780026DFF1 /* lstring.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21940BFF67B700CE63EC /* lstring.c */; }; + AEBDC6A02C4DF0780026DFF1 /* lstrlib.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21950BFF67B700CE63EC /* lstrlib.c */; }; + AEBDC6A12C4DF0780026DFF1 /* ltable.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21960BFF67B700CE63EC /* ltable.c */; }; + AEBDC6A22C4DF0780026DFF1 /* Statistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27FC2E091A7DF51E0057BF42 /* Statistics.cpp */; }; + AEBDC6A32C4DF0780026DFF1 /* ltablib.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21970BFF67B700CE63EC /* ltablib.c */; }; + AEBDC6A42C4DF0780026DFF1 /* ltm.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21980BFF67B700CE63EC /* ltm.c */; }; + AEBDC6A52C4DF0780026DFF1 /* lundump.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21990BFF67B700CE63EC /* lundump.c */; }; + AEBDC6A62C4DF0780026DFF1 /* lvm.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C219A0BFF67B700CE63EC /* lvm.c */; }; + AEBDC6A72C4DF0780026DFF1 /* lzio.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C219B0BFF67B700CE63EC /* lzio.c */; }; + AEBDC6A82C4DF0780026DFF1 /* Update.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21D50BFF688000CE63EC /* Update.cpp */; }; + AEBDC6A92C4DF0780026DFF1 /* ConnectPool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE9A39F60CCADFA7004717E3 /* ConnectPool.cpp */; }; + AEBDC6AA2C4DF0780026DFF1 /* lua_player.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE69B5DB0D404F0400C42C11 /* lua_player.cpp */; }; + AEBDC6AB2C4DF0780026DFF1 /* HTTP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 275A7BD71A60E9B9002EE952 /* HTTP.cpp */; }; + AEBDC6AC2C4DF0780026DFF1 /* lua_map.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE51545D0D46E84A00506B58 /* lua_map.cpp */; }; + AEBDC6AD2C4DF0780026DFF1 /* lua_monsters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEDCB5CB0D4ADB86004CB40E /* lua_monsters.cpp */; }; + AEBDC6AE2C4DF0780026DFF1 /* lua_projectiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEDCB5DA0D4AEC4D004CB40E /* lua_projectiles.cpp */; }; + AEBDC6AF2C4DF0780026DFF1 /* lua_objects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE38D10C0D555A3100FC2082 /* lua_objects.cpp */; }; + AEBDC6B02C4DF0780026DFF1 /* screen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE005FD30EE2D6DE007FE7C6 /* screen.cpp */; }; + AEBDC6B12C4DF0780026DFF1 /* joystick_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEAE12FE0FC9AB4900EDA5A6 /* joystick_sdl.cpp */; }; + AEBDC6B22C4DF0780026DFF1 /* lua_serialize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEAE131F0FC9C38400EDA5A6 /* lua_serialize.cpp */; }; + AEBDC6B32C4DF0780026DFF1 /* BStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEAE132C0FC9C3C800EDA5A6 /* BStream.cpp */; }; + AEBDC6B42C4DF0780026DFF1 /* lua_hud_objects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2784979B0FF5C308008DECC8 /* lua_hud_objects.cpp */; }; + AEBDC6B52C4DF0780026DFF1 /* lua_hud_script.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2784979D0FF5C308008DECC8 /* lua_hud_script.cpp */; }; + AEBDC6B62C4DF0780026DFF1 /* HUDRenderer_Lua.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27911B22100073460063ACB6 /* HUDRenderer_Lua.cpp */; }; + AEBDC6B72C4DF0780026DFF1 /* Image_Blitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27CE0841100ECDBC00F59FD1 /* Image_Blitter.cpp */; }; + AEBDC6B82C4DF0780026DFF1 /* Shape_Blitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2739B490101B862A00CC8098 /* Shape_Blitter.cpp */; }; + AEBDC6B92C4DF0780026DFF1 /* OGL_Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27DC606E10917F690062003A /* OGL_Shader.cpp */; }; + AEBDC6BA2C4DF0780026DFF1 /* Plugins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 277AB97E10A26AF40003402A /* Plugins.cpp */; }; + AEBDC6BB2C4DF0780026DFF1 /* Rasterizer_Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 277AB6BC109CE2570003402A /* Rasterizer_Shader.cpp */; }; + AEBDC6BC2C4DF0780026DFF1 /* RenderRasterize_Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 277AB6BE109CE2570003402A /* RenderRasterize_Shader.cpp */; }; + AEBDC6BD2C4DF0780026DFF1 /* SDL_rwops_zzip.c in Sources */ = {isa = PBXBuildFile; fileRef = 2759F31910D5BC9C000204DD /* SDL_rwops_zzip.c */; }; + AEBDC6BE2C4DF0780026DFF1 /* IMG_savepng.c in Sources */ = {isa = PBXBuildFile; fileRef = AEF1AC1510E05835007EE0D5 /* IMG_savepng.c */; }; + AEBDC6BF2C4DF0780026DFF1 /* SoundPlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE61F16728615A22003128EE /* SoundPlayer.cpp */; }; + AEBDC6C02C4DF0780026DFF1 /* csalerts.mm in Sources */ = {isa = PBXBuildFile; fileRef = AEA31D2B113C9DF700266621 /* csalerts.mm */; }; + AEBDC6C12C4DF0780026DFF1 /* OGL_FBO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2710CC5F1B8F94FC00CE2EAE /* OGL_FBO.cpp */; }; + AEBDC6C22C4DF0780026DFF1 /* lua_saved_objects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 276589F6119DF1DD0096F75B /* lua_saved_objects.cpp */; }; + AEBDC6C32C4DF0780026DFF1 /* cspaths.mm in Sources */ = {isa = PBXBuildFile; fileRef = 272BA5A01E6242F8008C5335 /* cspaths.mm */; }; + AEBDC6C42C4DF0780026DFF1 /* FilmProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27D1A4F112FDF3630085E79C /* FilmProfile.cpp */; }; + AEBDC6C52C4DF0780026DFF1 /* Movie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27ECF2911698DD7700BE9C35 /* Movie.cpp */; }; + AEBDC6C62C4DF0780026DFF1 /* SDL_ffmpeg.c in Sources */ = {isa = PBXBuildFile; fileRef = 27ECF2931698DD7700BE9C35 /* SDL_ffmpeg.c */; }; + AEBDC6C72C4DF0780026DFF1 /* lbitlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 27928610170F92D20005CD56 /* lbitlib.c */; }; + AEBDC6C82C4DF0780026DFF1 /* lctype.c in Sources */ = {isa = PBXBuildFile; fileRef = 27928611170F92D20005CD56 /* lctype.c */; }; + AEBDC6CA2C4DF0780026DFF1 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9975032661D63700DDD370 /* CoreMedia.framework */; }; + AEBDC6CB2C4DF0780026DFF1 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = AE99750F2661D81600DDD370 /* libz.tbd */; }; + AEBDC6CC2C4DF0780026DFF1 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9975122661D85000DDD370 /* Cocoa.framework */; }; + AEBDC6CD2C4DF0780026DFF1 /* libcurl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = AE99750C2661D71000DDD370 /* libcurl.tbd */; }; + AEBDC6CE2C4DF0780026DFF1 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9974FD2661D49E00DDD370 /* AudioToolbox.framework */; }; + AEBDC6CF2C4DF0780026DFF1 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9975052661D66600DDD370 /* Security.framework */; }; + AEBDC6D02C4DF0780026DFF1 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9975102661D82700DDD370 /* OpenGL.framework */; }; + AEBDC6D12C4DF0780026DFF1 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE99750D2661D7F200DDD370 /* IOKit.framework */; }; + AEBDC6D22C4DF0780026DFF1 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9974FF2661D4DD00DDD370 /* Carbon.framework */; }; + AEBDC6D32C4DF0780026DFF1 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9975072661D6E300DDD370 /* CoreAudio.framework */; }; + AEBDC6D42C4DF0780026DFF1 /* ForceFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9975012661D50F00DDD370 /* ForceFeedback.framework */; }; + AEBDC6D52C4DF0780026DFF1 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9975092661D6F400DDD370 /* AudioUnit.framework */; }; + AEBDC6DC2C4DF2170026DFF1 /* Marathon Infinity.icns in Resources */ = {isa = PBXBuildFile; fileRef = AEB4A2B214296DC000537AE7 /* Marathon Infinity.icns */; }; AEC02F910B6D8B310095E8C9 /* SW_Texture_Extras.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEC02F900B6D8B310095E8C9 /* SW_Texture_Extras.cpp */; }; AEC3C70109AD68AC003258E4 /* PlayerName.h in Headers */ = {isa = PBXBuildFile; fileRef = F522120C0136A6FD01000001 /* PlayerName.h */; }; AEC3C70209AD68AC003258E4 /* Random.h in Headers */ = {isa = PBXBuildFile; fileRef = F52212190136A6FD01000001 /* Random.h */; }; @@ -2999,6 +3453,7 @@ AEB4A2AD14296CAE00537AE7 /* Classic Marathon Infinity.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Classic Marathon Infinity.app"; sourceTree = BUILT_PRODUCTS_DIR; }; AEB4A2B214296DC000537AE7 /* Marathon Infinity.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = "Marathon Infinity.icns"; path = "AppStore/Marathon Infinity/Marathon Infinity.icns"; sourceTree = ""; }; AEB4A2B714296DCF00537AE7 /* Info-MAS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Info-MAS.plist"; path = "AppStore/Marathon Infinity/Info-MAS.plist"; sourceTree = ""; }; + AEBDC6DA2C4DF0780026DFF1 /* Classic Marathon Infinity Steam.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Classic Marathon Infinity Steam.app"; sourceTree = BUILT_PRODUCTS_DIR; }; AEC02F900B6D8B310095E8C9 /* SW_Texture_Extras.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SW_Texture_Extras.cpp; sourceTree = ""; }; AEC3C89609AD68AE003258E4 /* Aleph One.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Aleph One.app"; sourceTree = BUILT_PRODUCTS_DIR; }; AEC6C89B0879A5DE0055EC57 /* Console.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Console.cpp; path = ../Source_Files/Misc/Console.cpp; sourceTree = SOURCE_ROOT; }; @@ -3366,6 +3821,25 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AEBDC6C92C4DF0780026DFF1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AEBDC6CA2C4DF0780026DFF1 /* CoreMedia.framework in Frameworks */, + AEBDC6CB2C4DF0780026DFF1 /* libz.tbd in Frameworks */, + AEBDC6CC2C4DF0780026DFF1 /* Cocoa.framework in Frameworks */, + AEBDC6CD2C4DF0780026DFF1 /* libcurl.tbd in Frameworks */, + AEBDC6CE2C4DF0780026DFF1 /* AudioToolbox.framework in Frameworks */, + AEBDC6CF2C4DF0780026DFF1 /* Security.framework in Frameworks */, + AEBDC6D02C4DF0780026DFF1 /* OpenGL.framework in Frameworks */, + AEBDC6D12C4DF0780026DFF1 /* IOKit.framework in Frameworks */, + AEBDC6D22C4DF0780026DFF1 /* Carbon.framework in Frameworks */, + AEBDC6D32C4DF0780026DFF1 /* CoreAudio.framework in Frameworks */, + AEBDC6D42C4DF0780026DFF1 /* ForceFeedback.framework in Frameworks */, + AEBDC6D52C4DF0780026DFF1 /* AudioUnit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; AEC3C86F09AD68AC003258E4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -3417,6 +3891,7 @@ AE120D642BC77645001873DD /* Classic Marathon Steam.app */, AE8729C12BD1FBEA00426095 /* Classic Marathon Launcher */, AE1321FD2C1CB4D2009D34AA /* Classic Marathon 2 Steam.app */, + AEBDC6DA2C4DF0780026DFF1 /* Classic Marathon Infinity Steam.app */, ); name = Products; sourceTree = ""; @@ -5151,6 +5626,221 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AEBDC50C2C4DF0780026DFF1 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + AEBDC50D2C4DF0780026DFF1 /* PlayerName.h in Headers */, + AEBDC50E2C4DF0780026DFF1 /* Random.h in Headers */, + AEBDC50F2C4DF0780026DFF1 /* game_errors.h in Headers */, + AEBDC5102C4DF0780026DFF1 /* interface.h in Headers */, + AEBDC5112C4DF0780026DFF1 /* interface_menus.h in Headers */, + AEBDC5122C4DF0780026DFF1 /* Decoder.h in Headers */, + AEBDC5132C4DF0780026DFF1 /* key_definitions.h in Headers */, + AEBDC5142C4DF0780026DFF1 /* preferences.h in Headers */, + AEBDC5152C4DF0780026DFF1 /* progress.h in Headers */, + AEBDC5162C4DF0780026DFF1 /* sdl_dialogs.h in Headers */, + AEBDC5172C4DF0780026DFF1 /* sdl_network.h in Headers */, + AEBDC5182C4DF0780026DFF1 /* sdl_widgets.h in Headers */, + AEBDC5192C4DF0780026DFF1 /* shell.h in Headers */, + AEBDC51A2C4DF0780026DFF1 /* vbl_definitions.h in Headers */, + AEBDC51B2C4DF0780026DFF1 /* vbl.h in Headers */, + AEBDC51C2C4DF0780026DFF1 /* byte_swapping.h in Headers */, + AEBDC51D2C4DF0780026DFF1 /* csalerts.h in Headers */, + AEBDC51E2C4DF0780026DFF1 /* cscluts.h in Headers */, + AEBDC51F2C4DF0780026DFF1 /* csdialogs.h in Headers */, + AEBDC5202C4DF0780026DFF1 /* cseries.h in Headers */, + AEBDC5212C4DF0780026DFF1 /* Scenario.h in Headers */, + AEBDC5222C4DF0780026DFF1 /* csfonts.h in Headers */, + AEBDC5232C4DF0780026DFF1 /* csmacros.h in Headers */, + AEBDC5242C4DF0780026DFF1 /* csmisc.h in Headers */, + AEBDC5252C4DF0780026DFF1 /* CourierPrimeBold.h in Headers */, + AEBDC5262C4DF0780026DFF1 /* cspixels.h in Headers */, + AEBDC5272C4DF0780026DFF1 /* csstrings.h in Headers */, + AEBDC5282C4DF0780026DFF1 /* cstypes.h in Headers */, + AEBDC5292C4DF0780026DFF1 /* network.h in Headers */, + AEBDC52A2C4DF0780026DFF1 /* network_games.h in Headers */, + AEBDC52B2C4DF0780026DFF1 /* IMG_savepng.h in Headers */, + AEBDC52C2C4DF0780026DFF1 /* Model3D.h in Headers */, + AEBDC52D2C4DF0780026DFF1 /* ModelRenderer.h in Headers */, + AEBDC52E2C4DF0780026DFF1 /* StudioLoader.h in Headers */, + AEBDC52F2C4DF0780026DFF1 /* WavefrontLoader.h in Headers */, + AEBDC5302C4DF0780026DFF1 /* network_dialog_widgets_sdl.h in Headers */, + AEBDC5312C4DF0780026DFF1 /* Dim3_Loader.h in Headers */, + AEBDC5322C4DF0780026DFF1 /* FFmpegDecoder.h in Headers */, + AEBDC5332C4DF0780026DFF1 /* SW_Texture_Extras.h in Headers */, + AEBDC5342C4DF0780026DFF1 /* network_dialogs.h in Headers */, + AEBDC5352C4DF0780026DFF1 /* network_lookup_sdl.h in Headers */, + AEBDC5362C4DF0780026DFF1 /* ActionQueues.h in Headers */, + AEBDC5372C4DF0780026DFF1 /* CircularQueue.h in Headers */, + AEBDC5382C4DF0780026DFF1 /* preferences_widgets_sdl.h in Headers */, + AEBDC5392C4DF0780026DFF1 /* network_distribution_types.h in Headers */, + AEBDC53A2C4DF0780026DFF1 /* OGL_LoadScreen.h in Headers */, + AEBDC53B2C4DF0780026DFF1 /* crc.h in Headers */, + AEBDC53C2C4DF0780026DFF1 /* extensions.h in Headers */, + AEBDC53D2C4DF0780026DFF1 /* FileHandler.h in Headers */, + AEBDC53E2C4DF0780026DFF1 /* find_files.h in Headers */, + AEBDC53F2C4DF0780026DFF1 /* game_wad.h in Headers */, + AEBDC5402C4DF0780026DFF1 /* Packing.h in Headers */, + AEBDC5412C4DF0780026DFF1 /* resource_manager.h in Headers */, + AEBDC5422C4DF0780026DFF1 /* preference_dialogs.h in Headers */, + AEBDC5432C4DF0780026DFF1 /* tags.h in Headers */, + AEBDC5442C4DF0780026DFF1 /* wad.h in Headers */, + AEBDC5452C4DF0780026DFF1 /* wad_prefs.h in Headers */, + AEBDC5462C4DF0780026DFF1 /* dynamic_limits.h in Headers */, + AEBDC5472C4DF0780026DFF1 /* editor.h in Headers */, + AEBDC5482C4DF0780026DFF1 /* effect_definitions.h in Headers */, + AEBDC5492C4DF0780026DFF1 /* effects.h in Headers */, + AEBDC54A2C4DF0780026DFF1 /* flood_map.h in Headers */, + AEBDC54B2C4DF0780026DFF1 /* item_definitions.h in Headers */, + AEBDC54C2C4DF0780026DFF1 /* items.h in Headers */, + AEBDC54D2C4DF0780026DFF1 /* SDL_rwops_ostream.h in Headers */, + AEBDC54E2C4DF0780026DFF1 /* lightsource.h in Headers */, + AEBDC54F2C4DF0780026DFF1 /* map.h in Headers */, + AEBDC5502C4DF0780026DFF1 /* CourierPrimeBoldItalic.h in Headers */, + AEBDC5512C4DF0780026DFF1 /* confpaths.h in Headers */, + AEBDC5522C4DF0780026DFF1 /* media.h in Headers */, + AEBDC5532C4DF0780026DFF1 /* media_definitions.h in Headers */, + AEBDC5542C4DF0780026DFF1 /* monster_definitions.h in Headers */, + AEBDC5552C4DF0780026DFF1 /* monsters.h in Headers */, + AEBDC5562C4DF0780026DFF1 /* physics_models.h in Headers */, + AEBDC5572C4DF0780026DFF1 /* platform_definitions.h in Headers */, + AEBDC5582C4DF0780026DFF1 /* mytm.h in Headers */, + AEBDC5592C4DF0780026DFF1 /* CourierPrime.h in Headers */, + AEBDC55A2C4DF0780026DFF1 /* InfoTree.h in Headers */, + AEBDC55B2C4DF0780026DFF1 /* platforms.h in Headers */, + AEBDC55C2C4DF0780026DFF1 /* player.h in Headers */, + AEBDC55D2C4DF0780026DFF1 /* projectile_definitions.h in Headers */, + AEBDC55E2C4DF0780026DFF1 /* config.h in Headers */, + AEBDC55F2C4DF0780026DFF1 /* projectiles.h in Headers */, + AEBDC5602C4DF0780026DFF1 /* scenery.h in Headers */, + AEBDC5612C4DF0780026DFF1 /* scenery_definitions.h in Headers */, + AEBDC5622C4DF0780026DFF1 /* weapon_definitions.h in Headers */, + AEBDC5632C4DF0780026DFF1 /* weapons.h in Headers */, + AEBDC5642C4DF0780026DFF1 /* world.h in Headers */, + AEBDC5652C4DF0780026DFF1 /* mouse.h in Headers */, + AEBDC5662C4DF0780026DFF1 /* AnimatedTextures.h in Headers */, + AEBDC5672C4DF0780026DFF1 /* collection_definition.h in Headers */, + AEBDC5682C4DF0780026DFF1 /* Crosshairs.h in Headers */, + AEBDC5692C4DF0780026DFF1 /* low_level_textures.h in Headers */, + AEBDC56A2C4DF0780026DFF1 /* OGL_Faders.h in Headers */, + AEBDC56B2C4DF0780026DFF1 /* OGL_Render.h in Headers */, + AEBDC56C2C4DF0780026DFF1 /* OGL_Setup.h in Headers */, + AEBDC56D2C4DF0780026DFF1 /* OGL_Textures.h in Headers */, + AEBDC56E2C4DF0780026DFF1 /* Rasterizer.h in Headers */, + AEBDC56F2C4DF0780026DFF1 /* Rasterizer_OGL.h in Headers */, + AEBDC5702C4DF0780026DFF1 /* Rasterizer_SW.h in Headers */, + AEBDC5712C4DF0780026DFF1 /* render.h in Headers */, + AEBDC5722C4DF0780026DFF1 /* RenderPlaceObjs.h in Headers */, + AEBDC5732C4DF0780026DFF1 /* RenderRasterize.h in Headers */, + AEBDC5742C4DF0780026DFF1 /* RenderSortPoly.h in Headers */, + AEBDC5752C4DF0780026DFF1 /* ProFontAO.h in Headers */, + AEBDC5762C4DF0780026DFF1 /* RenderVisTree.h in Headers */, + AEBDC5772C4DF0780026DFF1 /* scottish_textures.h in Headers */, + AEBDC5782C4DF0780026DFF1 /* shape_definitions.h in Headers */, + AEBDC5792C4DF0780026DFF1 /* achievements.h in Headers */, + AEBDC57A2C4DF0780026DFF1 /* WadImageCache.h in Headers */, + AEBDC57B2C4DF0780026DFF1 /* shape_descriptors.h in Headers */, + AEBDC57C2C4DF0780026DFF1 /* textures.h in Headers */, + AEBDC57D2C4DF0780026DFF1 /* ChaseCam.h in Headers */, + AEBDC57E2C4DF0780026DFF1 /* sdl_resize.h in Headers */, + AEBDC57F2C4DF0780026DFF1 /* computer_interface.h in Headers */, + AEBDC5802C4DF0780026DFF1 /* PlayerImage_sdl.h in Headers */, + AEBDC5812C4DF0780026DFF1 /* fades.h in Headers */, + AEBDC5822C4DF0780026DFF1 /* FontHandler.h in Headers */, + AEBDC5832C4DF0780026DFF1 /* game_window.h in Headers */, + AEBDC5842C4DF0780026DFF1 /* HUDRenderer.h in Headers */, + AEBDC5852C4DF0780026DFF1 /* HUDRenderer_OGL.h in Headers */, + AEBDC5862C4DF0780026DFF1 /* HUDRenderer_SW.h in Headers */, + AEBDC5872C4DF0780026DFF1 /* powered_by_alephone_h.h in Headers */, + AEBDC5882C4DF0780026DFF1 /* OGL_FBO.h in Headers */, + AEBDC5892C4DF0780026DFF1 /* images.h in Headers */, + AEBDC58A2C4DF0780026DFF1 /* motion_sensor.h in Headers */, + AEBDC58B2C4DF0780026DFF1 /* powered_by_alephone.h in Headers */, + AEBDC58C2C4DF0780026DFF1 /* overhead_map.h in Headers */, + AEBDC58D2C4DF0780026DFF1 /* OverheadMap_OGL.h in Headers */, + AEBDC58E2C4DF0780026DFF1 /* OverheadMap_SDL.h in Headers */, + AEBDC58F2C4DF0780026DFF1 /* OverheadMapRenderer.h in Headers */, + AEBDC5902C4DF0780026DFF1 /* screen.h in Headers */, + AEBDC5912C4DF0780026DFF1 /* screen_definitions.h in Headers */, + AEBDC5922C4DF0780026DFF1 /* screen_drawing.h in Headers */, + AEBDC5932C4DF0780026DFF1 /* screen_shared.h in Headers */, + AEBDC5942C4DF0780026DFF1 /* sdl_fonts.h in Headers */, + AEBDC5952C4DF0780026DFF1 /* CourierPrimeItalic.h in Headers */, + AEBDC5962C4DF0780026DFF1 /* TextLayoutHelper.h in Headers */, + AEBDC5972C4DF0780026DFF1 /* TextStrings.h in Headers */, + AEBDC5982C4DF0780026DFF1 /* ViewControl.h in Headers */, + AEBDC5992C4DF0780026DFF1 /* song_definitions.h in Headers */, + AEBDC59A2C4DF0780026DFF1 /* OGL_Headers.h in Headers */, + AEBDC59B2C4DF0780026DFF1 /* SndfileDecoder.h in Headers */, + AEBDC59C2C4DF0780026DFF1 /* sound_definitions.h in Headers */, + AEBDC59D2C4DF0780026DFF1 /* DefaultStringSets.h in Headers */, + AEBDC59E2C4DF0780026DFF1 /* XML_LevelScript.h in Headers */, + AEBDC59F2C4DF0780026DFF1 /* XML_ParseTreeRoot.h in Headers */, + AEBDC5A02C4DF0780026DFF1 /* alephversion.h in Headers */, + AEBDC5A12C4DF0780026DFF1 /* Logging.h in Headers */, + AEBDC5A22C4DF0780026DFF1 /* steamshim_child.h in Headers */, + AEBDC5A32C4DF0780026DFF1 /* OGL_Model_Def.h in Headers */, + AEBDC5A42C4DF0780026DFF1 /* OGL_Subst_Texture_Def.h in Headers */, + AEBDC5A52C4DF0780026DFF1 /* OGL_Texture_Def.h in Headers */, + AEBDC5A62C4DF0780026DFF1 /* network_star.h in Headers */, + AEBDC5A72C4DF0780026DFF1 /* NetworkGameProtocol.h in Headers */, + AEBDC5A82C4DF0780026DFF1 /* RingGameProtocol.h in Headers */, + AEBDC5A92C4DF0780026DFF1 /* StarGameProtocol.h in Headers */, + AEBDC5AA2C4DF0780026DFF1 /* AStream.h in Headers */, + AEBDC5AB2C4DF0780026DFF1 /* TickBasedCircularQueue.h in Headers */, + AEBDC5AC2C4DF0780026DFF1 /* WindowedNthElementFinder.h in Headers */, + AEBDC5AD2C4DF0780026DFF1 /* thread_priority_sdl.h in Headers */, + AEBDC5AE2C4DF0780026DFF1 /* network_data_formats.h in Headers */, + AEBDC5AF2C4DF0780026DFF1 /* QuickSave.h in Headers */, + AEBDC5B02C4DF0780026DFF1 /* SDL_netx.h in Headers */, + AEBDC5B12C4DF0780026DFF1 /* SSLP_API.h in Headers */, + AEBDC5B22C4DF0780026DFF1 /* SSLP_Protocol.h in Headers */, + AEBDC5B32C4DF0780026DFF1 /* CircularByteBuffer.h in Headers */, + AEBDC5B42C4DF0780026DFF1 /* metaserver_dialogs.h in Headers */, + AEBDC5B52C4DF0780026DFF1 /* metaserver_messages.h in Headers */, + AEBDC5B62C4DF0780026DFF1 /* network_metaserver.h in Headers */, + AEBDC5B72C4DF0780026DFF1 /* CommunicationsChannel.h in Headers */, + AEBDC5B82C4DF0780026DFF1 /* Message.h in Headers */, + AEBDC5B92C4DF0780026DFF1 /* MessageDispatcher.h in Headers */, + AEBDC5BA2C4DF0780026DFF1 /* MessageHandler.h in Headers */, + AEBDC5BB2C4DF0780026DFF1 /* AlephSansMono-Bold.h in Headers */, + AEBDC5BC2C4DF0780026DFF1 /* MessageInflater.h in Headers */, + AEBDC5BD2C4DF0780026DFF1 /* network_capabilities.h in Headers */, + AEBDC5BE2C4DF0780026DFF1 /* shared_widgets.h in Headers */, + AEBDC5BF2C4DF0780026DFF1 /* Console.h in Headers */, + AEBDC5C02C4DF0780026DFF1 /* ImageLoader.h in Headers */, + AEBDC5C12C4DF0780026DFF1 /* DDS.h in Headers */, + AEBDC5C22C4DF0780026DFF1 /* Music.h in Headers */, + AEBDC5C32C4DF0780026DFF1 /* cspaths.h in Headers */, + AEBDC5C42C4DF0780026DFF1 /* SoundFile.h in Headers */, + AEBDC5C52C4DF0780026DFF1 /* SoundManager.h in Headers */, + AEBDC5C62C4DF0780026DFF1 /* binders.h in Headers */, + AEBDC5C72C4DF0780026DFF1 /* SoundManagerEnums.h in Headers */, + AEBDC5C82C4DF0780026DFF1 /* joystick.h in Headers */, + AEBDC5C92C4DF0780026DFF1 /* lua_serialize.h in Headers */, + AEBDC5CA2C4DF0780026DFF1 /* BStream.h in Headers */, + AEBDC5CB2C4DF0780026DFF1 /* OGL_Blitter.h in Headers */, + AEBDC5CC2C4DF0780026DFF1 /* HUDRenderer_Lua.h in Headers */, + AEBDC5CD2C4DF0780026DFF1 /* Image_Blitter.h in Headers */, + AEBDC5CE2C4DF0780026DFF1 /* Shape_Blitter.h in Headers */, + AEBDC5CF2C4DF0780026DFF1 /* OGL_Shader.h in Headers */, + AEBDC5D02C4DF0780026DFF1 /* vec3.h in Headers */, + AEBDC5D12C4DF0780026DFF1 /* Plugins.h in Headers */, + AEBDC5D22C4DF0780026DFF1 /* Rasterizer_Shader.h in Headers */, + AEBDC5D32C4DF0780026DFF1 /* RenderRasterize_Shader.h in Headers */, + AEBDC5D42C4DF0780026DFF1 /* SDL_rwops_zzip.h in Headers */, + AEBDC5D52C4DF0780026DFF1 /* ReplacementSounds.h in Headers */, + AEBDC5D62C4DF0780026DFF1 /* FilmProfile.h in Headers */, + AEBDC5D72C4DF0780026DFF1 /* VecOps.h in Headers */, + AEBDC5D82C4DF0780026DFF1 /* HTTP.h in Headers */, + AEBDC5D92C4DF0780026DFF1 /* Statistics.h in Headers */, + AEBDC5DA2C4DF0780026DFF1 /* Movie.h in Headers */, + AEBDC5DB2C4DF0780026DFF1 /* SDL_ffmpeg.h in Headers */, + AEBDC5DC2C4DF0780026DFF1 /* lctype.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; AEC3C6FF09AD68AC003258E4 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -5677,6 +6367,25 @@ productReference = AEB4A2AD14296CAE00537AE7 /* Classic Marathon Infinity.app */; productType = "com.apple.product-type.application"; }; + AEBDC50B2C4DF0780026DFF1 /* Marathon Infinity Steam */ = { + isa = PBXNativeTarget; + buildConfigurationList = AEBDC6D72C4DF0780026DFF1 /* Build configuration list for PBXNativeTarget "Marathon Infinity Steam" */; + buildPhases = ( + AEBDC50C2C4DF0780026DFF1 /* Headers */, + AEBDC5DD2C4DF0780026DFF1 /* Resources */, + AEBDC5EA2C4DF0780026DFF1 /* Sources */, + AEBDC6C92C4DF0780026DFF1 /* Frameworks */, + AEBDC6D62C4DF0780026DFF1 /* Insert Version */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Marathon Infinity Steam"; + productName = "SDL Application"; + productReference = AEBDC6DA2C4DF0780026DFF1 /* Classic Marathon Infinity Steam.app */; + productType = "com.apple.product-type.application"; + }; AEC3C6FE09AD68AC003258E4 /* Aleph One */ = { isa = PBXNativeTarget; buildConfigurationList = AEC3C87B09AD68AC003258E4 /* Build configuration list for PBXNativeTarget "Aleph One" */; @@ -5769,6 +6478,7 @@ AEB4A0DA14296CAE00537AE7 /* Marathon Infinity */, AE120B972BC77645001873DD /* Marathon Steam */, AE13202F2C1CB4D2009D34AA /* Marathon 2 Steam */, + AEBDC50B2C4DF0780026DFF1 /* Marathon Infinity Steam */, AE8729C02BD1FBEA00426095 /* Classic Marathon Launcher */, ); }; @@ -5851,6 +6561,25 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AEBDC5DD2C4DF0780026DFF1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AEBDC5DE2C4DF0780026DFF1 /* ImagesIcon.icns in Resources */, + AEBDC5DF2C4DF0780026DFF1 /* ShapesIcon.icns in Resources */, + AEBDC5E02C4DF0780026DFF1 /* SoundsIcon.icns in Resources */, + AEBDC5E12C4DF0780026DFF1 /* FilmIcon.icns in Resources */, + AEBDC5E22C4DF0780026DFF1 /* m1_achievements.lua in Resources */, + AEBDC5E32C4DF0780026DFF1 /* MapIcon.icns in Resources */, + AEBDC5E52C4DF0780026DFF1 /* MMLIcon.icns in Resources */, + AEBDC5E62C4DF0780026DFF1 /* MusakIcon.icns in Resources */, + AEBDC6DC2C4DF2170026DFF1 /* Marathon Infinity.icns in Resources */, + AEBDC5E72C4DF0780026DFF1 /* PhysIcon.icns in Resources */, + AEBDC5E82C4DF0780026DFF1 /* SaveIcon.icns in Resources */, + AEBDC5E92C4DF0780026DFF1 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; AEC3C7C209AD68AC003258E4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -5986,6 +6715,18 @@ shellPath = /bin/sh; shellScript = "rsync -aC \"$SRCROOT/../data/Scenarios/Marathon Infinity/\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources/DataFiles\"\nsed -i '' 's/\\$default\\$/$bundle$/' \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources/DataFiles/Scripts/Default Preferences.xml\"\n"; }; + AEBDC6D62C4DF0780026DFF1 /* Insert Version */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 12; + files = ( + ); + inputPaths = ( + ); + name = "Insert Version"; + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "DISPLAY_VERSION=$( grep '^#define A1_DISPLAY_VERSION' \"$SRCROOT\"/../Source_Files/Misc/alephversion.h | sed -e 's/\\(.*\\\"\\)\\(.*\\)\\(\\\"\\)/\\2/g' )\nDATE_VERSION=$( grep '^#define A1_DATE_VERSION' \"$SRCROOT\"/../Source_Files/Misc/alephversion.h | sed -e 's/\\(.*\\\"\\)\\(.*\\)\\(\\\"\\)/\\2/g' )\nsed -i '' -e s/A1_DISPLAY_VERSION/$DISPLAY_VERSION/g \"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"\nsed -i '' -e s/A1_DATE_VERSION/$DATE_VERSION/g \"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"\n"; + }; AEC3C87609AD68AC003258E4 /* Copy Default Theme */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 12; @@ -6950,6 +7691,235 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AEBDC5EA2C4DF0780026DFF1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AEBDC5EB2C4DF0780026DFF1 /* byte_swapping.cpp in Sources */, + AEBDC5EC2C4DF0780026DFF1 /* csalerts_sdl.cpp in Sources */, + AEBDC5ED2C4DF0780026DFF1 /* PortForward.cpp in Sources */, + AEBDC5EE2C4DF0780026DFF1 /* cscluts_sdl.cpp in Sources */, + AEBDC5EF2C4DF0780026DFF1 /* csmisc_sdl.cpp in Sources */, + AEBDC5F02C4DF0780026DFF1 /* achievements.cpp in Sources */, + AEBDC5F12C4DF0780026DFF1 /* game_errors.cpp in Sources */, + AEBDC5F22C4DF0780026DFF1 /* interface.cpp in Sources */, + AEBDC5F32C4DF0780026DFF1 /* PlayerName.cpp in Sources */, + AEBDC5F42C4DF0780026DFF1 /* preferences.cpp in Sources */, + AEBDC5F52C4DF0780026DFF1 /* sdl_dialogs.cpp in Sources */, + AEBDC5F62C4DF0780026DFF1 /* sdl_widgets.cpp in Sources */, + AEBDC5F72C4DF0780026DFF1 /* shell_misc.cpp in Sources */, + AEBDC5F82C4DF0780026DFF1 /* shell.cpp in Sources */, + AEBDC5F92C4DF0780026DFF1 /* vbl.cpp in Sources */, + AEBDC5FA2C4DF0780026DFF1 /* network_lookup_sdl.cpp in Sources */, + AEBDC5FB2C4DF0780026DFF1 /* network_udp.cpp in Sources */, + AEBDC5FC2C4DF0780026DFF1 /* network.cpp in Sources */, + AEBDC5FD2C4DF0780026DFF1 /* AudioPlayer.cpp in Sources */, + AEBDC5FE2C4DF0780026DFF1 /* cspaths_sdl.cpp in Sources */, + AEBDC5FF2C4DF0780026DFF1 /* network_games.cpp in Sources */, + AEBDC6002C4DF0780026DFF1 /* Model3D.cpp in Sources */, + AEBDC6012C4DF0780026DFF1 /* ModelRenderer.cpp in Sources */, + AEBDC6022C4DF0780026DFF1 /* StudioLoader.cpp in Sources */, + AEBDC6032C4DF0780026DFF1 /* WavefrontLoader.cpp in Sources */, + AEBDC6042C4DF0780026DFF1 /* csdialogs_sdl.cpp in Sources */, + AEBDC6052C4DF0780026DFF1 /* SDL_rwops_ostream.cpp in Sources */, + AEBDC6062C4DF0780026DFF1 /* mytm_sdl.cpp in Sources */, + AEBDC6072C4DF0780026DFF1 /* PlayerImage_sdl.cpp in Sources */, + AEBDC6082C4DF0780026DFF1 /* thread_priority_sdl_macosx.cpp in Sources */, + AEBDC6092C4DF0780026DFF1 /* network_data_formats.cpp in Sources */, + AEBDC60A2C4DF0780026DFF1 /* network_dialog_widgets_sdl.cpp in Sources */, + AEBDC60B2C4DF0780026DFF1 /* SDL_netx.cpp in Sources */, + AEBDC60C2C4DF0780026DFF1 /* SSLP_limited.cpp in Sources */, + AEBDC60D2C4DF0780026DFF1 /* network_dialogs.cpp in Sources */, + AEBDC60E2C4DF0780026DFF1 /* Dim3_Loader.cpp in Sources */, + AEBDC60F2C4DF0780026DFF1 /* preferences_widgets_sdl.cpp in Sources */, + AEBDC6102C4DF0780026DFF1 /* ActionQueues.cpp in Sources */, + AEBDC6112C4DF0780026DFF1 /* crc.cpp in Sources */, + AEBDC6122C4DF0780026DFF1 /* FileHandler.cpp in Sources */, + AEBDC6132C4DF0780026DFF1 /* find_files_sdl.cpp in Sources */, + AEBDC6142C4DF0780026DFF1 /* game_wad.cpp in Sources */, + AEBDC6152C4DF0780026DFF1 /* import_definitions.cpp in Sources */, + AEBDC6162C4DF0780026DFF1 /* preprocess_map_sdl.cpp in Sources */, + AEBDC6172C4DF0780026DFF1 /* resource_manager.cpp in Sources */, + AEBDC6182C4DF0780026DFF1 /* wad.cpp in Sources */, + AEBDC6192C4DF0780026DFF1 /* wad_prefs.cpp in Sources */, + AEBDC61A2C4DF0780026DFF1 /* MusicPlayer.cpp in Sources */, + AEBDC61B2C4DF0780026DFF1 /* wad_sdl.cpp in Sources */, + AEBDC61C2C4DF0780026DFF1 /* devices.cpp in Sources */, + AEBDC61D2C4DF0780026DFF1 /* dynamic_limits.cpp in Sources */, + AEBDC61E2C4DF0780026DFF1 /* effects.cpp in Sources */, + AEBDC61F2C4DF0780026DFF1 /* flood_map.cpp in Sources */, + AEBDC6202C4DF0780026DFF1 /* items.cpp in Sources */, + AEBDC6212C4DF0780026DFF1 /* lightsource.cpp in Sources */, + AEBDC6222C4DF0780026DFF1 /* map.cpp in Sources */, + AEBDC6232C4DF0780026DFF1 /* map_constructors.cpp in Sources */, + AEBDC6242C4DF0780026DFF1 /* marathon2.cpp in Sources */, + AEBDC6252C4DF0780026DFF1 /* media.cpp in Sources */, + AEBDC6262C4DF0780026DFF1 /* monsters.cpp in Sources */, + AEBDC6272C4DF0780026DFF1 /* pathfinding.cpp in Sources */, + AEBDC6282C4DF0780026DFF1 /* FFmpegDecoder.cpp in Sources */, + AEBDC6292C4DF0780026DFF1 /* physics.cpp in Sources */, + AEBDC62A2C4DF0780026DFF1 /* placement.cpp in Sources */, + AEBDC62B2C4DF0780026DFF1 /* lua_ephemera.cpp in Sources */, + AEBDC62C2C4DF0780026DFF1 /* OpenALManager.cpp in Sources */, + AEBDC62D2C4DF0780026DFF1 /* platforms.cpp in Sources */, + AEBDC62E2C4DF0780026DFF1 /* player.cpp in Sources */, + AEBDC62F2C4DF0780026DFF1 /* projectiles.cpp in Sources */, + AEBDC6302C4DF0780026DFF1 /* scenery.cpp in Sources */, + AEBDC6312C4DF0780026DFF1 /* weapons.cpp in Sources */, + AEBDC6322C4DF0780026DFF1 /* world.cpp in Sources */, + AEBDC6332C4DF0780026DFF1 /* mouse_sdl.cpp in Sources */, + AEBDC6342C4DF0780026DFF1 /* interpolated_world.cpp in Sources */, + AEBDC6352C4DF0780026DFF1 /* AnimatedTextures.cpp in Sources */, + AEBDC6362C4DF0780026DFF1 /* StreamPlayer.cpp in Sources */, + AEBDC6372C4DF0780026DFF1 /* Crosshairs_SDL.cpp in Sources */, + AEBDC6382C4DF0780026DFF1 /* ImageLoader_SDL.cpp in Sources */, + AEBDC6392C4DF0780026DFF1 /* WadImageCache.cpp in Sources */, + AEBDC63A2C4DF0780026DFF1 /* OGL_Faders.cpp in Sources */, + AEBDC63B2C4DF0780026DFF1 /* OGL_Render.cpp in Sources */, + AEBDC63C2C4DF0780026DFF1 /* OGL_Setup.cpp in Sources */, + AEBDC63D2C4DF0780026DFF1 /* OGL_Textures.cpp in Sources */, + AEBDC63E2C4DF0780026DFF1 /* render.cpp in Sources */, + AEBDC63F2C4DF0780026DFF1 /* RenderPlaceObjs.cpp in Sources */, + AEBDC6402C4DF0780026DFF1 /* RenderRasterize.cpp in Sources */, + AEBDC6412C4DF0780026DFF1 /* RenderSortPoly.cpp in Sources */, + AEBDC6422C4DF0780026DFF1 /* RenderVisTree.cpp in Sources */, + AEBDC6432C4DF0780026DFF1 /* scottish_textures.cpp in Sources */, + AEBDC6442C4DF0780026DFF1 /* shapes.cpp in Sources */, + AEBDC6452C4DF0780026DFF1 /* textures.cpp in Sources */, + AEBDC6462C4DF0780026DFF1 /* ChaseCam.cpp in Sources */, + AEBDC6472C4DF0780026DFF1 /* computer_interface.cpp in Sources */, + AEBDC6482C4DF0780026DFF1 /* fades.cpp in Sources */, + AEBDC6492C4DF0780026DFF1 /* FontHandler.cpp in Sources */, + AEBDC64A2C4DF0780026DFF1 /* game_window.cpp in Sources */, + AEBDC64B2C4DF0780026DFF1 /* HUDRenderer.cpp in Sources */, + AEBDC64C2C4DF0780026DFF1 /* HUDRenderer_OGL.cpp in Sources */, + AEBDC64D2C4DF0780026DFF1 /* HUDRenderer_SW.cpp in Sources */, + AEBDC64E2C4DF0780026DFF1 /* images.cpp in Sources */, + AEBDC64F2C4DF0780026DFF1 /* motion_sensor.cpp in Sources */, + AEBDC6502C4DF0780026DFF1 /* overhead_map.cpp in Sources */, + AEBDC6512C4DF0780026DFF1 /* OverheadMap_OGL.cpp in Sources */, + AEBDC6522C4DF0780026DFF1 /* OverheadMap_SDL.cpp in Sources */, + AEBDC6532C4DF0780026DFF1 /* OverheadMapRenderer.cpp in Sources */, + AEBDC6542C4DF0780026DFF1 /* screen_drawing.cpp in Sources */, + AEBDC6552C4DF0780026DFF1 /* sdl_fonts.cpp in Sources */, + AEBDC6562C4DF0780026DFF1 /* TextLayoutHelper.cpp in Sources */, + AEBDC6572C4DF0780026DFF1 /* TextStrings.cpp in Sources */, + AEBDC6582C4DF0780026DFF1 /* ViewControl.cpp in Sources */, + AEBDC6592C4DF0780026DFF1 /* XML_LevelScript.cpp in Sources */, + AEBDC65A2C4DF0780026DFF1 /* QuickSave.cpp in Sources */, + AEBDC65B2C4DF0780026DFF1 /* XML_MakeRoot.cpp in Sources */, + AEBDC65C2C4DF0780026DFF1 /* sdl_resize.cpp in Sources */, + AEBDC65D2C4DF0780026DFF1 /* Pinger.cpp in Sources */, + AEBDC65E2C4DF0780026DFF1 /* steamshim_child.c in Sources */, + AEBDC65F2C4DF0780026DFF1 /* Packing.cpp in Sources */, + AEBDC6602C4DF0780026DFF1 /* DefaultStringSets.cpp in Sources */, + AEBDC6612C4DF0780026DFF1 /* Logging.cpp in Sources */, + AEBDC6622C4DF0780026DFF1 /* main.cpp in Sources */, + AEBDC6632C4DF0780026DFF1 /* preprocess_map_shared.cpp in Sources */, + AEBDC6642C4DF0780026DFF1 /* OGL_Model_Def.cpp in Sources */, + AEBDC6652C4DF0780026DFF1 /* OGL_Subst_Texture_Def.cpp in Sources */, + AEBDC6662C4DF0780026DFF1 /* network_star_hub.cpp in Sources */, + AEBDC6672C4DF0780026DFF1 /* InfoTree.cpp in Sources */, + AEBDC6682C4DF0780026DFF1 /* network_star_spoke.cpp in Sources */, + AEBDC6692C4DF0780026DFF1 /* RingGameProtocol.cpp in Sources */, + AEBDC66A2C4DF0780026DFF1 /* StarGameProtocol.cpp in Sources */, + AEBDC66B2C4DF0780026DFF1 /* lua_music.cpp in Sources */, + AEBDC66C2C4DF0780026DFF1 /* AStream.cpp in Sources */, + AEBDC66D2C4DF0780026DFF1 /* CircularByteBuffer.cpp in Sources */, + AEBDC66E2C4DF0780026DFF1 /* lua_script.cpp in Sources */, + AEBDC66F2C4DF0780026DFF1 /* metaserver_dialogs.cpp in Sources */, + AEBDC6702C4DF0780026DFF1 /* metaserver_messages.cpp in Sources */, + AEBDC6712C4DF0780026DFF1 /* network_metaserver.cpp in Sources */, + AEBDC6722C4DF0780026DFF1 /* CommunicationsChannel.cpp in Sources */, + AEBDC6732C4DF0780026DFF1 /* Message.cpp in Sources */, + AEBDC6742C4DF0780026DFF1 /* MessageDispatcher.cpp in Sources */, + AEBDC6752C4DF0780026DFF1 /* MessageHandler.cpp in Sources */, + AEBDC6762C4DF0780026DFF1 /* MessageInflater.cpp in Sources */, + AEBDC6772C4DF0780026DFF1 /* network_messages.cpp in Sources */, + AEBDC6782C4DF0780026DFF1 /* csstrings.cpp in Sources */, + AEBDC6792C4DF0780026DFF1 /* SdlMetaserverClientUi.cpp in Sources */, + AEBDC67A2C4DF0780026DFF1 /* network_capabilities.cpp in Sources */, + AEBDC67B2C4DF0780026DFF1 /* shared_widgets.cpp in Sources */, + AEBDC67C2C4DF0780026DFF1 /* Console.cpp in Sources */, + AEBDC67D2C4DF0780026DFF1 /* ImageLoader_Shared.cpp in Sources */, + AEBDC67E2C4DF0780026DFF1 /* OGL_LoadScreen.cpp in Sources */, + AEBDC67F2C4DF0780026DFF1 /* ephemera.cpp in Sources */, + AEBDC6802C4DF0780026DFF1 /* Scenario.cpp in Sources */, + AEBDC6812C4DF0780026DFF1 /* preference_dialogs.cpp in Sources */, + AEBDC6822C4DF0780026DFF1 /* OGL_Blitter.cpp in Sources */, + AEBDC6832C4DF0780026DFF1 /* SW_Texture_Extras.cpp in Sources */, + AEBDC6842C4DF0780026DFF1 /* Music.cpp in Sources */, + AEBDC6852C4DF0780026DFF1 /* shell_options.cpp in Sources */, + AEBDC6862C4DF0780026DFF1 /* SoundFile.cpp in Sources */, + AEBDC6872C4DF0780026DFF1 /* SoundManager.cpp in Sources */, + AEBDC6882C4DF0780026DFF1 /* Decoder.cpp in Sources */, + AEBDC6892C4DF0780026DFF1 /* SndfileDecoder.cpp in Sources */, + AEBDC68A2C4DF0780026DFF1 /* ReplacementSounds.cpp in Sources */, + AEBDC68B2C4DF0780026DFF1 /* lapi.c in Sources */, + AEBDC68C2C4DF0780026DFF1 /* lauxlib.c in Sources */, + AEBDC68D2C4DF0780026DFF1 /* lbaselib.c in Sources */, + AEBDC68E2C4DF0780026DFF1 /* lcode.c in Sources */, + AEBDC68F2C4DF0780026DFF1 /* ldblib.c in Sources */, + AEBDC6902C4DF0780026DFF1 /* ldebug.c in Sources */, + AEBDC6912C4DF0780026DFF1 /* ldo.c in Sources */, + AEBDC6922C4DF0780026DFF1 /* ldump.c in Sources */, + AEBDC6932C4DF0780026DFF1 /* lfunc.c in Sources */, + AEBDC6942C4DF0780026DFF1 /* lgc.c in Sources */, + AEBDC6952C4DF0780026DFF1 /* linit.c in Sources */, + AEBDC6962C4DF0780026DFF1 /* liolib.c in Sources */, + AEBDC6972C4DF0780026DFF1 /* llex.c in Sources */, + AEBDC6982C4DF0780026DFF1 /* lmathlib.c in Sources */, + AEBDC6992C4DF0780026DFF1 /* lmem.c in Sources */, + AEBDC69A2C4DF0780026DFF1 /* lobject.c in Sources */, + AEBDC69B2C4DF0780026DFF1 /* lopcodes.c in Sources */, + AEBDC69C2C4DF0780026DFF1 /* loslib.c in Sources */, + AEBDC69D2C4DF0780026DFF1 /* lparser.c in Sources */, + AEBDC69E2C4DF0780026DFF1 /* lstate.c in Sources */, + AEBDC69F2C4DF0780026DFF1 /* lstring.c in Sources */, + AEBDC6A02C4DF0780026DFF1 /* lstrlib.c in Sources */, + AEBDC6A12C4DF0780026DFF1 /* ltable.c in Sources */, + AEBDC6A22C4DF0780026DFF1 /* Statistics.cpp in Sources */, + AEBDC6A32C4DF0780026DFF1 /* ltablib.c in Sources */, + AEBDC6A42C4DF0780026DFF1 /* ltm.c in Sources */, + AEBDC6A52C4DF0780026DFF1 /* lundump.c in Sources */, + AEBDC6A62C4DF0780026DFF1 /* lvm.c in Sources */, + AEBDC6A72C4DF0780026DFF1 /* lzio.c in Sources */, + AEBDC6A82C4DF0780026DFF1 /* Update.cpp in Sources */, + AEBDC6A92C4DF0780026DFF1 /* ConnectPool.cpp in Sources */, + AEBDC6AA2C4DF0780026DFF1 /* lua_player.cpp in Sources */, + AEBDC6AB2C4DF0780026DFF1 /* HTTP.cpp in Sources */, + AEBDC6AC2C4DF0780026DFF1 /* lua_map.cpp in Sources */, + AEBDC6AD2C4DF0780026DFF1 /* lua_monsters.cpp in Sources */, + AEBDC6AE2C4DF0780026DFF1 /* lua_projectiles.cpp in Sources */, + AEBDC6AF2C4DF0780026DFF1 /* lua_objects.cpp in Sources */, + AEBDC6B02C4DF0780026DFF1 /* screen.cpp in Sources */, + AEBDC6B12C4DF0780026DFF1 /* joystick_sdl.cpp in Sources */, + AEBDC6B22C4DF0780026DFF1 /* lua_serialize.cpp in Sources */, + AEBDC6B32C4DF0780026DFF1 /* BStream.cpp in Sources */, + AEBDC6B42C4DF0780026DFF1 /* lua_hud_objects.cpp in Sources */, + AEBDC6B52C4DF0780026DFF1 /* lua_hud_script.cpp in Sources */, + AEBDC6B62C4DF0780026DFF1 /* HUDRenderer_Lua.cpp in Sources */, + AEBDC6B72C4DF0780026DFF1 /* Image_Blitter.cpp in Sources */, + AEBDC6B82C4DF0780026DFF1 /* Shape_Blitter.cpp in Sources */, + AEBDC6B92C4DF0780026DFF1 /* OGL_Shader.cpp in Sources */, + AEBDC6BA2C4DF0780026DFF1 /* Plugins.cpp in Sources */, + AEBDC6BB2C4DF0780026DFF1 /* Rasterizer_Shader.cpp in Sources */, + AEBDC6BC2C4DF0780026DFF1 /* RenderRasterize_Shader.cpp in Sources */, + AEBDC6BD2C4DF0780026DFF1 /* SDL_rwops_zzip.c in Sources */, + AEBDC6BE2C4DF0780026DFF1 /* IMG_savepng.c in Sources */, + AEBDC6BF2C4DF0780026DFF1 /* SoundPlayer.cpp in Sources */, + AEBDC6C02C4DF0780026DFF1 /* csalerts.mm in Sources */, + AEBDC6C12C4DF0780026DFF1 /* OGL_FBO.cpp in Sources */, + AEBDC6C22C4DF0780026DFF1 /* lua_saved_objects.cpp in Sources */, + AEBDC6C32C4DF0780026DFF1 /* cspaths.mm in Sources */, + AEBDC6C42C4DF0780026DFF1 /* FilmProfile.cpp in Sources */, + AEBDC6C52C4DF0780026DFF1 /* Movie.cpp in Sources */, + AEBDC6C62C4DF0780026DFF1 /* SDL_ffmpeg.c in Sources */, + AEBDC6C72C4DF0780026DFF1 /* lbitlib.c in Sources */, + AEBDC6C82C4DF0780026DFF1 /* lctype.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; AEC3C7CF09AD68AC003258E4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -8031,6 +9001,58 @@ }; name = Debug; }; + AEBDC6D82C4DF0780026DFF1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = Marathon.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = E8K89CXZE7; + ENABLE_HARDENED_RUNTIME = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + SDL, + HAVE_BUNDLE_NAME, + HAVE_CONFIG_H, + HAVE_STEAM, + ); + INFOPLIST_FILE = "$(SRCROOT)/AppStore/Marathon Infinity/Info-Steam.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.bungie.source.MarathonInfinity; + PRODUCT_NAME = "Classic Marathon Infinity Steam"; + PROVISIONING_PROFILE_SPECIFIER = ""; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + AEBDC6D92C4DF0780026DFF1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = Marathon.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = E8K89CXZE7; + ENABLE_HARDENED_RUNTIME = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + SDL, + HAVE_BUNDLE_NAME, + HAVE_CONFIG_H, + HAVE_STEAM, + ); + INFOPLIST_FILE = "$(SRCROOT)/AppStore/Marathon Infinity/Info-Steam.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.bungie.source.MarathonInfinity; + PRODUCT_NAME = "Classic Marathon Infinity Steam"; + PROVISIONING_PROFILE_SPECIFIER = ""; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; AEFD87C113EB84CF00C1E687 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -8142,6 +9164,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + AEBDC6D72C4DF0780026DFF1 /* Build configuration list for PBXNativeTarget "Marathon Infinity Steam" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AEBDC6D82C4DF0780026DFF1 /* Release */, + AEBDC6D92C4DF0780026DFF1 /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; AEC3C87B09AD68AC003258E4 /* Build configuration list for PBXNativeTarget "Aleph One" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/PBProjects/AppStore/Marathon Infinity/Info-Steam.plist b/PBProjects/AppStore/Marathon Infinity/Info-Steam.plist new file mode 100644 index 000000000..b3be50171 --- /dev/null +++ b/PBProjects/AppStore/Marathon Infinity/Info-Steam.plist @@ -0,0 +1,558 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + shpA + shps + + CFBundleTypeIconFile + ShapesIcon.icns + CFBundleTypeName + Aleph One Shapes File + CFBundleTypeOSTypes + + shp∞ + shp2 + + CFBundleTypeRole + Viewer + LSItemContentTypes + + org.bungie.source.shapes + + NSDocumentClass + + + + CFBundleTypeExtensions + + sndA + snds + + CFBundleTypeIconFile + SoundsIcon.icns + CFBundleTypeName + Aleph One Sound Data + CFBundleTypeOSTypes + + snd∞ + snd2 + + CFBundleTypeRole + Viewer + LSItemContentTypes + + org.bungie.source.sounds + + NSDocumentClass + + + + CFBundleTypeExtensions + + imgA + + CFBundleTypeIconFile + ImagesIcon.icns + CFBundleTypeName + Aleph One Interface Images + CFBundleTypeOSTypes + + img∞ + img2 + + CFBundleTypeRole + Viewer + LSItemContentTypes + + org.bungie.source.images + + NSDocumentClass + + + + CFBundleTypeExtensions + + filA + + CFBundleTypeIconFile + FilmIcon.icns + CFBundleTypeName + Aleph One Replay + CFBundleTypeOSTypes + + fil∞ + fil2 + + CFBundleTypeRole + Viewer + LSItemContentTypes + + org.bungie.source.film + + NSDocumentClass + + + + CFBundleTypeExtensions + + sceA + scen + sce + * + + CFBundleTypeIconFile + MapIcon.icns + CFBundleTypeName + Aleph One Map File + CFBundleTypeOSTypes + + sce∞ + sce2 + + CFBundleTypeRole + Viewer + LSItemContentTypes + + org.bungie.source.map + + NSDocumentClass + + + + CFBundleTypeExtensions + + mml + + CFBundleTypeIconFile + MMLIcon.icns + CFBundleTypeName + Aleph One XML Configuration + CFBundleTypeRole + None + LSItemContentTypes + + org.bungie.source.mml + + NSDocumentClass + + + + CFBundleTypeExtensions + + pfhr + + CFBundleTypeIconFile + PFIcon.icns + CFBundleTypeName + Aleph One Pfhortran Script + CFBundleTypeRole + None + LSItemContentTypes + + org.bungie.source.pfhortran + + NSDocumentClass + + + + CFBundleTypeExtensions + + phyA + phys + * + + CFBundleTypeIconFile + PhysIcon.icns + CFBundleTypeName + Aleph One Physics File + CFBundleTypeOSTypes + + phy∞ + phy2 + + CFBundleTypeRole + Viewer + LSItemContentTypes + + org.bungie.source.physics + + NSDocumentClass + + + + CFBundleTypeExtensions + + sgaA + + CFBundleTypeIconFile + SaveIcon.icns + CFBundleTypeName + Aleph One Saved Game + CFBundleTypeOSTypes + + sga∞ + sga2 + + CFBundleTypeRole + Viewer + LSItemContentTypes + + org.bungie.source.save + + NSDocumentClass + + + + CFBundleTypeExtensions + + musA + + CFBundleTypeIconFile + MusakIcon.icns + CFBundleTypeName + Aleph One Music + CFBundleTypeOSTypes + + AIFF + MPEG + MP3 + + CFBundleTypeRole + None + NSDocumentClass + org.bungie.source.music + + + CFBundleTypeExtensions + + a1bndl + + CFBundleTypeIconFile + package.icns + CFBundleTypeName + Aleph One Bundle + CFBundleTypeRole + Viewer + LSItemContentTypes + + org.bungie.source.bundle + + LSTypeIsPackage + + NSDocumentClass + + + + CFBundleTypeExtensions + + appl + + CFBundleTypeIconFile + ImagesIcon.icns + CFBundleTypeName + Aleph One External Resources + CFBundleTypeRole + Viewer + LSItemContentTypes + + org.bungie.source.resources + + NSDocumentClass + + + + CFBundleExecutable + Classic Marathon Infinity Steam + CFBundleIconFile + Marathon Infinity.icns + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Marathon 2 + CFBundlePackageType + APPL + CFBundleShortVersionString + A1_DISPLAY_VERSION + CFBundleSignature + 26.A + CFBundleVersion + A1_DATE_VERSION + LSApplicationCategoryType + public.app-category.action-games + LSEnvironment + + ALEPHONE_FINDER_LAUNCH + 1 + + LSMinimumSystemVersion + 10.13 + NSHighResolutionCapable + + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + UTExportedTypeDeclarations + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Aleph One Shapes File + UTTypeIconFile + ShapesIcon + UTTypeIdentifier + org.bungie.source.shapes + UTTypeTagSpecification + + com.apple.ostype + + shp∞ + shp2 + + public.filename-extension + + shpA + shps + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Aleph One Sound Data + UTTypeIconFile + SoundsIcon + UTTypeIdentifier + org.bungie.source.sounds + UTTypeTagSpecification + + com.apple.ostype + + snd∞ + snd2 + + public.filename-extension + + sndA + snds + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Aleph One Interface Images + UTTypeIconFile + ImagesIcon + UTTypeIdentifier + org.bungie.source.images + UTTypeTagSpecification + + com.apple.ostype + + img∞ + img2 + + public.filename-extension + + imgA + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Aleph One Replay + UTTypeIconFile + FilmIcon + UTTypeIdentifier + org.bungie.source.film + UTTypeTagSpecification + + com.apple.ostype + + fil∞ + fil2 + + public.filename-extension + + filA + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Aleph One Map File + UTTypeIconFile + MapIcon + UTTypeIdentifier + org.bungie.source.map + UTTypeTagSpecification + + com.apple.ostype + + sce∞ + sce2 + + public.filename-extension + + sceA + scen + sce + + + + + UTTypeConformsTo + + public.xml + + UTTypeDescription + Aleph One XML Configuration + UTTypeIconFile + MMLIcon + UTTypeIdentifier + org.bungie.source.mml + UTTypeTagSpecification + + public.filename-extension + + mml + + + + + UTTypeConformsTo + + public.source-code + + UTTypeDescription + Aleph One Pfhortran Script + UTTypeIconFile + PFIcon + UTTypeIdentifier + org.bungie.source.pfhortran + UTTypeTagSpecification + + public.filename-extension + + pfhr + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Aleph One Physics File + UTTypeIconFile + PhysIcon + UTTypeIdentifier + org.bungie.source.physics + UTTypeTagSpecification + + com.apple.ostype + + phy∞ + phy2 + + public.filename-extension + + phyA + phys + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Aleph One Saved Game + UTTypeIconFile + SaveIcon + UTTypeIdentifier + org.bungie.source.save + UTTypeTagSpecification + + com.apple.ostype + + sga∞ + sga2 + + public.filename-extension + + sgaA + + + + + UTTypeConformsTo + + com.apple.package + + UTTypeDescription + Aleph One Bundle + UTTypeIconFile + package + UTTypeIdentifier + org.bungie.source.bundle + UTTypeTagSpecification + + public.filename-extension + + a1bndl + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Aleph One External Resources + UTTypeIconFile + ImagesIcon + UTTypeIdentifier + org.bungie.source.resources + UTTypeTagSpecification + + public.filename-extension + + appl + + + + + + diff --git a/Source_Files/Misc/Makefile.am b/Source_Files/Misc/Makefile.am index e316bb478..02c0f6797 100644 --- a/Source_Files/Misc/Makefile.am +++ b/Source_Files/Misc/Makefile.am @@ -26,7 +26,7 @@ libmisc_a_SOURCES = achievements.h ActionQueues.h alephversion.h binders.h Circu Statistics.cpp \ ProFontAO.h CourierPrime.h CourierPrimeBold.h CourierPrimeItalic.h CourierPrimeBoldItalic.h -EXTRA_libmisc_a_SOURCES = alephone.xpm alephone32.xpm thread_priority_sdl_posix.cpp thread_priority_sdl_dummy.cpp thread_priority_sdl_win32.cpp thread_priority_sdl_macosx.cpp m1_achievements.lua m2_achievements.lua steamshim_child.h steamshim_child.c +EXTRA_libmisc_a_SOURCES = alephone.xpm alephone32.xpm thread_priority_sdl_posix.cpp thread_priority_sdl_dummy.cpp thread_priority_sdl_win32.cpp thread_priority_sdl_macosx.cpp m1_achievements.lua m2_achievements.lua inf_achievements.lua steamshim_child.h steamshim_child.c AM_CPPFLAGS = -I$(top_srcdir)/Source_Files/CSeries -I$(top_srcdir)/Source_Files/Files \ -I$(top_srcdir)/Source_Files/GameWorld -I$(top_srcdir)/Source_Files/Input \ diff --git a/Source_Files/Misc/achievements.cpp b/Source_Files/Misc/achievements.cpp index b7db7f64f..9ac272d9c 100644 --- a/Source_Files/Misc/achievements.cpp +++ b/Source_Files/Misc/achievements.cpp @@ -36,6 +36,8 @@ std::string Achievements::get_lua() static constexpr uint32_t m2_map_checksum = 0x2d71ccb4; static constexpr uint32_t m2_win95_map_checksum = 0x5e0ba590; static constexpr uint32_t m2_physics_checksum = 0x91d72dab; + + static constexpr uint32_t inf_map_checksum = 0xA80E94B1; switch (map_checksum) { case m1_map_checksum: @@ -63,6 +65,11 @@ std::string Achievements::get_lua() set_disabled_reason("Achievements disabled (third party physics)"); } break; + case inf_map_checksum: + lua = + #include "inf_achievements.lua" + ; + break; } if (lua.size() == 0) diff --git a/Source_Files/Misc/inf_achievements.lua b/Source_Files/Misc/inf_achievements.lua new file mode 100644 index 000000000..97de0789d --- /dev/null +++ b/Source_Files/Misc/inf_achievements.lua @@ -0,0 +1,246 @@ +R"LUA( +Triggers = {} + +function got_achievement(achievement) + set_achievement(achievement) +end + +function Triggers.init(restored) + if Game.replay then + Triggers = {} + return + end + + if Game.ticks == 0 then + Game._initial_level = Level.index + Game._min_difficulty = Game.difficulty + elseif restored then + if not Game.restore_saved() or + Game._initial_level == nil or + Game._min_difficulty == nil + then + Players.print("Achievements disabled (missing saved game data)") + Triggers = {} + return + end + else + if not Game.restore_passed() then + Players.print("Achievements disabled (level transfer failure)") + Triggers = {} + return + end + end + + if Game.difficulty.index < Game._min_difficulty.index then + Game._min_difficulty = Game.difficulty + end + + if Level.index == 1 and Game._initial_level == 0 then + Triggers.terminal_enter = rrr_terminal_enter + end + + if Level.index == 2 then + Triggers.got_item = py_got_item + end + + if Level.index == 5 then + Triggers.monster_killed = wamid_monster_killed + end + + if Level.index == 6 and Game._initial_level == 0 then + Triggers.projectile_switch = as_projectile_switch + end + + if Level.index == 9 then + Triggers.platform_activated = twk_platform_activated + if Players[0]._doors_cycled == nil then + Players[0]._doors_cycled = {} + end + else + Players[0]._doors_cycled = nil + end + + if Level.index == 10 then + Triggers.idle = es2_idle + end + + if Level.index == 12 and Game._initial_level == 0 then + Triggers.platform_activated = nmhc_platform_activated + end + + if Level.index == 16 then + Triggers.terminal_enter = etp_terminal_enter + if Players[0]._terminals_read == nil then + Players[0]._terminals_read = {} + end + else + Players[0]._terminals_read = nil + end + + if Level.index == 17 and Game._initial_level == 0 then + Triggers.projectile_switch = bc_projectile_switch + end + + if Level.index == 19 then + if not Players[0]._accivi_over then + Triggers.platform_activated = accivi_platform_activated + Triggers.platform_switch = accivi_platform_switch + Triggers.projectile_switch = accivi_projectile_switch + Triggers.tag_switch = accivi_tag_switch + end + else + Players[0]._accivi_over = nil + end +end + +function Triggers.cleanup() + if not Level.completed then + return + end + + if Level.index == 24 and Game._initial_level == 0 then + got_achievement("ACH_VICTORY") + if Game._min_difficulty == "total carnage" then + got_achievement("ACH_TOTAL_VICTORY") + end + end + + if Level.index == 32 and + (Game._initial_level == 0 or Game._initial_level == 30) and + Game._min_difficulty == "total carnage" + then + got_achievement("ACH_VIDMASTER") + end +end + +function rrr_terminal_enter(terminal) + if terminal.index == 0 then + got_achievement("ACH_INSTIGATION") + Triggers.terminal_enter = nil + end +end + +function as_projectile_switch() + if Level.calculate_completion_state() == "finished" then + got_achievement("ACH_ACME") + Triggers.projectile_switch = nil + end +end + +function nmhc_platform_activated(polygon) + if polygon.index == 259 then + got_achievement("ACH_NAW_MAN") + Triggers.platform_activated = nil + end +end + +function etp_terminal_enter(terminal) + local p = Players[0] + p._terminals_read[terminal.index] = true + local complete = true + for i=0,6 do + if not p._terminals_read[i] then + complete = false + break + end + end + if complete then + got_achievement("ACH_PATHS") + Triggers.terminal_enter = nil + end +end + +function bc_projectile_switch() + if Level.calculate_completion_state() == "finished" then + got_achievement("ACH_BY_COMMITTEE") + Triggers.platform_activated = nil + end +end + +function accivi_path_unblocked() + for p in Platforms() do + if p.tag.index == 2 and not p.has_been_activated then + return false + end + end + + return true +end + +function accivi_over() + Players[0]._accivi_over = true + + Triggers.platform_activated = nil + Triggers.platform_switch = nil + Triggers.projectile_switch = nil + Triggers.tag_switch = nil +end + +function accivi_platform_activated(polygon) + if polygon.index == 638 then + accivi_over() + end +end + +function accivi_platform_switch(polygon, _, side) + if accivi_path_unblocked() then + got_achievement("ACH_CONVERTED_PRIEST") + accivi_over() + end +end + +function accivi_projectile_switch(_, side) + if side.index == 2598 then + accivi_over() + elseif accivi_path_unblocked() then + got_achievement("ACH_CONVERTED_PRIEST") + accivi_over() + end +end + +function accivi_tag_switch(_, _, side) + if side.index == 2598 then + accivi_over() + end +end + +function wamid_monster_killed(monster, _, projectile) + if monster.type == "major defender" and projectile.type == "missile" then + got_achievement("ACH_DREAM_MONSTER") + Triggers.monster_killed = nil + end +end + +function py_got_item(_, _) + if Players[0].items["shotgun"] == 1 and + Players[0].items["smg"] == 1 + then + got_achievement("ACH_FILM_BUFF") + Triggers.got_item = nil + end +end + +function twk_platform_activated(polygon) + if polygon.index == 28 or polygon.index == 33 then + local platform = Platforms[polygon.permutation] + if not platform.active + and platform.ceiling_height == platform.minimum_ceiling_height + then + Players[0]._doors_cycled[polygon.index] = true + + if Players[0]._doors_cycled[28] and Players[0]._doors_cycled[33] then + got_achievement("ACH_THING_WHAT_KICKS") + Triggers.platform_activated = nil + end + end + end +end + +function es2_idle() + if Players[0].teleporting and Players[0].polygon.index == 63 then + got_achievement("ACH_CYCLICAL") + Triggers.idle = nil + end +end + +)LUA" diff --git a/Steam/inf_build.vdf b/Steam/inf_build.vdf new file mode 100644 index 000000000..7120d6cee --- /dev/null +++ b/Steam/inf_build.vdf @@ -0,0 +1,49 @@ +"AppBuild" +{ + "AppID" "2398520" + "Desc" "Classic Marathon Infinity build script" + + "ContentRoot" "../" + "BuildOutput" "output/" + + "Depots" + { + "2398521" + { + // Scenario data + "FileMapping" + { + "LocalPath" "data/Scenarios/Marathon Infinity/*" + "DepotPath" "." + "recursive" "1" + } + + "FileExclusion" "*.git" + } + + // Windows executables + "2398522" + { + // Windows Steamshim + "FileMapping" + { + "LocalPath" "VisualStudio/x64/Release/Steam/Classic Marathon Launcher.exe" + "DepotPath" "." + } + + // Windows Exe + "FileMapping" + { + "LocalPath" "VisualStudio/x64/Release/Steam/Classic Marathon Infinity Steam.exe" + "DepotPath" "." + } + + // Windows Steam DLL Because why would they include this for you? + "FileMapping" + { + "LocalPath" "VisualStudio/x64/Release/Steam/steam_api64.dll" + "DepotPath" "." + } + } + } +} diff --git a/Steam/inf_mac.vdf b/Steam/inf_mac.vdf new file mode 100644 index 000000000..b00f9294e --- /dev/null +++ b/Steam/inf_mac.vdf @@ -0,0 +1,33 @@ +"AppBuild" +{ + "AppID" "2398520" + "Desc" "Classic Marathon Infinity macOS build script" + + "ContentRoot" ".." + "BuildOutput" "output\" + + "Depots" + { + "2398523" + { + "FileMapping" + { + "LocalPath" "PBProjects/build/Release/Classic Marathon Launcher" + "DepotPath" "." + } + + "FileMapping" + { + "LocalPath" "PBProjects/build/Release/libsteam_api.dylib" + "DepotPath" "." + } + + "FileMapping" + { + "LocalPath" "PBProjects/build/Release/Classic Marathon Infinity Steam.app/*" + "DepotPath" "Classic Marathon Infinity Steam.app" + "recursive" "1" + } + } + } +} diff --git a/VisualStudio/AlephOne.sln b/VisualStudio/AlephOne.sln index cc42db2c2..e4dc2c9d2 100644 --- a/VisualStudio/AlephOne.sln +++ b/VisualStudio/AlephOne.sln @@ -25,10 +25,12 @@ Global Marathon|x86 = Marathon|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 - Steam Marathon 2|x64 = Steam Marathon 2|x64 - Steam Marathon 2|x86 = Steam Marathon 2|x86 Standalone Hub|x64 = Standalone Hub|x64 Standalone Hub|x86 = Standalone Hub|x86 + Steam Marathon 2|x64 = Steam Marathon 2|x64 + Steam Marathon 2|x86 = Steam Marathon 2|x86 + Steam Marathon Infinity|x64 = Steam Marathon Infinity|x64 + Steam Marathon Infinity|x86 = Steam Marathon Infinity|x86 Steam Marathon|x64 = Steam Marathon|x64 Steam Marathon|x86 = Steam Marathon|x86 EndGlobalSection @@ -53,14 +55,18 @@ Global {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Release|x64.Build.0 = Release|x64 {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Release|x86.ActiveCfg = Release|Win32 {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Release|x86.Build.0 = Release|Win32 - {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon 2|x64.ActiveCfg = Steam Marathon 2|x64 - {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon 2|x64.Build.0 = Steam Marathon 2|x64 - {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon 2|x86.ActiveCfg = Steam Marathon|Win32 - {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon 2|x86.Build.0 = Steam Marathon|Win32 {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Standalone Hub|x64.ActiveCfg = Standalone Hub|x64 {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Standalone Hub|x64.Build.0 = Standalone Hub|x64 {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Standalone Hub|x86.ActiveCfg = Standalone Hub|Win32 {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Standalone Hub|x86.Build.0 = Standalone Hub|Win32 + {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon 2|x64.ActiveCfg = Steam Marathon 2|x64 + {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon 2|x64.Build.0 = Steam Marathon 2|x64 + {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon 2|x86.ActiveCfg = Steam Marathon|Win32 + {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon 2|x86.Build.0 = Steam Marathon|Win32 + {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon Infinity|x64.ActiveCfg = Steam Marathon Infinity|x64 + {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon Infinity|x64.Build.0 = Steam Marathon Infinity|x64 + {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon Infinity|x86.ActiveCfg = Marathon 2|Win32 + {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon Infinity|x86.Build.0 = Marathon 2|Win32 {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon|x64.ActiveCfg = Steam Marathon|x64 {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon|x64.Build.0 = Steam Marathon|x64 {9AF0CA66-A621-4FE5-B986-F0CAB7647C24}.Steam Marathon|x86.ActiveCfg = Steam Marathon|Win32 @@ -85,14 +91,18 @@ Global {D1A548FF-F15F-43CA-8891-F4B367122282}.Release|x64.Build.0 = Release|x64 {D1A548FF-F15F-43CA-8891-F4B367122282}.Release|x86.ActiveCfg = Release|Win32 {D1A548FF-F15F-43CA-8891-F4B367122282}.Release|x86.Build.0 = Release|Win32 - {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon 2|x64.ActiveCfg = Steam Marathon 2|x64 - {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon 2|x64.Build.0 = Steam Marathon 2|x64 - {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon 2|x86.ActiveCfg = Steam Marathon|Win32 - {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon 2|x86.Build.0 = Steam Marathon|Win32 {D1A548FF-F15F-43CA-8891-F4B367122282}.Standalone Hub|x64.ActiveCfg = Standalone Hub|x64 {D1A548FF-F15F-43CA-8891-F4B367122282}.Standalone Hub|x64.Build.0 = Standalone Hub|x64 {D1A548FF-F15F-43CA-8891-F4B367122282}.Standalone Hub|x86.ActiveCfg = Standalone Hub|Win32 {D1A548FF-F15F-43CA-8891-F4B367122282}.Standalone Hub|x86.Build.0 = Standalone Hub|Win32 + {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon 2|x64.ActiveCfg = Steam Marathon 2|x64 + {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon 2|x64.Build.0 = Steam Marathon 2|x64 + {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon 2|x86.ActiveCfg = Steam Marathon|Win32 + {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon 2|x86.Build.0 = Steam Marathon|Win32 + {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon Infinity|x64.ActiveCfg = Steam Marathon Infinity|x64 + {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon Infinity|x64.Build.0 = Steam Marathon Infinity|x64 + {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon Infinity|x86.ActiveCfg = Release|Win32 + {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon Infinity|x86.Build.0 = Release|Win32 {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon|x64.ActiveCfg = Steam Marathon|x64 {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon|x64.Build.0 = Steam Marathon|x64 {D1A548FF-F15F-43CA-8891-F4B367122282}.Steam Marathon|x86.ActiveCfg = Steam Marathon|Win32 @@ -117,14 +127,18 @@ Global {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Release|x64.Build.0 = Release|x64 {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Release|x86.ActiveCfg = Release|Win32 {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Release|x86.Build.0 = Release|Win32 - {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon 2|x64.ActiveCfg = Release|x64 - {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon 2|x64.Build.0 = Release|x64 - {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon 2|x86.ActiveCfg = Release|Win32 - {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon 2|x86.Build.0 = Release|Win32 {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Standalone Hub|x64.ActiveCfg = Release|x64 {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Standalone Hub|x64.Build.0 = Release|x64 {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Standalone Hub|x86.ActiveCfg = Release|Win32 {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Standalone Hub|x86.Build.0 = Release|Win32 + {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon 2|x64.ActiveCfg = Release|x64 + {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon 2|x64.Build.0 = Release|x64 + {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon 2|x86.ActiveCfg = Release|Win32 + {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon 2|x86.Build.0 = Release|Win32 + {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon Infinity|x64.ActiveCfg = Release|x64 + {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon Infinity|x64.Build.0 = Release|x64 + {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon Infinity|x86.ActiveCfg = Release|Win32 + {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon Infinity|x86.Build.0 = Release|Win32 {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon|x64.ActiveCfg = Release|x64 {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon|x64.Build.0 = Release|x64 {272161CB-F5DF-4F91-9C2F-D08E23FF1FDC}.Steam Marathon|x86.ActiveCfg = Release|Win32 @@ -149,14 +163,18 @@ Global {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Release|x64.Build.0 = Release|x64 {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Release|x86.ActiveCfg = Release|Win32 {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Release|x86.Build.0 = Release|Win32 - {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon 2|x64.ActiveCfg = Release|x64 - {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon 2|x64.Build.0 = Release|x64 - {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon 2|x86.ActiveCfg = Release|Win32 - {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon 2|x86.Build.0 = Release|Win32 {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Standalone Hub|x64.ActiveCfg = Release|x64 {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Standalone Hub|x64.Build.0 = Release|x64 {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Standalone Hub|x86.ActiveCfg = Release|Win32 {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Standalone Hub|x86.Build.0 = Release|Win32 + {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon 2|x64.ActiveCfg = Release|x64 + {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon 2|x64.Build.0 = Release|x64 + {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon 2|x86.ActiveCfg = Release|Win32 + {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon 2|x86.Build.0 = Release|Win32 + {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon Infinity|x64.ActiveCfg = Release|x64 + {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon Infinity|x64.Build.0 = Release|x64 + {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon Infinity|x86.ActiveCfg = Release|Win32 + {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon Infinity|x86.Build.0 = Release|Win32 {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon|x64.ActiveCfg = Release|x64 {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon|x64.Build.0 = Release|x64 {7FA2F95C-F6E9-4A89-BBD2-AF1D5B09B0B2}.Steam Marathon|x86.ActiveCfg = Release|Win32 @@ -181,14 +199,18 @@ Global {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Release|x64.Build.0 = Release|x64 {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Release|x86.ActiveCfg = Release|Win32 {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Release|x86.Build.0 = Release|Win32 - {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon 2|x64.ActiveCfg = Release|x64 - {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon 2|x64.Build.0 = Release|x64 - {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon 2|x86.ActiveCfg = Release|Win32 - {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon 2|x86.Build.0 = Release|Win32 {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Standalone Hub|x64.ActiveCfg = Release|x64 {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Standalone Hub|x64.Build.0 = Release|x64 {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Standalone Hub|x86.ActiveCfg = Release|Win32 {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Standalone Hub|x86.Build.0 = Release|Win32 + {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon 2|x64.ActiveCfg = Release|x64 + {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon 2|x64.Build.0 = Release|x64 + {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon 2|x86.ActiveCfg = Release|Win32 + {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon 2|x86.Build.0 = Release|Win32 + {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon Infinity|x64.ActiveCfg = Release|x64 + {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon Infinity|x64.Build.0 = Release|x64 + {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon Infinity|x86.ActiveCfg = Release|Win32 + {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon Infinity|x86.Build.0 = Release|Win32 {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon|x64.ActiveCfg = Release|x64 {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon|x64.Build.0 = Release|x64 {242043EF-8A1F-4BB3-82B1-B848B8AE6BE6}.Steam Marathon|x86.ActiveCfg = Release|Win32 diff --git a/VisualStudio/AlephOne/AlephOne.vcxproj b/VisualStudio/AlephOne/AlephOne.vcxproj index e4a7543f2..0a3c17ae3 100644 --- a/VisualStudio/AlephOne/AlephOne.vcxproj +++ b/VisualStudio/AlephOne/AlephOne.vcxproj @@ -57,6 +57,14 @@ Standalone Hub x64 + + Steam Marathon Infinity + Win32 + + + Steam Marathon Infinity + x64 + Steam Marathon Win32 @@ -113,6 +121,9 @@ + + + @@ -137,6 +148,9 @@ + + + @@ -177,6 +191,12 @@ $(SolutionDir)Release\Steam\ Steam Marathon\ + + false + Classic Marathon Steam + $(SolutionDir)Release\Steam\ + Steam Marathon\ + false Classic Marathon 2 @@ -219,6 +239,12 @@ $(SolutionDir)$(Platform)\Release\Steam\ $(Platform)\Steam Marathon\ + + false + Classic Marathon Infinity Steam + $(SolutionDir)$(Platform)\Release\Steam\ + $(Platform)\Steam Marathon\ + false Classic Marathon 2 @@ -256,6 +282,10 @@ true ..\..\vcpkg\installed-x86-windows + + true + ..\..\vcpkg\installed-x86-windows + true ..\..\vcpkg\installed-x86-windows @@ -288,6 +318,10 @@ true ..\..\vcpkg\installed-x64-windows + + true + ..\..\vcpkg\installed-x64-windows + true ..\..\vcpkg\installed-x64-windows @@ -440,6 +474,28 @@ SDL2main.lib;shlwapi.lib;dwmapi.lib;ws2_32.lib;Strmiids.lib;mfuuid.lib;mfplat.lib;imm32.lib;Setupapi.lib;Iphlpapi.lib;Version.lib;winmm.lib;crypt32.lib;Secur32.lib;%(AdditionalDependencies) + + + Level3 + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + Default + stdcpp17 + true + true + MultiThreaded + $(ProjectDir)..\..\Source_Files\;$(ProjectDir)..\..\Source_Files\XML;$(ProjectDir)..\..\Source_Files\TCPMess;$(ProjectDir)..\..\Source_Files\Sound;$(ProjectDir)..\..\Source_Files\RenderOther;$(ProjectDir)..\..\Source_Files\RenderMain;$(ProjectDir)..\..\Source_Files\Network\Metaserver;$(ProjectDir)..\..\Source_Files\Network;$(ProjectDir)..\..\Source_Files\ModelView;$(ProjectDir)..\..\Source_Files\Misc;$(ProjectDir)..\..\Source_Files\Lua;$(ProjectDir)..\..\Source_Files\Input;$(ProjectDir)..\..\Source_Files\GameWorld;$(ProjectDir)..\..\Source_Files\Files;$(ProjectDir)..\..\Source_Files\FFmpeg;$(ProjectDir)..\..\Source_Files\CSeries;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + UseLinkTimeCodeGeneration + SDL2main.lib;shlwapi.lib;dwmapi.lib;ws2_32.lib;Strmiids.lib;mfuuid.lib;mfplat.lib;imm32.lib;Setupapi.lib;Iphlpapi.lib;Version.lib;winmm.lib;crypt32.lib;Secur32.lib;%(AdditionalDependencies) + + Level3 @@ -610,6 +666,28 @@ SDL2main.lib;shlwapi.lib;dwmapi.lib;ws2_32.lib;Strmiids.lib;mfuuid.lib;mfplat.lib;imm32.lib;Setupapi.lib;Iphlpapi.lib;Version.lib;winmm.lib;crypt32.lib;Secur32.lib;%(AdditionalDependencies) + + + Level3 + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + Default + stdcpp17 + true + true + MultiThreaded + $(ProjectDir)..\..\Source_Files\;$(ProjectDir)..\..\Source_Files\XML;$(ProjectDir)..\..\Source_Files\TCPMess;$(ProjectDir)..\..\Source_Files\Sound;$(ProjectDir)..\..\Source_Files\RenderOther;$(ProjectDir)..\..\Source_Files\RenderMain;$(ProjectDir)..\..\Source_Files\Network\Metaserver;$(ProjectDir)..\..\Source_Files\Network;$(ProjectDir)..\..\Source_Files\ModelView;$(ProjectDir)..\..\Source_Files\Misc;$(ProjectDir)..\..\Source_Files\Lua;$(ProjectDir)..\..\Source_Files\Input;$(ProjectDir)..\..\Source_Files\GameWorld;$(ProjectDir)..\..\Source_Files\Files;$(ProjectDir)..\..\Source_Files\FFmpeg;$(ProjectDir)..\..\Source_Files\CSeries;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + UseLinkTimeCodeGeneration + SDL2main.lib;shlwapi.lib;dwmapi.lib;ws2_32.lib;Strmiids.lib;mfuuid.lib;mfplat.lib;imm32.lib;Setupapi.lib;Iphlpapi.lib;Version.lib;winmm.lib;crypt32.lib;Secur32.lib;%(AdditionalDependencies) + + Level3 @@ -642,6 +720,7 @@ $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) + $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) @@ -649,6 +728,7 @@ $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) + $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) WIN32 WIN32 @@ -658,6 +738,7 @@ WIN32 WIN32 WIN32 + WIN32 WIN32 WIN32 WIN32 @@ -665,6 +746,7 @@ WIN32 WIN32 WIN32 + WIN32 WIN32 false false @@ -674,6 +756,7 @@ true true true + true true false false @@ -681,6 +764,7 @@ true true true + true true @@ -692,6 +776,7 @@ true true true + true true true true @@ -699,6 +784,7 @@ true true true + false true WIN32 WIN32 @@ -708,6 +794,7 @@ WIN32 WIN32 WIN32 + WIN32 WIN32 WIN32 WIN32 @@ -715,6 +802,7 @@ WIN32 WIN32 WIN32 + WIN32 WIN32 $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) @@ -724,6 +812,7 @@ $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) + $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) @@ -731,6 +820,7 @@ $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) + $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) @@ -742,6 +832,7 @@ false false false + false true true true @@ -749,6 +840,7 @@ false false true + true true WIN32 WIN32 @@ -758,6 +850,7 @@ WIN32 WIN32 WIN32 + WIN32 WIN32 WIN32 WIN32 @@ -765,6 +858,7 @@ WIN32 WIN32 WIN32 + WIN32 WIN32 $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) @@ -774,6 +868,7 @@ $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) + $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) @@ -781,6 +876,7 @@ $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) + $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) @@ -792,6 +888,7 @@ true true true + true false true true @@ -799,6 +896,7 @@ true true false + true false WIN32 WIN32 @@ -808,6 +906,7 @@ WIN32 WIN32 WIN32 + WIN32 WIN32 WIN32 WIN32 @@ -815,6 +914,7 @@ WIN32 WIN32 WIN32 + WIN32 WIN32 $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) @@ -824,6 +924,7 @@ $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) + $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) @@ -831,6 +932,7 @@ $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) + $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) $(ProjectDir)\..\..\Source_Files\Misc;%(AdditionalIncludeDirectories) @@ -853,7 +955,9 @@ true true true + true true + true diff --git a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj index 5936eda01..bbf812eca 100644 --- a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj +++ b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj @@ -33,6 +33,14 @@ Standalone Hub x64 + + Steam Marathon Infinity + Win32 + + + Steam Marathon Infinity + x64 + Steam Marathon Win32 @@ -85,6 +93,9 @@ + + + @@ -100,6 +111,9 @@ + + + true @@ -119,6 +133,11 @@ $(SolutionDir)Release\Steam\ Steam Marathon\ + + false + $(SolutionDir)Release\Steam\ + Steam Marathon\ + true @@ -138,6 +157,11 @@ $(SolutionDir)$(Platform)\Release\Steam\ $(Platform)\Steam Marathon\ + + false + $(SolutionDir)$(Platform)\Release\Steam\ + $(Platform)\Steam Marathon\ + ..\..\vcpkg\installed-x86-windows @@ -150,6 +174,9 @@ ..\..\vcpkg\installed-x86-windows + + ..\..\vcpkg\installed-x86-windows + ..\..\vcpkg\installed-x86-windows @@ -168,6 +195,9 @@ ..\..\vcpkg\installed-x64-windows + + ..\..\vcpkg\installed-x64-windows + true true @@ -260,6 +290,24 @@ true + + + HAVE_NFD;HAVE_MINIUPNPC;MINIUPNP_STATICLIB;CURL_STATICLIB;HAVE_SDL_IMAGE;HAVE_CURL;HAVE_PNG;HAVE_ZZIP;HAVE_FFMPEG;HAVE_OPENGL;SDL;WIN32;__WIN32__;NDEBUG;_WINDOWS;HAVE_STEAM;%(PreprocessorDefinitions) + MultiThreaded + Level3 + ProgramDatabase + $(ProjectDir)..\..\Source_Files\;$(ProjectDir)..\..\Source_Files\XML;$(ProjectDir)..\..\Source_Files\TCPMess;$(ProjectDir)..\..\Source_Files\Sound;$(ProjectDir)..\..\Source_Files\RenderOther;$(ProjectDir)..\..\Source_Files\RenderMain;$(ProjectDir)..\..\Source_Files\Network\Metaserver;$(ProjectDir)..\..\Source_Files\Network;$(ProjectDir)..\..\Source_Files\ModelView;$(ProjectDir)..\..\Source_Files\Misc;$(ProjectDir)..\..\Source_Files\Lua;$(ProjectDir)..\..\Source_Files\Input;$(ProjectDir)..\..\Source_Files\GameWorld;$(ProjectDir)..\..\Source_Files\Files;$(ProjectDir)..\..\Source_Files\FFmpeg;$(ProjectDir)..\..\Source_Files\CSeries;%(AdditionalIncludeDirectories) + true + true + stdcpp17 + + + Console + true + true + true + + $(ProjectDir)..\..\Source_Files\;$(ProjectDir)..\..\Source_Files\XML;$(ProjectDir)..\..\Source_Files\TCPMess;$(ProjectDir)..\..\Source_Files\Sound;$(ProjectDir)..\..\Source_Files\RenderOther;$(ProjectDir)..\..\Source_Files\RenderMain;$(ProjectDir)..\..\Source_Files\Network\Metaserver;$(ProjectDir)..\..\Source_Files\Network;$(ProjectDir)..\..\Source_Files\ModelView;$(ProjectDir)..\..\Source_Files\Misc;$(ProjectDir)..\..\Source_Files\Lua;$(ProjectDir)..\..\Source_Files\Input;$(ProjectDir)..\..\Source_Files\GameWorld;$(ProjectDir)..\..\Source_Files\Files;$(ProjectDir)..\..\Source_Files\FFmpeg;$(ProjectDir)..\..\Source_Files\CSeries;%(AdditionalIncludeDirectories) @@ -342,6 +390,23 @@ true + + + $(ProjectDir)..\..\Source_Files\;$(ProjectDir)..\..\Source_Files\XML;$(ProjectDir)..\..\Source_Files\TCPMess;$(ProjectDir)..\..\Source_Files\Sound;$(ProjectDir)..\..\Source_Files\RenderOther;$(ProjectDir)..\..\Source_Files\RenderMain;$(ProjectDir)..\..\Source_Files\Network\Metaserver;$(ProjectDir)..\..\Source_Files\Network;$(ProjectDir)..\..\Source_Files\ModelView;$(ProjectDir)..\..\Source_Files\Misc;$(ProjectDir)..\..\Source_Files\Lua;$(ProjectDir)..\..\Source_Files\Input;$(ProjectDir)..\..\Source_Files\GameWorld;$(ProjectDir)..\..\Source_Files\Files;$(ProjectDir)..\..\Source_Files\FFmpeg;$(ProjectDir)..\..\Source_Files\CSeries;%(AdditionalIncludeDirectories) + HAVE_NFD;HAVE_MINIUPNPC;MINIUPNP_STATICLIB;CURL_STATICLIB;HAVE_SDL_IMAGE;HAVE_CURL;HAVE_PNG;HAVE_ZZIP;HAVE_FFMPEG;HAVE_OPENGL;SDL;WIN32;WIN64;__WIN32__;HAVE_STEAM;%(PreprocessorDefinitions) + MultiThreaded + Level3 + true + true + stdcpp17 + + + Console + true + true + true + + @@ -431,36 +496,42 @@ true true true + true true true true true true true + true true true true true + true true true true true true true + true true true true true + true true true true true true true + true From 1fc99f07f354866ff9b89e8cab42c97228a9b9cf Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Sat, 3 Aug 2024 21:56:09 -0400 Subject: [PATCH 02/58] add a basic scenario chooser Squashed commit of the following: commit 19b165dc9f7f10abdf37462a3c580c4e73b04135 Merge: b206b76b 4919300a Author: Gregory Smith Date: Sat Aug 3 16:23:07 2024 -0400 Merge branch 'master' into scenario-chooser commit b206b76b0f7b6b00dcc07fa7b5ee089fe021c456 Author: Gregory Smith Date: Thu Aug 1 22:07:23 2024 -0400 don't crash if enter is pressed but no selection has been made commit 240c1f40e841fc3bb7a17f6bed8385e8743c4ac7 Author: Gregory Smith Date: Wed Jul 31 22:02:26 2024 -0400 fix macOS build commit a07a4d6e7849f5df47139eca2718edddf2d73c32 Author: Gregory Smith Date: Wed Jul 31 22:02:05 2024 -0400 fix compile error with clang commit 5105a67c1435d689e19f25acf3554f27c8b3023d Author: Gregory Smith Date: Wed Jul 31 20:12:59 2024 -0400 handle page up / page down keys in Chooser commit 73a6d839c157da6acc7f9357a5546ca30363efde Author: Gregory Smith Date: Wed Jul 31 20:08:03 2024 -0400 destroy the window after the chooser runs commit 714e8cf39f42784a3fe3938e8147179cc2d08e72 Author: Gregory Smith Date: Tue Jul 30 22:20:08 2024 -0400 update Windows build files commit 7f18c2915d2948339c11ca411ce0214a586f0997 Author: Gregory Smith Date: Tue Jul 30 21:52:56 2024 -0400 add a basic scenario chooser --- PBProjects/AlephOne.xcodeproj/project.pbxproj | 70 ++- Source_Files/Misc/Makefile.am | 4 +- Source_Files/Misc/ScenarioChooser.cpp | 505 ++++++++++++++++++ Source_Files/Misc/ScenarioChooser.h | 78 +++ Source_Files/RenderOther/images.cpp | 43 ++ Source_Files/RenderOther/images.h | 3 + Source_Files/shell.cpp | 35 +- VisualStudio/LibAlephOne/LibAlephOne.vcxproj | 2 + .../LibAlephOne/LibAlephOne.vcxproj.filters | 6 + 9 files changed, 716 insertions(+), 30 deletions(-) create mode 100644 Source_Files/Misc/ScenarioChooser.cpp create mode 100644 Source_Files/Misc/ScenarioChooser.h diff --git a/PBProjects/AlephOne.xcodeproj/project.pbxproj b/PBProjects/AlephOne.xcodeproj/project.pbxproj index 4288d27ef..af1c6ba2f 100644 --- a/PBProjects/AlephOne.xcodeproj/project.pbxproj +++ b/PBProjects/AlephOne.xcodeproj/project.pbxproj @@ -1632,6 +1632,12 @@ AE7C21B60BFF67B700CE63EC /* lvm.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C219A0BFF67B700CE63EC /* lvm.c */; }; AE7C21B70BFF67B700CE63EC /* lzio.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7C219B0BFF67B700CE63EC /* lzio.c */; }; AE7C21D60BFF688000CE63EC /* Update.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE7C21D50BFF688000CE63EC /* Update.cpp */; }; + AE8342402C5B22EA00A4A530 /* ScenarioChooser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE83423F2C5B22EA00A4A530 /* ScenarioChooser.cpp */; }; + AE8342412C5B22EA00A4A530 /* ScenarioChooser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE83423F2C5B22EA00A4A530 /* ScenarioChooser.cpp */; }; + AE8342422C5B22EA00A4A530 /* ScenarioChooser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE83423F2C5B22EA00A4A530 /* ScenarioChooser.cpp */; }; + AE8342432C5B22EA00A4A530 /* ScenarioChooser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE83423F2C5B22EA00A4A530 /* ScenarioChooser.cpp */; }; + AE8342442C5B22EA00A4A530 /* ScenarioChooser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE83423F2C5B22EA00A4A530 /* ScenarioChooser.cpp */; }; + AE8342452C5B22EA00A4A530 /* ScenarioChooser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE83423F2C5B22EA00A4A530 /* ScenarioChooser.cpp */; }; AE8729C82BD1FBF700426095 /* steamshim_parent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE120B8F2BC76745001873DD /* steamshim_parent.cpp */; }; AE8729C92BD1FBFA00426095 /* libsteam_api.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = AE120B942BC77447001873DD /* libsteam_api.dylib */; }; AE8729CD2BD1FDAC00426095 /* libsteam_api.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = AE120B942BC77447001873DD /* libsteam_api.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; @@ -3419,6 +3425,8 @@ AE7C21D00BFF67FD00CE63EC /* language_definition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = language_definition.h; sourceTree = ""; }; AE7C21D40BFF686200CE63EC /* Update.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Update.h; path = ../Source_Files/Network/Update.h; sourceTree = ""; }; AE7C21D50BFF688000CE63EC /* Update.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Update.cpp; path = ../Source_Files/Network/Update.cpp; sourceTree = ""; }; + AE83423E2C5B22BE00A4A530 /* ScenarioChooser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ScenarioChooser.h; path = ../Source_Files/Misc/ScenarioChooser.h; sourceTree = ""; }; + AE83423F2C5B22EA00A4A530 /* ScenarioChooser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScenarioChooser.cpp; path = ../Source_Files/Misc/ScenarioChooser.cpp; sourceTree = ""; }; AE8729C12BD1FBEA00426095 /* Classic Marathon Launcher */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "Classic Marathon Launcher"; sourceTree = BUILT_PRODUCTS_DIR; }; AE941DE713E783F30077218A /* Info-AlephOne-Xcode4.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-AlephOne-Xcode4.plist"; sourceTree = ""; }; AE96370A2A39577800DE43FF /* lua_music.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lua_music.h; sourceTree = ""; }; @@ -4232,25 +4240,26 @@ F522144E0136C0C401000001 /* Misc */ = { isa = PBXGroup; children = ( - F522144F0136C0C401000001 /* Headers */, - F5CC94290240DB8801A80001 /* SDL */, AED959BE2BC235B2008EFCA2 /* achievements.cpp */, F5A00022023FDA1601A80001 /* ActionQueues.cpp */, EFEF1AC504AF552D00C3A19D /* CircularByteBuffer.cpp */, AEC6C89B0879A5DE0055EC57 /* Console.cpp */, 3DAC27A503DC9D1C00000104 /* DefaultStringSets.cpp */, - 3DAC27A603DC9D1C00000104 /* Logging.cpp */, - AE2FDECA09E934E000A18ABC /* preference_dialogs.cpp */, - F522120B0136A6FD01000001 /* PlayerName.cpp */, F52211970136A6FD01000001 /* game_errors.cpp */, + F522144F0136C0C401000001 /* Headers */, F52211C40136A6FD01000001 /* interface.cpp */, + 3DAC27A603DC9D1C00000104 /* Logging.cpp */, + F522120B0136A6FD01000001 /* PlayerName.cpp */, + AE2FDECA09E934E000A18ABC /* preference_dialogs.cpp */, F522120F0136A6FD01000001 /* preferences.cpp */, AE2A50CC09C67253007681A4 /* Scenario.cpp */, + AE83423F2C5B22EA00A4A530 /* ScenarioChooser.cpp */, + F5CC94290240DB8801A80001 /* SDL */, AE437C8E08779BE500038E30 /* shared_widgets.cpp */, 27FC2E091A7DF51E0057BF42 /* Statistics.cpp */, - F52212590136A6FD01000001 /* vbl.cpp */, - F5574EF601F4EC8501FEABBD /* thread_priority_sdl_macosx.cpp */, AE120D662BC776CE001873DD /* steamshim_child.c */, + F5574EF601F4EC8501FEABBD /* thread_priority_sdl_macosx.cpp */, + F52212590136A6FD01000001 /* vbl.cpp */, ); name = Misc; sourceTree = ""; @@ -4259,43 +4268,44 @@ isa = PBXGroup; children = ( AED959B12BC23591008EFCA2 /* achievements.h */, - C13C71E61B3FB4C500F1188D /* DefaultStringSets.h */, + F5A00027023FDA6101A80001 /* ActionQueues.h */, 276BECFE1A846FD900AE52F4 /* AlephSansMono-Bold.h */, + F5D11AE40326A93E01000105 /* alephversion.h */, 276BED2B1A8470A900AE52F4 /* binders.h */, + EFEF1AC404AF552D00C3A19D /* CircularByteBuffer.h */, + F5A00029023FDA7601A80001 /* CircularQueue.h */, + AEC6C89E0879A6020055EC57 /* Console.h */, 276BECFF1A846FD900AE52F4 /* CourierPrime.h */, 276BED001A846FD900AE52F4 /* CourierPrimeBold.h */, 276BED011A846FD900AE52F4 /* CourierPrimeBoldItalic.h */, 276BED021A846FD900AE52F4 /* CourierPrimeItalic.h */, - AED959B02BC23591008EFCA2 /* m1_achievements.lua */, - 276BED2C1A8470A900AE52F4 /* PlayerImage_sdl.h */, - 276BED211A84701E00AE52F4 /* powered_by_alephone.h */, - AED959AF2BC23591008EFCA2 /* powered_by_alephone_h.h */, - 276BED031A846FD900AE52F4 /* ProFontAO.h */, - 276BED1C1A846FF600AE52F4 /* VecOps.h */, - AE48F3551421900900051D61 /* Statistics.h */, - AE2FDED109E9352B00A18ABC /* preference_dialogs.h */, - AE2A50CF09C6727C007681A4 /* Scenario.h */, - AE437C8B08779BC900038E30 /* shared_widgets.h */, - F5A00027023FDA6101A80001 /* ActionQueues.h */, - EFEF1AC404AF552D00C3A19D /* CircularByteBuffer.h */, - F5A00029023FDA7601A80001 /* CircularQueue.h */, - AEC6C89E0879A6020055EC57 /* Console.h */, - 3DAC27A703DC9D1C00000104 /* Logging.h */, - F522120C0136A6FD01000001 /* PlayerName.h */, - F52212190136A6FD01000001 /* Random.h */, + C13C71E61B3FB4C500F1188D /* DefaultStringSets.h */, F52211AE0136A6FD01000001 /* game_errors.h */, F52211C20136A6FD01000001 /* interface_menus.h */, F52211C50136A6FD01000001 /* interface.h */, F52211CB0136A6FD01000001 /* key_definitions.h */, + 3DAC27A703DC9D1C00000104 /* Logging.h */, + AED959B02BC23591008EFCA2 /* m1_achievements.lua */, + 276BED2C1A8470A900AE52F4 /* PlayerImage_sdl.h */, + F522120C0136A6FD01000001 /* PlayerName.h */, + AED959AF2BC23591008EFCA2 /* powered_by_alephone_h.h */, + 276BED211A84701E00AE52F4 /* powered_by_alephone.h */, + AE2FDED109E9352B00A18ABC /* preference_dialogs.h */, F52212100136A6FD01000001 /* preferences.h */, + 276BED031A846FD900AE52F4 /* ProFontAO.h */, F52212140136A6FD01000001 /* progress.h */, + F52212190136A6FD01000001 /* Random.h */, + AE2A50CF09C6727C007681A4 /* Scenario.h */, + AE83423E2C5B22BE00A4A530 /* ScenarioChooser.h */, F522123E0136A6FD01000001 /* sdl_network.h */, + AE437C8B08779BC900038E30 /* shared_widgets.h */, + AE48F3551421900900051D61 /* Statistics.h */, + AE120D682BC776E7001873DD /* steamshim_child.h */, EF2EF5F00481A07000A8000D /* thread_priority_sdl.h */, F52212560136A6FD01000001 /* vbl_definitions.h */, F522125A0136A6FD01000001 /* vbl.h */, + 276BED1C1A846FF600AE52F4 /* VecOps.h */, EF2EF5EC04819F8400A8000D /* WindowedNthElementFinder.h */, - F5D11AE40326A93E01000105 /* alephversion.h */, - AE120D682BC776E7001873DD /* steamshim_child.h */, ); name = Headers; sourceTree = ""; @@ -6913,6 +6923,7 @@ AE120CFD2BC77645001873DD /* MessageDispatcher.cpp in Sources */, AE120CFE2BC77645001873DD /* MessageHandler.cpp in Sources */, AE120CFF2BC77645001873DD /* MessageInflater.cpp in Sources */, + AE8342442C5B22EA00A4A530 /* ScenarioChooser.cpp in Sources */, AE120D002BC77645001873DD /* network_messages.cpp in Sources */, AE120D012BC77645001873DD /* csstrings.cpp in Sources */, AE120D022BC77645001873DD /* SdlMetaserverClientUi.cpp in Sources */, @@ -7142,6 +7153,7 @@ AE1321972C1CB4D2009D34AA /* MessageDispatcher.cpp in Sources */, AE1321982C1CB4D2009D34AA /* MessageHandler.cpp in Sources */, AE1321992C1CB4D2009D34AA /* MessageInflater.cpp in Sources */, + AE8342452C5B22EA00A4A530 /* ScenarioChooser.cpp in Sources */, AE13219A2C1CB4D2009D34AA /* network_messages.cpp in Sources */, AE13219B2C1CB4D2009D34AA /* csstrings.cpp in Sources */, AE13219C2C1CB4D2009D34AA /* SdlMetaserverClientUi.cpp in Sources */, @@ -7316,6 +7328,7 @@ AE505C5B141D45E600915344 /* OGL_Textures.cpp in Sources */, AE505C5C141D45E600915344 /* render.cpp in Sources */, AE505C5D141D45E600915344 /* RenderPlaceObjs.cpp in Sources */, + AE8342422C5B22EA00A4A530 /* ScenarioChooser.cpp in Sources */, AE505C5E141D45E600915344 /* RenderRasterize.cpp in Sources */, AE505C5F141D45E600915344 /* RenderSortPoly.cpp in Sources */, AE505C60141D45E600915344 /* RenderVisTree.cpp in Sources */, @@ -7552,6 +7565,7 @@ AEB4A1FC14296CAE00537AE7 /* OGL_Textures.cpp in Sources */, AEB4A1FD14296CAE00537AE7 /* render.cpp in Sources */, AEB4A1FE14296CAE00537AE7 /* RenderPlaceObjs.cpp in Sources */, + AE8342432C5B22EA00A4A530 /* ScenarioChooser.cpp in Sources */, AEB4A1FF14296CAE00537AE7 /* RenderRasterize.cpp in Sources */, AEB4A20014296CAE00537AE7 /* RenderSortPoly.cpp in Sources */, AEB4A20114296CAE00537AE7 /* RenderVisTree.cpp in Sources */, @@ -8009,6 +8023,7 @@ AEC3C82509AD68AC003258E4 /* OGL_Textures.cpp in Sources */, AEC3C82609AD68AC003258E4 /* render.cpp in Sources */, AEC3C82709AD68AC003258E4 /* RenderPlaceObjs.cpp in Sources */, + AE8342402C5B22EA00A4A530 /* ScenarioChooser.cpp in Sources */, AEC3C82809AD68AC003258E4 /* RenderRasterize.cpp in Sources */, AEC3C82909AD68AC003258E4 /* RenderSortPoly.cpp in Sources */, 275A7BD81A60E9B9002EE952 /* HTTP.cpp in Sources */, @@ -8237,6 +8252,7 @@ AEFD870813EB84CF00C1E687 /* OGL_Textures.cpp in Sources */, AEFD870913EB84CF00C1E687 /* render.cpp in Sources */, AEFD870A13EB84CF00C1E687 /* RenderPlaceObjs.cpp in Sources */, + AE8342412C5B22EA00A4A530 /* ScenarioChooser.cpp in Sources */, AEFD870B13EB84CF00C1E687 /* RenderRasterize.cpp in Sources */, AEFD870C13EB84CF00C1E687 /* RenderSortPoly.cpp in Sources */, AEFD870D13EB84CF00C1E687 /* RenderVisTree.cpp in Sources */, diff --git a/Source_Files/Misc/Makefile.am b/Source_Files/Misc/Makefile.am index 02c0f6797..71254c53f 100644 --- a/Source_Files/Misc/Makefile.am +++ b/Source_Files/Misc/Makefile.am @@ -16,14 +16,14 @@ libmisc_a_SOURCES = achievements.h ActionQueues.h alephversion.h binders.h Circu preferences_widgets_sdl.h progress.h Random.h Scenario.h sdl_dialogs.h sdl_network.h \ sdl_widgets.h shared_widgets.h thread_priority_sdl.h vbl_definitions.h vbl.h VecOps.h \ WindowedNthElementFinder.h AlephSansMono-Bold.h powered_by_alephone.h powered_by_alephone_h.h \ - Statistics.h \ + Statistics.h ScenarioChooser.h \ \ achievements.cpp ActionQueues.cpp CircularByteBuffer.cpp Console.cpp DefaultStringSets.cpp game_errors.cpp \ interface.cpp \ Logging.cpp PlayerImage_sdl.cpp PlayerName.cpp preferences.cpp \ preference_dialogs.cpp preferences_widgets_sdl.cpp Scenario.cpp sdl_dialogs.cpp $(THREAD_PRIORITY) \ sdl_widgets.cpp shared_widgets.cpp vbl.cpp \ - Statistics.cpp \ + Statistics.cpp ScenarioChooser.cpp \ ProFontAO.h CourierPrime.h CourierPrimeBold.h CourierPrimeItalic.h CourierPrimeBoldItalic.h EXTRA_libmisc_a_SOURCES = alephone.xpm alephone32.xpm thread_priority_sdl_posix.cpp thread_priority_sdl_dummy.cpp thread_priority_sdl_win32.cpp thread_priority_sdl_macosx.cpp m1_achievements.lua m2_achievements.lua inf_achievements.lua steamshim_child.h steamshim_child.c diff --git a/Source_Files/Misc/ScenarioChooser.cpp b/Source_Files/Misc/ScenarioChooser.cpp new file mode 100644 index 000000000..4eabd49ca --- /dev/null +++ b/Source_Files/Misc/ScenarioChooser.cpp @@ -0,0 +1,505 @@ +#include "ScenarioChooser.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "cseries.h" + +#ifdef HAVE_SDL_IMAGE +#include +#endif + +#include "find_files.h" +#include "images.h" +#include "sdl_fonts.h" + +using SurfacePtr = std::unique_ptr; +using WindowPtr = std::unique_ptr; + +class Scenario +{ +public: + bool operator<(const Scenario& other) const; + + std::string path; + + std::string name; // unused + std::string image_path; + std::string release; // unused + + std::shared_ptr image; + + bool load(const std::string& path); + void find_image(); +}; + +class TitleScreenFinder : public FileFinder +{ +public: + TitleScreenFinder(Scenario& scenario) : FileFinder(), scenario_{scenario} { } + virtual bool found(FileSpecifier& file) + { + if (boost::algorithm::ends_with(file.GetPath(), ".imgA")) + { + auto full_size = find_title_screen(file); + if (full_size) + { + scenario_.image = std::move(full_size); + return true; + } + } + else if (boost::algorithm::ends_with(file.GetPath(), ".appl")) + { + auto full_size = find_m1_title_screen(file); + if (full_size) + { + scenario_.image = std::move(full_size); + return true; + } + } + + return false; + } + +private: + Scenario& scenario_; +}; + +bool Scenario::operator<(const Scenario& other) const +{ + return std::lexicographical_compare(name.begin(), + name.end(), + other.name.begin(), + other.name.end(), + [](const char& a, const char& b) { + return tolower(a) < tolower(b); + }); +} + +bool Scenario::load(const std::string& path) +{ + DirectorySpecifier directory(path); + + if (!(directory + "Scripts").Exists()) + { + return false; + } + + std::string base; + std::string part; + + directory.SplitPath(base, part); + + this->path = path; + + FileSpecifier config = directory + "Scripts" + "chooser.xml"; + if (config.Exists()) + { + boost::property_tree::ptree tree; + boost::property_tree::read_xml(config.GetPath(), tree); + + image_path = tree.get("chooser.image", ""); + name = tree.get("chooser.name", part); + release = tree.get("chooser.release", "1994-12-21"); + + FileSpecifier image_file = directory + image_path; + OpenedFile of; + if (image_file.Open(of)) + { +#ifdef HAVE_SDL_IMAGE + image.reset(IMG_Load_RW(of.GetRWops(), 0)); +#else + image.reset(SDL_LoadBMP_RW(of.GetRWops(), 0)); +#endif + } + } + else + { + name = part; + release = "1994-12-21"; + } + + if (!image) + { + find_image(); + } + + return image.get(); +} + +void Scenario::find_image() +{ + TitleScreenFinder finder(*this); + FileSpecifier f(path); + finder.Find(f, WILDCARD_TYPE, true); +} + +ScenarioChooser::ScenarioChooser() : + scroll_{0}, selection_{-1} +{ + +} + +ScenarioChooser::~ScenarioChooser() +{ + +} + +void ScenarioChooser::add_scenario(const std::string& path) +{ + Scenario scenario; + if (scenario.load(path)) + { + scenarios_.push_back(scenario); + } +} + +void ScenarioChooser::add_directory(const std::string& path) +{ + DirectorySpecifier d(path); + + // assume each visible subdirectory is a scenario + std::vector entries; + if (d.ReadDirectory(entries)) + { + for (auto& entry : entries) + { + if (entry.is_directory) + { + add_scenario((d + entry.name).GetPath()); + } + } + } +} + +std::string ScenarioChooser::run() +{ + std::sort(scenarios_.begin(), scenarios_.end()); + + SDL_DisplayMode mode; + SDL_GetDesktopDisplayMode(0, &mode); + + window_width_ = mode.w; + window_height_ = mode.h; + + determine_cols_rows(); + WindowPtr window(SDL_CreateWindow("Choose a Scenario", + SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, + window_width_, + window_height_, + SDL_WINDOW_FULLSCREEN_DESKTOP), + SDL_DestroyWindow); + + for (auto& scenario : scenarios_) + { + optimize_image(scenario, window.get()); + } + + SDL_ShowWindow(window.get()); + + done_ = false; + while (!done_) + { + SDL_Event e; + while (SDL_PollEvent(&e)) + { + handle_event(e); + } + + redraw(window.get()); + SDL_Delay(30); + } + + return scenarios_[selection_].path; +} + +void ScenarioChooser::determine_cols_rows() +{ + auto available_width = window_width_ - margin; + auto widget_width = scenario_width + margin; + + cols_ = available_width / widget_width; + if (cols_ > scenarios_.size()) + { + cols_ = scenarios_.size(); + } + + rows_ = (scenarios_.size() + (cols_ - 1)) / cols_; + + // center + offsetx_ = (window_width_ - cols_ * (scenario_width + margin) - margin) / 2; + + auto total_height = rows_ * scenario_height + (rows_ + 1) * margin; + if (total_height > window_height_) + { + offsety_ = 0; + max_scroll_ = total_height - window_height_; + } + else + { + offsety_ = (window_height_ - total_height) / 2; + max_scroll_ = 0; + } + + if (scroll_ > max_scroll_) + { + scroll_ = max_scroll_; + } +} + +void ScenarioChooser::ensure_selection_visible() +{ + auto row = selection_ / cols_; + + auto top = offsety_ + row * (scenario_height + margin); + auto bottom = top + scenario_height + 2 * margin; + + if (scroll_ > top || scroll_ < bottom - window_height_) + { + scroll_ = (top + bottom - window_height_) / 2; + } + + if (scroll_ < 0) + { + scroll_ = 0; + } + else if (scroll_ > max_scroll_) + { + scroll_ = max_scroll_; + } +} + +void ScenarioChooser::handle_event(SDL_Event& e) +{ + switch (e.type) + { + case SDL_CONTROLLERBUTTONDOWN: + switch (e.cbutton.button) + { + case SDL_CONTROLLER_BUTTON_B: + exit(0); + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + move_selection(0, 1); + break; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + move_selection(-1, 0); + break; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + move_selection(1, 0); + break; + case SDL_CONTROLLER_BUTTON_DPAD_UP: + move_selection(0, -1); + break; + } + break; + case SDL_KEYDOWN: + switch (e.key.keysym.sym) + { + case SDLK_DOWN: + move_selection(0, 1); + break; + case SDLK_ESCAPE: + exit(0); + case SDLK_LEFT: + move_selection(-1, 0); + break; + case SDLK_PAGEDOWN: + scroll_ += window_height_; + if (scroll_ > max_scroll_) + { + scroll_ = max_scroll_; + } + break; + case SDLK_PAGEUP: + scroll_ -= window_height_; + if (scroll_ < 0) + { + scroll_ = 0; + } + break; + case SDLK_RETURN: + if (selection_ >= 0) + { + done_ = true; + } + break; + case SDLK_RIGHT: + move_selection(1, 0); + break; + case SDLK_TAB: + if (e.key.keysym.mod & KMOD_SHIFT) + { + if (selection_ > 0) + { + --selection_; + ensure_selection_visible(); + } + else if (selection_ < 0) + { + selection_ = static_cast(scenarios_.size()) - 1; + ensure_selection_visible(); + } + } + else + { + if (selection_ < static_cast(scenarios_.size()) - 1) + { + ++selection_; + ensure_selection_visible(); + } + } + break; + case SDLK_UP: + move_selection(0, -1); + break; + } + break; + case SDL_MOUSEBUTTONDOWN: + { + auto x = e.button.x; + auto y = e.button.y; + + for (auto i = 0; i < scenarios_.size(); ++i) { + auto row = i / cols_; + auto col = i % cols_; + + auto left = offsetx_ + margin + col * (scenario_width + margin); + auto top = offsety_ + margin + row * (scenario_height + margin) - scroll_; + + if (x >= left && x < left + scenario_width && + y >= top && y <= top + scenario_height) + { + selection_ = i; + done_ = true; + break; + } + } + } + break; + + case SDL_MOUSEWHEEL: + scroll_ -= e.wheel.y * 40; + if (scroll_ < 0) + { + scroll_ = 0; + } + + if (scroll_ > max_scroll_) + { + scroll_ = max_scroll_; + } + break; + case SDL_QUIT: + exit(0); + } +} + +void ScenarioChooser::move_selection(int col_delta, int row_delta) +{ + auto selection = selection_; + if (selection == -1) + { + if (row_delta > 0 || col_delta > 0) + { + selection = 0; + row_delta = 0; + col_delta = 0; + } + else if (row_delta < 0) + { + selection = cols_ - 1 + (rows_ - 1) * cols_; + } + else + { + selection = static_cast(scenarios_.size()); + } + } + + auto col = selection % cols_; + auto row = selection / cols_; + + col += col_delta; + if (col < 0) + { + col = 0; + } + + if (col > cols_ - 1) + { + col = cols_ - 1; + } + + row += row_delta; + if (row < 0) + { + row = 0; + } + + if (row > rows_ - 1) + { + row = rows_ - 1; + } + + selection = col + row * cols_; + if (selection >= 0 && selection < static_cast(scenarios_.size())) + { + selection_ = selection; + ensure_selection_visible(); + } +} + +void ScenarioChooser::optimize_image(Scenario& scenario, SDL_Window* window) +{ + auto format = SDL_GetWindowSurface(window)->format; + SurfacePtr optimized(SDL_ConvertSurface(scenario.image.get(), format, 0), SDL_FreeSurface); + + SDL_Rect src_rect{0, 0, optimized->w, optimized->h}; + SDL_Rect dst_rect{0, 0, scenario_width, scenario_height}; + + scenario.image.reset(SDL_CreateRGBSurface(0, scenario_width, scenario_height, format->BitsPerPixel, format->Rmask, format->Gmask, format->Bmask, format->Amask)); + + SDL_SoftStretchLinear(optimized.get(), &src_rect, scenario.image.get(), &dst_rect); +} + +void ScenarioChooser::redraw(SDL_Window* window) +{ + auto surface = SDL_GetWindowSurface(window); + + SDL_FillRect(surface, nullptr, SDL_MapRGB(surface->format, 23, 23, 23)); + + for (auto i = 0; i < scenarios_.size(); ++i) + { + auto row = i / cols_; + auto col = i % cols_; + + auto x = offsetx_ + margin + col * (scenario_width + margin); + auto y = offsety_ + margin + row * (scenario_height + margin) - scroll_; + + if (y > window_height_ || y + scenario_height < 0) + { + continue; + } + + if (i == selection_) + { + SDL_Rect r{x - 2, y - 2, scenario_width + 4, scenario_height + 4}; + SDL_FillRect(surface, &r, SDL_MapRGB(surface->format, 191, 191, 191)); + } + + SDL_Rect src_rect{0, 0, scenario_width, scenario_height}; + SDL_Rect dst_rect{x, y, scenario_width, scenario_height}; + + SDL_BlitSurface(scenarios_[i].image.get(), &src_rect, surface, &dst_rect); + } + + SDL_UpdateWindowSurface(window); +} + diff --git a/Source_Files/Misc/ScenarioChooser.h b/Source_Files/Misc/ScenarioChooser.h new file mode 100644 index 000000000..35b119f99 --- /dev/null +++ b/Source_Files/Misc/ScenarioChooser.h @@ -0,0 +1,78 @@ +#ifndef SCENARIO_CHOOSER_H +#define SCENARIO_CHOOSER_H + +/* + Copyright (C) 2024 by Gregory Smith and the Aleph One developers + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + This license is contained in the file "COPYING", + which is included with this source code; it is available online at + http://www.gnu.org/licenses/gpl.html + */ + +#include +#include + +#include + +class Scenario; +class font_info; + +class ScenarioChooser +{ +public: +// static constexpr auto scenario_width = 300; + // static constexpr auto scenario_height= 450; + static constexpr auto scenario_width = 320; + static constexpr auto scenario_height = 200; + + static constexpr auto margin = 10; + + ScenarioChooser(); + ~ScenarioChooser(); + + void add_scenario(const std::string& path); + void add_directory(const std::string& path); + + int num_scenarios() const { return static_cast(scenarios_.size()); } + + std::string run(); + +private: + bool done_; + + int window_width_; + int window_height_; + + int rows_; + int cols_; + int margin_; + + int scroll_; + int max_scroll_; + + int offsetx_; + int offsety_; + + int selection_; + + std::vector scenarios_; + + void determine_cols_rows(); + void ensure_selection_visible(); + void handle_event(SDL_Event& e); + void move_selection(int col_delta, int row_delta); + void optimize_image(Scenario& scenario, SDL_Window* window); + void redraw(SDL_Window* window); +}; + +#endif diff --git a/Source_Files/RenderOther/images.cpp b/Source_Files/RenderOther/images.cpp index b371d4e02..e0bf0451b 100644 --- a/Source_Files/RenderOther/images.cpp +++ b/Source_Files/RenderOther/images.cpp @@ -1763,3 +1763,46 @@ bool image_file_t::make_rsrc_from_clut(void *data, size_t length, LoadedResource rsrc.SetData(clut_rsrc, output_length); return true; } + +std::unique_ptr find_title_screen(FileSpecifier& file) +{ + image_file_t image_file; + if (image_file.open_file(file)) + { + for (auto i = 2; i >= 0; --i) + { + LoadedResource title_screen; + if (image_file.get_pict(INTRO_SCREEN_BASE + i + _images_file_delta32, title_screen)) + { + return picture_to_surface(title_screen); + } + + if (image_file.get_pict(INTRO_SCREEN_BASE + i + _images_file_delta16, title_screen)) + { + return picture_to_surface(title_screen); + } + + if (image_file.get_pict(INTRO_SCREEN_BASE + i, title_screen)) + { + return picture_to_surface(title_screen); + } + } + } + + return std::unique_ptr(nullptr, SDL_FreeSurface); +} + +std::unique_ptr find_m1_title_screen(FileSpecifier& file) +{ + image_file_t shapes_file; + if (shapes_file.open_file(file)) + { + LoadedResource title_screen; + if (shapes_file.get_pict(1114, title_screen)) + { + return picture_to_surface(title_screen); + } + } + + return std::unique_ptr(nullptr, SDL_FreeSurface); +} diff --git a/Source_Files/RenderOther/images.h b/Source_Files/RenderOther/images.h index 9ea339d48..9d87d639d 100644 --- a/Source_Files/RenderOther/images.h +++ b/Source_Files/RenderOther/images.h @@ -82,5 +82,8 @@ extern std::unique_ptr picture_to_surfa extern SDL_Surface *rescale_surface(SDL_Surface *s, int width, int height); extern SDL_Surface *tile_surface(SDL_Surface *s, int width, int height); +std::unique_ptr find_title_screen(FileSpecifier& file); +std::unique_ptr find_m1_title_screen(FileSpecifier& file); + #endif diff --git a/Source_Files/shell.cpp b/Source_Files/shell.cpp index dc4737de9..d8b7e118e 100644 --- a/Source_Files/shell.cpp +++ b/Source_Files/shell.cpp @@ -58,6 +58,7 @@ #include "FileHandler.h" #include "Plugins.h" #include "FilmProfile.h" +#include "ScenarioChooser.h" #include "mytm.h" // mytm_initialize(), for platform-specific shell_*.h @@ -294,6 +295,39 @@ void initialize_application(void) SDL_EventState(SDL_DROPFILE, SDL_DISABLE); } + const string default_data_env = a1_getenv("ALEPHONE_DEFAULT_DATA"); +#ifndef SCENARIO_IS_BUNDLED + // see if there are scenarios to choose from + DirectorySpecifier scenario_dir(get_data_path(kPathDefaultData)); + if (!shell_options.directory.empty()) + { + scenario_dir = shell_options.directory; + } + else if (!default_data_env.empty()) + { + scenario_dir = default_data_env; + } + + ScenarioChooser chooser; + chooser.add_scenario(scenario_dir.GetPath()); + + if (chooser.num_scenarios() == 0) + { + chooser.add_directory(scenario_dir.GetPath()); + } + else if (chooser.num_scenarios() == 1) + { + chooser.add_directory((scenario_dir + "Scenarios").GetPath()); + } + + if (chooser.num_scenarios() > 1) + { + auto chosen_path = chooser.run(); + // ugh + shell_options.directory = chosen_path; + } +#endif + // Find data directories, construct search path InitDefaultStringSets(); @@ -320,7 +354,6 @@ void initialize_application(void) size_t dsp_insert_pos = data_search_path.size(); size_t dsp_delete_pos = (size_t)-1; - const string default_data_env = a1_getenv("ALEPHONE_DEFAULT_DATA"); if (shell_options.directory != "") { default_data_dir = shell_options.directory; diff --git a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj index bbf812eca..113bf868c 100644 --- a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj +++ b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj @@ -486,6 +486,7 @@ + @@ -746,6 +747,7 @@ + diff --git a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj.filters b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj.filters index 5e61daeb2..d8bdbb456 100644 --- a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj.filters +++ b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj.filters @@ -742,6 +742,9 @@ Network\StandaloneHub\Source Files + + Misc\Source Files + @@ -1443,5 +1446,8 @@ Network\StandaloneHub\Header Files + + Misc\Header Files + \ No newline at end of file From e33bc32fe11c504fb5ae7253f26f68672a2e862d Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Sun, 4 Aug 2024 20:23:01 -0400 Subject: [PATCH 03/58] correct the aspect ratio of the 32-bit M2/Inf title screens in the scenario chooser --- Source_Files/Misc/ScenarioChooser.cpp | 7 +++++++ Source_Files/Misc/ScenarioChooser.h | 4 +--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Source_Files/Misc/ScenarioChooser.cpp b/Source_Files/Misc/ScenarioChooser.cpp index 4eabd49ca..c03ec8a1e 100644 --- a/Source_Files/Misc/ScenarioChooser.cpp +++ b/Source_Files/Misc/ScenarioChooser.cpp @@ -464,6 +464,13 @@ void ScenarioChooser::optimize_image(Scenario& scenario, SDL_Window* window) SDL_Rect src_rect{0, 0, optimized->w, optimized->h}; SDL_Rect dst_rect{0, 0, scenario_width, scenario_height}; + // the 32-bit title screens in M2 / Inf are 640x480; crop to the middle + if (optimized->h > scenario_height * 2) + { + src_rect.h = scenario_height * 2; + src_rect.y = (optimized->h - scenario_height * 2) / 2; + } + scenario.image.reset(SDL_CreateRGBSurface(0, scenario_width, scenario_height, format->BitsPerPixel, format->Rmask, format->Gmask, format->Bmask, format->Amask)); SDL_SoftStretchLinear(optimized.get(), &src_rect, scenario.image.get(), &dst_rect); diff --git a/Source_Files/Misc/ScenarioChooser.h b/Source_Files/Misc/ScenarioChooser.h index 35b119f99..eed6c0b5d 100644 --- a/Source_Files/Misc/ScenarioChooser.h +++ b/Source_Files/Misc/ScenarioChooser.h @@ -30,10 +30,8 @@ class font_info; class ScenarioChooser { public: -// static constexpr auto scenario_width = 300; - // static constexpr auto scenario_height= 450; static constexpr auto scenario_width = 320; - static constexpr auto scenario_height = 200; + static constexpr auto scenario_height = 193; static constexpr auto margin = 10; From d030977aa2e3cfe616cffffbeecc27800982a4b6 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Tue, 6 Aug 2024 19:15:00 +0200 Subject: [PATCH 04/58] Don't disconnect gatherer (& everyone) from dedicated server if a 9th player is accepted in the game but just ignore it instead --- Source_Files/Network/network.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Source_Files/Network/network.cpp b/Source_Files/Network/network.cpp index 1732416bb..898dd0d16 100644 --- a/Source_Files/Network/network.cpp +++ b/Source_Files/Network/network.cpp @@ -747,11 +747,7 @@ void Client::handleRemoteHubCommandMessage(RemoteHubCommandMessage* message, Com { case RemoteHubCommand::kAcceptJoiner_Command: { - if (NetGetNumberOfPlayers() >= MAXIMUM_NUMBER_OF_PLAYERS) - { - state = Client::_disconnect; - } - else + if (NetGetNumberOfPlayers() < MAXIMUM_NUMBER_OF_PLAYERS) { prospective_joiner_info info = {}; info.stream_id = message->data(); From 3514d2ef95aebf9e9dd6e907ffe1afc30fd0017d Mon Sep 17 00:00:00 2001 From: Kolfering Date: Tue, 6 Aug 2024 22:45:49 +0200 Subject: [PATCH 05/58] Change DefaultMinimumSendPeriod from 5 to 3 --- Source_Files/Network/network_star_hub.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source_Files/Network/network_star_hub.cpp b/Source_Files/Network/network_star_hub.cpp index 49241b01e..9c35fdb6d 100644 --- a/Source_Files/Network/network_star_hub.cpp +++ b/Source_Files/Network/network_star_hub.cpp @@ -148,7 +148,7 @@ enum { kDefaultInGameTicksBeforeNetDeath = 5 * TICKS_PER_SECOND, kDefaultSendPeriod = 1, kDefaultRecoverySendPeriod = TICKS_PER_SECOND / 2, - kDefaultMinimumSendPeriod = 5, + kDefaultMinimumSendPeriod = 3, kLossyByteStreamDataBufferSize = 1280, kTypicalLossyByteStreamChunkSize = 56, kLossyByteStreamDescriptorCount = kLossyByteStreamDataBufferSize / kTypicalLossyByteStreamChunkSize, From 53220a04a7e1cf9aac56c150fbf6e624ed6e4571 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Wed, 7 Aug 2024 20:27:09 -0400 Subject: [PATCH 06/58] use 640x480 for scenario images; some title screens use the full height. Letterbox the rest --- Source_Files/Misc/ScenarioChooser.cpp | 9 +-------- Source_Files/Misc/ScenarioChooser.h | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Source_Files/Misc/ScenarioChooser.cpp b/Source_Files/Misc/ScenarioChooser.cpp index c03ec8a1e..824b41671 100644 --- a/Source_Files/Misc/ScenarioChooser.cpp +++ b/Source_Files/Misc/ScenarioChooser.cpp @@ -462,14 +462,7 @@ void ScenarioChooser::optimize_image(Scenario& scenario, SDL_Window* window) SurfacePtr optimized(SDL_ConvertSurface(scenario.image.get(), format, 0), SDL_FreeSurface); SDL_Rect src_rect{0, 0, optimized->w, optimized->h}; - SDL_Rect dst_rect{0, 0, scenario_width, scenario_height}; - - // the 32-bit title screens in M2 / Inf are 640x480; crop to the middle - if (optimized->h > scenario_height * 2) - { - src_rect.h = scenario_height * 2; - src_rect.y = (optimized->h - scenario_height * 2) / 2; - } + SDL_Rect dst_rect{0, (scenario_height - optimized->h / 2) / 2, scenario_width, optimized->h / 2}; scenario.image.reset(SDL_CreateRGBSurface(0, scenario_width, scenario_height, format->BitsPerPixel, format->Rmask, format->Gmask, format->Bmask, format->Amask)); diff --git a/Source_Files/Misc/ScenarioChooser.h b/Source_Files/Misc/ScenarioChooser.h index eed6c0b5d..b69ae2e2f 100644 --- a/Source_Files/Misc/ScenarioChooser.h +++ b/Source_Files/Misc/ScenarioChooser.h @@ -31,7 +31,7 @@ class ScenarioChooser { public: static constexpr auto scenario_width = 320; - static constexpr auto scenario_height = 193; + static constexpr auto scenario_height = 240; static constexpr auto margin = 10; From 1208238984c6687e0b05ad144bdff1d327931160 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Fri, 9 Aug 2024 17:16:01 -0400 Subject: [PATCH 07/58] add a "load other" button to the env selector; use env selector for more file choices --- Source_Files/Files/FileHandler.cpp | 2 + Source_Files/Files/tags.h | 1 + Source_Files/Misc/preferences.cpp | 12 +++--- Source_Files/Misc/preferences_widgets_sdl.cpp | 40 ++++++++++--------- Source_Files/Misc/preferences_widgets_sdl.h | 24 ++++++++++- Source_Files/Network/network_dialogs.cpp | 8 ++-- Source_Files/Network/network_dialogs.h | 5 ++- 7 files changed, 58 insertions(+), 34 deletions(-) diff --git a/Source_Files/Files/FileHandler.cpp b/Source_Files/Files/FileHandler.cpp index 01b337234..b010a13fe 100644 --- a/Source_Files/Files/FileHandler.cpp +++ b/Source_Files/Files/FileHandler.cpp @@ -594,6 +594,8 @@ static extension_mapping extensions[] = { "mpg", false, _typecode_movie }, + { "appl", false, _typecode_application }, + {0, false, _typecode_unknown} }; diff --git a/Source_Files/Files/tags.h b/Source_Files/Files/tags.h index c4e20f53e..0b6acca4b 100644 --- a/Source_Files/Files/tags.h +++ b/Source_Files/Files/tags.h @@ -85,6 +85,7 @@ enum Typecode { _typecode_netscript, // ZZZ pseudo typecode _typecode_shapespatch, _typecode_movie, + _typecode_application, NUMBER_OF_TYPECODES }; diff --git a/Source_Files/Misc/preferences.cpp b/Source_Files/Misc/preferences.cpp index 591ed9c63..f33121791 100644 --- a/Source_Files/Misc/preferences.cpp +++ b/Source_Files/Misc/preferences.cpp @@ -3152,7 +3152,7 @@ static void environment_dialog(void *arg) table->dual_add(sounds_w->label("Sounds"), d); table->dual_add(sounds_w, d); - w_env_select* resources_w = new w_env_select(environment_preferences->resources_file, "AVAILABLE FILES", _typecode_unknown, &d); + w_env_select* resources_w = new w_env_select(environment_preferences->resources_file, "AVAILABLE FILES", _typecode_application, &d); table->dual_add(resources_w->label("External Resources"), d); table->dual_add(resources_w, d); #endif @@ -3164,8 +3164,7 @@ static void environment_dialog(void *arg) table->dual_add(use_solo_lua_w->label("Use Solo Script"), d); table->dual_add(use_solo_lua_w, d); - w_file_chooser *solo_lua_w = new w_file_chooser("Choose Script", _typecode_netscript); - solo_lua_w->set_file(environment_preferences->solo_lua_file); + w_env_select *solo_lua_w = new w_env_select(environment_preferences->solo_lua_file, "AVAILABLE SOLO SCRIPTS", _typecode_netscript, &d); table->dual_add(solo_lua_w->label("Script File"), d); table->dual_add(solo_lua_w, d); use_solo_lua_w->add_dependent_widget(solo_lua_w); @@ -3183,8 +3182,7 @@ static void environment_dialog(void *arg) table->dual_add(use_replay_net_lua_w->label("Use Netscript in Films"), d); table->dual_add(use_replay_net_lua_w, d); - w_file_chooser *replay_net_lua_w = new w_file_chooser("Choose Script", _typecode_netscript); - replay_net_lua_w->set_file(network_preferences->netscript_file); + w_env_select *replay_net_lua_w = new w_env_select(network_preferences->netscript_file, "AVAILABLE NETSCRIPTS", _typecode_netscript, &d); table->dual_add(replay_net_lua_w->label("Netscript File"), d); table->dual_add(replay_net_lua_w, d); use_replay_net_lua_w->add_dependent_widget(replay_net_lua_w); @@ -3281,7 +3279,7 @@ static void environment_dialog(void *arg) changed = true; } - path = solo_lua_w->get_file().GetPath(); + path = solo_lua_w->get_path(); if (strcmp(path, environment_preferences->solo_lua_file)) { strncpy(environment_preferences->solo_lua_file, path, 256); changed = true; @@ -3294,7 +3292,7 @@ static void environment_dialog(void *arg) changed = true; } - path = replay_net_lua_w->get_file().GetPath(); + path = replay_net_lua_w->get_path(); if (strcmp(path, network_preferences->netscript_file)) { strncpy(network_preferences->netscript_file, path, 256); changed = true; diff --git a/Source_Files/Misc/preferences_widgets_sdl.cpp b/Source_Files/Misc/preferences_widgets_sdl.cpp index 2327512a9..3f7166413 100644 --- a/Source_Files/Misc/preferences_widgets_sdl.cpp +++ b/Source_Files/Misc/preferences_widgets_sdl.cpp @@ -46,22 +46,6 @@ void w_env_select::select_item_callback(void* arg) { void w_env_select::select_item(dialog *parent) { -#ifdef HAVE_NFD - if (environment_preferences->use_native_file_dialogs) - { - auto spec = item; - if (spec.ReadDialog(type, nullptr)) - { - set_path(spec.GetPath()); - if (mCallback) - { - mCallback(this); - } - } - } - else - { -#endif // Find available files vector files; if (type != _typecode_theme) { @@ -105,7 +89,15 @@ void w_env_select::select_item(dialog *parent) w_env_list *list_w = new w_env_list(items, item.GetPath(), &d); placer->dual_add(list_w, d); placer->add(new w_spacer(), true); - placer->dual_add(new w_button("CANCEL", dialog_cancel, &d), d); + + auto load_other = false; + horizontal_placer* button_placer = new horizontal_placer; +#ifndef MAC_APP_STORE + w_button* other_w = new w_button("LOAD OTHER", [&](void* p) { load_other = true; dialog_cancel(p); }, &d); + button_placer->dual_add(other_w, d); +#endif + button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &d), d); + placer->add(button_placer, true); d.activate_widget(list_w); d.set_widget_placer(placer); @@ -121,9 +113,19 @@ void w_env_select::select_item(dialog *parent) if(mCallback) mCallback(this); } -#ifdef HAVE_NFD + else if (load_other) + { + FileSpecifier spec(get_path()); + if (spec.ReadDialog(type)) + { + set_path(spec.GetPath()); + + if (mCallback) + { + mCallback(this); + } + } } -#endif } w_crosshair_display::w_crosshair_display() : surface(0) diff --git a/Source_Files/Misc/preferences_widgets_sdl.h b/Source_Files/Misc/preferences_widgets_sdl.h index 5b7f81d2e..6974e4924 100644 --- a/Source_Files/Misc/preferences_widgets_sdl.h +++ b/Source_Files/Misc/preferences_widgets_sdl.h @@ -109,7 +109,7 @@ class w_env_list : public w_list { // Environment selection button // ZZZ: added callback stuff - callback is made if user clicks on an entry in the selection dialog. class w_env_select; -typedef void (*selection_made_callback_t)(w_env_select* inWidget); +using selection_made_callback_t = std::function; class w_env_select : public w_select_button { public: @@ -122,7 +122,7 @@ w_env_select(const char *path, const char *m, Typecode t, dialog *d) } ~w_env_select() {} - void set_selection_made_callback(selection_made_callback_t inCallback) { + void set_selection_made_callback(selection_made_callback_t inCallback) { mCallback = inCallback; } @@ -159,6 +159,26 @@ w_env_select(const char *path, const char *m, Typecode t, dialog *d) selection_made_callback_t mCallback; }; +class EnvSelectWidget : public SDLWidgetWidget, public Bindable +{ +public: + EnvSelectWidget(w_env_select* env_select) : + SDLWidgetWidget(env_select), + m_env_select(env_select) + { + } + + void set_callback(ControlHitCallback callback) { m_env_select->set_selection_made_callback([=](w_env_select*) { callback(); }); } + void set_file(const FileSpecifier& file) { m_env_select->set_path(file.GetPath()); } + FileSpecifier get_file() { return m_env_select->get_file_specifier(); } + + virtual FileSpecifier bind_export() { return get_file(); } + virtual void bind_import(FileSpecifier f) { set_file(f); } + +private: + w_env_select* m_env_select; +}; + class w_crosshair_display : public widget { public: enum { diff --git a/Source_Files/Network/network_dialogs.cpp b/Source_Files/Network/network_dialogs.cpp index 3066b2c53..4569a73c8 100644 --- a/Source_Files/Network/network_dialogs.cpp +++ b/Source_Files/Network/network_dialogs.cpp @@ -2743,7 +2743,7 @@ class SdlSetupNetgameDialog : public SetupNetgameDialog // Could eventually store this path in network_preferences somewhere, so to have separate map file // prefs for single- and multi-player. - w_file_chooser* map_w = new w_file_chooser ("Choose Map", _typecode_scenario); + w_env_select* map_w = new w_env_select ("", "AVAILABLE MAPS", _typecode_scenario, &m_dialog); #ifndef MAC_APP_STORE player_table->dual_add(map_w->label("Map"), m_dialog); player_table->dual_add(map_w, m_dialog); @@ -2773,7 +2773,7 @@ class SdlSetupNetgameDialog : public SetupNetgameDialog network_table->dual_add(use_netscript_w->label("Use Netscript"), m_dialog); #endif - w_file_chooser* choose_script_w = new w_file_chooser ("Choose Script", _typecode_netscript); + w_env_select* choose_script_w = new w_env_select ("", "AVAILABLE NETSCRIPTS", _typecode_netscript, &m_dialog); #ifndef MAC_APP_STORE network_table->add(new w_spacer(), true); network_table->dual_add(choose_script_w, m_dialog); @@ -2885,7 +2885,7 @@ class SdlSetupNetgameDialog : public SetupNetgameDialog m_colourWidget = new ColourSelectorWidget (pcolor_w); m_teamWidget = new ColourSelectorWidget (tcolor_w); - m_mapWidget = new FileChooserWidget (map_w); + m_mapWidget = new EnvSelectWidget (map_w); m_levelWidget = new PopupSelectorWidget (entry_point_w); m_gameTypeWidget = new PopupSelectorWidget (game_type_w); @@ -2904,7 +2904,7 @@ class SdlSetupNetgameDialog : public SetupNetgameDialog m_useMetaserverWidget = new ToggleWidget (advertise_on_metaserver_w); m_useScriptWidget = new ToggleWidget (use_netscript_w); - m_scriptWidget = new FileChooserWidget (choose_script_w); + m_scriptWidget = new EnvSelectWidget (choose_script_w); m_liveCarnageWidget = new ToggleWidget (live_w); m_motionSensorWidget = new ToggleWidget (sensor_w); diff --git a/Source_Files/Network/network_dialogs.h b/Source_Files/Network/network_dialogs.h index 05590c657..871b915be 100644 --- a/Source_Files/Network/network_dialogs.h +++ b/Source_Files/Network/network_dialogs.h @@ -45,6 +45,7 @@ Mar 1, 2002 (Woody Zenfell): #include "metaserver_dialogs.h" #include "shared_widgets.h" +#include "preferences_widgets_sdl.h" #include @@ -404,7 +405,7 @@ class SetupNetgameDialog SelectorWidget* m_colourWidget; SelectorWidget* m_teamWidget; - FileChooserWidget* m_mapWidget; + EnvSelectWidget* m_mapWidget; SelectorWidget* m_levelWidget; SelectorWidget* m_gameTypeWidget; SelectorWidget* m_difficultyWidget; @@ -422,7 +423,7 @@ class SetupNetgameDialog ToggleWidget* m_useMetaserverWidget; ToggleWidget* m_useScriptWidget; - FileChooserWidget* m_scriptWidget; + EnvSelectWidget* m_scriptWidget; ToggleWidget* m_liveCarnageWidget; ToggleWidget* m_motionSensorWidget; From 5f5168f974ed57e966993bb28a9e6c34e0a6bcd0 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Wed, 14 Aug 2024 21:50:57 -0400 Subject: [PATCH 08/58] parse MML instead of having a separate chooser XML; load chooser.png/chooser.bmp from root directory if present --- Source_Files/Misc/ScenarioChooser.cpp | 66 +++++++++++++++++---------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/Source_Files/Misc/ScenarioChooser.cpp b/Source_Files/Misc/ScenarioChooser.cpp index 824b41671..7c59d6244 100644 --- a/Source_Files/Misc/ScenarioChooser.cpp +++ b/Source_Files/Misc/ScenarioChooser.cpp @@ -30,10 +30,7 @@ class Scenario std::string path; - std::string name; // unused - std::string image_path; - std::string release; // unused - + std::string name; std::shared_ptr image; bool load(const std::string& path); @@ -86,8 +83,9 @@ bool Scenario::operator<(const Scenario& other) const bool Scenario::load(const std::string& path) { DirectorySpecifier directory(path); + DirectorySpecifier scripts = directory + "Scripts"; - if (!(directory + "Scripts").Exists()) + if (!scripts.Exists()) { return false; } @@ -98,34 +96,56 @@ bool Scenario::load(const std::string& path) directory.SplitPath(base, part); this->path = path; + name = part; - FileSpecifier config = directory + "Scripts" + "chooser.xml"; - if (config.Exists()) + std::vector entries; + if (scripts.ReadDirectory(entries)) { - boost::property_tree::ptree tree; - boost::property_tree::read_xml(config.GetPath(), tree); + std::sort(entries.begin(), entries.end()); + for (auto it = entries.rbegin(); it != entries.rend(); ++it) + { + if (it->is_directory || + it->name[it->name.length() - 1] == '~' || + boost::algorithm::ends_with(it->name, ".lua")) + { + continue; + } + + FileSpecifier mml = scripts + it->name; + boost::property_tree::ptree tree; + boost::property_tree::read_xml(mml.GetPath(), tree); + + try + { + name = tree.get("marathon.scenario..name"); + break; + } + catch (const boost::property_tree::ptree_error&) + { - image_path = tree.get("chooser.image", ""); - name = tree.get("chooser.name", part); - release = tree.get("chooser.release", "1994-12-21"); + } + } + } - FileSpecifier image_file = directory + image_path; +#ifdef HAVE_SDL_IMAGE + FileSpecifier image_file = directory + "chooser.png"; + OpenedFile of; + if (image_file.Open(of)) + { + image.reset(IMG_Load_RW(of.GetRWops(), 0)); + } +#endif + + if (!image) + { + FileSpecifier image_file = directory + "chooser.bmp"; OpenedFile of; if (image_file.Open(of)) { -#ifdef HAVE_SDL_IMAGE - image.reset(IMG_Load_RW(of.GetRWops(), 0)); -#else image.reset(SDL_LoadBMP_RW(of.GetRWops(), 0)); -#endif } } - else - { - name = part; - release = "1994-12-21"; - } - + if (!image) { find_image(); From b5ab475b0cbcb77bcd274406e34e652d081ef916 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Thu, 15 Aug 2024 20:19:10 -0400 Subject: [PATCH 09/58] fix ODR violation; fixes clang (macOS) builds --- Source_Files/Misc/ScenarioChooser.cpp | 23 ++++++++++++++--------- Source_Files/Misc/ScenarioChooser.h | 8 ++++---- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Source_Files/Misc/ScenarioChooser.cpp b/Source_Files/Misc/ScenarioChooser.cpp index 7c59d6244..afae62afb 100644 --- a/Source_Files/Misc/ScenarioChooser.cpp +++ b/Source_Files/Misc/ScenarioChooser.cpp @@ -23,10 +23,10 @@ using SurfacePtr = std::unique_ptr; using WindowPtr = std::unique_ptr; -class Scenario +class ScenarioChooserScenario { public: - bool operator<(const Scenario& other) const; + bool operator<(const ScenarioChooserScenario& other) const; std::string path; @@ -40,7 +40,7 @@ class Scenario class TitleScreenFinder : public FileFinder { public: - TitleScreenFinder(Scenario& scenario) : FileFinder(), scenario_{scenario} { } + TitleScreenFinder(ScenarioChooserScenario& scenario) : FileFinder(), scenario_{scenario} { } virtual bool found(FileSpecifier& file) { if (boost::algorithm::ends_with(file.GetPath(), ".imgA")) @@ -66,10 +66,10 @@ class TitleScreenFinder : public FileFinder } private: - Scenario& scenario_; + ScenarioChooserScenario& scenario_; }; -bool Scenario::operator<(const Scenario& other) const +bool ScenarioChooserScenario::operator<(const ScenarioChooserScenario& other) const { return std::lexicographical_compare(name.begin(), name.end(), @@ -80,7 +80,7 @@ bool Scenario::operator<(const Scenario& other) const }); } -bool Scenario::load(const std::string& path) +bool ScenarioChooserScenario::load(const std::string& path) { DirectorySpecifier directory(path); DirectorySpecifier scripts = directory + "Scripts"; @@ -154,7 +154,7 @@ bool Scenario::load(const std::string& path) return image.get(); } -void Scenario::find_image() +void ScenarioChooserScenario::find_image() { TitleScreenFinder finder(*this); FileSpecifier f(path); @@ -174,7 +174,7 @@ ScenarioChooser::~ScenarioChooser() void ScenarioChooser::add_scenario(const std::string& path) { - Scenario scenario; + ScenarioChooserScenario scenario; if (scenario.load(path)) { scenarios_.push_back(scenario); @@ -199,6 +199,11 @@ void ScenarioChooser::add_directory(const std::string& path) } } +int ScenarioChooser::num_scenarios() const +{ + return static_cast(scenarios_.size()); +} + std::string ScenarioChooser::run() { std::sort(scenarios_.begin(), scenarios_.end()); @@ -476,7 +481,7 @@ void ScenarioChooser::move_selection(int col_delta, int row_delta) } } -void ScenarioChooser::optimize_image(Scenario& scenario, SDL_Window* window) +void ScenarioChooser::optimize_image(ScenarioChooserScenario& scenario, SDL_Window* window) { auto format = SDL_GetWindowSurface(window)->format; SurfacePtr optimized(SDL_ConvertSurface(scenario.image.get(), format, 0), SDL_FreeSurface); diff --git a/Source_Files/Misc/ScenarioChooser.h b/Source_Files/Misc/ScenarioChooser.h index b69ae2e2f..775f9dba5 100644 --- a/Source_Files/Misc/ScenarioChooser.h +++ b/Source_Files/Misc/ScenarioChooser.h @@ -24,7 +24,7 @@ #include -class Scenario; +class ScenarioChooserScenario; class font_info; class ScenarioChooser @@ -41,7 +41,7 @@ class ScenarioChooser void add_scenario(const std::string& path); void add_directory(const std::string& path); - int num_scenarios() const { return static_cast(scenarios_.size()); } + int num_scenarios() const; std::string run(); @@ -63,13 +63,13 @@ class ScenarioChooser int selection_; - std::vector scenarios_; + std::vector scenarios_; void determine_cols_rows(); void ensure_selection_visible(); void handle_event(SDL_Event& e); void move_selection(int col_delta, int row_delta); - void optimize_image(Scenario& scenario, SDL_Window* window); + void optimize_image(ScenarioChooserScenario& scenario, SDL_Window* window); void redraw(SDL_Window* window); }; From 7d737aa48d1f8af0e091f7d57b98485fbce78cc0 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Thu, 15 Aug 2024 20:50:09 -0400 Subject: [PATCH 10/58] move brightness controls to shift+F11/shift+F12 for Steam builds, so they don't interfere with screenshots --- Source_Files/Misc/preferences.cpp | 5 +++++ Source_Files/shell.cpp | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Source_Files/Misc/preferences.cpp b/Source_Files/Misc/preferences.cpp index f33121791..2e84bbd17 100644 --- a/Source_Files/Misc/preferences.cpp +++ b/Source_Files/Misc/preferences.cpp @@ -2909,8 +2909,13 @@ static void controls_dialog(void *arg) "F8", "Crosshairs", "F9", "Screenshot", "F10", "Debug info", +#ifdef HAVE_STEAM + "Shift+F11", "Decrease brightness", + "Shift+F12", "Increase brightness", +#else "F11", "Decrease brightness", "F12", "Increase brightness", +#endif #if (defined(__APPLE__) && defined(__MACH__)) "Cmd-Return", "Toggle fullscreen", #else diff --git a/Source_Files/shell.cpp b/Source_Files/shell.cpp index d8b7e118e..c68cddcbe 100644 --- a/Source_Files/shell.cpp +++ b/Source_Files/shell.cpp @@ -1090,7 +1090,11 @@ static void handle_game_key(const SDL_Event &event) ShowPosition = !ShowPosition; } } - else if (sc == SDL_SCANCODE_F11) // Decrease gamma level + else if (sc == SDL_SCANCODE_F11 +#ifdef HAVE_STEAM + && (event.key.keysym.mod & KMOD_SHIFT) +#endif + ) // Decrease gamma level { if (graphics_preferences->screen_mode.gamma_level) { PlayInterfaceButtonSound(Sound_ButtonSuccess()); @@ -1100,7 +1104,11 @@ static void handle_game_key(const SDL_Event &event) } else PlayInterfaceButtonSound(Sound_ButtonFailure()); } - else if (sc == SDL_SCANCODE_F12) // Increase gamma level + else if (sc == SDL_SCANCODE_F12 +#ifdef HAVE_STEAM + && (event.key.keysym.mod & KMOD_SHIFT) +#endif + ) // Increase gamma level { if (graphics_preferences->screen_mode.gamma_level < NUMBER_OF_GAMMA_LEVELS - 1) { PlayInterfaceButtonSound(Sound_ButtonSuccess()); From 4d8d30e8528ac370a776f4839aa1701962869854 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Thu, 15 Aug 2024 20:50:54 -0400 Subject: [PATCH 11/58] ScenarioChooser was missing from Marathon Infinity Steam target --- PBProjects/AlephOne.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PBProjects/AlephOne.xcodeproj/project.pbxproj b/PBProjects/AlephOne.xcodeproj/project.pbxproj index af1c6ba2f..313bcca1b 100644 --- a/PBProjects/AlephOne.xcodeproj/project.pbxproj +++ b/PBProjects/AlephOne.xcodeproj/project.pbxproj @@ -1179,6 +1179,7 @@ AE2A50CE09C67253007681A4 /* Scenario.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE2A50CC09C67253007681A4 /* Scenario.cpp */; }; AE2FDECC09E934E000A18ABC /* preference_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE2FDECA09E934E000A18ABC /* preference_dialogs.cpp */; }; AE38D10E0D555A3100FC2082 /* lua_objects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE38D10C0D555A3100FC2082 /* lua_objects.cpp */; }; + AE3AF3962C6ED7200066F090 /* ScenarioChooser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE83423F2C5B22EA00A4A530 /* ScenarioChooser.cpp */; }; AE3C01A42C13DB8B002A3EB2 /* Pinger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE3C01A32C13DB8B002A3EB2 /* Pinger.cpp */; }; AE3C01A52C13DB8B002A3EB2 /* Pinger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE3C01A32C13DB8B002A3EB2 /* Pinger.cpp */; }; AE3C01A62C13DB8B002A3EB2 /* Pinger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE3C01A32C13DB8B002A3EB2 /* Pinger.cpp */; }; @@ -7849,6 +7850,7 @@ AEBDC6742C4DF0780026DFF1 /* MessageDispatcher.cpp in Sources */, AEBDC6752C4DF0780026DFF1 /* MessageHandler.cpp in Sources */, AEBDC6762C4DF0780026DFF1 /* MessageInflater.cpp in Sources */, + AE3AF3962C6ED7200066F090 /* ScenarioChooser.cpp in Sources */, AEBDC6772C4DF0780026DFF1 /* network_messages.cpp in Sources */, AEBDC6782C4DF0780026DFF1 /* csstrings.cpp in Sources */, AEBDC6792C4DF0780026DFF1 /* SdlMetaserverClientUi.cpp in Sources */, From 0b611539aa04464d80be059e7ca3afd551569731 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Fri, 16 Aug 2024 17:00:58 +0200 Subject: [PATCH 12/58] Remove RingGameProtocol --- PBProjects/AlephOne.xcodeproj/project.pbxproj | 32 - Source_Files/Misc/preferences.cpp | 8 +- Source_Files/Misc/preferences.h | 1 - Source_Files/Network/Makefile.am | 4 +- Source_Files/Network/RingGameProtocol.cpp | 2435 ----------------- Source_Files/Network/RingGameProtocol.h | 59 - Source_Files/Network/network.cpp | 16 +- Source_Files/Network/network_capabilities.cpp | 1 - Source_Files/Network/network_capabilities.h | 2 - VisualStudio/LibAlephOne/LibAlephOne.vcxproj | 2 - .../LibAlephOne/LibAlephOne.vcxproj.filters | 6 - 11 files changed, 4 insertions(+), 2562 deletions(-) delete mode 100644 Source_Files/Network/RingGameProtocol.cpp delete mode 100644 Source_Files/Network/RingGameProtocol.h diff --git a/PBProjects/AlephOne.xcodeproj/project.pbxproj b/PBProjects/AlephOne.xcodeproj/project.pbxproj index 313bcca1b..0fbd73c41 100644 --- a/PBProjects/AlephOne.xcodeproj/project.pbxproj +++ b/PBProjects/AlephOne.xcodeproj/project.pbxproj @@ -383,7 +383,6 @@ AE120C302BC77645001873DD /* OGL_Texture_Def.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DF290E9046F5BED00000104 /* OGL_Texture_Def.h */; }; AE120C312BC77645001873DD /* network_star.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CA04819BD700A8000D /* network_star.h */; }; AE120C322BC77645001873DD /* NetworkGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CC04819BD700A8000D /* NetworkGameProtocol.h */; }; - AE120C332BC77645001873DD /* RingGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CE04819BD700A8000D /* RingGameProtocol.h */; }; AE120C342BC77645001873DD /* StarGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5D004819BD700A8000D /* StarGameProtocol.h */; }; AE120C352BC77645001873DD /* AStream.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E404819EBF00A8000D /* AStream.h */; }; AE120C362BC77645001873DD /* TickBasedCircularQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E904819F2300A8000D /* TickBasedCircularQueue.h */; }; @@ -572,7 +571,6 @@ AE120CEF2BC77645001873DD /* network_star_hub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C804819BD700A8000D /* network_star_hub.cpp */; }; AE120CF02BC77645001873DD /* InfoTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27FF265E1B6F170600DA0A19 /* InfoTree.cpp */; }; AE120CF12BC77645001873DD /* network_star_spoke.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C904819BD700A8000D /* network_star_spoke.cpp */; }; - AE120CF22BC77645001873DD /* RingGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CD04819BD700A8000D /* RingGameProtocol.cpp */; }; AE120CF32BC77645001873DD /* StarGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CF04819BD700A8000D /* StarGameProtocol.cpp */; }; AE120CF42BC77645001873DD /* lua_music.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE96370B2A39578600DE43FF /* lua_music.cpp */; }; AE120CF52BC77645001873DD /* AStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5E304819EBF00A8000D /* AStream.cpp */; }; @@ -837,7 +835,6 @@ AE1320C92C1CB4D2009D34AA /* OGL_Texture_Def.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DF290E9046F5BED00000104 /* OGL_Texture_Def.h */; }; AE1320CA2C1CB4D2009D34AA /* network_star.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CA04819BD700A8000D /* network_star.h */; }; AE1320CB2C1CB4D2009D34AA /* NetworkGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CC04819BD700A8000D /* NetworkGameProtocol.h */; }; - AE1320CC2C1CB4D2009D34AA /* RingGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CE04819BD700A8000D /* RingGameProtocol.h */; }; AE1320CD2C1CB4D2009D34AA /* StarGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5D004819BD700A8000D /* StarGameProtocol.h */; }; AE1320CE2C1CB4D2009D34AA /* AStream.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E404819EBF00A8000D /* AStream.h */; }; AE1320CF2C1CB4D2009D34AA /* TickBasedCircularQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E904819F2300A8000D /* TickBasedCircularQueue.h */; }; @@ -1026,7 +1023,6 @@ AE1321892C1CB4D2009D34AA /* network_star_hub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C804819BD700A8000D /* network_star_hub.cpp */; }; AE13218A2C1CB4D2009D34AA /* InfoTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27FF265E1B6F170600DA0A19 /* InfoTree.cpp */; }; AE13218B2C1CB4D2009D34AA /* network_star_spoke.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C904819BD700A8000D /* network_star_spoke.cpp */; }; - AE13218C2C1CB4D2009D34AA /* RingGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CD04819BD700A8000D /* RingGameProtocol.cpp */; }; AE13218D2C1CB4D2009D34AA /* StarGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CF04819BD700A8000D /* StarGameProtocol.cpp */; }; AE13218E2C1CB4D2009D34AA /* lua_music.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE96370B2A39578600DE43FF /* lua_music.cpp */; }; AE13218F2C1CB4D2009D34AA /* AStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5E304819EBF00A8000D /* AStream.cpp */; }; @@ -1314,7 +1310,6 @@ AE505BCB141D45E600915344 /* OGL_Texture_Def.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DF290E9046F5BED00000104 /* OGL_Texture_Def.h */; }; AE505BCC141D45E600915344 /* network_star.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CA04819BD700A8000D /* network_star.h */; }; AE505BCD141D45E600915344 /* NetworkGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CC04819BD700A8000D /* NetworkGameProtocol.h */; }; - AE505BCE141D45E600915344 /* RingGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CE04819BD700A8000D /* RingGameProtocol.h */; }; AE505BCF141D45E600915344 /* StarGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5D004819BD700A8000D /* StarGameProtocol.h */; }; AE505BD0141D45E600915344 /* AStream.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E404819EBF00A8000D /* AStream.h */; }; AE505BD1141D45E600915344 /* TickBasedCircularQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E904819F2300A8000D /* TickBasedCircularQueue.h */; }; @@ -1474,7 +1469,6 @@ AE505C87141D45E600915344 /* OGL_Subst_Texture_Def.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DF290F0046F5C5B00000104 /* OGL_Subst_Texture_Def.cpp */; }; AE505C88141D45E600915344 /* network_star_hub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C804819BD700A8000D /* network_star_hub.cpp */; }; AE505C89141D45E600915344 /* network_star_spoke.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C904819BD700A8000D /* network_star_spoke.cpp */; }; - AE505C8B141D45E600915344 /* RingGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CD04819BD700A8000D /* RingGameProtocol.cpp */; }; AE505C8C141D45E600915344 /* StarGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CF04819BD700A8000D /* StarGameProtocol.cpp */; }; AE505C8D141D45E600915344 /* AStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5E304819EBF00A8000D /* AStream.cpp */; }; AE505C8F141D45E600915344 /* CircularByteBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EFEF1AC504AF552D00C3A19D /* CircularByteBuffer.cpp */; }; @@ -1799,7 +1793,6 @@ AEB4A16B14296CAE00537AE7 /* OGL_Texture_Def.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DF290E9046F5BED00000104 /* OGL_Texture_Def.h */; }; AEB4A16C14296CAE00537AE7 /* network_star.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CA04819BD700A8000D /* network_star.h */; }; AEB4A16D14296CAE00537AE7 /* NetworkGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CC04819BD700A8000D /* NetworkGameProtocol.h */; }; - AEB4A16E14296CAE00537AE7 /* RingGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CE04819BD700A8000D /* RingGameProtocol.h */; }; AEB4A16F14296CAE00537AE7 /* StarGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5D004819BD700A8000D /* StarGameProtocol.h */; }; AEB4A17014296CAE00537AE7 /* AStream.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E404819EBF00A8000D /* AStream.h */; }; AEB4A17114296CAE00537AE7 /* TickBasedCircularQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E904819F2300A8000D /* TickBasedCircularQueue.h */; }; @@ -1960,7 +1953,6 @@ AEB4A22814296CAE00537AE7 /* OGL_Subst_Texture_Def.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DF290F0046F5C5B00000104 /* OGL_Subst_Texture_Def.cpp */; }; AEB4A22914296CAE00537AE7 /* network_star_hub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C804819BD700A8000D /* network_star_hub.cpp */; }; AEB4A22A14296CAE00537AE7 /* network_star_spoke.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C904819BD700A8000D /* network_star_spoke.cpp */; }; - AEB4A22C14296CAE00537AE7 /* RingGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CD04819BD700A8000D /* RingGameProtocol.cpp */; }; AEB4A22D14296CAE00537AE7 /* StarGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CF04819BD700A8000D /* StarGameProtocol.cpp */; }; AEB4A22E14296CAE00537AE7 /* AStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5E304819EBF00A8000D /* AStream.cpp */; }; AEB4A23014296CAE00537AE7 /* CircularByteBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EFEF1AC504AF552D00C3A19D /* CircularByteBuffer.cpp */; }; @@ -2201,7 +2193,6 @@ AEBDC5A52C4DF0780026DFF1 /* OGL_Texture_Def.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DF290E9046F5BED00000104 /* OGL_Texture_Def.h */; }; AEBDC5A62C4DF0780026DFF1 /* network_star.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CA04819BD700A8000D /* network_star.h */; }; AEBDC5A72C4DF0780026DFF1 /* NetworkGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CC04819BD700A8000D /* NetworkGameProtocol.h */; }; - AEBDC5A82C4DF0780026DFF1 /* RingGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CE04819BD700A8000D /* RingGameProtocol.h */; }; AEBDC5A92C4DF0780026DFF1 /* StarGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5D004819BD700A8000D /* StarGameProtocol.h */; }; AEBDC5AA2C4DF0780026DFF1 /* AStream.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E404819EBF00A8000D /* AStream.h */; }; AEBDC5AB2C4DF0780026DFF1 /* TickBasedCircularQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E904819F2300A8000D /* TickBasedCircularQueue.h */; }; @@ -2391,7 +2382,6 @@ AEBDC6662C4DF0780026DFF1 /* network_star_hub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C804819BD700A8000D /* network_star_hub.cpp */; }; AEBDC6672C4DF0780026DFF1 /* InfoTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27FF265E1B6F170600DA0A19 /* InfoTree.cpp */; }; AEBDC6682C4DF0780026DFF1 /* network_star_spoke.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C904819BD700A8000D /* network_star_spoke.cpp */; }; - AEBDC6692C4DF0780026DFF1 /* RingGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CD04819BD700A8000D /* RingGameProtocol.cpp */; }; AEBDC66A2C4DF0780026DFF1 /* StarGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CF04819BD700A8000D /* StarGameProtocol.cpp */; }; AEBDC66B2C4DF0780026DFF1 /* lua_music.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE96370B2A39578600DE43FF /* lua_music.cpp */; }; AEBDC66C2C4DF0780026DFF1 /* AStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5E304819EBF00A8000D /* AStream.cpp */; }; @@ -2627,7 +2617,6 @@ AEC3C7A509AD68AC003258E4 /* OGL_Texture_Def.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DF290E9046F5BED00000104 /* OGL_Texture_Def.h */; }; AEC3C7A609AD68AC003258E4 /* network_star.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CA04819BD700A8000D /* network_star.h */; }; AEC3C7A709AD68AC003258E4 /* NetworkGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CC04819BD700A8000D /* NetworkGameProtocol.h */; }; - AEC3C7A809AD68AC003258E4 /* RingGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CE04819BD700A8000D /* RingGameProtocol.h */; }; AEC3C7A909AD68AC003258E4 /* StarGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5D004819BD700A8000D /* StarGameProtocol.h */; }; AEC3C7AA09AD68AC003258E4 /* AStream.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E404819EBF00A8000D /* AStream.h */; }; AEC3C7AB09AD68AC003258E4 /* TickBasedCircularQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E904819F2300A8000D /* TickBasedCircularQueue.h */; }; @@ -2768,7 +2757,6 @@ AEC3C85509AD68AC003258E4 /* OGL_Subst_Texture_Def.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DF290F0046F5C5B00000104 /* OGL_Subst_Texture_Def.cpp */; }; AEC3C85609AD68AC003258E4 /* network_star_hub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C804819BD700A8000D /* network_star_hub.cpp */; }; AEC3C85709AD68AC003258E4 /* network_star_spoke.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C904819BD700A8000D /* network_star_spoke.cpp */; }; - AEC3C85909AD68AC003258E4 /* RingGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CD04819BD700A8000D /* RingGameProtocol.cpp */; }; AEC3C85A09AD68AC003258E4 /* StarGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CF04819BD700A8000D /* StarGameProtocol.cpp */; }; AEC3C85B09AD68AC003258E4 /* AStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5E304819EBF00A8000D /* AStream.cpp */; }; AEC3C85D09AD68AC003258E4 /* CircularByteBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EFEF1AC504AF552D00C3A19D /* CircularByteBuffer.cpp */; }; @@ -2940,7 +2928,6 @@ AEFD867913EB84CF00C1E687 /* OGL_Texture_Def.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DF290E9046F5BED00000104 /* OGL_Texture_Def.h */; }; AEFD867A13EB84CF00C1E687 /* network_star.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CA04819BD700A8000D /* network_star.h */; }; AEFD867B13EB84CF00C1E687 /* NetworkGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CC04819BD700A8000D /* NetworkGameProtocol.h */; }; - AEFD867C13EB84CF00C1E687 /* RingGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5CE04819BD700A8000D /* RingGameProtocol.h */; }; AEFD867D13EB84CF00C1E687 /* StarGameProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5D004819BD700A8000D /* StarGameProtocol.h */; }; AEFD867E13EB84CF00C1E687 /* AStream.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E404819EBF00A8000D /* AStream.h */; }; AEFD867F13EB84CF00C1E687 /* TickBasedCircularQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2EF5E904819F2300A8000D /* TickBasedCircularQueue.h */; }; @@ -3099,7 +3086,6 @@ AEFD873413EB84CF00C1E687 /* OGL_Subst_Texture_Def.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DF290F0046F5C5B00000104 /* OGL_Subst_Texture_Def.cpp */; }; AEFD873513EB84CF00C1E687 /* network_star_hub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C804819BD700A8000D /* network_star_hub.cpp */; }; AEFD873613EB84CF00C1E687 /* network_star_spoke.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5C904819BD700A8000D /* network_star_spoke.cpp */; }; - AEFD873813EB84CF00C1E687 /* RingGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CD04819BD700A8000D /* RingGameProtocol.cpp */; }; AEFD873913EB84CF00C1E687 /* StarGameProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5CF04819BD700A8000D /* StarGameProtocol.cpp */; }; AEFD873A13EB84CF00C1E687 /* AStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF2EF5E304819EBF00A8000D /* AStream.cpp */; }; AEFD873C13EB84CF00C1E687 /* CircularByteBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EFEF1AC504AF552D00C3A19D /* CircularByteBuffer.cpp */; }; @@ -3489,8 +3475,6 @@ EF2EF5C904819BD700A8000D /* network_star_spoke.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = network_star_spoke.cpp; path = ../Source_Files/Network/network_star_spoke.cpp; sourceTree = ""; }; EF2EF5CA04819BD700A8000D /* network_star.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = network_star.h; path = ../Source_Files/Network/network_star.h; sourceTree = ""; }; EF2EF5CC04819BD700A8000D /* NetworkGameProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkGameProtocol.h; path = ../Source_Files/Network/NetworkGameProtocol.h; sourceTree = ""; }; - EF2EF5CD04819BD700A8000D /* RingGameProtocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RingGameProtocol.cpp; path = ../Source_Files/Network/RingGameProtocol.cpp; sourceTree = ""; }; - EF2EF5CE04819BD700A8000D /* RingGameProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RingGameProtocol.h; path = ../Source_Files/Network/RingGameProtocol.h; sourceTree = ""; }; EF2EF5CF04819BD700A8000D /* StarGameProtocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StarGameProtocol.cpp; path = ../Source_Files/Network/StarGameProtocol.cpp; sourceTree = ""; }; EF2EF5D004819BD700A8000D /* StarGameProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StarGameProtocol.h; path = ../Source_Files/Network/StarGameProtocol.h; sourceTree = ""; }; EF2EF5E304819EBF00A8000D /* AStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AStream.cpp; sourceTree = ""; }; @@ -4318,7 +4302,6 @@ F52214520136C0C401000001 /* Headers */, AE9A39F60CCADFA7004717E3 /* ConnectPool.cpp */, 275A7BD71A60E9B9002EE952 /* HTTP.cpp */, - EF2EF5CD04819BD700A8000D /* RingGameProtocol.cpp */, F5574EFC01F4ED4801FEABBD /* SDL_netx.cpp */, F5574EFE01F4ED6501FEABBD /* SSLP_limited.cpp */, EF2EF5CF04819BD700A8000D /* StarGameProtocol.cpp */, @@ -4348,7 +4331,6 @@ AEDF1A121416FE2200183689 /* HTTP.h */, AE7C21D40BFF686200CE63EC /* Update.h */, EF2EF5CC04819BD700A8000D /* NetworkGameProtocol.h */, - EF2EF5CE04819BD700A8000D /* RingGameProtocol.h */, EFBAF0170485BEA500A8000D /* SDL_netx.h */, EFBAF0180485BEA500A8000D /* SSLP_API.h */, EFBAF0190485BEA500A8000D /* SSLP_Protocol.h */, @@ -4938,7 +4920,6 @@ AE120C302BC77645001873DD /* OGL_Texture_Def.h in Headers */, AE120C312BC77645001873DD /* network_star.h in Headers */, AE120C322BC77645001873DD /* NetworkGameProtocol.h in Headers */, - AE120C332BC77645001873DD /* RingGameProtocol.h in Headers */, AE120C342BC77645001873DD /* StarGameProtocol.h in Headers */, AE120C352BC77645001873DD /* AStream.h in Headers */, AE120C362BC77645001873DD /* TickBasedCircularQueue.h in Headers */, @@ -5153,7 +5134,6 @@ AE1320C92C1CB4D2009D34AA /* OGL_Texture_Def.h in Headers */, AE1320CA2C1CB4D2009D34AA /* network_star.h in Headers */, AE1320CB2C1CB4D2009D34AA /* NetworkGameProtocol.h in Headers */, - AE1320CC2C1CB4D2009D34AA /* RingGameProtocol.h in Headers */, AE1320CD2C1CB4D2009D34AA /* StarGameProtocol.h in Headers */, AE1320CE2C1CB4D2009D34AA /* AStream.h in Headers */, AE1320CF2C1CB4D2009D34AA /* TickBasedCircularQueue.h in Headers */, @@ -5367,7 +5347,6 @@ AE505BCB141D45E600915344 /* OGL_Texture_Def.h in Headers */, AE505BCC141D45E600915344 /* network_star.h in Headers */, AE505BCD141D45E600915344 /* NetworkGameProtocol.h in Headers */, - AE505BCE141D45E600915344 /* RingGameProtocol.h in Headers */, AE505BCF141D45E600915344 /* StarGameProtocol.h in Headers */, AE505BD0141D45E600915344 /* AStream.h in Headers */, AE505BD1141D45E600915344 /* TickBasedCircularQueue.h in Headers */, @@ -5581,7 +5560,6 @@ AEB4A16B14296CAE00537AE7 /* OGL_Texture_Def.h in Headers */, AEB4A16C14296CAE00537AE7 /* network_star.h in Headers */, AEB4A16D14296CAE00537AE7 /* NetworkGameProtocol.h in Headers */, - AEB4A16E14296CAE00537AE7 /* RingGameProtocol.h in Headers */, AEB4A16F14296CAE00537AE7 /* StarGameProtocol.h in Headers */, AEB4A17014296CAE00537AE7 /* AStream.h in Headers */, AEB4A17114296CAE00537AE7 /* TickBasedCircularQueue.h in Headers */, @@ -5796,7 +5774,6 @@ AEBDC5A52C4DF0780026DFF1 /* OGL_Texture_Def.h in Headers */, AEBDC5A62C4DF0780026DFF1 /* network_star.h in Headers */, AEBDC5A72C4DF0780026DFF1 /* NetworkGameProtocol.h in Headers */, - AEBDC5A82C4DF0780026DFF1 /* RingGameProtocol.h in Headers */, AEBDC5A92C4DF0780026DFF1 /* StarGameProtocol.h in Headers */, AEBDC5AA2C4DF0780026DFF1 /* AStream.h in Headers */, AEBDC5AB2C4DF0780026DFF1 /* TickBasedCircularQueue.h in Headers */, @@ -6010,7 +5987,6 @@ AEC3C7A509AD68AC003258E4 /* OGL_Texture_Def.h in Headers */, AEC3C7A609AD68AC003258E4 /* network_star.h in Headers */, AEC3C7A709AD68AC003258E4 /* NetworkGameProtocol.h in Headers */, - AEC3C7A809AD68AC003258E4 /* RingGameProtocol.h in Headers */, AEC3C7A909AD68AC003258E4 /* StarGameProtocol.h in Headers */, AEC3C7AA09AD68AC003258E4 /* AStream.h in Headers */, AEC3C7AB09AD68AC003258E4 /* TickBasedCircularQueue.h in Headers */, @@ -6224,7 +6200,6 @@ AEFD867913EB84CF00C1E687 /* OGL_Texture_Def.h in Headers */, AEFD867A13EB84CF00C1E687 /* network_star.h in Headers */, AEFD867B13EB84CF00C1E687 /* NetworkGameProtocol.h in Headers */, - AEFD867C13EB84CF00C1E687 /* RingGameProtocol.h in Headers */, AEFD867D13EB84CF00C1E687 /* StarGameProtocol.h in Headers */, AEFD867E13EB84CF00C1E687 /* AStream.h in Headers */, AEFD867F13EB84CF00C1E687 /* TickBasedCircularQueue.h in Headers */, @@ -6910,7 +6885,6 @@ AE120CEF2BC77645001873DD /* network_star_hub.cpp in Sources */, AE120CF02BC77645001873DD /* InfoTree.cpp in Sources */, AE120CF12BC77645001873DD /* network_star_spoke.cpp in Sources */, - AE120CF22BC77645001873DD /* RingGameProtocol.cpp in Sources */, AE120CF32BC77645001873DD /* StarGameProtocol.cpp in Sources */, AE120CF42BC77645001873DD /* lua_music.cpp in Sources */, AE120CF52BC77645001873DD /* AStream.cpp in Sources */, @@ -7140,7 +7114,6 @@ AE1321892C1CB4D2009D34AA /* network_star_hub.cpp in Sources */, AE13218A2C1CB4D2009D34AA /* InfoTree.cpp in Sources */, AE13218B2C1CB4D2009D34AA /* network_star_spoke.cpp in Sources */, - AE13218C2C1CB4D2009D34AA /* RingGameProtocol.cpp in Sources */, AE13218D2C1CB4D2009D34AA /* StarGameProtocol.cpp in Sources */, AE13218E2C1CB4D2009D34AA /* lua_music.cpp in Sources */, AE13218F2C1CB4D2009D34AA /* AStream.cpp in Sources */, @@ -7369,7 +7342,6 @@ AE505C88141D45E600915344 /* network_star_hub.cpp in Sources */, 27FF26611B6F170600DA0A19 /* InfoTree.cpp in Sources */, AE505C89141D45E600915344 /* network_star_spoke.cpp in Sources */, - AE505C8B141D45E600915344 /* RingGameProtocol.cpp in Sources */, AE505C8C141D45E600915344 /* StarGameProtocol.cpp in Sources */, AE96370E2A39578600DE43FF /* lua_music.cpp in Sources */, AE505C8D141D45E600915344 /* AStream.cpp in Sources */, @@ -7606,7 +7578,6 @@ AEB4A22914296CAE00537AE7 /* network_star_hub.cpp in Sources */, 27FF26621B6F170600DA0A19 /* InfoTree.cpp in Sources */, AEB4A22A14296CAE00537AE7 /* network_star_spoke.cpp in Sources */, - AEB4A22C14296CAE00537AE7 /* RingGameProtocol.cpp in Sources */, AEB4A22D14296CAE00537AE7 /* StarGameProtocol.cpp in Sources */, AE96370F2A39578600DE43FF /* lua_music.cpp in Sources */, AEB4A22E14296CAE00537AE7 /* AStream.cpp in Sources */, @@ -7836,7 +7807,6 @@ AEBDC6662C4DF0780026DFF1 /* network_star_hub.cpp in Sources */, AEBDC6672C4DF0780026DFF1 /* InfoTree.cpp in Sources */, AEBDC6682C4DF0780026DFF1 /* network_star_spoke.cpp in Sources */, - AEBDC6692C4DF0780026DFF1 /* RingGameProtocol.cpp in Sources */, AEBDC66A2C4DF0780026DFF1 /* StarGameProtocol.cpp in Sources */, AEBDC66B2C4DF0780026DFF1 /* lua_music.cpp in Sources */, AEBDC66C2C4DF0780026DFF1 /* AStream.cpp in Sources */, @@ -8065,7 +8035,6 @@ AEC3C85609AD68AC003258E4 /* network_star_hub.cpp in Sources */, 27FF26631B6F1E0700DA0A19 /* InfoTree.cpp in Sources */, AEC3C85709AD68AC003258E4 /* network_star_spoke.cpp in Sources */, - AEC3C85909AD68AC003258E4 /* RingGameProtocol.cpp in Sources */, AEC3C85A09AD68AC003258E4 /* StarGameProtocol.cpp in Sources */, AE96370C2A39578600DE43FF /* lua_music.cpp in Sources */, AEC3C85B09AD68AC003258E4 /* AStream.cpp in Sources */, @@ -8294,7 +8263,6 @@ AEFD873513EB84CF00C1E687 /* network_star_hub.cpp in Sources */, 27FF26601B6F170600DA0A19 /* InfoTree.cpp in Sources */, AEFD873613EB84CF00C1E687 /* network_star_spoke.cpp in Sources */, - AEFD873813EB84CF00C1E687 /* RingGameProtocol.cpp in Sources */, AEFD873913EB84CF00C1E687 /* StarGameProtocol.cpp in Sources */, AE96370D2A39578600DE43FF /* lua_music.cpp in Sources */, AEFD873A13EB84CF00C1E687 /* AStream.cpp in Sources */, diff --git a/Source_Files/Misc/preferences.cpp b/Source_Files/Misc/preferences.cpp index 2e84bbd17..f3a4dc7d6 100644 --- a/Source_Files/Misc/preferences.cpp +++ b/Source_Files/Misc/preferences.cpp @@ -75,7 +75,6 @@ May 22, 2003 (Woody Zenfell): #include "InfoTree.h" #include "StarGameProtocol.h" -#include "RingGameProtocol.h" #include "tags.h" #include "Logging.h" @@ -123,8 +122,7 @@ using namespace alephone; static const char sPasswordMask[] = "reverof nohtaram"; static const char* sNetworkGameProtocolNames[] = -{ // These should match up with _network_game_protocol_ring, etc. - "ring", +{ // These should match up with _network_game_protocol_star, etc. "star" }; @@ -3958,7 +3956,6 @@ InfoTree network_preferences_tree() root.add_color("color", network_preferences->metaserver_colors[i], i); root.put_child("star_protocol", StarPreferencesTree()); - root.put_child("ring_protocol", RingPreferencesTree()); return root; } @@ -4122,7 +4119,6 @@ static void default_network_preferences(network_preferences_data *preferences) preferences->game_protocol= _network_game_protocol_default; #if !defined(DISABLE_NETWORKING) DefaultStarPreferences(); - DefaultRingPreferences(); #endif // !defined(DISABLE_NETWORKING) preferences->use_netscript = false; preferences->netscript_file[0] = '\0'; @@ -4993,8 +4989,6 @@ void parse_network_preferences(InfoTree root, std::string version) for (const InfoTree &child : root.children_named("star_protocol")) StarGameProtocol::ParsePreferencesTree(child, version); - for (const InfoTree &child : root.children_named("ring_protocol")) - RingGameProtocol::ParsePreferencesTree(child, version); } void parse_environment_preferences(InfoTree root, std::string version) diff --git a/Source_Files/Misc/preferences.h b/Source_Files/Misc/preferences.h index e8932eea7..5269be2ff 100644 --- a/Source_Files/Misc/preferences.h +++ b/Source_Files/Misc/preferences.h @@ -103,7 +103,6 @@ struct graphics_preferences_data }; enum { - _network_game_protocol_ring, _network_game_protocol_star, NUMBER_OF_NETWORK_GAME_PROTOCOLS, diff --git a/Source_Files/Network/Makefile.am b/Source_Files/Network/Makefile.am index 3f9e987c0..a2584ceb4 100644 --- a/Source_Files/Network/Makefile.am +++ b/Source_Files/Network/Makefile.am @@ -8,14 +8,14 @@ libnetwork_a_SOURCES = ConnectPool.h network.h network_capabilities.h \ network_data_formats.h network_dialog_widgets_sdl.h network_dialogs.h \ network_distribution_types.h network_games.h network_lookup_sdl.h \ network_messages.h network_private.h network_star.h NetworkGameProtocol.h \ - RingGameProtocol.h SDL_netx.h SSLP_API.h SSLP_Protocol.h StarGameProtocol.h \ + SDL_netx.h SSLP_API.h SSLP_Protocol.h StarGameProtocol.h \ Update.h HTTP.h PortForward.h Pinger.h \ \ ConnectPool.cpp network.cpp network_capabilities.cpp \ network_data_formats.cpp network_dialogs.cpp network_dialog_widgets_sdl.cpp \ network_games.cpp network_lookup_sdl.cpp network_messages.cpp \ network_star_hub.cpp network_star_spoke.cpp network_udp.cpp \ - RingGameProtocol.cpp SDL_netx.cpp SSLP_limited.cpp StarGameProtocol.cpp \ + SDL_netx.cpp SSLP_limited.cpp StarGameProtocol.cpp \ Update.cpp HTTP.cpp PortForward.cpp Pinger.cpp EXTRA_libnetwork_a_SOURCES = network_dummy.cpp diff --git a/Source_Files/Network/RingGameProtocol.cpp b/Source_Files/Network/RingGameProtocol.cpp deleted file mode 100644 index d07a9359b..000000000 --- a/Source_Files/Network/RingGameProtocol.cpp +++ /dev/null @@ -1,2435 +0,0 @@ -/* - * network_ring.cpp - - Copyright (C) 1991-2003 and beyond by Bungie Studios, Inc. - and the "Aleph One" developers. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - This license is contained in the file "COPYING", - which is included with this source code; it is available online at - http://www.gnu.org/licenses/gpl.html - - * File created by Woody Zenfell, III on Sat May 17 2003: split out from network.cpp. - * - * Implementation of the old ring-topology network game protocol, as a module in the new scheme. - */ - -#if !defined(DISABLE_NETWORKING) - -#include "cseries.h" - -#include "RingGameProtocol.h" - -#include "ActionQueues.h" -#include "player.h" // GetRealActionQueues -#include "network.h" -#include "network_private.h" -#include "network_data_formats.h" -#include "mytm.h" -#include "map.h" // TICKS_PER_SECOND -#include "vbl.h" // parse_keymap -#include "interface.h" // process_action_flags -#include "InfoTree.h" -#include "Logging.h" - -// Optional features, disabled by default on Mac to preserve existing behavior (I hope ;) ) -#undef NETWORK_ADAPTIVE_LATENCY_2 // use this one instead; it should be good. no wait... -#define NETWORK_ADAPTIVE_LATENCY_3 // there, this one ought to get it right, finally. -#undef NETWORK_USE_RECENT_FLAGS // if the game stalls, use flags at the end of the stall, not the more stale ones at the beginning -#define NETWORK_SMARTER_FLAG_DITCHING // this mechanism won't be quite as hasty to toss flags as Bungie's - -// ZZZ: This structure is never placed on the wire, so you can do whatever you want with it -// without having to worry about updating additional structures. -struct NetStatus -{ - /* we receive packets from downring and send them upring */ - NetAddrBlock upringAddress, downringAddress; - int16 upringPlayerIndex; - - int32 lastValidRingSequence; /* the sequence number of the last valid ring packet we received */ - int32 ringPacketCount; /* the number of ring packets we have received */ - - bool receivedAcknowledgement; /* true if we received a valid acknowledgement for the last ring packet we sent */ - bool canForwardRing; - bool clearToForwardRing; /* true if we are the server and we got a valid ring packet but we didn’t send it */ - bool acceptPackets; /* true if we want to get packets */ - bool acceptRingPackets; /* true if we want to get ring packets */ - bool oldSelfSendStatus; - - int16 retries; - - int16 action_flags_per_packet; - int16 last_extra_flags; - int16 update_latency; - - bool iAmTheServer; - bool single_player; /* Set true if I dropped everyone else. */ - short server_player_index; - int16 new_packet_tag; /* Valid _only_ if you are the server, and is only set when you just became the server. */ - - uint8 *buffer; - - int32 localNetTime; - bool worldUpdate; -}; -typedef struct NetStatus NetStatus, *NetStatusPtr; - -// ZZZ: I believe this is never placed on the wire either. If I have not come back and changed -// this note, that's probably right. :) -struct NetQueue -{ - int16 read_index, write_index; - int32 buffer[NET_QUEUE_SIZE]; -}; -typedef struct NetQueue NetQueue, *NetQueuePtr; - -static volatile NetStatusPtr status; - -struct RingPreferences -{ - bool mAcceptPacketsFromAnyone; - bool mAdaptToLatency; - int32 mLatencyHoldTicks; -}; - -static RingPreferences sRingPreferences; - -// ZZZ: note: these will always be used in _NET (packed) format. Fortunately, the existing code only -// works directly with these in a few very specific places, so it's reasonable to hold this invariant. -// Observe that these are only used in the preparation of _outgoing_ frames. They are read only (umm, -// those are two words, not "read-only") in -// special circumstances - when debugging code wants to see what was ACKed, or when we've retried the -// upring player too many times and want to drop him (in which case we modify the ringFrame and pass it -// to the upring's upring). -static DDPFramePtr ackFrame, ringFrame; /* ddp frames for sending ring/acknowledgement packets */ -static DDPFramePtr distributionFrame; - -// ZZZ: On packet reception, we copy the _NET (packed) data into the local preferred format. This is -// the storage for the unpacked copy. Note that few folks refer to it directly - usually a pointer -// to the unpacked data (i.e. into this buffer) is passed along as an argument. -static char unpackedReceiveBuffer[ddpMaxData]; - -// ZZZ note: originally in IPring, I had every function that dealt with network data packing and unpacking -// its own stuff. That's probably easier to follow and more correct, but there are a few problems: -// 1) It requires more changes to the original code. -// 2) It requires that the original code be VERY carefully combed-through to catch all references. -// 3) It requires a lot of extra byte-swapping and copying (to and from non-aligned structures). - -// Now, as noted above, I am trying to convert an entire incoming/outgoing packet only just after it arrives -// or just before it leaves. This should help with all three issues just mentioned. - -// ZZZ random observation #3,792: -// Why use datagrams if we're not going to change the data we retransmit? We might as well just use -// TCP and save ourselves some hassle, don'cha think?? I don't really see any other reason we would -// want to take over the task of handling ACKs and retransmissions... there's not any clever -// "implicit ACK" mechanism or updating of data between retransmissions going on here, and I don't -// think retransmission timing here is customized in any way that would be preferable over TCP's -// behavior...? - -// ZZZ: observe: only one of {server, queueing} should be active at a time. -// NetServerTask is used only on, you guessed it, the server. NetQueueingTask is used on all others. -// Everyone uses NetCheckResendRingPacket to retransmit the ring packet if no ACK has come in. -// (Distribution datagrams currently are only 'lossy', so no ACKs or retransmissions are used there.) - -static myTMTaskPtr resendTMTask = (myTMTaskPtr) NULL; -static myTMTaskPtr serverTMTask = (myTMTaskPtr) NULL; -static myTMTaskPtr queueingTMTask= (myTMTaskPtr) NULL; - -// ZZZ: observe: in a ring topology especially, everyone must treat the ring token as a 'hot potato' - i.e. -// deal with it and pass it on ASAP - to avoid introducing ring latency (which of course impacts all hosts). -// This is why we use separately scheduled elements (like the original) and don't depend on occasional polling -// from the main thread (e.g. between frames). -// In a star (client-server) topology, this should be less of an issue, since overall latency would be related -// to the slowest station's latency, rather than the sum of everyone's latency. -// We want these scheduling elements to have higher priority than the main thread to make sure they are -// scheduled as close as possible to the time they ought to be scheduled. SDL_Thread provides no mechanism -// to alter thread priority currently. I guess we'll either have to extend it somehow, or else pray that -// the OS considers these occasionally-runnable threads I/O-bound and the constantly-working main thread -// CPU-bound, and boosts these threads' priority appropriately. -// (Update: I'm now boosting thread priorities programmatically - see SDL_threadx.) - - -// ZZZ annotation: this holds action_flags we've captured (e.g. in NetQueueingTask) that have not been placed -// into a ring packet yet. We don't get to process our own action_flags until they've been queued here, sent -// around the ring in the ring packet, and come back to us in NetDDPPacketHandler. -static volatile NetQueue local_queue; - -// ZZZ addition: here we fake having another queue. The idea here is that if the ring comes around and we need -// to "smear", we effectively extend the NetQueueingTask "credit" of a sort. NQT, when it does run, will see -// that it "owes" us some action_flags, and will work with this pseudo-queue rather than with the real local_queue. -// Of course, it won't bother getting or storing real action_flags, since the packet handler already did that. -// This way we avoid pumping too many action_flags into the pipeline. -// Note that this is based on the idea that NQT will run, on average, n times in n periods - it just may be a little more -// jittery than we'd like. In the SDL version this is true. In the 'classic' Mac version, well, I'm not sure -// what the Time Manager does if it misses a deadline. If it runs its task an extra time, this is the way to go. -// If it shrugs and the call for that period is lost forever, it should NOT use this mechanism. -// In the spirit of leaving things alone if they work, I'll leave this just as an IPring thing for now. -#ifdef NETWORK_FAUX_QUEUE -static volatile uint32 faux_queue_due; // packet handler increments each time it smears -static volatile uint32 faux_queue_paid; // NQT increments this each time it throws away action_flags instead of queueing them -#endif - -// ZZZ annotation: I suspect these were used for something like what I'm about to do again. -// I'm putting in my own system (NETWORK_ADAPTIVE_LATENCY) though to make sure I understand all the interactions. -// Besides, it looks like these values never "adapt". -static short initial_updates_per_packet = UPDATES_PER_PACKET; -static short initial_update_latency = UPDATE_LATENCY; - -// ZZZ addition: adaptive latency mechanism. Here's the problem. We want to minimize latency, but also mask -// jitter (i.e. variation in latency). If we see too much latency, the game will feel "sluggish" in the sense -// that your player will respond late to all your commands - might feel sort of like "driving a boat". -// OTOH if we keep latency at the absolute minimum, we expose ourselves to jitter - if there's a "burp" in -// the system somewhere (either in the network or in an endsystem's scheduling), the game freezes up for the -// duration of that burp. If small burps happen frequently, we might be better off adding an extra frame of -// latency to smooth over all those little burps. - -// Before I begin my changes, let me review how things are working (at least with the way the SDL version -// schedules things). - -// If a non-server has a *scheduling* burp, that means we see a too-long period with no calls to NetQueueingTask, -// followed by a bunch of calls to NQT to make up for the losses. - -// If a ring packet (maybe more than one, depending on the nature of the burp) arrived and was processed during -// that dry spell, we "smeared" - the packet handler grabbed however many input_flags it needed directly from -// the input system instead of taking from the queue that NQT fills (because the queue was empty/not full enough). -// The extra calls to NQT at the end of the dry spell will go into the regular local_queue, but will probably be -// discarded the next time we feed the ring since we'll have too many flags waiting. - -// Endstations upring (i.e. which receive the ring packet later) from the burper will (assuming they are not -// simultaneously burping :) ) queue up a bunch of action_flags as normal in NQT while they wait. (Note that this also applies to -// a situation where network congestion causes a burp "between" stations - e.g. we have to retransmit due to -// lack of ACK, etc.) When the ring packet gets around to the next endstations, they will discard the oldest -// action_flags and pass along only the newest few (if my NETWORK_USE_RECENT_FLAGS change is active - it used to -// pass along the oldest ones and throw out the newer ones.) So far, everything looks peachy - we've had to -// freeze our animation while the burp happened, but at least we're not introducing any new latency (i.e. -// we are making sure our local queue is as empty as possible by throwing away extra flags, etc.) - -// The problem comes when we look at the server (and NetServerTask). It makes no effort to empty its queue -// currently - instead, when the ring comes back to it after a burp, it has a lot of extra flags waiting to -// go. Instead of ditching the old ones, it sends them _all_ along, and tells the non-servers (via the packet's -// required_action_flags) that they owe a lot of flags. So, when the ring packet gets to them, and they don't -// have enough flags, they "smear" to make up the difference. The end result is that a lot of extra flags -// end up in the "player" queue - the one where flags sit after being received from the network but before being acted -// on by the main game code. The main game takes from that queue only at the TICK rate, so if there are extra -// flags sitting there, any new flags will have to wait to be acted on until they make their way through the -// queue - hello latency. - -// Here's my crack at a solution. The server is responsible for making the decisions here. - -// Simply ditching old flags at the server the way we do at endstations seems like the simplest way, but I -// believe it has an important drawback: what if the latency in the ring is greater than the duration of a -// TICK? What if the average latency in the ring is less than the duration of a TICK, but we tend to jitter -// a fair amount over the TICK duration (but, we hope, not much more)? In the former case, the game would -// proceed at half the normal TICK rate (or worse) because endstations would be constantly starved for data, -// and thus would be stalling the game all the time. In the latter case, we wouldn't be stalling *all* the -// time, but every time we jittered past the TICK duration - too frequently to make playing pleasant. - -// What we need is to adapt to the network conditions - if we seem to be starving a lot, we want to bump up -// the number of action_flags in our queues so we can use the extras to smooth over the gaps. OTOH though -// if conditions improve, we want to reduce the number of flags so we don't have gratuitous extra latency -// between player inputs and screen updates. I think one could argue that the code I inherited did the -// first part just fine, but never readjusted the queue size back down to remove latency when possible. -// (Perhaps this is what Jason's comment in the header means? "(can only be adjusted upward, not downward)") - -// Maybe on the cooperatively-scheduled Mac, using very-low-latency interrupts to do time-sensitive processing, -// burps were uncommon. But on most systems, our code will probably get scheduled erraticly, so we need to -// be more jitter-tolerant. In particular, we don't want a big burp to build a whole bunch of latency in -// to the rest of the game, if we can recover from it (exposing ourselves to another big burp later, but we -// hope that those are uncommon enough that we'd rather have a responsive game between stalls than a sluggish -// game that is unaffected by stalls). - -// Actually this is all building a compelling argument for changing from a ring to a star, since endstation -// latency in a star has much less impact on the overall system (which here I use to mean all machines involved) -// that does endstation latency in a ring, especially as the number of endstations grows. - -// So here's how my scheme works: we maintain a sampling window of how many TICKs it's actually taken the ring -// to go around (remember, this is all done by the server). As this window slides along in time, we track -// (1) the number of rings that needed more time than we're currently allowing, and -// (2) the number of rings that actually needed the amount of time we're allowing (i.e. that were not 'early' -// by a tick or more). -// If (1) exceeds some threshhold, we add in another required_action_flag, so the queue grows a little longer -// to tolerate constant latency or frequent jitter. -// OTOH if (2) is less than some threshhold, we reduce the number of required_action_flags, so the queue -// shrinks and we have less overall latency. -// Update: instead of using the count of rings that were early or late, we just use the average ring latency -// and compare it to our current setting. That way we can reuse our window data without having to go -// touch all the samples to recalculate stuff. (Not that it would really take all *that* long, but...) - -// I use these same things, slightly differently in the code, to do NETWORK_ADAPTIVE_LATENCY_2 (see below). -#if defined(NETWORK_ADAPTIVE_LATENCY) || defined(NETWORK_ADAPTIVE_LATENCY_2) -enum { - kAdaptiveLatencyWindowSize = 3 * TICKS_PER_SECOND, // number of rings we look at for deciding whether to change latency - kAdaptiveLatencyInitialValue = 1, // our first guess at a good latency value - kAdaptiveLatencyMaximumValue = MAXIMUM_UPDATES_PER_PACKET // cap on the latency value -}; - -// We adjust the ring latency when (average measured ring latency over window) - (current latency setting) -// is greater than the increase threshhold or less than the decrease threshhold. Note that the decrease -// threshhold ought to be < (increase threshhold - 1), or we are likely to bounce back and forth between -// settings. I have set these pretty low, which favors adding latency over allowing choppiness. I suppose -// these could be made more dynamically settable (via MML or dialog-box) to let users decide where they want -// the tradeoff, but I doubt most really care to tweak such settings themselves. -const float kNeedToIncreaseLatencyThreshhold = .1F; -const float kNeedToDecreaseLatencyThreshhold = -.95F; - -static int sAdaptiveLatencySamples[kAdaptiveLatencyWindowSize]; // sample buffer, used much like a circular queue. -static int sAdaptiveLatencyWindowEdge; // so we know where in the sample buffer our window starts/ends - // between calls to update_adaptive_latency, it indicates the head of the queue. -static int sAdaptiveLatencySampleCount; // so we don't try to make decisions without enough samples -static int sAdaptiveLatencyRunningTotal; // total of latencies in the sample window -static volatile int sCurrentAdaptiveLatency; // how many action_flags we want going around in those packets - -// Hmm, now not only am I concerned about the concept of "net time", but I'm worried that the faux-queue idea I implemented -// before is now going to interfere with the adaptive latency scheme, or vice-versa. I mean, if adaptive latency decides that -// we need another action_flag per packet, we're probably going to catch some non-servers unawares, and they'll have to smear -// to meet our requirement (which is fine) - but then when they run their NetQueueingTask, they'll try to pay back for the smear, -// which means they'll have to smear again next time... it's not the end of the world, but it defeats the purpose of calling NQT -// periodically instead of just smearing every time we need data. -// OK OK I convinced myself. Disabling FAUX_QUEUE. That didn't help with erratic server scheduling anyway. -#endif//NETWORK_ADAPTIVE_LATENCY || NETWORK_ADAPTIVE_LATENCY_2 - -// Adaptive latency take 2... heh heh... -// Here's the problem with the first effort. (Or second, if you count FAUX_QUEUE as an effort.) -// It assumes that the engine consumes action_flags at a constant rate, and in particular that if -// the engine starves, it does not take any special steps to catch up later. Au contraire!, it turns -// out (quite sensibly) that the engine, after starving, consumes action_flags voraciously to try to -// catch back up to real game time. So let's try this analysis: - -// Endstations produce action_flags at a constant, but perhaps jittery, rate of one per GAME_TICK. -// Endstations consume action_flags at a constant, but perhaps jittery, rate of one per GAME_TICK. - -// If the ring gets held up somewhere, endstations build up flags in their local_queues. -// The next time it comes around *after reaching the server*, the ring will consume all the extras. -// Observe: this means that, ideally, we should *not* discard action_flags from the local_queue if -// we get the ring packet and we have more than it wants - it should gobble up our extras next time. -// We *could* make sure our extras get eaten - we could increment a counter for every ring that leaves -// us with flags still in our local_queue. (When a ring leaves us empty, we reset the counter.) -// We could consider incrementing the counter by the NUMBER of flags we have left sitting around, so if -// we have somehow gotten a large number jammed in our queue, it corrects more quickly. -// If the counter exceeds a threshhold, we throw away an action_flag from the head of the queue (stale) -// and reset the counter. -// If an endstation takes too long between flag productions, it "smears" when the ring reaches it. -// The endstation thus produces too many flags. If we use the above correction mechanism, we will -// compensate eventually by throwing out extra flags. But if for some reason drift has caused our -// average rate to fall slightly below what's needed, the extra flag or two from smearing will bring -// our production back up to the needed rate - and that in a timely manner. - -// Endstations that take too long between consumption binges build up flags in their player_queues. -// At the next consumption binge, they will eat all the extras. Note that consumption is tied -// directly to production on an endstation - if the production element runs dry for a while, the consumer -// will not be allowed to consume, even if there are queued flags (in player_queues) available. - -// A one-time dry spell and then compensating deluge in the player_queues will be correctly handled by -// the voracious-consumer approach. The game will freeze up during the dry spell, then suddenly lurch -// ahead several frames to get back to the "present". -// It seems like there could be a problem if the consumer drifts from what's coming to it, but I think -// that having the consumer rate tied to the producer rate - and having everyone agree on that rate by -// the server dictating the net_time - gets around any such problems. - -// Actually, I think we should see the following behaviors with regard to net_time: - -// If the server's net_time coming in is greater than ours, we should see ourselves smear... unless we recently -// saw a server net_time less than ours, in which case we have queued flags to make up the difference. -// If the server's net_time coming in is less than ours, we should see ourselves ditch a flag. -// (Note that these may not happen at the same packet arrival, but should be nonetheless linked.) - -// I have now implemented the flag ditching mechanism outlined above: -#ifdef NETWORK_SMARTER_FLAG_DITCHING -static int sFlagDitchingCounter; // reset if local_queue empties; increments by local_queue leftovers otherwise. - -enum { - kFlagDitchingThreshhold = TICKS_PER_SECOND // if counter exceeds this, ditch a flag and reset counter. -}; -#endif -// We're really splitting hairs at this point. I think this is only better than the Bungie mechanism if -// we have several late packets in a row followed by a return to normal - and even then we're just honoring -// the user's input a little more accurately. Oh well, this was probably a poorly spent 15 minutes, but it -// can only help, I think... -// I can convince myself of some pretty odd things if I think about them long enough. ;) - -// Does the net_time mechanism alone solve everything?? - -// dynamic_world is not allowed to get ahead of net_time. -// Suppose we see a ring packet every three GAME_TICKs. The ring packet should carry three action_flags with it. -// Let's watch the action starting at 0 (this may not be EXACTLY what the ring protocol does, since it has special -// startup stuff, but if this bothers you, imagine the latency suddenly jumps up to this level at some time T. -// Our "0", then, is the offset from some point in time T.): - -// NQT queues a local flag. Our local net_time increases. Consumer tries to update dynamic_world, but there's not -// enough data. -// Same thing. Now local net_time is 2, and there are 2 flags in local_queue. player_queue is still empty, so -// dynamic_world cannot update. -// Same thing. net_time is 3, there are 3 flags in local_queue, and player_queue is empty. dynamic_world is oddly still. -// The ring packet comes in! It has a required_flags of 1, and every player's data in the packet has 1 flag in it. -// The server's net time was 1 when the packet was sent. *We set our local net_time to 1.* We move a local_flag into the -// packet and pass the ring on. net_time is 1, there are 2 flags in local_queue, and player_queue has 1. -// NQT queues a local flag. net_time is 2. There are 3 flags in local_queue. -// dynamic_world updates to time 1 - it could try to go to 2, but there's only 1 flag. player_queue is now empty. -// NQT queues a local flag. net_time is 3. There are 4 flags in local_queue. player_queue is empty. dynamic_world is stopped. -// NQT queues a local flag. net_time is 4. There are 5 flags in local_queue. player_queue is empty. dynamic_world is stopped. -// The ring packet comes in! required_flags is 3; every player has 3 flags. The server's net_time was 4. -// Our net_time agrees with the server's. We pack up 3 local_flags for the packet and pass it on. -// net_time = 4, |local_queue| = 2, |player_queue| = 3, DWTC = 1. -// dynamic_world wants to update to time 4, and CAN - it voraciously consumes all 3 player_flags. -// net_time = 4, |local_queue| = 2, |player_queue| = 0, DWTC = 4. -// NQT: net_time = 5, |local_queue| = 3, |player_queue| = 0, DWTC = 4. -// NQT: net_time = 6, |local_queue| = 4, |player_queue| = 0, DWTC = 4. -// NQT: net_time = 7, |local_queue| = 5, |player_queue| = 0, DWTC = 4. -// RING net_time = 7, |local_queue| = 2, |player_queue| = 3, DWTC = 4. -// DRAW net_time = 7, |local_queue| = 2, |player_queue| = 0, DWTC = 7. - -// Note: if latency suddenly drops back to 1 GAME_TICK per ring, the extra flags in local_queue will drain, and DWTC -// will be able to track net_time more closely. -// If instead latency stays high, we will eventually discard the extra elements in local_queue, reducing overall -// user-input-to-screen-update latency. - -// Note: if bandwidth is no problem but latency is high ("long fat pipe"?), we could have multiple updates "on the wire" -// at a time, thus letting DWTC remain in sync with net_time -> smoother updates. Our net_time would stay a few ticks -// behind the server's net_time. - -// OK, this behavior is not so good because we're only drawing the screen at 10fps (once every 3 GAME_TICKs). -// Options are to speculatively update dynamic_world, thus letting DWTC track net_time (but without "real data" to go on), (HARD), -// or to delay the engine's view of net_time by some amount (EASY), introducing even more latency but smoothing out the frames. - -// How do we decide to raise or lower the amount of delay? -// Should be based on, when a packet comes in, how many player_flags there are? How DWTC compares to (net_time - delay)? - -// We would want to see -// INIT net_time = 4, |local_queue| = 2, |player_queue| = 0, DWTC = 4. -// NQT: net_time = 5, |local_queue| = 3, |player_queue| = 0, DWTC = 4. -// NQT: net_time = 6, |local_queue| = 4, |player_queue| = 0, DWTC = 4. -// NQT: net_time = 7, |local_queue| = 5, |player_queue| = 0, DWTC = 4. -// RING net_time = 7, |local_queue| = 2, |player_queue| = 3, DWTC = 4. -// DRAW net_time = 7, |local_queue| = 2, |player_queue| = 2, DWTC = 5. -// NQT: net_time = 8, |local_queue| = 3, |player_queue| = 2, DWTC = 5. -// DRAW net_time = 8, |local_queue| = 3, |player_queue| = 1, DWTC = 6. -// NQT: net_time = 9, |local_queue| = 4, |player_queue| = 1, DWTC = 6. -// DRAW net_time = 9, |local_queue| = 4, |player_queue| = 0, DWTC = 7. -// NQT: net_time = 10,|local_queue| = 5, |player_queue| = 0, DWTC = 7. -// RING net_time = 10,|local_queue| = 2, |player_queue| = 3, DWTC = 7. -// DRAW net_time = 10,|local_queue| = 2, |player_queue| = 2, DWTC = 8. -// NQT: net_time = 11,|local_queue| = 3, |player_queue| = 2, DWTC = 8. -// DRAW net_time = 11,|local_queue| = 3, |player_queue| = 1, DWTC = 9. -// NQT: net_time = 12,|local_queue| = 4, |player_queue| = 1, DWTC = 9. -// DRAW net_time = 12,|local_queue| = 4, |player_queue| = 0, DWTC = 10. -// NQT: net_time = 13,|local_queue| = 5, |player_queue| = 0, DWTC = 10. - -// Looks like it should be based on (required_action_flags - delay) - try to make that 0. -// It should be harder to reduce delay than to increase it. - -// This is the basis for NETWORK_ADAPTIVE_LATENCY_2, then: compute (on all stations) when packet -// arrives, based on required_action_flags - delay. USE the delay in NetGetNetTime() to hold the -// reins on the consumer a bit. - - -#ifdef NETWORK_ADAPTIVE_LATENCY_3 -// ZZZ: and now for something completely different... -// Instead of considering average latency as above, we're going to look at the largest -// recent latency value, and go with that for a while. If we don't see any latency value -// that big or bigger for a while, then we'll go with the second-highest latency value we've -// seen recently for a while, etc. -// This ought to handle jittery cases more easily, I think. - -static int sCurrentAdaptiveLatency; -static int sGreatestRecentLatencyMeasurement; -static int sGreatestRecentLatencyTick; -static int sSecondGreatestRecentLatencyMeasurement; -#endif - - -static NetTopology* topology; -static short localPlayerIndex; -static short* sNetStatePtr; - -// XXX (ZZZ): this is a nasty kludge. Originally, I think, NetDDP* interfaces -// dealt in sockets - so one could potentially have multiple open sockets. -// NetDDP* for IP use some "socket" parameters etc. for port numbers instead, -// and in other interfaces (like NetDDPSendFrame()) the socket parameter is ignored. -// Here we exploit the "ignored" property. -static short ddpSocket = 0; - - -// ZZZ: again, buffer is always going to be NetDistributionPacket_NET* -static void NetProcessLossyDistribution(void *buffer); -// ZZZ: this is used to handle an incoming ring packet; it'll always be NetPacket_NET* -static void NetProcessIncomingBuffer(void *buffer, int32 buffer_size, int32 sequence); - -static size_t NetPacketSize(NetPacketPtr packet); -static void NetBuildRingPacket(DDPFramePtr frame, byte *data, size_t data_size, int32 sequence); -static void NetBuildFirstRingPacket(DDPFramePtr frame, int32 sequence); -static void NetRebuildRingPacket(DDPFramePtr frame, short tag, int32 sequence); -static void NetAddFlagsToPacket(NetPacketPtr packet); - -static void NetSendRingPacket(DDPFramePtr frame); -static void NetSendAcknowledgement(DDPFramePtr frame, int32 sequence); - -static bool NetCheckResendRingPacket(void); -static bool NetServerTask(void); -static bool NetQueueingTask(void); - -#if defined(NETWORK_ADAPTIVE_LATENCY) || defined(NETWORK_ADAPTIVE_LATENCY_2) || defined(NETWORK_ADAPTIVE_LATENCY_3) -// ZZZ addition, for adaptive latency business. measurement is only used for adaptive_latency_2 -// tick is used only for adaptive_latency_3. -static void update_adaptive_latency(int measurement = 0, int tick = 0); -#endif//NETWORK_ADAPTIVE_LATENCY || NETWORK_ADAPTIVE_LATENCY_2 || NETWORK_ADAPTIVE_LATENCY_3 - -static short NetAdjustUpringAddressUpwards(void); -static short NetSizeofLocalQueue(void); - -static void process_packet_buffer_flags(void *buffer, int32 buffer_size, short packet_tag); -static void process_flags(NetPacketPtr packet_data); - -/* Note that both of these functions may result in a change of gatherer. the first one is */ -/* called when the other guy hasn't responded after a kRETRY times to our packet, so we */ -/* drop him and if he was gatherer, we become the gatherer. The second function is called */ -/* when the gatherer sends out an unsync packet, but we aren't ready to quit. Therefore we */ -/* must become the gatherer. */ -static void drop_upring_player(void); - -#ifdef DEBUG_NET_RECORD_PROFILE -void record_profile(int raf); -#endif - -#ifdef DEBUG_NET -struct network_statistics { - int32 numSmears; - int32 numCountChanges; - - int32 ontime_acks; - int32 sync_ontime_acks; - int32 time_ontime_acks; - int32 unsync_ontime_acks; - int32 dead_ontime_acks; - - int32 late_acks; - int32 packets_from_the_unknown; - int32 retry_count; - int32 sync_retry_count; - int32 time_retry_count; - int32 unsync_retry_count; - int32 dead_retry_count; - - int32 late_unsync_rings; - int32 late_sync_rings; - int32 late_rings; - int32 late_time_rings; - int32 late_dead_rings; - - int32 change_ring_packet_count; - - int32 rebuilt_server_tag; - int32 packets_with_zero_flags; - - short spurious_unsyncs; - short unsync_while_coming_down; - short upring_drops; - short server_set_required_flags_to_zero; - short unsync_returned_to_sender; - short server_unsyncing; - short assuming_control; - short assuming_control_on_retry; - short server_bailing_early; - - uint32 action_flags_processed; -} net_stats; - -#endif - - -bool -RingGameProtocol::Enter(short* inNetStatePtr) -{ - bool success= false; - sNetStatePtr= inNetStatePtr; - status = (NetStatusPtr)malloc(sizeof(NetStatus)); - if(status) - { - memset(status, 0, sizeof(NetStatus)); - status->buffer = (byte *)malloc(ddpMaxData); - if (status->buffer) - { - ringFrame= NetDDPNewFrame(); - if (ringFrame) - { - ackFrame= NetDDPNewFrame(); - if (ackFrame) - { - distributionFrame= NetDDPNewFrame(); - if (distributionFrame) - { - status->single_player= false; -#ifdef DEBUG_NET - obj_clear(net_stats); -#endif - success= true; - } - } - } - } - } - return success; -} - - -void -RingGameProtocol::Exit1() -{ - /* These functions do the right thing for NULL pointers */ - resendTMTask= myTMRemove(resendTMTask); - serverTMTask= myTMRemove(serverTMTask); - queueingTMTask= myTMRemove(queueingTMTask); -} - - -void -RingGameProtocol::Exit2() -{ -#ifdef DEBUG_NET - NetPrintInfo(); -#endif - - free(status->buffer); - free(status); - status= NULL; - - NetDDPDisposeFrame(ackFrame); - NetDDPDisposeFrame(ringFrame); - NetDDPDisposeFrame(distributionFrame); -} - - -/* - ------- - NetSync - ------- - - (no parameters) - - make sure all players are present (by waiting for the ring to come around twice). this is what - actually jump-starts the ring. - - returns true if we synched successfully. false otherwise. - - ------- - NetUnSync - ------- - - (no parameters) - - called at the end of a network game to ensure a clean exit from the net game. - (we make sure that we don’t quit the game holding the ring packet.) - - */ - -bool -RingGameProtocol::Sync(NetTopology* inTopology, int32 inSmallestGameTick, int inLocalPlayerIndex, int inServerPlayerIndex) -{ - uint32 ticks; - bool success= true; -#ifdef TEST_MODEM - return ModemSync(); -#else - localPlayerIndex= inLocalPlayerIndex; - topology= inTopology; - - // ZZZ: taking the net-time from the dynamic_world; whittling away at network/game code separation again? - // anyway we need to do this for restoring a saved-game, since DWTC won't start at 0 in that case (but - // without the following line, the netTime would have...) Anyway yeah NetSync() is only called after - // the dynamic_world is set up - I'm pretty sure ;) - so this should be ok. - status->localNetTime= inSmallestGameTick; - status->action_flags_per_packet= initial_updates_per_packet; - status->update_latency= initial_update_latency; - status->lastValidRingSequence= 0; - status->ringPacketCount= 0; - status->server_player_index= inServerPlayerIndex; - status->last_extra_flags= 0; - status->worldUpdate = false; - status->acceptPackets= true; /* let the PacketHandler see incoming packets */ - status->acceptRingPackets= true; - local_queue.read_index= local_queue.write_index= 0; -#ifdef NETWORK_FAUX_QUEUE - // ZZZ addition: faux queue mechanism to handle jittery scheduling correctly - faux_queue_due = faux_queue_paid = 0; -#endif - -#if defined(NETWORK_ADAPTIVE_LATENCY) || defined(NETWORK_ADAPTIVE_LATENCY_2) - // ZZZ addition: initialize adaptive latency mechanism - sCurrentAdaptiveLatency = kAdaptiveLatencyInitialValue; - sAdaptiveLatencyRunningTotal = 0; - sAdaptiveLatencySampleCount = 0; - sAdaptiveLatencyWindowEdge = 0; -#endif - -#if defined(NETWORK_ADAPTIVE_LATENCY_3) - // ZZZ addition: initialize adaptive latency mechanism - sCurrentAdaptiveLatency = 0; - sGreatestRecentLatencyTick = 0; - sGreatestRecentLatencyMeasurement = 0; - sSecondGreatestRecentLatencyMeasurement = 0; -#endif - - // Calculate up- and downring neighbors - short previousPlayerIndex, nextPlayerIndex; - - // ZZZ: changes to these to skip players with identifier NONE, in support of generalized resume-game - // (They Might Be Zombies) - /* recalculate downringAddress */ - previousPlayerIndex = localPlayerIndex; - do - { - previousPlayerIndex = (topology->player_count + previousPlayerIndex - 1) % topology->player_count; - } while(topology->players[previousPlayerIndex].identifier == NONE && previousPlayerIndex != localPlayerIndex); - - status->downringAddress= topology->players[previousPlayerIndex].ddpAddress; - - /* recalculate upringAddress */ - nextPlayerIndex = localPlayerIndex; - do - { - nextPlayerIndex = (topology->player_count + nextPlayerIndex + 1) % topology->player_count; - } while(topology->players[nextPlayerIndex].identifier == NONE && nextPlayerIndex != localPlayerIndex); - - status->upringAddress= topology->players[nextPlayerIndex].ddpAddress; - status->upringPlayerIndex = nextPlayerIndex; - - *sNetStatePtr= netStartingUp; - - /* if we are the server (player index zero), start the ring */ - if (localPlayerIndex==status->server_player_index) - { - status->iAmTheServer= true; - - /* act like somebody just sent us this packet */ - status->ringPacketCount= 1; - - NetBuildFirstRingPacket(ringFrame, status->lastValidRingSequence+1); - NetSendRingPacket(ringFrame); - } - else - { - status->iAmTheServer = false; - } - - /* once we get a normal packet, netState will be set, and we can cruise. */ - ticks= machine_tick_count(); - while (success && *sNetStatePtr != netActive) // packet handler changes this variable. - { - if (machine_tick_count() - ticks > NET_SYNC_TIME_OUT) - { - alert_user(infoError, strNETWORK_ERRORS, netErrSyncFailed, 0); - - /* How did Alain do this? */ - status->acceptPackets= false; - status->acceptRingPackets= false; - *sNetStatePtr= netDown; - success= false; - } - } -#endif // ndef TEST_MODEM - - return success; -} - - - -/* - New unsync: - 1) Server tells everyone to give him 0 action flags. - 2) Server then waits for the packet to go all the way around the loop. - */ -bool -RingGameProtocol::UnSync(bool inGraceful, int32 inSmallestPostgameTick) -{ - bool success= true; - uint32 ticks; - -#ifdef TEST_MODEM - success= ModemUnsync(); -#else - - if (*sNetStatePtr==netStartingUp || *sNetStatePtr==netActive) - { - *sNetStatePtr= netComingDown; - - /* Next time the server receives a packet, and if the netState==netComingDown */ - /* the server will send a packet with zero flags, which means process the remaining */ - /* flags, and get ready to change level. Once the packet with zero flags gets back */ - /* to the server, the server sends an unsync ring packet. This will cause all the other */ - /* machines to unsync, and when the server gets the packet back, it turns the net off */ - - ticks= machine_tick_count(); - // we wait until the packet handler changes "acceptPackets" or until we hit a serious - // timeout, in case we are quitting and someone else is refusing to give up the ring. - while((status->acceptRingPackets || !status->receivedAcknowledgement) - && (machine_tick_count()-ticksacceptRingPackets) - { - status->acceptRingPackets= success= false; - } - status->acceptPackets= false; // in case we just timed out. - *sNetStatePtr= netDown; - -#ifdef DEBUG_NET - fdprintf("Flags processed: %d Time: %d;g", net_stats.action_flags_processed, TickCount()-ticks); - net_stats.action_flags_processed= 0; -#endif -#endif // ndef TEST_MODEM - - return success; -} - - - -/* Distribute information to the whole net. */ -void -RingGameProtocol::DistributeInformation( - short type, - void *buffer, - short buffer_size, - bool send_to_self, - bool) -{ - NetDistributionPacket distribution_header; - NetDistributionPacket_NET distribution_header_NET; - -#ifdef TEST_MODEM - ModemDistributeInformation(type, buffer, buffer_size, send_to_self); -#else - - // Sanity Check! Sanity Check! - // Hand Check! Hand Check! - // ZZZ: there ought to be some kind of check here on buffer size, but it should be based on - // the size of the DDP (UDP) packet storage allocated and the sizes of stuff to be crammed in there. - // assert(buffer_size <= MAX_NET_DISTRIBUTION_BUFFER_SIZE); - - // ZZZ: I suppose one could argue that you should be able to send distribution types you don't - // process, but currently anyway this is used to lookup lossless/lossy. Maybe the caller should - // specify lossless/lossy as a parameter to this function rather than associating it with a - // distribution type anyway. The two seem to be at least somewhat independent. - const NetDistributionInfo* theInfo = NetGetDistributionInfoForType(type); - assert(theInfo != NULL); - - if (send_to_self) - { - theInfo->distribution_proc(buffer, buffer_size, localPlayerIndex); - } - - distributionFrame->data_size = sizeof(NetPacketHeader_NET) + sizeof(NetDistributionPacket_NET) + buffer_size; - { - NetPacketHeader_NET* header_NET = (NetPacketHeader_NET*) distributionFrame->data; - NetPacketHeader header_storage; - NetPacketHeader* header = &header_storage; - - header->tag = theInfo->lossy ? tagLOSSY_DISTRIBUTION : tagLOSSLESS_DISTRIBUTION; - header->sequence = 0; - - netcpy(header_NET, header); - } - distribution_header.distribution_type = type; - distribution_header.first_player_index = localPlayerIndex; - distribution_header.data_size = buffer_size; - - // Probably could just netcpy this straight into distributionFrame->data. - netcpy(&distribution_header_NET, &distribution_header); - - memcpy(distributionFrame->data + sizeof(NetPacketHeader_NET), &distribution_header_NET, sizeof(NetDistributionPacket_NET)); - memcpy(distributionFrame->data + sizeof(NetPacketHeader_NET) + sizeof(NetDistributionPacket_NET) /*- 2*sizeof(byte)*/, buffer, buffer_size); - - NetDDPSendFrame(distributionFrame, &status->upringAddress, kPROTOCOL_TYPE, ddpSocket); -#endif // TEST_MODEM -} - - - -/* - ------------------- - NetDDPPacketHandler - ------------------- - - ---> DDPPacketBufferPtr - - called at interrupt time; will send an acknowledgement and (if not the server node) forward the - ring packet and spawn a time manager task to verify that it was acknowledged. because these all - work off global data structures, we can only have one ring packet ‘in the air’ (i.e., waiting to - be acknowledged) at a time. - */ - -// ZZZ: this is the first place an incoming packet is seen by the networking subsystem. -// The job of the packetHandler is to demultiplex to NetProcessIncomingBuffer or to a -// distribution-processing function (currently, NetProcessLossyDistribution is the only one). -void -RingGameProtocol::PacketHandler(DDPPacketBufferPtr packet) -{ - static bool already_here = false; - - // ZZZ: netcpy some of the packet's data into unpacked-storage area - - NetPacketHeaderPtr header = (NetPacketHeaderPtr) unpackedReceiveBuffer; - NetPacketHeader_NET* header_NET = (NetPacketHeader_NET*) packet->datagramData; - - netcpy(header, header_NET); - - // NetPacketHeaderPtr header= (NetPacketHeaderPtr) packet->datagramData; - - assert(!already_here); - already_here = true; - - if (status->acceptPackets) - { - if (packet->datagramSize >= sizeof(NetPacketHeader_NET) && packet->protocolType == kPROTOCOL_TYPE) - { - switch (header->tag) - { - case tagLOSSLESS_DISTRIBUTION: - vpause("received lossless distribution packet. not implemented."); - break; - case tagLOSSY_DISTRIBUTION: - NetProcessLossyDistribution(packet->datagramData+sizeof(NetPacketHeader_NET)); - break; - case tagACKNOWLEDGEMENT: -if (sRingPreferences.mAcceptPacketsFromAnyone || - (packet->sourceAddress.host == status->upringAddress.host && - packet->sourceAddress.port == status->upringAddress.port)) -{ - if (header->sequence==status->lastValidRingSequence+1) - { - /* on-time acknowledgement; set a global so our time manager task doesn’t resend - this packet when it fires */ - // fdprintf("ontime ack;g"); -#ifdef DEBUG_NET - { - // Figure out what was ACKed - NetPacket packet_data_storage; - NetPacket* packet_data = &packet_data_storage; - NetPacket_NET* packet_data_NET = (NetPacket_NET*) - (ringFrame->data + sizeof(NetPacketHeader_NET)); - - netcpy(packet_data, packet_data_NET); - - //NetPacketPtr packet_data= (NetPacketPtr) (ringFrame->data+sizeof(NetPacketHeader)); - - switch(packet_data->ring_packet_type) - { - case typeSYNC_RING_PACKET: - net_stats.sync_ontime_acks++; - break; - - case typeTIME_RING_PACKET: - net_stats.time_ontime_acks++; - break; - - case typeUNSYNC_RING_PACKET: - net_stats.unsync_ontime_acks++; - break; - - case typeNORMAL_RING_PACKET: - net_stats.ontime_acks++; - break; - - case typeDEAD_PACKET: - net_stats.dead_ontime_acks++; - break; - - default: - assert(false); - break; - } - } -#endif//DEBUG_NET - status->receivedAcknowledgement= true; - } - else - { - if (header->sequence<=status->lastValidRingSequence) - { - /* late acknowledgement; ignore */ - // fdprintf("late ack;g"); -#ifdef DEBUG_NET - net_stats.late_acks++; -#endif - } - else - { - /* early acknowledgement; wet our pants (this should never happen) */ - // fdprintf("early ack (%d>%d);g", header->sequence, status->lastValidRingSequence); - assert(false); - } - } -} -break; - -case tagCHANGE_RING_PACKET: - status->downringAddress = packet->sourceAddress; - -#ifdef DEBUG_NET - net_stats.change_ring_packet_count++; -#endif - // fdprintf("got change ring packet %d;g", header->sequence); - - /* fall through to tagRING_PACKET */ - -case tagRING_PACKET: - if(status->acceptRingPackets) - { -if (sRingPreferences.mAcceptPacketsFromAnyone || - (packet->sourceAddress.host == status->downringAddress.host && - packet->sourceAddress.port == status->downringAddress.port)) -{ - if (header->sequence <= status->lastValidRingSequence) - { -#ifdef DEBUG_NET - { - // Log what we saw - NetPacket packet_data_storage; - NetPacket* packet_data = &packet_data_storage; - NetPacket_NET* packet_data_NET = (NetPacket_NET*) - (packet->datagramData + sizeof(NetPacketHeader_NET)); - - netcpy(packet_data, packet_data_NET); - - //NetPacketPtr packet_data= (NetPacketPtr) (packet->datagramData+sizeof(NetPacketHeader)); - - switch(packet_data->ring_packet_type) - { - case typeUNSYNC_RING_PACKET: - net_stats.late_unsync_rings++; - break; - - case typeSYNC_RING_PACKET: - net_stats.late_sync_rings++; - break; - - case typeTIME_RING_PACKET: - net_stats.late_time_rings++; - break; - - case typeNORMAL_RING_PACKET: - net_stats.late_rings++; - break; - - case typeDEAD_PACKET: - net_stats.late_dead_rings++; - break; - - default: - assert(false); - break; - } - } -#endif // DEBUG_NET - /* late ring packet; acknowledge but ignore */ - NetSendAcknowledgement(ackFrame, header->sequence); - // fdprintf("late ring (%d<=%d);g", header->sequence, status->lastValidRingSequence); - } // sequence <= lastValidRingSequence - else - { - /* on-time or early ring packet */ - // fdprintf("Got ring.;g"); - // fdprintf("on-time ring %p (%d bytes);dm #%d #%d;g", packet, packet->datagramSize, packet->datagramData, packet->datagramSize); - - /* process remote actions, add our local actions, build ringFrame for sending */ - NetProcessIncomingBuffer(packet->datagramData+sizeof(NetPacketHeader_NET), - packet->datagramSize-sizeof(NetPacketHeader_NET), header->sequence); - } -} // came from expected source -/* Note that I ignore packets from an unknown source. There's a valid reason that we could get -* them. Imagine a ring with 3+ players. A->B->C->...->A. Player B sends to C, and crashes before -* getting the ack. but it's not a fatal crash. (macsbug warning...) C sends an ack though and -* forwards the packet. within 2 seconds, A drops B from the game. B recovers from the crash -* and says "Whoa! I didn't get an ack from C, let's resend". Then C gets a packet from the -* wrong person. (Note that time didn't pass for B while in macsbug, that's why he didn't just drop - * c from the game) */ -/* Come to think of it, B could have had a fatal crash. He goes into macsbug with an assert, then -* when he comes out, the network code hasn't been halted quite yet, so everything still happens -* for a moment. */ -else -{ -#ifdef DEBUG_NET - net_stats.packets_from_the_unknown++; -#endif - // fdprintf("packet from unknown source %8x!=%8x.;g;", *((long*)&packet->sourceAddress), *((long*)&status->downringAddress)); -} - } // accept_ring_packets -break; -// (was tagRING_PACKET, or tagRING_CHANGE_PACKET) - -default: - assert(false); - break; - } // switch(header->tag) - } // packet seems legitimate (correct protocolType and size) - } // accept_packets - -already_here= false; -} // NetDDPPacketHandler - - - -// Act on an incoming lossy-distribution datagram -// i.e., call the distribution function registered earlier, and ship the datagram along -// upring (unless upring is the one who sent it). -static void NetProcessLossyDistribution( - void *buffer) -{ - short type; - - // ZZZ: convert from NET format - NetDistributionPacket_NET* packet_data_NET = (NetDistributionPacket_NET*) buffer; - NetDistributionPacketPtr packet_data = (NetDistributionPacketPtr) (unpackedReceiveBuffer + sizeof(NetPacketHeader)); - - netcpy(packet_data, packet_data_NET); - - type = packet_data->distribution_type; - - // Act upon the data, if possible - const NetDistributionInfo* theInfo = NetGetDistributionInfoForType(type); - - if (theInfo != NULL) - { - theInfo->distribution_proc(((char*) buffer) + sizeof(NetDistributionPacket_NET), packet_data->data_size, - packet_data->first_player_index); - } - - // Should we pass the data on around the ring? - // ZZZ: this used to only happen if the type_in_use was set, above. I think we have an - // obligation to pass the data along to others: even if _we_ don't know what to do with it, - // someone else might. - if (packet_data->first_player_index != status->upringPlayerIndex) - { - // ZZZ: set up for conversion to NET format - NetPacketHeader_NET* header_NET; - NetPacketHeader header_storage; - NetPacketHeaderPtr header = &header_storage; - - // fill in data - distributionFrame->data_size = sizeof(NetPacketHeader_NET) + sizeof(NetDistributionPacket_NET) + packet_data->data_size; - - header->tag = tagLOSSY_DISTRIBUTION; - header->sequence = 0; - - // do the conversion - header_NET = (NetPacketHeader_NET*) distributionFrame->data; - netcpy(header_NET, header); - - // (conversion complete) - - // copy in distribution data (raw, since we don't know what it is) - memcpy(distributionFrame->data + sizeof(NetPacketHeader_NET), - buffer, - sizeof(NetDistributionPacket_NET) + packet_data->data_size); - - NetDDPSendFrame(distributionFrame, &status->upringAddress, kPROTOCOL_TYPE, ddpSocket); - } -} // NetProcessLossyDistribution - -/* - ------------------------ - NetProcessIncomingBuffer - ------------------------ - - this function queues flags from remote players, adds the local player’s latest command (thus - modifying the buffer in place), calls NetBuildRingPacket to set up ringFrame based on this new - data and then returns. - */ - -/* •••• Marathon Specific Code (some of it, anyway) •••• */ -static void NetProcessIncomingBuffer( - void *buffer, - int32 buffer_size, - int32 sequence) -{ - // ZZZ: convert from _NET format - NetPacket* packet_data = (NetPacket*) (unpackedReceiveBuffer + sizeof(NetPacketHeader)); - NetPacket_NET* packet_data_NET = (NetPacket_NET*) buffer; - - netcpy(packet_data, packet_data_NET); - -#ifdef DEBUG_NET_RECORD_PROFILE - record_profile(packet_data->required_action_flags); -#endif - -#if defined(NETWORK_ADAPTIVE_LATENCY_2) || defined(NETWORK_ADAPTIVE_LATENCY_3) - // ZZZ: this is the only spot we sample/adjust our adaptive_latency_2 (or 3): when we've received a valid ring packet. - // We sample the server's required_action_flags (set to its SizeofLocalQueue before sent) as that should be a - // good indicator of actual ring latency. - update_adaptive_latency(packet_data->required_action_flags, packet_data->server_net_time); -#endif - - // ZZZ: copy (byte-swapped) the action_flags into the unpacked buffer. - netcpy(&packet_data->action_flags[0], (uint32*) (((char*) buffer) + sizeof(NetPacket_NET)), NetPacketSize(packet_data)); - - short packet_tag= NONE; - int32 previous_lastValidRingSequence= status->lastValidRingSequence; - - status->server_player_index= packet_data->server_player_index; - - /* remember this as the last valid ring sequence we received (set it now so we can send sequence+1) */ - status->lastValidRingSequence= sequence; - status->ringPacketCount+= 1; - - switch(packet_data->ring_packet_type) - { - case typeSYNC_RING_PACKET: - /* We sent this out to start the game, and now it has made it back to us. */ - /* This means that we are ready to start. */ - if (status->iAmTheServer) - { - packet_data->ring_packet_type= typeTIME_RING_PACKET; - // I hearby declare that time starts now! Let There Be Light! - // packet_data->server_net_time= 0; - // status->localNetTime= 0; - // packet_data->server_net_time= dynamic_world->tick_count; - // status->localNetTime= dynamic_world->tick_count; - - if(serverTMTask) - { - /* This can only happen if we are resyncing for a changed level */ - myTMReset(serverTMTask); - } else { - serverTMTask= myXTMSetup(1000/TICKS_PER_SECOND, NetServerTask); - } - } - /* else forward immediately. */ - break; - - case typeTIME_RING_PACKET: - *sNetStatePtr= netActive; // we are live! - if (status->iAmTheServer) - { - /* We have completed the sequence, and got our time packet back */ - packet_data->ring_packet_type= typeNORMAL_RING_PACKET; - } - else // the server tells us that now is the beginning of time. - { - // status->localNetTime= 0; - // status->localNetTime= packet_data->server_net_time; - - if(queueingTMTask) - { - /* This can only happen if we are resyncing for a changed level */ - myTMReset(queueingTMTask); - } else { - queueingTMTask= myXTMSetup(1000/TICKS_PER_SECOND, NetQueueingTask); - } - } - break; - - case typeNORMAL_RING_PACKET: - break; - - case typeUNSYNC_RING_PACKET: - /* We sent this out to end the game, and now it has made it back to us. */ - /* This means that we are ready to exit. */ - if(*sNetStatePtr==netComingDown) - { -#ifdef DEBUG_NET - // fdprintf("Got an unsync packet.. (%d);g", net_stats.action_flags_processed); - net_stats.unsync_while_coming_down++; -#endif - status->acceptRingPackets= false; - if(status->iAmTheServer) - { -#ifdef DEBUG_NET - // fdprintf("Unsync returned to sender. Going down;g"); - net_stats.unsync_returned_to_sender++; -#endif - packet_data->ring_packet_type= typeDEAD_PACKET; - } - } -#ifdef DEBUG_NET - else - { - // fdprintf("Got a spurious unsync packet...;g"); - net_stats.spurious_unsyncs++; - } -#endif - break; - - default: - assert(false); - break; - } - - switch(packet_data->ring_packet_type) - { - case typeSYNC_RING_PACKET: - case typeTIME_RING_PACKET: - NetBuildRingPacket(ringFrame, (unsigned char *)packet_data, NetPacketSize(packet_data), status->lastValidRingSequence+1); - /* We acknowledge just before sending the ring frame.... */ - NetSendAcknowledgement(ackFrame, status->lastValidRingSequence); - NetSendRingPacket(ringFrame); - break; - - case typeUNSYNC_RING_PACKET: - /* Don't ack it unless we did something with it. They will spam us with them and then */ - /* time out. (important if one machine is slower than the others. */ - if(*sNetStatePtr==netComingDown) - { - NetBuildRingPacket(ringFrame, (unsigned char *)packet_data, NetPacketSize(packet_data), status->lastValidRingSequence+1); - - NetSendAcknowledgement(ackFrame, status->lastValidRingSequence); - NetSendRingPacket(ringFrame); - } else { - /* Got it but ignored it. lastValidRingSequence should be reset to what it was before. */ - status->lastValidRingSequence= previous_lastValidRingSequence; - } - break; - - case typeNORMAL_RING_PACKET: - process_packet_buffer_flags(packet_data, buffer_size, packet_tag); - break; - - case typeDEAD_PACKET: - /* The buck stops here (after acknowledging it). */ - NetSendAcknowledgement(ackFrame, status->lastValidRingSequence); - break; - - default: - assert(false); - break; - } -} // NetProcessIncomingBuffer - - -static void NetAddFlagsToPacket( - NetPacketPtr packet) -{ - uint32 *action_flags; - short player_index; - short action_flag_index; - static bool already_here = false; -#ifdef NETWORK_USE_RECENT_FLAGS - short extra_flags; -#endif - - assert(already_here == false); - already_here= true; - - vwarn(packet->required_action_flags >= 0 && packet->required_action_flags <= MAXIMUM_UPDATES_PER_PACKET, - csprintf(temporary, "the server asked for %d flags. bastard. fucking ram doubler.", packet->required_action_flags)); - - // figure out where our action flags are. - action_flags= packet->action_flags; - for (player_index= 0; player_indexaction_flag_count[player_index] >= -1 && packet->action_flag_count[player_index] <= MAXIMUM_UPDATES_PER_PACKET, - csprintf(temporary, "action_flag_count[%d] = %d", player_index, packet->action_flag_count[player_index])); - - if (packet->action_flag_count[player_index] != NET_DEAD_ACTION_FLAG_COUNT) // player is net dead - { - action_flags += packet->action_flag_count[player_index]; - } - } - - /* readjust the packet if the required action flag doesn't equal the action flag count */ - /* for me and I am not the last player (if I am the last, I can just overflow.. */ - if (packet->required_action_flags != packet->action_flag_count[localPlayerIndex] - && localPlayerIndex != topology->player_count - 1) - { - short count= 0; - -#ifdef DEBUG_NET - net_stats.numCountChanges++; -#endif - for (player_index= localPlayerIndex+1; player_indexplayer_count; player_index++) - { - if (packet->action_flag_count[player_index] != NET_DEAD_ACTION_FLAG_COUNT) // player is net dead. - { - count+= packet->action_flag_count[player_index]; - } - } - - vassert(count>=0 && count<=(MAXIMUM_UPDATES_PER_PACKET * MAXIMUM_NUMBER_OF_NETWORK_PLAYERS), - csprintf(temporary, "bad count. count = %d. packet:; dm #%p", count, ((byte*)packet)-sizeof(NetPacketHeader))); - - // ZZZ: potential very sneaky bug: memcpy is not required to correctly handle overlapping copies, and - // I think we probably have an overlapping copy here. memmove it is. - // memcpy(action_flags + packet->required_action_flags, action_flags + packet->action_flag_count[localPlayerIndex], count * sizeof(uint32)); - memmove(action_flags + packet->required_action_flags, action_flags + packet->action_flag_count[localPlayerIndex], count * sizeof(uint32)); - //BlockMove(action_flags + packet->action_flag_count[localPlayerIndex], - // action_flags + packet->required_action_flags, - // count * sizeof(int32)); - } - -#ifdef DEBUG_NET - if(packet->required_action_flags==0) net_stats.packets_with_zero_flags++; -#endif - -#ifndef NETWORK_SMARTER_FLAG_DITCHING -#ifdef NETWORK_USE_RECENT_FLAGS - // ZZZ change: ditch older flags first, send newer flags. I think this will "feel" better to players. - // Consider: if we have too many flags, that probably means there was a "burp" somewhere along the line - // that held up the ring packet. We have already had to freeze our animation (since we didn't have enough - // information to proceed) - the extra flags were accumulated during that freeze. Wouldn't you want your - // actions following the freeze to reflect what you were doing at the end of the freeze, not at the beginning? - // Or, look at it this way: if you keep the early flags but throw away the later ones, you've added latency - // (at least for those few flags that do get sent along) between the player's inputs and his screen updates. - extra_flags = NetSizeofLocalQueue() - packet->required_action_flags; - while(extra_flags-- > 0) { - local_queue.read_index++; - if (local_queue.read_index >= NET_QUEUE_SIZE) local_queue.read_index= 0; - } - // end of that change -#endif // NETWORK_USE_RECENT_FLAGS -#endif // !NETWORK_SMARTER_FLAG_DITCHING - - // plug in our action flags. - for (action_flag_index= 0; action_flag_indexrequired_action_flags; action_flag_index++) - { - if (local_queue.read_index != local_queue.write_index) - { - action_flags[action_flag_index] = local_queue.buffer[local_queue.read_index]; - local_queue.read_index++; - if (local_queue.read_index >= NET_QUEUE_SIZE) local_queue.read_index = 0; - } - else // we unfortunately need to smear. - { - action_flags[action_flag_index]= parse_keymap(); -#ifdef NETWORK_FAUX_QUEUE - // ZZZ: faux queue mechanism to handle jittery scheduling - faux_queue_due++; -#endif -#ifdef DEBUG_NET - net_stats.numSmears++; -#endif - } - } - -#ifdef NETWORK_SMARTER_FLAG_DITCHING - int leftover_flags = NetSizeofLocalQueue(); - - // If no leftover flags, reset the counter. - if(leftover_flags == 0) - sFlagDitchingCounter = 0; - - // Otherwise, increment the counter. Inc it faster if there are more leftovers. - else - sFlagDitchingCounter += leftover_flags; - - // If we've crossed the threshhold, we've got some flags that are just taking up space (and time!). - // Ditch one, and reset the counter. Note that as long as kFlagDitchingThreshhold is positive - // (should be!), there must be at least one flag in the queue now, or else sFlagDitchingCounter - // would have been reset above. - if(sFlagDitchingCounter >= kFlagDitchingThreshhold) { - local_queue.read_index++; - - if(local_queue.read_index >= NET_QUEUE_SIZE) - local_queue.read_index = 0; - - sFlagDitchingCounter = 0; - } - -#else // !NETWORK_SMARTER_FLAG_DITCHING - - // ZZZ: this is the code that (effectively) was moved above -#ifndef NETWORK_USE_RECENT_FLAGS - // if we're accumulating too many flags, just ditch some to avoid latency - // (which we assume is worse than losing a couple of flags) - extra_flags= NetSizeofLocalQueue(); - short flags_to_remove= MIN(extra_flags, status->last_extra_flags); - status->last_extra_flags = extra_flags - flags_to_remove; - while (flags_to_remove--) - { - local_queue.read_index++; - if (local_queue.read_index >= NET_QUEUE_SIZE) local_queue.read_index= 0; - } -#endif // !NETWORK_USE_RECENT_FLAGS - -#endif // !NETWORK_SMARTER_FLAG_DITCHING - - /* Sync the net time... */ - if (!status->iAmTheServer) - { - status->localNetTime= packet->server_net_time; - } - - // tell everyone that we’re meeting code. - packet->action_flag_count[localPlayerIndex]= packet->required_action_flags; - - // fdprintf("NETPACKET:;dm %x %x;g;", packet, sizeof(NetPacket)+sizeof(long)*2*8); - - /* Allow for reentrance into this function */ - already_here= false; -} - - - -static size_t NetPacketSize( - NetPacketPtr packet) -{ - size_t size = 0; - short i; - - /* ZZZ: should not do this now, data was already converted elsewhere and we've been passed the unpacked version. - NetPacket packet_storage; - NetPacket* packet = &packet_storage; - - netcpy(packet, packet_NET); - */ - for (i = 0; i < topology->player_count; ++i) - { - if (packet->action_flag_count[i] != NET_DEAD_ACTION_FLAG_COUNT) // player has become net dead. - { - assert(packet->action_flag_count[i]>=0&&packet->action_flag_count[i]<=MAXIMUM_UPDATES_PER_PACKET); - size += packet->action_flag_count[i] * sizeof(int32); - } - } - - // ZZZ: CHANGE OF SEMANTICS from Bungie version - this gives only the size of the variable part - // of the packet (instead of the variable part + sizeof(NetPacket)). - // Since NetPacketSize is ONLY used to compute a size value for calls to NetBuildRingPacket, and - // NetBuildRingPacket is ONLY called with a value computed by NetPacketSize, this is safe - I will - // alter NetBuildRingPacket to expect this different value. - return size; -} - -/* - ---------------------- - NetSendAcknowledgement - ---------------------- - - --> DDPFramePtr (usually ackFrame) // ZZZ note: currently, ALWAYS ackFrame. - --> sequence to acknowledge // ZZZ note: always status->lastValidRingSequence EXCEPT when acking a late ring packet. - - always sends the acknowledgement to downringAddress - - ------------------ - NetBuildRingPacket - ------------------ - - ----------------- - NetSendRingPacket - ----------------- - */ - -static void NetSendAcknowledgement( - DDPFramePtr frame, - int32 sequence) -{ - NetPacketHeader_NET* header_NET = (NetPacketHeader_NET*) frame->data; - NetPacketHeader header_storage; - NetPacketHeader* header = &header_storage; - - // fdprintf("sending ack.;g"); - - /* build the acknowledgement */ - frame->data_size= sizeof(NetPacketHeader_NET); - header->tag= tagACKNOWLEDGEMENT; - header->sequence= sequence; - - // (ZZZ) format the ack for the network - netcpy(header_NET, header); - - /* send the acknowledgement */ - NetDDPSendFrame(frame, &status->downringAddress, kPROTOCOL_TYPE, ddpSocket); -} - -/* Only the server can call this... */ -static void NetBuildFirstRingPacket( - DDPFramePtr frame, - int32 sequence) -{ - short player_index; - NetPacketPtr data; - - // ZZZ: why doesn't he let this be automatically allocated on the stack? It's small, and is only needed for - // the duration of the function call... well, no changes made, just curious. - data = (NetPacketPtr)malloc(sizeof(NetPacket)); - //data = (NetPacketPtr) NewPtr(sizeof(NetPacket)); - assert(data); - - data->server_player_index= localPlayerIndex; - data->ring_packet_type= typeSYNC_RING_PACKET; - data->required_action_flags= UPDATES_PER_PACKET; - - /* This is a very important step- the first time the server gets the packet back */ - /* it strips flags. It should not find any... */ - for (player_index= 0; player_indexplayer_count; player_index++) - { - data->action_flag_count[player_index]= 0; - } - - NetBuildRingPacket(frame, (byte *)data, NetPacketSize(data), sequence); - - free(data); - //DisposePtr((Ptr) data); -} - -// ZZZ: now, we build a packed (_NET format) ring packet from unpacked source data. -static void NetBuildRingPacket( - DDPFramePtr frame, - byte *data, - size_t data_size, - int32 sequence) -{ - NetPacketHeader header_storage; - NetPacketHeader* header = &header_storage; - NetPacketHeader_NET* header_NET = (NetPacketHeader_NET*) frame->data; - - /* build the ring packet */ - // ZZZ: note that data_size is now just the size of the variable-length part (i.e. the action_flags) - // so we will add the sizeof both _NET format structures first. - assert(sizeof(NetPacketHeader_NET) + sizeof(NetPacket_NET) + data_size - == static_cast(static_cast(sizeof(NetPacketHeader_NET) + sizeof(NetPacket_NET) + data_size))); - frame->data_size= static_cast(sizeof(NetPacketHeader_NET) + sizeof(NetPacket_NET) + data_size); - - // ZZZ: set up our local header buffer's data - header->tag= tagRING_PACKET; - header->sequence= sequence; - - // ZZZ: changed this check to frame->data_size from just data_size, seems to be more accurate - assert(frame->data_sizedata + sizeof(NetPacketHeader_NET)); - - netcpy(packet_data_NET, packet_data); - - // ZZZ: I guess this would still do the right thing if netcpy (or memcpy, in some cases) gets 0 for the - // length, but to avoid taking that risk and to save a little work, we skip if it there aren't any flags - // (like, if we were called from NetBuildFirstRingPacket()) - if(data_size > 0) { - // ZZZ: copy in the action_flags from the unpacked, passed-in data. - uint32* action_flags = &packet_data->action_flags[0]; - uint32* action_flags_NET = (uint32*) (frame->data + sizeof(NetPacketHeader_NET) + sizeof(NetPacket_NET)); - - netcpy(action_flags_NET, action_flags, data_size); - } -} - -// ZZZ: fixed to deal with packed (_NET) format -static void NetRebuildRingPacket( - DDPFramePtr frame, - short tag, - int32 sequence) -{ - NetPacketHeader header_storage; - NetPacketHeader* header = &header_storage; - NetPacketHeader_NET* header_NET = (NetPacketHeader_NET*) frame->data; - // NetPacketHeaderPtr header= (NetPacketHeaderPtr) frame->data; - - header->tag= tag; - header->sequence= sequence; - - netcpy(header_NET, header); -} - -static void NetSendRingPacket( - DDPFramePtr frame) -{ - // fdprintf("sent frame;g"); - - status->retries= 0; // needs to be here, in case retry task was canceled (’cuz it likes to set retries) - status->receivedAcknowledgement= false; /* will not be set until we receive an acknowledgement for this packet */ - - if (!resendTMTask) - { - resendTMTask= myTMSetup(kACK_TIMEOUT, NetCheckResendRingPacket); - } else { - myTMReset(resendTMTask); - } - - status->canForwardRing= false; /* will not be set unless this task fires without a packet to forward */ - status->clearToForwardRing= false; /* will not be set until we receive the next valid ring packet but will be irrelevant if serverCanForwardRing is true */ - // LP: NetAddrBlock is the trouble here - NetDDPSendFrame(frame, &status->upringAddress, kPROTOCOL_TYPE, ddpSocket); -} - -/* - ------------------------ - NetCheckResendRingPacket - ------------------------ - - (no parameters) - - this function is called kACK_TIMEOUT after a ring packet has been sent. if the ring - packet has not been acknowledged during this time, it will be resent from within this timer - task and the task will be requeued to check again in kACK_TIMEOUT. - - */ -/* Possibly this should check for status->receivedAcknowledgement before !reinstalling.. */ -static bool NetCheckResendRingPacket( - void) -{ - bool reinstall= (*sNetStatePtr != netDown); - - if(reinstall) - { - if (!status->receivedAcknowledgement) - { - if(++status->retries>=kRETRIES) - { - switch(*sNetStatePtr) - { - case netStartingUp: - /* There might be several retries as we start up */ - break; - - case netComingDown: -#ifdef DEBUG_NET - fdprintf("Never got confirmation on NetUnsync packet. They don't love us."); -#endif - reinstall= false; - status->acceptRingPackets= false; - break; - - default: - /* They have been gone too long.. */ - drop_upring_player(); - break; - } - } - -#ifdef DEBUG_NET - // #error need to alter this to work with new (_NET) packet formats, or data will be screwy. - { - NetPacketPtr packet_data= (NetPacketPtr) (ringFrame->data+sizeof(NetPacketHeader)); - switch(packet_data->ring_packet_type) - { - case typeSYNC_RING_PACKET: - net_stats.sync_retry_count++; - break; - - case typeTIME_RING_PACKET: - net_stats.time_retry_count++; - break; - - case typeUNSYNC_RING_PACKET: - net_stats.unsync_retry_count++; - break; - - case typeNORMAL_RING_PACKET: - net_stats.retry_count++; - break; - - case typeDEAD_PACKET: - net_stats.dead_retry_count++; - break; - - default: - assert(false); - break; - } - } -#endif - /* Resend it.. */ - // LP: NetAddrBlock is the trouble here - NetDDPSendFrame(ringFrame, &status->upringAddress, kPROTOCOL_TYPE, ddpSocket); - } - else - { - status->retries = 0; - } - } - - return reinstall; -} - -static bool NetServerTask( - void) -{ - short local_queue_size = NetSizeofLocalQueue(); - bool reinstall= (*sNetStatePtr != netDown); - - if(reinstall) - { - /* Call the local net queueing proc.. */ - if (local_queue_size < MAXIMUM_UPDATES_PER_PACKET) - { - // ZZZ: did not put faux queue here since server should be right-on - local_queue_size++; // Random voodoo... - local_queue.buffer[local_queue.write_index++] = parse_keymap(); - if (local_queue.write_index >= NET_QUEUE_SIZE) - local_queue.write_index = 0; - status->localNetTime++; - } - -#ifdef NETWORK_ADAPTIVE_LATENCY - // ZZZ change: send the packet along if we've covered the current adaptive latency. - if(local_queue_size >= sCurrentAdaptiveLatency) -#else - if (local_queue_size >= status->action_flags_per_packet) -#endif - { - // This weird voodoo with canForwardRing prevents a problem if a packet arrives at the wrong time. - status->canForwardRing = true; /* tell the socket listener it can forward the ring if it receives it */ - if (status->clearToForwardRing) /* has the socket listener already received the ring? and not forwarded it? */ - { // ZZZ: this control path is taken if the ring is waiting for us. The packet we received is in - // status->buffer. - // For the other case (we are ready, but ring is not), see NetDDPPacketHandler. - // The effect is to impose a "ring speed limit" - rings will not go around faster than - // we accumulate data to put in them. (Makes sense...) - NetPacketPtr packet_data= (NetPacketPtr) status->buffer; - - // status->canForwardRing = false; - // XXX (ZZZ): I need to investigate this net_time business; now that I am throwing away - // server flags, I may need to throw away server time as well (?). - packet_data->server_net_time= status->localNetTime; - if(*sNetStatePtr==netComingDown) - { - if(packet_data->required_action_flags==0) - { -#ifdef DEBUG_NET - // fdprintf("I Server got a normal packet, at zero. unsyncing... (%d);g", net_stats.action_flags_processed); - net_stats.server_unsyncing++; -#endif - packet_data->ring_packet_type= typeUNSYNC_RING_PACKET; - } - else - { -#ifdef DEBUG_NET - // fdprintf("I Server got a normal packet & net was coming down required flags at 0. (%d);g", net_stats.action_flags_processed); - net_stats.server_set_required_flags_to_zero++; -#endif - /* Change the type to an unsync ring packet... */ - packet_data->required_action_flags= 0; - } - } // netComingDown - else // netState != netComingDown - { -#ifdef NETWORK_ADAPTIVE_LATENCY - // ZZZ change: only send out as many flags as adaptive latency suggests - packet_data->required_action_flags = sCurrentAdaptiveLatency; -#else - packet_data->required_action_flags= NetSizeofLocalQueue(); -#endif - } - - NetAddFlagsToPacket(packet_data); - NetBuildRingPacket(ringFrame, (byte *) packet_data, NetPacketSize(packet_data), status->lastValidRingSequence+1); - if(status->new_packet_tag != NONE) - { -#ifdef DEBUG_NET - // fdprintf("rebuilding the server tag (%d);g", status->new_packet_tag); - net_stats.rebuilt_server_tag++; -#endif - NetRebuildRingPacket(ringFrame, status->new_packet_tag, status->lastValidRingSequence+1); - } - - /* Send the Ack just before we pass the token along.. */ - NetSendAcknowledgement(ackFrame, status->lastValidRingSequence); - NetSendRingPacket(ringFrame); - } // clearToForwardRing (ring was already here waiting for us to accumulate enough data) - } // we have accumulated enough data to let the ring go on - } // reinstall (netState != netDown) - - status->worldUpdate = true; - - return reinstall; -} // NetServerTask - -static bool NetQueueingTask( - void) -{ - bool reinstall= (*sNetStatePtr != netDown); - - if(reinstall) - { - if (NetSizeofLocalQueue() < MAXIMUM_UPDATES_PER_PACKET) - { -#ifdef NETWORK_FAUX_QUEUE - // ZZZ: if we owe the packet handler flags (since it smeared to cover for us), pay up. - if(faux_queue_paid != faux_queue_due) { - faux_queue_paid++; - } - // OTOH if we're even-steven, we will go ahead and queue some flags for the next ring packet. - else { -#endif - local_queue.buffer[local_queue.write_index++] = parse_keymap(); - if (local_queue.write_index >= NET_QUEUE_SIZE) - local_queue.write_index = 0; -#ifdef NETWORK_FAUX_QUEUE - } -#endif - status->localNetTime++; - } // room to store an action_flag - } // reinstall (netState != netDown) - - status->worldUpdate = true; - - return reinstall; -} // NetQueueingTask - - - -#if defined(NETWORK_ADAPTIVE_LATENCY) || defined(NETWORK_ADAPTIVE_LATENCY_2) -// ZZZ addition: adaptive latency business. measurement used only in adaptive_latency_2. -// tick used only in adaptive_latency_3. -static void -update_adaptive_latency(int measurement, int tick) { - -#ifdef NETWORK_ADAPTIVE_LATENCY_2 - // Use the provided measurement - int theCurrentLatencyMeasurement = measurement; -#else - // Take the current local_queue_size as a measurement of ring latency - int theCurrentLatencyMeasurement = NetGetSizeofLocalQueue(); -#endif - - // Subtract the sample leaving the window from the running total - if(sAdaptiveLatencySampleCount >= kAdaptiveLatencyWindowSize) - sAdaptiveLatencyRunningTotal -= sAdaptiveLatencySamples[sAdaptiveLatencyWindowEdge]; - - // Put the new sample in as the newest sample in the sample buffer - sAdaptiveLatencySamples[sAdaptiveLatencyWindowEdge] = theCurrentLatencyMeasurement; - - // Slide the window one sample - sAdaptiveLatencyWindowEdge = (sAdaptiveLatencyWindowEdge + 1) % kAdaptiveLatencyWindowSize; - - // If we're still collecting the initial set of samples, update our count - if(sAdaptiveLatencySampleCount < kAdaptiveLatencyWindowSize) - sAdaptiveLatencySampleCount++; - - // Add the newest sample into our running total - sAdaptiveLatencyRunningTotal += theCurrentLatencyMeasurement; - - // Don't adjust the latency until we have a window's worth of samples to work from - if(sAdaptiveLatencySampleCount >= kAdaptiveLatencyWindowSize) { - // Find the average latency for the past window's worth of samples - float theAverageLatencyMeasurement = (float) sAdaptiveLatencyRunningTotal / (float) kAdaptiveLatencyWindowSize; - - // See if we should adjust our latency based on that average measurement. Be careful not to adjust - // latency below 1 or above the cap. - if(theAverageLatencyMeasurement - sCurrentAdaptiveLatency > kNeedToIncreaseLatencyThreshhold - && sCurrentAdaptiveLatency < kAdaptiveLatencyMaximumValue) - { - sCurrentAdaptiveLatency++; - logNote1("adjusted latency upwards to %d", sCurrentAdaptiveLatency); - } - else if(theAverageLatencyMeasurement - sCurrentAdaptiveLatency < kNeedToDecreaseLatencyThreshhold - && sCurrentAdaptiveLatency > 1) - { - sCurrentAdaptiveLatency--; - logNote1("adjusted latency downwards to %d", sCurrentAdaptiveLatency); - } - } - -} // update_adaptive_latency -#endif// NETWORK_ADAPTIVE_LATENCY || NETWORK_ADAPTIVE_LATENCY_2 - -#ifdef NETWORK_ADAPTIVE_LATENCY_3 -// ZZZ addition: adaptive latency business. -static void -update_adaptive_latency(int measurement, int tick) { - // Ignore samples from old packets that may show up; also bail if user doesn't love us - if(tick <= sGreatestRecentLatencyTick || !sRingPreferences.mAdaptToLatency) - return; - - // Update our measurements etc. - if(measurement > sGreatestRecentLatencyMeasurement) - { - sSecondGreatestRecentLatencyMeasurement = sGreatestRecentLatencyMeasurement; - sGreatestRecentLatencyMeasurement = measurement; - sGreatestRecentLatencyTick = tick; - } - else if(measurement == sGreatestRecentLatencyMeasurement) - { - sGreatestRecentLatencyTick = tick; - } - else if(measurement > sSecondGreatestRecentLatencyMeasurement) - { - sSecondGreatestRecentLatencyMeasurement = measurement; - } - - // If it's been long enough since we've seen our current greatest, fall back to second-greatest - if(tick - sGreatestRecentLatencyTick > sRingPreferences.mLatencyHoldTicks) - { - sGreatestRecentLatencyTick = tick; - sGreatestRecentLatencyMeasurement = sSecondGreatestRecentLatencyMeasurement; - sSecondGreatestRecentLatencyMeasurement = 0; - } - - int theNewAdaptiveLatency = MIN(sGreatestRecentLatencyMeasurement, MAXIMUM_UPDATES_PER_PACKET); - - if(sCurrentAdaptiveLatency != theNewAdaptiveLatency) - { - logDump("tick %d: setting adaptive latency to %d", tick, theNewAdaptiveLatency); - sCurrentAdaptiveLatency = theNewAdaptiveLatency; - } -} -#endif // NETWORK_ADAPTIVE_LATENCY_3 - - - -// This function does two things. It changes the upring address to be the upring address -// of the next dude in the ring. It also returns the playerIndex of what used to be -// the next player, so that we can fiddle with things. -static short NetAdjustUpringAddressUpwards( - void) -{ - short nextPlayerIndex, newNextPlayerIndex; - NetAddrBlock *address; - - // figure out where the current upring address is. - for (nextPlayerIndex= 0; nextPlayerIndexplayer_count; nextPlayerIndex++) - { - address = &(topology->players[nextPlayerIndex].ddpAddress); - if (address->host == status->upringAddress.host && - address->port == status->upringAddress.port) - { - break; - } - } - assert(nextPlayerIndex != topology->player_count); - - // ZZZ: changed to deal with 'gaps' (players with identifier NONE), in support of generalized game-resumption - newNextPlayerIndex = nextPlayerIndex; - do - { - newNextPlayerIndex = (topology->player_count + newNextPlayerIndex + 1) % topology->player_count; - } while(topology->players[newNextPlayerIndex].identifier == NONE && newNextPlayerIndex != localPlayerIndex); - - status->upringAddress= topology->players[newNextPlayerIndex].ddpAddress; - status->upringPlayerIndex= newNextPlayerIndex; - - return nextPlayerIndex; -} - -static void drop_upring_player( - void) -{ - // ZZZ: unpack existing ringFrame (from _NET format) - byte unpackedBuffer[ddpMaxData]; - - NetPacket* packet_data = (NetPacket*) unpackedBuffer; - NetPacket_NET* packet_data_NET = (NetPacket_NET*) (ringFrame->data + sizeof(NetPacketHeader_NET)); - - netcpy(packet_data, packet_data_NET); - - uint32* action_flags = &packet_data->action_flags[0]; - uint32* action_flags_NET = (uint32*) (ringFrame->data + sizeof(NetPacketHeader_NET) + sizeof(NetPacket_NET)); - - size_t data_size = NetPacketSize(packet_data); - - netcpy(action_flags, action_flags_NET, data_size); - - // (done unpacking) - - short flag_count, index, oldNextPlayerIndex; - // NetPacketPtr packet_data= (NetPacketPtr) (ringFrame->data + sizeof (NetPacketHeader)); - - /* Reset the retries for the new packet. */ - status->retries= 0; - - flag_count= 0; - -#ifdef DEBUG_NET - // fdprintf("Dropping upring- Attempting to delete upring (node %d) from ring. muhaha.;g", status->upringAddress.aNode); - net_stats.upring_drops++; -#endif - - // uh-oh. looks like the upring address has gone down. - // modify the ring packet to zero out the players action flags - // and find a new downring address. - oldNextPlayerIndex= NetAdjustUpringAddressUpwards(); - - /* If the next player upring was the server, and the next player upring wasn't us.. */ - if (oldNextPlayerIndex==status->server_player_index && !status->iAmTheServer) - { - // let us crown ourselves! - status->server_player_index= localPlayerIndex; - status->iAmTheServer= true; -#ifdef DEBUG_NET - // fdprintf("Trying to become the server (drop_upring);g"); - net_stats.assuming_control_on_retry++; -#endif - - // now down to work. gotta switch tasks. Take a deep breath... - queueingTMTask = myTMRemove(queueingTMTask); - assert(!serverTMTask); - serverTMTask = myXTMSetup(1000/TICKS_PER_SECOND, NetServerTask); - - packet_data->server_net_time= status->localNetTime; - } - - // adjust the packet to indicate that our fellow player has become deceased. - // (is this an obituary?) - action_flags = packet_data->action_flags; - for (index= 0; indexaction_flag_count[index] != NET_DEAD_ACTION_FLAG_COUNT) - { - action_flags += packet_data->action_flag_count[index]; - } - } - - for (index= oldNextPlayerIndex+1; indexplayer_count; index++) - { - if (packet_data->action_flag_count[index] != NET_DEAD_ACTION_FLAG_COUNT) - { - flag_count += packet_data->action_flag_count[index]; - } - } - - /* Remove the servers flags.. */ - if (flag_count > 0) - { - // changed "flag_count" to "sizeof(long)*flag_count" - // ZZZ: here's that sneaky bug again, memcpy is not guaranteed to work for overlapping src and dest; - // we use memmove instead. - memmove(action_flags, action_flags + packet_data->action_flag_count[oldNextPlayerIndex], flag_count * sizeof(uint32)); - //memcpy(action_flags, action_flags + packet_data->action_flag_count[oldNextPlayerIndex], flag_count * sizeof(uint32)); - //BlockMove(action_flags + packet_data->action_flag_count[oldNextPlayerIndex], - // action_flags, sizeof(long)*flag_count); - } - /* Mark the server as net dead */ - packet_data->action_flag_count[oldNextPlayerIndex]= NET_DEAD_ACTION_FLAG_COUNT; - - /* If everyone else is netdead, set the single player flag. */ - for(index= 0; indexplayer_count; ++index) - { - if(index!=localPlayerIndex && packet_data->action_flag_count[index]!=NET_DEAD_ACTION_FLAG_COUNT) - { - break; - } - } - if(index==topology->player_count) status->single_player= true; - - // we have to increment the ring sequence counter in case we’re sending to ourselves - // to prevent "late ring packets" - // ZZZ: to take advantage of repacking, I pass our buffer into NetBuildRingPacket. - // (original code used just Rebuild, below.) - NetBuildRingPacket(ringFrame, unpackedBuffer, data_size, status->lastValidRingSequence+1); - - // ZZZ: still need this though to change tag. - NetRebuildRingPacket(ringFrame, tagCHANGE_RING_PACKET, status->lastValidRingSequence+1); -} - - - -int32 -RingGameProtocol::GetNetTime(void) -{ - // ZZZ: modified so as not to introduce ANY gratuitous latency. May make play a little choppy. - // Consider falling back to localNetTime - action_flags_per_packet... - // (later) Took that back out. It did make play nicely responsive, but opened us up wide to latency and jitter. - // I hope adaptive_latency_2 will be the final meddling with this stuff. - // return status->localNetTime; -#if defined(NETWORK_ADAPTIVE_LATENCY_2) || defined(NETWORK_ADAPTIVE_LATENCY_3) - // This is it - this is the only place sCurrentAdaptiveLatency has any effect in adaptive_latency_2 (or 3). - // The effect is to get the game engine to drain the player_queues more smoothly than they would - // if we returned status_localNetTime. - // Later: adding 1 in an effort to decrease lag (is this a good idea?) - // Later than that: getting rid of that "+1", need to subtract sCurrentAdaptiveLatency and that's that. - // Unless rings are taking less than a tick-time to get around, in which case we need not introduce - // any latency, which is why we special-case that. - return status->localNetTime - (sCurrentAdaptiveLatency > 1 ? sCurrentAdaptiveLatency : 0); -#else - return status->localNetTime - 2*status->action_flags_per_packet - status->update_latency; -#endif -} - -bool -RingGameProtocol::CheckWorldUpdate() -{ - if (status->worldUpdate) - { - status->worldUpdate = false; - return true; - } - else - { - return false; - } -} - -int32 RingGameProtocol::GetUnconfirmedActionFlagsCount() -{ - return GetRealActionQueues()->countActionFlags(NetGetLocalPlayerIndex()); -} - -uint32 RingGameProtocol::PeekUnconfirmedActionFlag(int32 offset) -{ - return GetRealActionQueues()->peekActionFlags(NetGetLocalPlayerIndex(), offset); -} - -void RingGameProtocol::UpdateUnconfirmedActionFlags() { } - - -// brazenly copied and modified from player.c (though i clearly format it much better) -static short NetSizeofLocalQueue( - void) -{ - short size; - - if ((size= local_queue.write_index-local_queue.read_index) < 0) - size += NET_QUEUE_SIZE; - - return size; -} - - - -void NetPrintInfo( - void) -{ -#ifdef DEBUG_NET - fdprintf("numSmears= %d numCountChanges= %d ring packet_count= %d Single: %d;g", net_stats.numSmears, - net_stats.numCountChanges, status->ringPacketCount, status->single_player); - fdprintf("localPlayerIndex= %d, server_player_index= %d;g", localPlayerIndex, status->server_player_index); - fdprintf("tick_count= %d, localNetTime= %d;g", dynamic_world->tick_count, status->localNetTime); - fdprintf("Unknown packets: %d Upring Drops: %d Rebuilt server Tags: %d;g", net_stats.packets_from_the_unknown, net_stats.upring_drops, net_stats.rebuilt_server_tag); - fdprintf("Late Rings: Sync: %d Time: %d Normal: %d Unsync: %d Dead: %d;g", net_stats.late_sync_rings, net_stats.late_time_rings, net_stats.late_rings, net_stats.late_unsync_rings, net_stats.late_dead_rings); - fdprintf("---Retries: Sync: %d Time: %d Normal: %d Unsync: %d Dead: %d;g", net_stats.sync_retry_count, net_stats.time_retry_count, net_stats.retry_count, net_stats.unsync_retry_count, net_stats.dead_retry_count); - fdprintf("Ontime Ack: Sync: %d Time: %d Normal: %d Unsync: %d Dead: %d Late: %d;g", net_stats.sync_ontime_acks, net_stats.time_ontime_acks, net_stats.ontime_acks, net_stats.unsync_ontime_acks, net_stats.dead_ontime_acks, net_stats.late_acks); - if(localPlayerIndex==status->server_player_index) - { - fdprintf("Server: Req to zero: %d Unsyncing: %d Returned: %d;g", net_stats.server_set_required_flags_to_zero, net_stats.server_unsyncing, net_stats.unsync_returned_to_sender); - } - fdprintf("Packets w/zero flags: %d Spurious Unsyncs: %d;g", net_stats.packets_with_zero_flags, net_stats.spurious_unsyncs); - fdprintf("Assumed control: Normal: %d Retry: %d (Server bailed early: %d);g", net_stats.assuming_control, net_stats.assuming_control_on_retry, net_stats.server_bailing_early); - fdprintf("Proper unsyncs: %d", net_stats.unsync_while_coming_down); -#endif//DEBUG_NET -} // NetPrintInfo - -static void process_packet_buffer_flags( - void *buffer, - int32 buffer_size, - short packet_tag) -{ - // ZZZ: By now, the buffer passed to us is unpacked and contains action flags. - /* NetPacket packet_data_storage; - NetPacket* packet_data = &packet_data_storage; - NetPacket_NET* packet_data_NET = (NetPacket_NET*) buffer; - - netcpy(packet_data, packet_data_NET); - */ - NetPacketPtr packet_data= (NetPacketPtr) buffer; - - /* The only time we don't process all flags is on network Unsyncing.. */ - process_flags(packet_data); - -#ifdef DEBUG_NET - if(packet_data->required_action_flags==0) - { - short index; - - for(index= status->server_player_index; indexaction_flag_count[index]<=0); - } - - for(index= 0; indexserver_player_index; index++) - { - warn(packet_data->action_flag_count[index]<=0); - } - } -#endif - - // can we send on the packet? - if (!status->iAmTheServer || status->canForwardRing) - { - status->canForwardRing = false; - if (status->iAmTheServer) - { // (ZZZ) This is the (server) control path if there is enough data available to send on the ring - packet_data->server_player_index= localPlayerIndex; - packet_data->server_net_time= status->localNetTime; - if(*sNetStatePtr==netComingDown) - { - /* Change the type to an unsync ring packet... */ - if(packet_data->required_action_flags==0) - { -#ifdef DEBUG_NET - // fdprintf("Server got a final packet & net was coming down (changed) type: %d (%d);g", packet_data->ring_packet_type, net_stats.action_flags_processed); - net_stats.server_unsyncing++; -#endif - packet_data->ring_packet_type= typeUNSYNC_RING_PACKET; - } - else - { -#ifdef DEBUG_NET - // fdprintf("Server got a packet & net was coming down (changed) (%d) current: %d;g", net_stats.action_flags_processed, packet_data->required_action_flags); - net_stats.server_set_required_flags_to_zero++; -#endif - packet_data->required_action_flags= 0; - } - } // netState == netComingDown - else // netState != netComingDown - { -#ifdef NETWORK_ADAPTIVE_LATENCY - // ZZZ addition: update the adaptive latency state - update_adaptive_latency(); - // ZZZ change: use the number of flags the adaptive latency system tells us. - // It's ok if this increases the number of flags needed; we'll just smear. - packet_data->required_action_flags = sCurrentAdaptiveLatency; -#else - packet_data->required_action_flags= NetSizeofLocalQueue(); -#endif - } - } // status->iAmTheServer - - NetAddFlagsToPacket(packet_data); - NetBuildRingPacket(ringFrame, (byte *) packet_data, NetPacketSize(packet_data), status->lastValidRingSequence+1); - - /* We just became the server.. */ - if(packet_tag != NONE) - { - NetRebuildRingPacket(ringFrame, packet_tag, status->lastValidRingSequence+1); - } - - /* Send the Ack just after we pass the token along.. */ - NetSendAcknowledgement(ackFrame, status->lastValidRingSequence); - NetSendRingPacket(ringFrame); - } - // tell the server task to send on the packet - else // status->iAmTheServer && !status->canForwardRing - { // (ZZZ note) This is the control path if we receive the ring before we have enough data to send the next one. - // Essentially, we package up the packet we received and wait for NetServerTask to deal with it later. - memcpy(status->buffer, packet_data, buffer_size - sizeof(NetPacket_NET) + sizeof(NetPacket)); - //BlockMove(buffer, status->buffer, buffer_size); - status->clearToForwardRing = true; - status->new_packet_tag= packet_tag; -#ifdef NETWORK_ADAPTIVE_LATENCY - // ZZZ addition: also, we update the adaptive latency now, while we know what time the packet arrived. - // It will be used in NetServerTask next time that's scheduled. - update_adaptive_latency(); -#endif - } -} // process_packet_buffer_flags - -/* - 0 tick0 tick0 tick0 tick1 Pulls (0, 1, 2) - 1 ----- tick0 (Pulls 0) tick0 tick0 - 2 ----- ----- tick0 (Pulls 0, 1, 2(none)) tick0 - - must pull yourself and everything above you to complete the ring. - */ - -/* On friday, the counts were different. I don't think that should have been the case- the */ -/* flags should have been different though.. */ -/* Got rid of the redundant action_flag_index, by using the more convenient and faster */ -/* pointer arithmetic. */ -static void process_flags( - NetPacket* packet_data) -{ - uint32 *action_flags= packet_data->action_flags; - short player_index; - - /* Process the action flags (including our old ones) */ - for (player_index= 0; player_indexplayer_count; ++player_index) - { - short player_flag_count= packet_data->action_flag_count[player_index]; - - vassert(player_flag_count >= -1 && player_flag_count <= MAXIMUM_UPDATES_PER_PACKET, - csprintf(temporary, "UGH! count= %d;dm #%p", player_flag_count, - ((byte*)packet_data)-sizeof(NetPacketHeader))); - - /* if the player is not net dead */ - if (player_flag_count != NET_DEAD_ACTION_FLAG_COUNT) - { - process_action_flags(player_index, action_flags, player_flag_count); -#ifdef DEBUG_NET - net_stats.action_flags_processed+= player_flag_count; -#endif - /* Regardless of whether you process this player, you need to increment past */ - /* this player's flags */ - action_flags+= player_flag_count; - } - else // stuff zeroes, for the good of the recording, and everyone’s sanity. - { - /* Only process if this is in our range of flags. */ - short index; - - // fdprintf("will stuff %d flags", packet_data->required_action_flags); - for (index= 0; indexrequired_action_flags; index++) - { - uint32 flag= (uint32)NET_DEAD_ACTION_FLAG; - - topology->players[player_index].net_dead= true; - - process_action_flags(player_index, &flag, 1); -#ifdef DEBUG_NET - net_stats.action_flags_processed+= 1; -#endif - } - } - } -} - - - -#ifdef DEBUG_NET_RECORD_PROFILE -// ZZZ: this was used (by me) for some debugging stuff -struct net_profile_record { - uint32 timestamp; - int32 local_queue_size; - int32 required_action_flags; - int32 player_queue_size; - int32 other_player_queue_size; - int32 net_time; - int32 supposed_net_time; - int32 world_time; -}; - -net_profile_record net_profile[1000]; -int net_profile_index = 0; - -#include "player.h" - -void -record_profile(int req_action_flags) { - if(net_profile_index < 1000) { - // capture 1000 profiling entries - net_profile[net_profile_index].timestamp = machine_tick_count(); - net_profile[net_profile_index].local_queue_size = NetSizeofLocalQueue(); - net_profile[net_profile_index].required_action_flags = req_action_flags; - net_profile[net_profile_index].player_queue_size= get_action_queue_size(local_player_index); - net_profile[net_profile_index].other_player_queue_size= get_action_queue_size(1-local_player_index); - net_profile[net_profile_index].net_time = status->localNetTime; - net_profile[net_profile_index].supposed_net_time = NetGetNetTime(); - net_profile[net_profile_index].world_time = dynamic_world->tick_count; - - net_profile_index++; - } - else - // hop into debugger to see the results - assert(false); -} -#endif // DEBUG_NET_RECORD_PROFILE - - - -void -RingGameProtocol::ParsePreferencesTree(InfoTree prefs, std::string version) -{ - prefs.read_attr("accept_packets_from_anyone", sRingPreferences.mAcceptPacketsFromAnyone); - prefs.read_attr("adapt_to_latency", sRingPreferences.mAdaptToLatency); - prefs.read_attr_bounded("latency_hold_ticks", sRingPreferences.mLatencyHoldTicks, 2, INT32_MAX); -} - -InfoTree RingPreferencesTree() -{ - InfoTree root; - root.put_attr("accept_packets_from_anyone", sRingPreferences.mAcceptPacketsFromAnyone); - root.put_attr("adapt_to_latency", sRingPreferences.mAdaptToLatency); - root.put_attr("latency_hold_ticks", sRingPreferences.mLatencyHoldTicks); - - return root; -} - - - -void -DefaultRingPreferences() -{ - sRingPreferences.mAcceptPacketsFromAnyone = false; - sRingPreferences.mAdaptToLatency = true; - sRingPreferences.mLatencyHoldTicks = 2 * TICKS_PER_SECOND; -} - -#endif // !defined(DISABLE_NETWORKING) diff --git a/Source_Files/Network/RingGameProtocol.h b/Source_Files/Network/RingGameProtocol.h deleted file mode 100644 index 431327fd0..000000000 --- a/Source_Files/Network/RingGameProtocol.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * network_ring.h - - Copyright (C) 2003 and beyond by Woody Zenfell, III - and the "Aleph One" developers. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - This license is contained in the file "COPYING", - which is included with this source code; it is available online at - http://www.gnu.org/licenses/gpl.html - - * Created by Woody Zenfell, III on Sat May 17 2003. - * - * Interface between the old ring game protocol module and the rest of the game. - */ - -#ifndef NETWORK_RING -#define NETWORK_RING - -#include "NetworkGameProtocol.h" - -#include - -class InfoTree; - -class RingGameProtocol : public NetworkGameProtocol -{ -public: - bool Enter(short* inNetStatePtr); - void Exit1(); - void Exit2(); - void DistributeInformation(short type, void *buffer, short buffer_size, bool send_to_self, bool only_send_to_team); - bool Sync(NetTopology* inTopology, int32 inSmallestGameTick, int inLocalPlayerIndex, int inServerPlayerIndex); - bool UnSync(bool inGraceful, int32 inSmallestPostgameTick); - int32 GetNetTime(); - void PacketHandler(DDPPacketBuffer* inPacket); - - int32 GetUnconfirmedActionFlagsCount(); - uint32 PeekUnconfirmedActionFlag(int32 offset); - void UpdateUnconfirmedActionFlags(); - - static void ParsePreferencesTree(InfoTree prefs, std::string version); - - bool CheckWorldUpdate() override; -}; - -extern void DefaultRingPreferences(); -InfoTree RingPreferencesTree(); - -#endif // NETWORK_RING diff --git a/Source_Files/Network/network.cpp b/Source_Files/Network/network.cpp index 898dd0d16..7506c95cd 100644 --- a/Source_Files/Network/network.cpp +++ b/Source_Files/Network/network.cpp @@ -154,7 +154,6 @@ clearly this is all broken until we have packet types #include "NetworkGameProtocol.h" -#include "RingGameProtocol.h" #include "StarGameProtocol.h" #include "lua_script.h" @@ -178,7 +177,6 @@ static std::string gameSessionIdentifier; static NetTopologyPtr topology; static short sServerPlayerIndex; static bool sOldSelfSendStatus; -static RingGameProtocol sRingGameProtocol; static StarGameProtocol sStarGameProtocol; static NetworkGameProtocol* sCurrentGameProtocol = NULL; @@ -465,14 +463,6 @@ bool Client::capabilities_indicate_player_is_gatherable(bool warn_joiner) } return false; } - } else { - if (capabilities[Capabilities::kRing] == 0) { - if (warn_joiner) { - ServerWarningMessage serverWarningMessage(getcstr(s, strNETWORK_ERRORS, netWarnJoinerHasNoRing), ServerWarningMessage::kJoinerUngatherable); - channel->enqueueOutgoingMessage(serverWarningMessage); - } - return false; - } } if (do_netscript) @@ -1280,9 +1270,7 @@ bool NetEnter(bool use_remote_hub) added_exit_procedure= true; } - sCurrentGameProtocol = (network_preferences->game_protocol == _network_game_protocol_star) ? - static_cast(&sStarGameProtocol) : - static_cast(&sRingGameProtocol); + sCurrentGameProtocol = static_cast(&sStarGameProtocol); error= NetDDPOpen(); if (!error) { @@ -1373,8 +1361,6 @@ bool NetEnter(bool use_remote_hub) my_capabilities[Capabilities::kGameworldM1] = Capabilities::kGameworldM1Version; if (network_preferences->game_protocol == _network_game_protocol_star) { my_capabilities[Capabilities::kStar] = Capabilities::kStarVersion; - } else { - my_capabilities[Capabilities::kRing] = Capabilities::kRingVersion; } my_capabilities[Capabilities::kLua] = Capabilities::kLuaVersion; my_capabilities[Capabilities::kGatherable] = Capabilities::kGatherableVersion; diff --git a/Source_Files/Network/network_capabilities.cpp b/Source_Files/Network/network_capabilities.cpp index 46d113150..d4ea8d4ba 100644 --- a/Source_Files/Network/network_capabilities.cpp +++ b/Source_Files/Network/network_capabilities.cpp @@ -24,7 +24,6 @@ const string Capabilities::kGameworld = "Gameworld"; const string Capabilities::kGameworldM1 = "GameworldM1"; const string Capabilities::kStar = "Star"; -const string Capabilities::kRing = "Ring"; const string Capabilities::kLua = "Lua"; const string Capabilities::kGatherable = "Gatherable"; const string Capabilities::kZippedData = "ZippedData"; diff --git a/Source_Files/Network/network_capabilities.h b/Source_Files/Network/network_capabilities.h index 6ce88ea05..b2ad6c90d 100644 --- a/Source_Files/Network/network_capabilities.h +++ b/Source_Files/Network/network_capabilities.h @@ -40,7 +40,6 @@ class Capabilities : public capabilities_t static const int kGameworldVersion = 5; static const int kGameworldM1Version = 4; static const int kStarVersion = 6; - static const int kRingVersion = 2; static const int kLuaVersion = 2; static const int kGatherableVersion = 1; static const int kZippedDataVersion = 1; // map, lua, physics @@ -50,7 +49,6 @@ class Capabilities : public capabilities_t static const string kGameworld; // the PRNG, physics, etc. static const string kGameworldM1; // like gameworld, but for Marathon 1 compatibility static const string kStar; // the star network protocol - static const string kRing; // the ring network protocol static const string kLua; // Lua script support static const string kGatherable; // joiner's response indicating he can be // gathered diff --git a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj index 113bf868c..4788d3bb1 100644 --- a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj +++ b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj @@ -560,7 +560,6 @@ - @@ -783,7 +782,6 @@ - diff --git a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj.filters b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj.filters index d8bdbb456..d4608fa2a 100644 --- a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj.filters +++ b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj.filters @@ -460,9 +460,6 @@ Network\Source Files - - Network\Source Files - Network\Source Files @@ -1128,9 +1125,6 @@ Network\Header Files - - Network\Header Files - Network\Header Files From b76120b6e2cd78cd0ee0dff8b0f2bd2863327982 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Fri, 16 Aug 2024 17:27:52 +0200 Subject: [PATCH 13/58] Rework net server detection and fix resuming joiner's saved games assert/crash --- Source_Files/Misc/sdl_network.h | 2 -- Source_Files/Network/NetworkGameProtocol.h | 2 +- Source_Files/Network/StarGameProtocol.cpp | 6 ++-- Source_Files/Network/StarGameProtocol.h | 2 +- Source_Files/Network/network.cpp | 37 ++++++---------------- 5 files changed, 14 insertions(+), 35 deletions(-) diff --git a/Source_Files/Misc/sdl_network.h b/Source_Files/Misc/sdl_network.h index d316a863d..05577b36b 100644 --- a/Source_Files/Misc/sdl_network.h +++ b/Source_Files/Misc/sdl_network.h @@ -89,8 +89,6 @@ typedef void (*PacketHandlerProcPtr)(DDPPacketBufferPtr packet); short NetState(void); std::string NetSessionIdentifier(void); -void NetSetServerIdentifier(short identifier); - /* for giving to NetLookupOpen() as a filter procedure */ bool NetEntityNotInGame(NetEntityName *entity, NetAddrBlock *address); diff --git a/Source_Files/Network/NetworkGameProtocol.h b/Source_Files/Network/NetworkGameProtocol.h index e01af3731..ca380a2e3 100644 --- a/Source_Files/Network/NetworkGameProtocol.h +++ b/Source_Files/Network/NetworkGameProtocol.h @@ -36,7 +36,7 @@ class NetworkGameProtocol virtual void Exit1() = 0; virtual void Exit2() = 0; virtual void DistributeInformation(short type, void *buffer, short buffer_size, bool send_to_self, bool only_send_to_team) = 0; - virtual bool Sync(NetTopology* inTopology, int32 inSmallestGameTick, int inLocalPlayerIndex, int inServerPlayerIndex) = 0; + virtual bool Sync(NetTopology* inTopology, int32 inSmallestGameTick, int inLocalPlayerIndex, bool isServer) = 0; virtual bool UnSync(bool inGraceful, int32 inSmallestPostgameTick) = 0; virtual int32 GetNetTime() = 0; virtual void PacketHandler(DDPPacketBuffer* inPacket) = 0; diff --git a/Source_Files/Network/StarGameProtocol.cpp b/Source_Files/Network/StarGameProtocol.cpp index 5aca0cc37..21ca613d3 100644 --- a/Source_Files/Network/StarGameProtocol.cpp +++ b/Source_Files/Network/StarGameProtocol.cpp @@ -116,12 +116,12 @@ StarGameProtocol::PacketHandler(DDPPacketBufferPtr packet) bool -StarGameProtocol::Sync(NetTopology* inTopology, int32 inSmallestGameTick, int inLocalPlayerIndex, int inServerPlayerIndex) +StarGameProtocol::Sync(NetTopology* inTopology, int32 inSmallestGameTick, int inLocalPlayerIndex, bool isServer) { assert(inTopology != NULL); #ifdef A1_NETWORK_STANDALONE_HUB - assert(inLocalPlayerIndex == inServerPlayerIndex && inLocalPlayerIndex == NONE); + assert(isServer && inLocalPlayerIndex == NONE); #endif sTopology = inTopology; @@ -138,7 +138,7 @@ StarGameProtocol::Sync(NetTopology* inTopology, int32 inSmallestGameTick, int in theConnectedPlayerStatus[i] = ((sTopology->players[i].identifier != NONE) && !sTopology->players[i].net_dead); } - if(inLocalPlayerIndex == inServerPlayerIndex) + if(isServer) { #ifndef A1_NETWORK_STANDALONE_HUB sHubIsLocal = true; diff --git a/Source_Files/Network/StarGameProtocol.h b/Source_Files/Network/StarGameProtocol.h index 6b0b240b8..bee6bc936 100644 --- a/Source_Files/Network/StarGameProtocol.h +++ b/Source_Files/Network/StarGameProtocol.h @@ -39,7 +39,7 @@ class StarGameProtocol : public NetworkGameProtocol void Exit1(); void Exit2(); void DistributeInformation(short type, void *buffer, short buffer_size, bool send_to_self, bool only_send_to_team); - bool Sync(NetTopology* inTopology, int32 inSmallestGameTick, int inLocalPlayerIndex, int inServerPlayerIndex); + bool Sync(NetTopology* inTopology, int32 inSmallestGameTick, int inLocalPlayerIndex, bool isServer); bool UnSync(bool inGraceful, int32 inSmallestPostgameTick); int32 GetNetTime(); void PacketHandler(DDPPacketBuffer* inPacket); diff --git a/Source_Files/Network/network.cpp b/Source_Files/Network/network.cpp index 7506c95cd..9dd95563f 100644 --- a/Source_Files/Network/network.cpp +++ b/Source_Files/Network/network.cpp @@ -175,7 +175,6 @@ static short localPlayerIndex; static short localPlayerIdentifier; static std::string gameSessionIdentifier; static NetTopologyPtr topology; -static short sServerPlayerIndex; static bool sOldSelfSendStatus; static StarGameProtocol sStarGameProtocol; static NetworkGameProtocol* sCurrentGameProtocol = NULL; @@ -225,11 +224,16 @@ const static int network_stats_send_period = MACHINE_TICKS_PER_SECOND; // ignore list static std::set sIgnoredPlayers; -bool player_is_ignored(int player_index) +static bool player_is_ignored(int player_index) { return (sIgnoredPlayers.find(player_index) != sIgnoredPlayers.end()); } +static bool local_is_server() +{ + return !connection_to_server; +} + struct ignore_player { void operator()(const std::string& s) const { int player_index = atoi(s.c_str()); @@ -1278,12 +1282,6 @@ bool NetEnter(bool use_remote_hub) assert(topology); memset(topology, 0, sizeof(NetTopology)); -#ifdef A1_NETWORK_STANDALONE_HUB - NetSetServerIdentifier(NONE); -#else - NetSetServerIdentifier(use_remote_hub ? NONE : 0); -#endif - // ZZZ: Sorry, if this swapping is not supported on all current A1 // platforms, feel free to rewrite it in a way that is. ddpSocket = SDL_SwapBE16(GAME_PORT); @@ -1472,7 +1470,7 @@ void NetExit( bool NetSync() { - return sCurrentGameProtocol->Sync(topology, dynamic_world->tick_count, localPlayerIndex, sServerPlayerIndex); + return sCurrentGameProtocol->Sync(topology, dynamic_world->tick_count, localPlayerIndex, local_is_server()); } @@ -1916,18 +1914,6 @@ void NetChangeColors(int16 color, int16 team) { } } -/* - Externally, this is only called before a new game. It removes the reliance that - localPlayerIndex of zero is the server, which is not necessarily true if we are - resyncing for another cooperative level. -*/ -void NetSetServerIdentifier( - short identifier) -{ - sServerPlayerIndex= identifier; -} - - /* net accessor functions */ @@ -2308,12 +2294,8 @@ bool NetChangeMap( /* If the guy that was the server died, and we are trying to change levels, we lose */ // ZZZ: if we used the parent_wad_checksum stuff to locate the containing Map file, // this would be the case somewhat less frequently, probably... - if(localPlayerIndex==sServerPlayerIndex && localPlayerIndex > 0) { - logError("server died while trying to get another level"); - success= false; - } else { // being the server, we must send out the map to everyone. - if(localPlayerIndex==sServerPlayerIndex) { + if (local_is_server()) { #ifdef A1_NETWORK_STANDALONE_HUB @@ -2357,7 +2339,6 @@ bool NetChangeMap( process_net_map_data(wad); } #endif - } return success; } @@ -3082,7 +3063,7 @@ bool NetAllowCarnageMessages() { bool NetAllowSavingLevel() { return (dynamic_world->player_count == 1 || - localPlayerIndex == sServerPlayerIndex || + local_is_server() || use_remote_hub || !(dynamic_world->game_information.cheat_flags & _disable_saving_level)); } From 7681fdeabba9f29bb4849c2eac57234a39b5bf6f Mon Sep 17 00:00:00 2001 From: Kolfering Date: Fri, 16 Aug 2024 17:34:48 +0200 Subject: [PATCH 14/58] Fix remote hub player data not loaded on resumed games --- Source_Files/Files/game_wad.cpp | 19 +++++++++++++------ Source_Files/Files/game_wad.h | 1 + .../StandaloneHub/standalone_hub_main.cpp | 4 ++-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Source_Files/Files/game_wad.cpp b/Source_Files/Files/game_wad.cpp index 2b98f1f95..dbbc59941 100644 --- a/Source_Files/Files/game_wad.cpp +++ b/Source_Files/Files/game_wad.cpp @@ -1854,13 +1854,10 @@ bool process_map_wad( MapIndexList.resize(count); StreamToList(data,map_indexes,count); - data= (uint8 *)extract_type_from_wad(wad, PLAYER_STRUCTURE_TAG, &data_length); - count= data_length/SIZEOF_player_data; - assert(count*SIZEOF_player_data==data_length); - unpack_player_data(data,players,count); - team_damage_from_player_data(); + bool result = get_player_data_from_wad(wad); + assert(result); - bool result = get_dynamic_data_from_wad(wad, dynamic_world); + result = get_dynamic_data_from_wad(wad, dynamic_world); assert(result); data= (uint8 *)extract_type_from_wad(wad, OBJECT_STRUCTURE_TAG, &data_length); @@ -1960,6 +1957,16 @@ bool get_dynamic_data_from_wad(wad_data* wad, dynamic_data* dest) return data && data_length == SIZEOF_dynamic_data ? (bool)unpack_dynamic_data(data, dest, 1) : false; } +bool get_player_data_from_wad(wad_data* wad) +{ + size_t data_length; + auto data = (uint8*)extract_type_from_wad(wad, PLAYER_STRUCTURE_TAG, &data_length); + auto count = data_length / SIZEOF_player_data; + bool success = count * SIZEOF_player_data == data_length ? (bool)unpack_player_data(data, players, count) : false; + if (success) team_damage_from_player_data(); + return success; +} + static void allocate_map_structure_for_map( struct wad_data *wad) { diff --git a/Source_Files/Files/game_wad.h b/Source_Files/Files/game_wad.h index 6c2936b17..34a15d23e 100644 --- a/Source_Files/Files/game_wad.h +++ b/Source_Files/Files/game_wad.h @@ -59,6 +59,7 @@ bool match_checksum_with_map(short vRefNum, long dirID, uint32 checksum, void set_map_file(FileSpecifier& File, bool runScript = true); dynamic_data get_dynamic_data_from_save(FileSpecifier& File); bool get_dynamic_data_from_wad(wad_data* wad, dynamic_data* dest); +bool get_player_data_from_wad(wad_data* wad); //CP Addition: get_map_file returns the FileDesc pointer to the current map FileSpecifier& get_map_file(void); diff --git a/Source_Files/Network/StandaloneHub/standalone_hub_main.cpp b/Source_Files/Network/StandaloneHub/standalone_hub_main.cpp index 344ee4df7..2a5ebbe82 100644 --- a/Source_Files/Network/StandaloneHub/standalone_hub_main.cpp +++ b/Source_Files/Network/StandaloneHub/standalone_hub_main.cpp @@ -81,9 +81,9 @@ static bool hub_init_game(void) wad_header header; auto wad_data = inflate_flat_data(wad_copy, &header); - if (!wad_data) return false; + if (!wad_data) { delete[] wad_copy; return false; } - bool success = get_dynamic_data_from_wad(wad_data, dynamic_world); + bool success = get_dynamic_data_from_wad(wad_data, dynamic_world) && get_player_data_from_wad(wad_data); free_wad(wad_data); return success; From c9c7c934a748c244b1de1389ab4f2ba1227656ad Mon Sep 17 00:00:00 2001 From: Kolfering Date: Fri, 16 Aug 2024 20:45:05 +0200 Subject: [PATCH 15/58] Clear previous game "errors" before trying to save the game --- Source_Files/Files/game_wad.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source_Files/Files/game_wad.cpp b/Source_Files/Files/game_wad.cpp index dbbc59941..02203a1f2 100644 --- a/Source_Files/Files/game_wad.cpp +++ b/Source_Files/Files/game_wad.cpp @@ -1427,6 +1427,8 @@ bool save_game_file(FileSpecifier& File, const std::string& metadata, const std: struct directory_entry entries[2]; struct wad_data *wad, *meta_wad; + clear_game_error(); + /* Save off the random seed. */ dynamic_world->random_seed= get_random_seed(); From 4f58239382e4cb07668159a28d05fdfc6e3ed0a4 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Fri, 16 Aug 2024 22:29:56 +0200 Subject: [PATCH 16/58] Don't find more net teams than there are players (fix rare assert) --- Source_Files/Network/network_dialogs.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Source_Files/Network/network_dialogs.cpp b/Source_Files/Network/network_dialogs.cpp index 4569a73c8..d26e866e7 100644 --- a/Source_Files/Network/network_dialogs.cpp +++ b/Source_Files/Network/network_dialogs.cpp @@ -1874,10 +1874,6 @@ void draw_team_totals_graph( objlist_clear(ranks, MAXIMUM_NUMBER_OF_PLAYERS); for (team_index = 0, num_teams = 0; team_index < NUMBER_OF_TEAM_COLORS; team_index++) { found_team_of_current_color = false; - if (team_damage_given[team_index].kills || - (team_damage_taken[team_index].kills + team_monster_damage_taken[team_index].kills)) { - found_team_of_current_color = true; - } else { for (player_index = 0; player_index < dynamic_world->player_count; player_index++) { struct player_data *player = get_player_data(player_index); if (player->team == team_index) { @@ -1885,7 +1881,6 @@ void draw_team_totals_graph( break; } } - } if (found_team_of_current_color) { ranks[num_teams].player_index = NONE; ranks[num_teams].color = team_index; From 9f2819cec4f9686f081a3fe1caf1ec00b9ec20d7 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Fri, 16 Aug 2024 23:44:03 +0200 Subject: [PATCH 17/58] Fix joystick initialization too late for ScenarioChooser & add joystick added/removed events --- Source_Files/Misc/ScenarioChooser.cpp | 9 +++++++++ Source_Files/shell.cpp | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Source_Files/Misc/ScenarioChooser.cpp b/Source_Files/Misc/ScenarioChooser.cpp index afae62afb..0e64e2bcf 100644 --- a/Source_Files/Misc/ScenarioChooser.cpp +++ b/Source_Files/Misc/ScenarioChooser.cpp @@ -19,6 +19,7 @@ #include "find_files.h" #include "images.h" #include "sdl_fonts.h" +#include "joystick.h" using SurfacePtr = std::unique_ptr; using WindowPtr = std::unique_ptr; @@ -306,6 +307,14 @@ void ScenarioChooser::handle_event(SDL_Event& e) { switch (e.type) { + case SDL_JOYDEVICEADDED: + joystick_added(e.jdevice.which); + break; + + case SDL_JOYDEVICEREMOVED: + joystick_removed(e.jdevice.which); + break; + case SDL_CONTROLLERBUTTONDOWN: switch (e.cbutton.button) { diff --git a/Source_Files/shell.cpp b/Source_Files/shell.cpp index c68cddcbe..ac725ee32 100644 --- a/Source_Files/shell.cpp +++ b/Source_Files/shell.cpp @@ -295,6 +295,8 @@ void initialize_application(void) SDL_EventState(SDL_DROPFILE, SDL_DISABLE); } + initialize_joystick(); + const string default_data_env = a1_getenv("ALEPHONE_DEFAULT_DATA"); #ifndef SCENARIO_IS_BUNDLED // see if there are scenarios to choose from @@ -510,7 +512,6 @@ void initialize_application(void) SoundManager::instance()->Initialize(*sound_preferences); initialize_marathon_music_handler(); initialize_keyboard_controller(); - initialize_joystick(); initialize_gamma(); alephone::Screen::instance()->Initialize(&graphics_preferences->screen_mode); initialize_marathon(); From f7d41a4f128a465ae7e513a617115b4e31a46fad Mon Sep 17 00:00:00 2001 From: Kolfering Date: Sat, 17 Aug 2024 00:08:59 +0200 Subject: [PATCH 18/58] Remove mystic controller setting file user is supposed to know about --- Source_Files/Input/joystick_sdl.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Source_Files/Input/joystick_sdl.cpp b/Source_Files/Input/joystick_sdl.cpp index f82519136..81013d922 100644 --- a/Source_Files/Input/joystick_sdl.cpp +++ b/Source_Files/Input/joystick_sdl.cpp @@ -29,7 +29,6 @@ May 18, 2009 (Eric Peterson): #include "preferences.h" #include "joystick.h" #include "Logging.h" -#include "FileHandler.h" // internal handles int joystick_active = true; @@ -38,12 +37,6 @@ int axis_values[SDL_CONTROLLER_AXIS_MAX] = {}; bool button_values[NUM_SDL_JOYSTICK_BUTTONS] = {}; void initialize_joystick(void) { - // Look for "gamecontrollerdb.txt" in default search path - FileSpecifier fs; - if (fs.SetNameWithPath("gamecontrollerdb.txt")) { - SDL_GameControllerAddMappingsFromFile(fs.GetPath()); - } - SDL_GameControllerEventState(SDL_ENABLE); for (int i = 0; i < SDL_NumJoysticks(); ++i) joystick_added(i); From 5173d6d29ccdbdc74f3e65497a58a60c31a40c33 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Fri, 16 Aug 2024 20:23:15 -0400 Subject: [PATCH 19/58] pad title screens to 640x480 before scaling down in the scenario chooser --- Source_Files/Misc/ScenarioChooser.cpp | 7 ++++++- Source_Files/Misc/ScenarioChooser.h | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Source_Files/Misc/ScenarioChooser.cpp b/Source_Files/Misc/ScenarioChooser.cpp index 0e64e2bcf..0a4d170b7 100644 --- a/Source_Files/Misc/ScenarioChooser.cpp +++ b/Source_Files/Misc/ScenarioChooser.cpp @@ -496,7 +496,12 @@ void ScenarioChooser::optimize_image(ScenarioChooserScenario& scenario, SDL_Wind SurfacePtr optimized(SDL_ConvertSurface(scenario.image.get(), format, 0), SDL_FreeSurface); SDL_Rect src_rect{0, 0, optimized->w, optimized->h}; - SDL_Rect dst_rect{0, (scenario_height - optimized->h / 2) / 2, scenario_width, optimized->h / 2}; + SDL_Rect dst_rect; + + dst_rect.w = optimized->w * scenario_width / title_screen_width; + dst_rect.h = optimized->h * scenario_height / title_screen_height; + dst_rect.x = (scenario_width - dst_rect.w) / 2; + dst_rect.y = (scenario_height - dst_rect.h) / 2; scenario.image.reset(SDL_CreateRGBSurface(0, scenario_width, scenario_height, format->BitsPerPixel, format->Rmask, format->Gmask, format->Bmask, format->Amask)); diff --git a/Source_Files/Misc/ScenarioChooser.h b/Source_Files/Misc/ScenarioChooser.h index 775f9dba5..e0f913ed4 100644 --- a/Source_Files/Misc/ScenarioChooser.h +++ b/Source_Files/Misc/ScenarioChooser.h @@ -30,6 +30,9 @@ class font_info; class ScenarioChooser { public: + static constexpr auto title_screen_width = 640; // nominal + static constexpr auto title_screen_height = 480; // nominal + static constexpr auto scenario_width = 320; static constexpr auto scenario_height = 240; From ec5880cae06263985c37fb12336637cca640e32b Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Fri, 16 Aug 2024 21:16:23 -0400 Subject: [PATCH 20/58] use breadth first search to find files; skip top level Scenarios dir --- Source_Files/Files/find_files.h | 5 +- Source_Files/Files/find_files_sdl.cpp | 79 +++++++++++++++------------ 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/Source_Files/Files/find_files.h b/Source_Files/Files/find_files.h index 64af22f60..75cec05dd 100644 --- a/Source_Files/Files/find_files.h +++ b/Source_Files/Files/find_files.h @@ -41,12 +41,9 @@ class FileFinder { FileFinder() {} virtual ~FileFinder() {} - bool Find(DirectorySpecifier &dir, Typecode type, bool recursive = true) { - return _Find(dir, type, recursive, 0); - } + bool Find(DirectorySpecifier &dir, Typecode type, bool recursive = true); protected: - bool _Find(DirectorySpecifier& dir, Typecode type, bool recursive, int depth); // Gets called for each found file, returns true if search is to be aborted virtual bool found(FileSpecifier &file) = 0; }; diff --git a/Source_Files/Files/find_files_sdl.cpp b/Source_Files/Files/find_files_sdl.cpp index 082b4179a..ca82e9f88 100644 --- a/Source_Files/Files/find_files_sdl.cpp +++ b/Source_Files/Files/find_files_sdl.cpp @@ -31,49 +31,58 @@ #include #include +#include - -/* - * File finder base class - */ - -bool FileFinder::_Find(DirectorySpecifier &dir, Typecode type, bool recursive, int depth) +bool FileFinder::Find(DirectorySpecifier& dir, Typecode type, bool recursive) { - // Get list of entries in directory - vector entries; - if (!dir.ReadDirectory(entries)) - return false; - sort(entries.begin(), entries.end()); - - // Iterate through entries - vector::const_iterator i, end = entries.end(); - for (i = entries.begin(); i != end; i++) { - - // Construct full specifier of file/dir - FileSpecifier file = dir + i->name; - - if (i->is_directory) { - - if (depth == 0 && i->name == "Plugins") - continue; - - // Recurse into directory - if (recursive) - if (_Find(file, type, recursive, depth + 1)) - return true; - - } else { + std::queue> directories; + directories.push(std::make_pair(0, dir)); + + while (!directories.empty()) + { + auto [depth, directory] = directories.front(); + directories.pop(); + + std::vector entries; + if (!directory.ReadDirectory(entries)) + { + return false; + } - // Check file type and call found() function - if (type == WILDCARD_TYPE || type == file.GetType()) - if (found(file)) - return true; + std::sort(entries.begin(), entries.end()); + + for (const auto& entry : entries) + { + FileSpecifier file = directory + entry.name; + if (entry.is_directory) + { + if (depth == 0 && + (entry.name == "Plugins" || entry.name == "Scenarios")) + { + continue; + } + + if (recursive) + { + directories.push(std::make_pair(depth + 1, file)); + } + } + else + { + if (type == WILDCARD_TYPE || type == file.GetType()) + { + if (found(file)) + { + return true; + } + } + } } } + return false; } - /* * Find all files of given type */ From 574397f6d781b0bb588aa79a3decaa18c76e3ccc Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Sat, 17 Aug 2024 10:36:19 -0400 Subject: [PATCH 21/58] use MacBinary for Images.imgA files so Atque can split them include folder path in Marathon Infinity physics filenames MML so it finds physics on startup --- data/Scenarios/Marathon 2 | 2 +- data/Scenarios/Marathon Infinity | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/Scenarios/Marathon 2 b/data/Scenarios/Marathon 2 index fff4f7401..794167c7a 160000 --- a/data/Scenarios/Marathon 2 +++ b/data/Scenarios/Marathon 2 @@ -1 +1 @@ -Subproject commit fff4f740124228dbaaeddb44e4aa6120263bb29b +Subproject commit 794167c7ae686a567ef70c2f1444b5f2fcd0c046 diff --git a/data/Scenarios/Marathon Infinity b/data/Scenarios/Marathon Infinity index 8f3cec778..13eefa897 160000 --- a/data/Scenarios/Marathon Infinity +++ b/data/Scenarios/Marathon Infinity @@ -1 +1 @@ -Subproject commit 8f3cec778225f6507db20e8bff995767d317df7d +Subproject commit 13eefa8979e3a248248f9abea72771f31268bbcf From a43b1649b8d81934652dd0a58bc1ecb3a668fef2 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Wed, 24 Jul 2024 21:15:26 +0200 Subject: [PATCH 22/58] Implement steam workshop uploader --- PBProjects/AlephOne.xcodeproj/project.pbxproj | 19 +- Source_Files/CSeries/csalerts.h | 3 +- Source_Files/CSeries/csalerts_sdl.cpp | 48 +- Source_Files/Files/FileHandler.cpp | 31 + Source_Files/Files/FileHandler.h | 1 + Source_Files/Misc/DefaultStringSets.cpp | 3 + Source_Files/Misc/Makefile.am | 2 +- Source_Files/Misc/interface.cpp | 306 +++++++++- Source_Files/Misc/progress.h | 4 + Source_Files/Misc/sdl_widgets.cpp | 43 ++ Source_Files/Misc/sdl_widgets.h | 22 + ...{steamshim_child.c => steamshim_child.cpp} | 157 ++++- Source_Files/Misc/steamshim_child.h | 162 ++++- Source_Files/Network/network_dialogs.cpp | 6 + Source_Files/shell.cpp | 40 +- Steam/steamshim_parent.cpp | 558 +++++++++++++++++- VisualStudio/LibAlephOne/LibAlephOne.vcxproj | 2 +- .../LibAlephOne/LibAlephOne.vcxproj.filters | 2 +- 18 files changed, 1318 insertions(+), 91 deletions(-) rename Source_Files/Misc/{steamshim_child.c => steamshim_child.cpp} (70%) mode change 100755 => 100644 diff --git a/PBProjects/AlephOne.xcodeproj/project.pbxproj b/PBProjects/AlephOne.xcodeproj/project.pbxproj index 0fbd73c41..4770c5ce0 100644 --- a/PBProjects/AlephOne.xcodeproj/project.pbxproj +++ b/PBProjects/AlephOne.xcodeproj/project.pbxproj @@ -678,7 +678,6 @@ AE120D5C2BC77645001873DD /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9975072661D6E300DDD370 /* CoreAudio.framework */; }; AE120D5D2BC77645001873DD /* ForceFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9975012661D50F00DDD370 /* ForceFeedback.framework */; }; AE120D5E2BC77645001873DD /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9975092661D6F400DDD370 /* AudioUnit.framework */; }; - AE120D672BC776CE001873DD /* steamshim_child.c in Sources */ = {isa = PBXBuildFile; fileRef = AE120D662BC776CE001873DD /* steamshim_child.c */; }; AE120D692BC776E7001873DD /* steamshim_child.h in Headers */ = {isa = PBXBuildFile; fileRef = AE120D682BC776E7001873DD /* steamshim_child.h */; }; AE1320312C1CB4D2009D34AA /* PlayerName.h in Headers */ = {isa = PBXBuildFile; fileRef = F522120C0136A6FD01000001 /* PlayerName.h */; }; AE1320322C1CB4D2009D34AA /* Random.h in Headers */ = {isa = PBXBuildFile; fileRef = F52212190136A6FD01000001 /* Random.h */; }; @@ -1012,7 +1011,6 @@ AE13217E2C1CB4D2009D34AA /* QuickSave.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 276D4E761A2E734E00C16CF5 /* QuickSave.cpp */; }; AE13217F2C1CB4D2009D34AA /* XML_MakeRoot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC94410240DE0E01A80001 /* XML_MakeRoot.cpp */; }; AE1321802C1CB4D2009D34AA /* sdl_resize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27EFC4BC1A7D8CBF00A95592 /* sdl_resize.cpp */; }; - AE1321812C1CB4D2009D34AA /* steamshim_child.c in Sources */ = {isa = PBXBuildFile; fileRef = AE120D662BC776CE001873DD /* steamshim_child.c */; }; AE1321822C1CB4D2009D34AA /* Packing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5837191031EEE0201000105 /* Packing.cpp */; }; AE1321832C1CB4D2009D34AA /* DefaultStringSets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DAC27A503DC9D1C00000104 /* DefaultStringSets.cpp */; }; AE1321842C1CB4D2009D34AA /* Logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DAC27A603DC9D1C00000104 /* Logging.cpp */; }; @@ -1134,6 +1132,10 @@ AE171BCE2A59F6EE00A4D3FC /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE171BCC2A59F6EE00A4D3FC /* main.cpp */; }; AE171BCF2A59F6EE00A4D3FC /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE171BCC2A59F6EE00A4D3FC /* main.cpp */; }; AE171BD02A59F6EE00A4D3FC /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE171BCC2A59F6EE00A4D3FC /* main.cpp */; }; + AE1D0DEA2C6198500083010F /* steamshim_child.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE1D0DE92C6198500083010F /* steamshim_child.cpp */; }; + AE1D0DEB2C6198500083010F /* steamshim_child.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE1D0DE92C6198500083010F /* steamshim_child.cpp */; }; + AE1D0DEC2C6198500083010F /* steamshim_child.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE1D0DE92C6198500083010F /* steamshim_child.cpp */; }; + AE1D0DED2C6198AE0083010F /* ScenarioChooser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE83423F2C5B22EA00A4A530 /* ScenarioChooser.cpp */; }; AE1F1B952662C69500E6390E /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9974FD2661D49E00DDD370 /* AudioToolbox.framework */; }; AE1F1B962662C69600E6390E /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9974FD2661D49E00DDD370 /* AudioToolbox.framework */; }; AE1F1B972662C69600E6390E /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE9974FD2661D49E00DDD370 /* AudioToolbox.framework */; }; @@ -2371,7 +2373,6 @@ AEBDC65B2C4DF0780026DFF1 /* XML_MakeRoot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC94410240DE0E01A80001 /* XML_MakeRoot.cpp */; }; AEBDC65C2C4DF0780026DFF1 /* sdl_resize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27EFC4BC1A7D8CBF00A95592 /* sdl_resize.cpp */; }; AEBDC65D2C4DF0780026DFF1 /* Pinger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE3C01A32C13DB8B002A3EB2 /* Pinger.cpp */; }; - AEBDC65E2C4DF0780026DFF1 /* steamshim_child.c in Sources */ = {isa = PBXBuildFile; fileRef = AE120D662BC776CE001873DD /* steamshim_child.c */; }; AEBDC65F2C4DF0780026DFF1 /* Packing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5837191031EEE0201000105 /* Packing.cpp */; }; AEBDC6602C4DF0780026DFF1 /* DefaultStringSets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DAC27A503DC9D1C00000104 /* DefaultStringSets.cpp */; }; AEBDC6612C4DF0780026DFF1 /* Logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DAC27A603DC9D1C00000104 /* Logging.cpp */; }; @@ -3297,10 +3298,10 @@ AE120B8F2BC76745001873DD /* steamshim_parent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = steamshim_parent.cpp; path = ../../Steam/steamshim_parent.cpp; sourceTree = ""; }; AE120B942BC77447001873DD /* libsteam_api.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsteam_api.dylib; path = "../vcpkg/installed-x64-osx/x64-osx/lib/libsteam_api.dylib"; sourceTree = SOURCE_ROOT; }; AE120D642BC77645001873DD /* Classic Marathon Steam.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Classic Marathon Steam.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - AE120D662BC776CE001873DD /* steamshim_child.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = steamshim_child.c; path = ../Source_Files/Misc/steamshim_child.c; sourceTree = ""; }; AE120D682BC776E7001873DD /* steamshim_child.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = steamshim_child.h; path = ../Source_Files/Misc/steamshim_child.h; sourceTree = ""; }; AE1321FD2C1CB4D2009D34AA /* Classic Marathon 2 Steam.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Classic Marathon 2 Steam.app"; sourceTree = BUILT_PRODUCTS_DIR; }; AE171BCC2A59F6EE00A4D3FC /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = ../Source_Files/main.cpp; sourceTree = ""; }; + AE1D0DE92C6198500083010F /* steamshim_child.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = steamshim_child.cpp; path = ../Source_Files/Misc/steamshim_child.cpp; sourceTree = ""; }; AE1F1B912662C5A500E6390E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; AE1F1B922662C5A500E6390E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = AppStore/Marathon/en.lproj/InfoPlist.strings; sourceTree = ""; }; AE1F1B932662C5A600E6390E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = "AppStore/Marathon 2/en.lproj/InfoPlist.strings"; sourceTree = ""; }; @@ -4242,7 +4243,7 @@ F5CC94290240DB8801A80001 /* SDL */, AE437C8E08779BE500038E30 /* shared_widgets.cpp */, 27FC2E091A7DF51E0057BF42 /* Statistics.cpp */, - AE120D662BC776CE001873DD /* steamshim_child.c */, + AE1D0DE92C6198500083010F /* steamshim_child.cpp */, F5574EF601F4EC8501FEABBD /* thread_priority_sdl_macosx.cpp */, F52212590136A6FD01000001 /* vbl.cpp */, ); @@ -6827,6 +6828,7 @@ AE120CB72BC77645001873DD /* OpenALManager.cpp in Sources */, AE120CB82BC77645001873DD /* platforms.cpp in Sources */, AE120CB92BC77645001873DD /* player.cpp in Sources */, + AE1D0DEA2C6198500083010F /* steamshim_child.cpp in Sources */, AE120CBA2BC77645001873DD /* projectiles.cpp in Sources */, AE120CBB2BC77645001873DD /* scenery.cpp in Sources */, AE120CBC2BC77645001873DD /* weapons.cpp in Sources */, @@ -6874,7 +6876,6 @@ AE120CE62BC77645001873DD /* XML_MakeRoot.cpp in Sources */, AE120CE72BC77645001873DD /* sdl_resize.cpp in Sources */, AE3C01A82C13DB8B002A3EB2 /* Pinger.cpp in Sources */, - AE120D672BC776CE001873DD /* steamshim_child.c in Sources */, AE120CE82BC77645001873DD /* Packing.cpp in Sources */, AE120CE92BC77645001873DD /* DefaultStringSets.cpp in Sources */, AE120CEA2BC77645001873DD /* Logging.cpp in Sources */, @@ -7056,6 +7057,7 @@ AE1321502C1CB4D2009D34AA /* OpenALManager.cpp in Sources */, AE1321512C1CB4D2009D34AA /* platforms.cpp in Sources */, AE1321522C1CB4D2009D34AA /* player.cpp in Sources */, + AE1D0DEB2C6198500083010F /* steamshim_child.cpp in Sources */, AE1321532C1CB4D2009D34AA /* projectiles.cpp in Sources */, AE1321542C1CB4D2009D34AA /* scenery.cpp in Sources */, AE1321552C1CB4D2009D34AA /* weapons.cpp in Sources */, @@ -7103,7 +7105,6 @@ AE13217F2C1CB4D2009D34AA /* XML_MakeRoot.cpp in Sources */, AE1321802C1CB4D2009D34AA /* sdl_resize.cpp in Sources */, AE235A4A2C261FEE0085BF9C /* Pinger.cpp in Sources */, - AE1321812C1CB4D2009D34AA /* steamshim_child.c in Sources */, AE1321822C1CB4D2009D34AA /* Packing.cpp in Sources */, AE1321832C1CB4D2009D34AA /* DefaultStringSets.cpp in Sources */, AE1321842C1CB4D2009D34AA /* Logging.cpp in Sources */, @@ -7796,7 +7797,6 @@ AEBDC65B2C4DF0780026DFF1 /* XML_MakeRoot.cpp in Sources */, AEBDC65C2C4DF0780026DFF1 /* sdl_resize.cpp in Sources */, AEBDC65D2C4DF0780026DFF1 /* Pinger.cpp in Sources */, - AEBDC65E2C4DF0780026DFF1 /* steamshim_child.c in Sources */, AEBDC65F2C4DF0780026DFF1 /* Packing.cpp in Sources */, AEBDC6602C4DF0780026DFF1 /* DefaultStringSets.cpp in Sources */, AEBDC6612C4DF0780026DFF1 /* Logging.cpp in Sources */, @@ -7815,12 +7815,13 @@ AEBDC66F2C4DF0780026DFF1 /* metaserver_dialogs.cpp in Sources */, AEBDC6702C4DF0780026DFF1 /* metaserver_messages.cpp in Sources */, AEBDC6712C4DF0780026DFF1 /* network_metaserver.cpp in Sources */, + AE1D0DEC2C6198500083010F /* steamshim_child.cpp in Sources */, AEBDC6722C4DF0780026DFF1 /* CommunicationsChannel.cpp in Sources */, AEBDC6732C4DF0780026DFF1 /* Message.cpp in Sources */, AEBDC6742C4DF0780026DFF1 /* MessageDispatcher.cpp in Sources */, AEBDC6752C4DF0780026DFF1 /* MessageHandler.cpp in Sources */, AEBDC6762C4DF0780026DFF1 /* MessageInflater.cpp in Sources */, - AE3AF3962C6ED7200066F090 /* ScenarioChooser.cpp in Sources */, + AE1D0DED2C6198AE0083010F /* ScenarioChooser.cpp in Sources */, AEBDC6772C4DF0780026DFF1 /* network_messages.cpp in Sources */, AEBDC6782C4DF0780026DFF1 /* csstrings.cpp in Sources */, AEBDC6792C4DF0780026DFF1 /* SdlMetaserverClientUi.cpp in Sources */, diff --git a/Source_Files/CSeries/csalerts.h b/Source_Files/CSeries/csalerts.h index a3e512436..cc3d64a00 100644 --- a/Source_Files/CSeries/csalerts.h +++ b/Source_Files/CSeries/csalerts.h @@ -33,7 +33,8 @@ enum { infoError, - fatalError + fatalError, + infoNoError }; extern void alert_user(const char *message, short severity = infoError); diff --git a/Source_Files/CSeries/csalerts_sdl.cpp b/Source_Files/CSeries/csalerts_sdl.cpp index 983316b43..8361b34b7 100644 --- a/Source_Files/CSeries/csalerts_sdl.cpp +++ b/Source_Files/CSeries/csalerts_sdl.cpp @@ -146,12 +146,48 @@ void alert_user(const char *message, short severity) { #ifndef A1_NETWORK_STANDALONE_HUB - if (!MainScreenVisible()) { - SDL_ShowSimpleMessageBox(severity == infoError ? SDL_MESSAGEBOX_WARNING : SDL_MESSAGEBOX_ERROR, severity == infoError ? "Warning" : "Error", message, NULL); + if (!MainScreenVisible()) { + std::string title; + uint32 box_type; + switch (severity) { + case fatalError: + title = "Error"; + box_type = SDL_MESSAGEBOX_ERROR; + break; + case infoNoError: + title = "Information"; + box_type = SDL_MESSAGEBOX_INFORMATION; + break; + case infoError: + default: + title = "Warning"; + box_type = SDL_MESSAGEBOX_WARNING; + break; + } + SDL_ShowSimpleMessageBox(box_type, title.c_str(), message, NULL); } else { + + std::string title; + std::string box_button; + switch (severity) { + case fatalError: + title = "ERROR"; + box_button = "QUIT"; + break; + case infoNoError: + title = "INFORMATION"; + box_button = "OK"; + break; + case infoError: + default: + title = "WARNING"; + box_button = "OK"; + break; + } + dialog d; vertical_placer *placer = new vertical_placer; - placer->dual_add(new w_title(severity == infoError ? "WARNING" : "ERROR"), d); + placer->dual_add(new w_title(title.c_str()), d); placer->add(new w_spacer, true); // Wrap lines @@ -179,20 +215,20 @@ void alert_user(const char *message, short severity) } free(p); placer->add(new w_spacer, true); - w_button *button = new w_button(severity == infoError ? "OK" : "QUIT", dialog_ok, &d); + w_button *button = new w_button(box_button.c_str(), dialog_ok, &d); placer->dual_add (button, d); d.set_widget_placer(placer); d.activate_widget(button); d.run(); - if (severity == infoError && top_dialog == NULL) + if (severity != fatalError && top_dialog == NULL) update_game_window(); } #endif - if (severity != infoError) exit(1); + if (severity == fatalError) exit(1); } void alert_user(short severity, short resid, short item, int error) diff --git a/Source_Files/Files/FileHandler.cpp b/Source_Files/Files/FileHandler.cpp index b010a13fe..801ae8c72 100644 --- a/Source_Files/Files/FileHandler.cpp +++ b/Source_Files/Files/FileHandler.cpp @@ -1324,6 +1324,37 @@ static std::map typecode_filters { {_typecode_movie, "webm"} }; +bool FileSpecifier::ReadDirectoryDialog() //needs native file dialog to work +{ +#ifdef HAVE_NFD +#if defined(_WIN32) + auto fullscreen = get_screen_mode()->fullscreen; + if (fullscreen) + { + toggle_fullscreen(false); + } +#endif + nfdchar_t* outpath; + auto result = NFD_PickFolder(nullptr, &outpath); +#if defined(_WIN32) + if (fullscreen) + { + toggle_fullscreen(true); + } +#endif + + if (result == NFD_OKAY) + { + name = outpath; + free(outpath); + return true; + } + +#endif + return false; +} + + bool FileSpecifier::ReadDialog(Typecode type, const char *prompt) { #ifdef HAVE_NFD diff --git a/Source_Files/Files/FileHandler.h b/Source_Files/Files/FileHandler.h index 1a8a6f6e3..6b6a16dad 100644 --- a/Source_Files/Files/FileHandler.h +++ b/Source_Files/Files/FileHandler.h @@ -273,6 +273,7 @@ class FileSpecifier // These calls are for creating dialog boxes to set the filespec // A null pointer means an empty string + bool ReadDirectoryDialog(); bool ReadDialog(Typecode Type, const char *Prompt=NULL); bool WriteDialog(Typecode Type, const char *Prompt=NULL, const char *DefaultName=NULL); diff --git a/Source_Files/Misc/DefaultStringSets.cpp b/Source_Files/Misc/DefaultStringSets.cpp index 3ab6e6a75..83a0d70bd 100644 --- a/Source_Files/Misc/DefaultStringSets.cpp +++ b/Source_Files/Misc/DefaultStringSets.cpp @@ -414,6 +414,9 @@ static const char* sStringSetNumber143[] = { "Sending environment information to the other players.", "Receiving environment information from server.", "Loading...", + "Submitting item content to Steam...", + "Preparing upload to Steam...", + "Uploading content to Steam...", "Attempting to open router ports...", "Closing router ports...", "Checking for updates...", diff --git a/Source_Files/Misc/Makefile.am b/Source_Files/Misc/Makefile.am index 71254c53f..98180c0b2 100644 --- a/Source_Files/Misc/Makefile.am +++ b/Source_Files/Misc/Makefile.am @@ -26,7 +26,7 @@ libmisc_a_SOURCES = achievements.h ActionQueues.h alephversion.h binders.h Circu Statistics.cpp ScenarioChooser.cpp \ ProFontAO.h CourierPrime.h CourierPrimeBold.h CourierPrimeItalic.h CourierPrimeBoldItalic.h -EXTRA_libmisc_a_SOURCES = alephone.xpm alephone32.xpm thread_priority_sdl_posix.cpp thread_priority_sdl_dummy.cpp thread_priority_sdl_win32.cpp thread_priority_sdl_macosx.cpp m1_achievements.lua m2_achievements.lua inf_achievements.lua steamshim_child.h steamshim_child.c +EXTRA_libmisc_a_SOURCES = alephone.xpm alephone32.xpm thread_priority_sdl_posix.cpp thread_priority_sdl_dummy.cpp thread_priority_sdl_win32.cpp thread_priority_sdl_macosx.cpp m1_achievements.lua m2_achievements.lua inf_achievements.lua steamshim_child.h steamshim_child.cpp AM_CPPFLAGS = -I$(top_srcdir)/Source_Files/CSeries -I$(top_srcdir)/Source_Files/Files \ -I$(top_srcdir)/Source_Files/GameWorld -I$(top_srcdir)/Source_Files/Input \ diff --git a/Source_Files/Misc/interface.cpp b/Source_Files/Misc/interface.cpp index 6f50d9e2e..34129dd23 100644 --- a/Source_Files/Misc/interface.cpp +++ b/Source_Files/Misc/interface.cpp @@ -199,6 +199,8 @@ const short max_handled_recording= RECORDING_VERSION_ALEPH_ONE_1_7; #include "lua_hud_script.h" +#include + using alephone::Screen; /* ------------- enums */ @@ -265,6 +267,14 @@ struct screen_data { int32 duration; }; +struct steam_workshop_uploader_ui_data { + uint64_t item_id; + int item_type; + FileSpecifier directory_path; + FileSpecifier thumbnail_path; + bool is_scenarios_compatible; +}; + /* -------------- constants */ struct screen_data display_screens[]= { { INTRO_SCREEN_BASE, NUMBER_OF_INTRO_SCREENS, INTRO_SCREEN_DURATION }, @@ -331,6 +341,7 @@ static void display_screen(short base_pict_id); static void display_introduction_screen_for_demo(void); static void display_epilogue(void); static void display_about_dialog(); +static void display_steam_workshop_uploader_dialog(void *arg); static void force_system_colors(void); static bool point_in_rectangle(short x, short y, screen_rectangle *rect); @@ -1578,7 +1589,7 @@ bool enabled_item( case iReplaySavedFilm: case iCredits: case iQuit: - case iAbout: + case iAbout: case iCenterButton: break; @@ -1713,6 +1724,294 @@ class w_authors_list : public w_string_list void item_selected(void) { } }; +#include + +static item_upload_data steam_workshop_prepare_upload(steam_workshop_uploader_ui_data& data) +{ + item_upload_data workshop_item; + + if (!data.is_scenarios_compatible) + { + const auto scenario_name = Scenario::instance()->GetName(); + + if (scenario_name.empty()) + { + throw std::runtime_error("The scenario for this item couldn't be deduced"); + } + + workshop_item.required_scenario = scenario_name; + } + + workshop_item.id = data.item_id; + workshop_item.type = (ItemType)data.item_type; + workshop_item.directory_path = data.directory_path.GetPath(); + workshop_item.thumbnail_path = data.thumbnail_path.GetPath(); + return workshop_item; +} + +static const STEAMSHIM_Event* steam_workshop_upload_result() +{ + const STEAMSHIM_Event* result = nullptr; + bool end_of_upload = false; + int progress_value = 0, upload_status = 0; + + std::unordered_map upload_messages = + { + {STEAM_EItemUpdateStatus::k_EItemUpdateStatusPreparingConfig, _uploading_steam_workshop_prepare}, + {STEAM_EItemUpdateStatus::k_EItemUpdateStatusPreparingContent, _uploading_steam_workshop_prepare}, + {STEAM_EItemUpdateStatus::k_EItemUpdateStatusUploadingContent, _uploading_steam_workshop_upload}, + {STEAM_EItemUpdateStatus::k_EItemUpdateStatusUploadingPreviewFile, _uploading_steam_workshop_upload}, + {STEAM_EItemUpdateStatus::k_EItemUpdateStatusCommittingChanges, _uploading_steam_workshop_upload} + }; + + open_progress_dialog(_uploading_steam_workshop_default, true); + + while (STEAMSHIM_alive() && !end_of_upload) + { + progress_dialog_event(); + + result = STEAMSHIM_pump(); + + if (result) + { + switch (result->type) + { + case SHIMEVENT_WORKSHOP_UPLOAD_PROGRESS: + if (upload_status != result->okay) + { + upload_status = result->okay; + auto message_id = upload_messages.find(upload_status); + set_progress_dialog_message(message_id != upload_messages.end() ? message_id->second : _uploading_steam_workshop_default); + } + progress_value = result->ivalue; + break; + case SHIMEVENT_WORKSHOP_UPLOAD_RESULT: + progress_value = 100; + end_of_upload = true; + break; + default: + break; + } + } + + draw_progress_bar(progress_value, 100); + } + + close_progress_dialog(); + return result; +} + +static void steam_workshop_upload_item_callback(void* arg) +{ + auto params = reinterpret_cast*>(arg); + auto item = params->first; + auto dialog = params->second; + + if (!item->item_id && (!item->directory_path.IsDir() || !item->directory_path.Exists())) + { + alert_user("The item directory is not valid."); + return; + } + + item_upload_data steam_upload_data; + + try + { + steam_upload_data = steam_workshop_prepare_upload(*item); + } + catch (std::exception& ex) + { + alert_user(ex.what()); + return; + } + + STEAMSHIM_uploadWorkshopItem(steam_upload_data); + auto result = steam_workshop_upload_result(); + + if (result && result->type == SHIMEVENT_WORKSHOP_UPLOAD_RESULT) + { + if (result->okay) + { + alert_user("Your item was correctly uploaded on Steam", infoNoError); + dialog->quit(0); + } + else + { + std::string error_code = std::to_string(result->ivalue); + std::string message = "Your item couldn't be uploaded on Steam. Steam error code was: " + error_code; + alert_user(message.c_str()); + } + } + else + alert_user("Something went wrong while uploading to Steam. Restart the game and try again."); +} + +static item_owned_query_result steam_get_owned_items(const std::string& scenario_name) +{ + open_progress_dialog(_loading); + + STEAMSHIM_queryWorkshopItemOwned(scenario_name); + + const STEAMSHIM_Event* result = nullptr; + while (STEAMSHIM_alive()) + { + progress_dialog_event(); + + result = STEAMSHIM_pump(); + + if (result && result->type == SHIMEVENT_WORKSHOP_QUERY_ITEM_OWNED_RESULT) + { + break; + } + } + + close_progress_dialog(); + return result ? result->items_owned : item_owned_query_result { 0 }; +} + +static void display_steam_workshop_uploader_dialog(void* arg) +{ + force_system_colors(); + + const auto scenario_name = Scenario::instance()->GetName(); + + auto item_list = steam_get_owned_items(scenario_name); + std::vector item_labels; + + item_owned_query_result::item new_item; + new_item.id = 0; + new_item.title = "New Item"; + new_item.type = ItemType::Plugin; + new_item.is_scenarios_compatible = true; + item_list.items.insert(item_list.items.begin(), new_item); + + if (item_list.result_code != 1) + { + std::string error_code = std::to_string(item_list.result_code); + std::string message = "Your workshop items couldn't be retrieved from Steam. Steam error code was: " + error_code; + alert_user(message.c_str()); + } + + for (const auto& item : item_list.items) + { + auto label = item.title.size() > 28 ? item.title.substr(0, 25) + "..." : item.title; + item_labels.push_back(label); + } + + steam_workshop_uploader_ui_data ui_data; + ui_data.item_type = static_cast(new_item.type); + ui_data.is_scenarios_compatible = new_item.is_scenarios_compatible; + ui_data.item_id = new_item.id; + + dialog d; + + auto placer = new vertical_placer; + + placer->dual_add(new w_title("STEAM WORKSHOP UPLOADER"), d); + placer->add(new w_spacer, true); + + auto table = new table_placer(2, get_theme_space(ITEM_WIDGET), true); + table->col_flags(0, placeable::kAlignRight); + + auto items_popup = new w_select_popup(); + items_popup->set_labels(item_labels); + items_popup->set_selection(0); + table->dual_add(items_popup->label("Upload For"), d); + table->dual_add(items_popup, d); + + table->add_row(new w_spacer(), true); + + static const std::vector item_types = { "Scenario", "Plugin", "Other"}; + auto types_popup = new w_select_popup(); + types_popup->set_labels(item_types); + types_popup->set_selection(static_cast(new_item.type)); + + table->dual_add(types_popup->label("Item Type"), d); + table->dual_add(types_popup, d); + + table->add_row(new w_spacer(), true); + + auto custom_scenarios = new w_toggle(true); + table->dual_add(custom_scenarios->label("Scenarios Compatible"), d); + table->dual_add(custom_scenarios, d); + table->dual_add_row(new w_static_text("Uncheck if the item is only compatible with this scenario"), d); + table->add_row(new w_spacer(), true); + + auto thumbnail_path = new w_file_chooser("Choose Preview Image", _typecode_unknown); + table->dual_add(thumbnail_path->label("Preview Image"), d); + table->dual_add(thumbnail_path, d); + + table->add_row(new w_spacer(), true); + + auto directory_path = new w_directory_chooser(); + table->dual_add(directory_path->label("Item Directory"), d); + table->dual_add(directory_path, d); + + placer->add(table, true); + + placer->add(new w_spacer, true); + + auto button_placer = new horizontal_placer; + + auto callback_params = std::make_pair(&ui_data, &d); + button_placer->dual_add(new w_button("UPLOAD", steam_workshop_upload_item_callback, &callback_params), d); + button_placer->dual_add(new w_button("RETURN", dialog_cancel, &d), d); + + placer->add(button_placer, true); + + d.set_widget_placer(placer); + + items_popup->set_popup_callback([&](void*) + { + auto item_index = items_popup->get_selection(); + auto& item = item_list.items.at(item_index); + + ui_data.item_id = item.id; + ui_data.item_type = static_cast(item.type); + ui_data.directory_path = ""; + ui_data.thumbnail_path = ""; + ui_data.is_scenarios_compatible = item.is_scenarios_compatible; + + types_popup->set_selection(ui_data.item_type); + types_popup->set_enabled(!ui_data.item_id); + + directory_path->set_directory(ui_data.directory_path); + thumbnail_path->set_file(ui_data.thumbnail_path); + + custom_scenarios->set_selection(ui_data.is_scenarios_compatible); + custom_scenarios->set_enabled(static_cast(ui_data.item_type) != ItemType::Scenario); + + }, nullptr); + + types_popup->set_popup_callback([&](void*) + { + ui_data.item_type = types_popup->get_selection(); + bool is_scenario = static_cast(ui_data.item_type) == ItemType::Scenario; + custom_scenarios->set_enabled(!is_scenario); + custom_scenarios->set_selection(!is_scenario); + + }, nullptr); + + custom_scenarios->set_selection_changed_callback([&](void*) + { + ui_data.is_scenarios_compatible = custom_scenarios->get_selection(); + }); + + directory_path->set_callback([&]() + { + ui_data.directory_path = directory_path->get_directory().GetPath(); + }); + + thumbnail_path->set_callback([&]() + { + ui_data.thumbnail_path = thumbnail_path->get_file().GetPath(); + }); + + clear_screen(); + + d.run(); +} + static void display_about_dialog() { force_system_colors(); @@ -1763,6 +2062,11 @@ static void display_about_dialog() about_placer->dual_add(new w_static_text(expand_app_variables("Scenario loaded: $scenarioName$ $scenarioVersion$").c_str()), d); +#ifdef HAVE_STEAM + about_placer->add(new w_spacer, true); + about_placer->dual_add(new w_button("STEAM WORKSHOP UPLOADER", display_steam_workshop_uploader_dialog, &d), d); +#endif + vertical_placer *authors_placer = new vertical_placer(); authors_placer->dual_add(new w_static_text("Aleph One is based on the source code for Marathon 2 and"), d); diff --git a/Source_Files/Misc/progress.h b/Source_Files/Misc/progress.h index a16620442..a613255b9 100644 --- a/Source_Files/Misc/progress.h +++ b/Source_Files/Misc/progress.h @@ -38,6 +38,9 @@ enum { _receiving_physics, // non-network ones _loading, + _uploading_steam_workshop_default, + _uploading_steam_workshop_prepare, + _uploading_steam_workshop_upload, // more network ones _opening_router_ports, _closing_router_ports, @@ -53,6 +56,7 @@ void set_progress_dialog_message(size_t message_id); void draw_progress_bar(size_t sent, size_t total); void reset_progress_bar(void); +void progress_dialog_event(void); #endif diff --git a/Source_Files/Misc/sdl_widgets.cpp b/Source_Files/Misc/sdl_widgets.cpp index 86be5c471..e72400c60 100644 --- a/Source_Files/Misc/sdl_widgets.cpp +++ b/Source_Files/Misc/sdl_widgets.cpp @@ -2400,6 +2400,49 @@ w_file_chooser::update_filename() set_selection(sFileChooserInvalidFileString); } +w_directory_chooser::w_directory_chooser() + : w_select_button("", NULL, NULL, true) +{ + set_selection(sFileChooserInvalidFileString); +} + + + +void +w_directory_chooser::set_directory(const FileSpecifier& inDirectory) +{ + directory = inDirectory; + update_directoryname(); +} + + + +void +w_directory_chooser::click(int, int) +{ + if (enabled) + { + if (directory.ReadDirectoryDialog()) + { + update_directoryname(); + if (m_callback) + m_callback(); + } + } +} + + +void +w_directory_chooser::update_directoryname() +{ + if (directory.Exists()) + { + directory.GetName(directory_name); + set_selection(directory_name); + } + else + set_selection(sFileChooserInvalidFileString); +} const string w_items_in_room_get_name_of_item (GameListMessage::GameListEntry item) { diff --git a/Source_Files/Misc/sdl_widgets.h b/Source_Files/Misc/sdl_widgets.h index 786d00f0b..d5496abfe 100644 --- a/Source_Files/Misc/sdl_widgets.h +++ b/Source_Files/Misc/sdl_widgets.h @@ -888,6 +888,28 @@ class w_file_chooser : public w_select_button ControlHitCallback m_callback; }; +class w_directory_chooser : public w_select_button +{ +public: + w_directory_chooser(); + + void click(int x, int y); + + void set_directory(const FileSpecifier& inFile); + const FileSpecifier& get_directory() { return directory; } + + // we also have void set_callback(action_proc, void*) + // as inherited from w_select_button + void set_callback(ControlHitCallback callback) { m_callback = callback; } + +private: + void update_directoryname(); + + FileSpecifier directory; + char directory_name[256]; + ControlHitCallback m_callback; +}; + /* * Lists for metaserver dialog; moved from SdlMetaserverClientUi.cpp diff --git a/Source_Files/Misc/steamshim_child.c b/Source_Files/Misc/steamshim_child.cpp old mode 100755 new mode 100644 similarity index 70% rename from Source_Files/Misc/steamshim_child.c rename to Source_Files/Misc/steamshim_child.cpp index e39d07c15..d684f05dd --- a/Source_Files/Misc/steamshim_child.c +++ b/Source_Files/Misc/steamshim_child.cpp @@ -23,6 +23,7 @@ typedef int PipeType; #define NULLPIPE -1 #endif +#include #include "steamshim_child.h" #define DEBUGPIPE 1 @@ -120,7 +121,7 @@ static char *getEnvVar(const char *key, char *buf, const size_t buflen) static PipeType GPipeRead = NULLPIPE; static PipeType GPipeWrite = NULLPIPE; -typedef enum ShimCmd +enum ShimCmd { SHIMCMD_BYE, SHIMCMD_PUMP, @@ -133,17 +134,25 @@ typedef enum ShimCmd SHIMCMD_GETSTATI, SHIMCMD_SETSTATF, SHIMCMD_GETSTATF, -} ShimCmd; + SHIMCMD_WORKSHOP_UPLOAD, + SHIMCMD_WORKSHOP_QUERY_ITEM_OWNED, + SHIMCMD_WORKSHOP_QUERY_ITEM_MOD, + SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO +}; static int write1ByteCmd(const uint8 b1) { - const uint8 buf[] = { 1, b1 }; + uint16_t length = 1; + uint8* length_bytes = (uint8*)&length; + const uint8 buf[] = { length_bytes[0], length_bytes[1], b1}; return writePipe(GPipeWrite, buf, sizeof (buf)); } /* write1ByteCmd */ static int write2ByteCmd(const uint8 b1, const uint8 b2) { - const uint8 buf[] = { 2, b1, b2 }; + uint16_t length = 2; + uint8* length_bytes = (uint8*)&length; + const uint8 buf[] = { length_bytes[0], length_bytes[1], b1, b2}; return writePipe(GPipeWrite, buf, sizeof (buf)); } /* write2ByteCmd */ @@ -246,7 +255,11 @@ static const STEAMSHIM_Event *processEvent(const uint8 *buf, size_t buflen) PRINTGOTEVENT(SHIMEVENT_GETSTATI); PRINTGOTEVENT(SHIMEVENT_SETSTATF); PRINTGOTEVENT(SHIMEVENT_GETSTATF); - PRINTGOTEVENT(SHIMEVENT_ISOVERLAYACTIVATED); + PRINTGOTEVENT(SHIMEVENT_IS_OVERLAY_ACTIVATED); + PRINTGOTEVENT(SHIMEVENT_WORKSHOP_UPLOAD_RESULT); + PRINTGOTEVENT(SHIMEVENT_WORKSHOP_UPLOAD_PROGRESS); + PRINTGOTEVENT(SHIMEVENT_WORKSHOP_QUERY_ITEM_OWNED_RESULT); + PRINTGOTEVENT(SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT); #undef PRINTGOTEVENT else printf("Child got unknown shimevent %d.\n", (int) type); #endif @@ -258,7 +271,7 @@ static const STEAMSHIM_Event *processEvent(const uint8 *buf, size_t buflen) case SHIMEVENT_STATSRECEIVED: case SHIMEVENT_STATSSTORED: - case SHIMEVENT_ISOVERLAYACTIVATED: + case SHIMEVENT_IS_OVERLAY_ACTIVATED: if (!buflen) return NULL; event.okay = *(buf++) ? 1 : 0; break; @@ -302,6 +315,32 @@ static const STEAMSHIM_Event *processEvent(const uint8 *buf, size_t buflen) strcpy(event.name, (const char *) buf); break; + case SHIMEVENT_WORKSHOP_UPLOAD_RESULT: + event.ivalue = (int)*(buf++); + event.okay = event.ivalue == 1; + break; + + case SHIMEVENT_WORKSHOP_UPLOAD_PROGRESS: + event.okay = (int)*(buf++); + event.ivalue = (int)*(buf++); + break; + + case SHIMEVENT_WORKSHOP_QUERY_ITEM_OWNED_RESULT: + { + event.items_owned = {}; + event.items_owned.shim_deserialize(buf, buflen); + event.okay = event.items_owned.result_code == 1; + break; + } + + case SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT: + { + event.items_subscribed = {}; + event.items_subscribed.shim_deserialize(buf, buflen); + event.okay = event.items_owned.result_code == 1; + break; + } + default: /* uh oh */ return NULL; } /* switch */ @@ -311,14 +350,14 @@ static const STEAMSHIM_Event *processEvent(const uint8 *buf, size_t buflen) const STEAMSHIM_Event *STEAMSHIM_pump(void) { - static uint8 buf[256]; + static uint8 buf[65536]; static int br = 0; - int evlen = (br > 0) ? ((int) buf[0]) : 0; + int evlen = (br > 1) ? *reinterpret_cast(buf) : 0; if (isDead()) return NULL; - if (br <= evlen) /* we have an incomplete commmand. Try to read more. */ + if (br - 2 < evlen) /* we have an incomplete commmand. Try to read more. */ { if (pipeReady(GPipeRead)) { @@ -333,12 +372,12 @@ const STEAMSHIM_Event *STEAMSHIM_pump(void) } /* if */ } /* if */ - if (evlen && (br > evlen)) + if (evlen && (br - 2 >= evlen)) { - const STEAMSHIM_Event *retval = processEvent(buf+1, evlen); - br -= evlen + 1; + const STEAMSHIM_Event *retval = processEvent(buf+2, evlen); + br -= evlen + 2; if (br > 0) - memmove(buf, buf+evlen+1, br); + memmove(buf, buf+evlen+2, br); return retval; } /* if */ @@ -369,30 +408,99 @@ void STEAMSHIM_storeStats(void) void STEAMSHIM_setAchievement(const char *name, const int enable) { uint8 buf[256]; - uint8 *ptr = buf+1; + uint8 *ptr = buf+2; if (isDead()) return; dbgpipe("Child sending SHIMCMD_SETACHIEVEMENT('%s', %senable).\n", name, enable ? "" : "!"); *(ptr++) = (uint8) SHIMCMD_SETACHIEVEMENT; *(ptr++) = enable ? 1 : 0; strcpy((char *) ptr, name); ptr += strlen(name) + 1; - buf[0] = (uint8) ((ptr-1) - buf); - writePipe(GPipeWrite, buf, buf[0] + 1); + uint16_t length = ((ptr - 1) - buf); + uint8* length_bytes = (uint8*)&length; + buf[0] = length_bytes[0]; + buf[1] = length_bytes[1]; + writePipe(GPipeWrite, buf, length + 2); } /* STEAMSHIM_setAchievement */ void STEAMSHIM_getAchievement(const char *name) { uint8 buf[256]; - uint8 *ptr = buf+1; + uint8 *ptr = buf+2; if (isDead()) return; dbgpipe("Child sending SHIMCMD_GETACHIEVEMENT('%s').\n", name); *(ptr++) = (uint8) SHIMCMD_GETACHIEVEMENT; strcpy((char *) ptr, name); ptr += strlen(name) + 1; - buf[0] = (uint8) ((ptr-1) - buf); - writePipe(GPipeWrite, buf, buf[0] + 1); + uint16_t length = ((ptr - 1) - buf); + uint8* length_bytes = (uint8*)&length; + buf[0] = length_bytes[0]; + buf[1] = length_bytes[1]; + writePipe(GPipeWrite, buf, length + 2); } /* STEAMSHIM_getAchievement */ +void STEAMSHIM_uploadWorkshopItem(const item_upload_data& item) +{ + if (isDead()) return; + dbgpipe("Child sending SHIMCMD_UPLOADWORKSHOP.\n"); + + auto data_stream = item.shim_serialize(); + data_stream = std::ostringstream() << (uint8)SHIMCMD_WORKSHOP_UPLOAD << data_stream.str(); + + std::ostringstream data_stream_shim; + + uint16_t length = data_stream.str().length(); + data_stream_shim.write(reinterpret_cast(&length), sizeof(length)); + data_stream_shim << data_stream.str(); + + auto buffer = data_stream_shim.str(); + writePipe(GPipeWrite, buffer.data(), buffer.length()); +} + +void STEAMSHIM_queryWorkshopItemOwned(const std::string& scenario_name) +{ + if (isDead()) return; + + dbgpipe("Child sending SHIMCMD_WORKSHOP_QUERY_ITEM_OWNED.\n"); + + std::ostringstream data_stream; + data_stream << (uint8)SHIMCMD_WORKSHOP_QUERY_ITEM_OWNED << scenario_name << '\0'; + + std::ostringstream data_stream_shim; + + uint16_t length = data_stream.str().length(); + data_stream_shim.write(reinterpret_cast(&length), sizeof(length)); + data_stream_shim << data_stream.str(); + + auto buffer = data_stream_shim.str(); + writePipe(GPipeWrite, buffer.data(), buffer.length()); +} + +void STEAMSHIM_queryWorkshopItemMod(const std::string& scenario_name) +{ + if (isDead()) return; + + dbgpipe("Child sending SHIMCMD_WORKSHOP_QUERY_ITEM_MOD.\n"); + + std::ostringstream data_stream; + data_stream << (uint8)SHIMCMD_WORKSHOP_QUERY_ITEM_MOD << scenario_name << '\0'; + + std::ostringstream data_stream_shim; + + uint16_t length = data_stream.str().length(); + data_stream_shim.write(reinterpret_cast(&length), sizeof(length)); + data_stream_shim << data_stream.str(); + + auto buffer = data_stream_shim.str(); + writePipe(GPipeWrite, buffer.data(), buffer.length()); +} + +void STEAMSHIM_queryWorkshopItemScenario() +{ + if (isDead()) return; + dbgpipe("Child sending SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO.\n"); + write1ByteCmd(SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO); +} + void STEAMSHIM_resetStats(const int bAlsoAchievements) { if (isDead()) return; @@ -403,7 +511,7 @@ void STEAMSHIM_resetStats(const int bAlsoAchievements) static void writeStatThing(const ShimCmd cmd, const char *name, const void *val, const size_t vallen) { uint8 buf[256]; - uint8 *ptr = buf+1; + uint8 *ptr = buf+2; if (isDead()) return; *(ptr++) = (uint8) cmd; if (vallen) @@ -413,8 +521,11 @@ static void writeStatThing(const ShimCmd cmd, const char *name, const void *val, } /* if */ strcpy((char *) ptr, name); ptr += strlen(name) + 1; - buf[0] = (uint8) ((ptr-1) - buf); - writePipe(GPipeWrite, buf, buf[0] + 1); + uint16_t length = ((ptr - 1) - buf); + uint8* length_bytes = (uint8*)&length; + buf[0] = length_bytes[0]; + buf[1] = length_bytes[1]; + writePipe(GPipeWrite, buf, length + 2); } /* writeStatThing */ void STEAMSHIM_setStatI(const char *name, const int _val) @@ -442,5 +553,5 @@ void STEAMSHIM_getStatF(const char *name) writeStatThing(SHIMCMD_GETSTATF, name, NULL, 0); } /* STEAMSHIM_getStatF */ -/* end of steamshim_child.c ... */ +/* end of steamshim_child.cpp ... */ diff --git a/Source_Files/Misc/steamshim_child.h b/Source_Files/Misc/steamshim_child.h index 15db75939..096a3c9af 100755 --- a/Source_Files/Misc/steamshim_child.h +++ b/Source_Files/Misc/steamshim_child.h @@ -1,11 +1,132 @@ #ifndef _INCL_STEAMSHIM_CHILD_H_ #define _INCL_STEAMSHIM_CHILD_H_ -#ifdef __cplusplus -extern "C" { -#endif +#include +#include -typedef enum STEAMSHIM_EventType +enum class ItemType { + Scenario, + Plugin, + Other +}; + +struct item_upload_data { + + uint64_t id; + ItemType type; + std::string directory_path; + std::string thumbnail_path; + std::string required_scenario; + std::vector tags; + + std::ostringstream shim_serialize() const + { + std::ostringstream data_stream; + data_stream.write(reinterpret_cast(&id), sizeof(id)); + data_stream.write(reinterpret_cast(&type), sizeof(type)); + + data_stream << directory_path << '\0'; + data_stream << thumbnail_path << '\0'; + data_stream << required_scenario << '\0'; + + for (const auto& tag : tags) + { + data_stream << tag << '\0'; + } + + data_stream << '\0'; + + return data_stream; + } +}; + +struct item_owned_query_result +{ + struct item + { + uint64_t id; + ItemType type; + bool is_scenarios_compatible; + std::string title; + std::vector tags; + }; + + int result_code; //steam code (EResult) where 1 is success + std::vector items; + + void shim_deserialize(const uint8* buf, unsigned int buflen) + { + std::istringstream iss(std::string((const char*)buf, buflen)); + + iss.read(reinterpret_cast(&result_code), sizeof(result_code)); + + int number_items; + iss.read(reinterpret_cast(&number_items), sizeof(number_items)); + + for (int i = 0; i < number_items; i++) + { + item deserialized_item = {}; + + iss.read(reinterpret_cast(&deserialized_item.id), sizeof(deserialized_item.id)); + + int type; + iss.read(reinterpret_cast(&type), sizeof(type)); + deserialized_item.type = (ItemType)type; + + iss.read(reinterpret_cast(&deserialized_item.is_scenarios_compatible), sizeof(deserialized_item.is_scenarios_compatible)); + std::getline(iss, deserialized_item.title, '\0'); + + while (true) + { + std::string tag; + std::getline(iss, tag, '\0'); + if (tag.empty()) break; + deserialized_item.tags.push_back(tag); + } + + items.push_back(deserialized_item); + } + } +}; + +struct item_subscribed_query_result +{ + struct item + { + uint64_t id; + ItemType type; + std::string install_folder_path; + }; + + int result_code; //steam code (EResult) where 1 is success + std::vector items; + + void shim_deserialize(const uint8* buf, unsigned int buflen) + { + std::istringstream iss(std::string((const char*)buf, buflen)); + + iss.read(reinterpret_cast(&result_code), sizeof(result_code)); + + int number_items; + iss.read(reinterpret_cast(&number_items), sizeof(number_items)); + + for (int i = 0; i < number_items; i++) + { + item deserialized_item = {}; + iss.read(reinterpret_cast(&deserialized_item.id), sizeof(deserialized_item.id)); + + int type; + iss.read(reinterpret_cast(&type), sizeof(type)); + deserialized_item.type = (ItemType)type; + + std::getline(iss, deserialized_item.install_folder_path, '\0'); + + items.push_back(deserialized_item); + } + } +}; + +enum STEAMSHIM_EventType { SHIMEVENT_BYE, SHIMEVENT_STATSRECEIVED, @@ -17,11 +138,25 @@ typedef enum STEAMSHIM_EventType SHIMEVENT_GETSTATI, SHIMEVENT_SETSTATF, SHIMEVENT_GETSTATF, - SHIMEVENT_ISOVERLAYACTIVATED -} STEAMSHIM_EventType; + SHIMEVENT_IS_OVERLAY_ACTIVATED, + SHIMEVENT_WORKSHOP_UPLOAD_RESULT, + SHIMEVENT_WORKSHOP_UPLOAD_PROGRESS, + SHIMEVENT_WORKSHOP_QUERY_ITEM_OWNED_RESULT, + SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT +}; + +enum STEAM_EItemUpdateStatus //from steam API +{ + k_EItemUpdateStatusInvalid = 0, // The item update handle was invalid, job might be finished, listen too SubmitItemUpdateResult_t + k_EItemUpdateStatusPreparingConfig = 1, // The item update is processing configuration data + k_EItemUpdateStatusPreparingContent = 2, // The item update is reading and processing content files + k_EItemUpdateStatusUploadingContent = 3, // The item update is uploading content changes to Steam + k_EItemUpdateStatusUploadingPreviewFile = 4, // The item update is uploading new preview file image + k_EItemUpdateStatusCommittingChanges = 5 // The item update is committing all changes +}; /* not all of these fields make sense in a given event. */ -typedef struct STEAMSHIM_Event +struct STEAMSHIM_Event { STEAMSHIM_EventType type; int okay; @@ -29,7 +164,9 @@ typedef struct STEAMSHIM_Event float fvalue; unsigned long long epochsecs; char name[256]; -} STEAMSHIM_Event; + item_owned_query_result items_owned; + item_subscribed_query_result items_subscribed; +}; int STEAMSHIM_init(void); /* non-zero on success, zero on failure. */ void STEAMSHIM_deinit(void); @@ -39,16 +176,15 @@ void STEAMSHIM_requestStats(void); void STEAMSHIM_storeStats(void); void STEAMSHIM_setAchievement(const char *name, const int enable); void STEAMSHIM_getAchievement(const char *name); +void STEAMSHIM_uploadWorkshopItem(const item_upload_data& item); void STEAMSHIM_resetStats(const int bAlsoAchievements); void STEAMSHIM_setStatI(const char *name, const int _val); void STEAMSHIM_getStatI(const char *name); void STEAMSHIM_setStatF(const char *name, const float val); void STEAMSHIM_getStatF(const char *name); - -#ifdef __cplusplus -} -#endif - +void STEAMSHIM_queryWorkshopItemOwned(const std::string& scenario_name); +void STEAMSHIM_queryWorkshopItemMod(const std::string& scenario_name); +void STEAMSHIM_queryWorkshopItemScenario(); #endif /* include-once blocker */ /* end of steamshim_child.h ... */ diff --git a/Source_Files/Network/network_dialogs.cpp b/Source_Files/Network/network_dialogs.cpp index d26e866e7..c99978281 100644 --- a/Source_Files/Network/network_dialogs.cpp +++ b/Source_Files/Network/network_dialogs.cpp @@ -3050,6 +3050,12 @@ void reset_progress_bar(void) sProgressDialog->draw(); } +void progress_dialog_event() +{ + assert(sProgressDialog != NULL); + sProgressDialog->process_events(); +} + #ifdef NETWORK_TEST_POSTGAME_DIALOG static const char* sTestingNames[] = { diff --git a/Source_Files/shell.cpp b/Source_Files/shell.cpp index ac725ee32..07457e62d 100644 --- a/Source_Files/shell.cpp +++ b/Source_Files/shell.cpp @@ -313,6 +313,36 @@ void initialize_application(void) ScenarioChooser chooser; chooser.add_scenario(scenario_dir.GetPath()); +#ifdef HAVE_STEAM + if (!STEAMSHIM_init()) + { + alert_user("You must launch the Steam version of Classic Marathon using the Classic Marathon Launcher.", fatalError); + exit(1); + } + + STEAMSHIM_queryWorkshopItemScenario(); + + while (STEAMSHIM_alive()) + { + auto result = STEAMSHIM_pump(); + + if (result && result->type == SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT) + { + if (result->items_subscribed.result_code == 1) + { + for (const auto& steam_scenario : result->items_subscribed.items) + { + chooser.add_scenario(steam_scenario.install_folder_path); + } + } + + break; + } + + sleep_for_machine_ticks(30); + } +#endif // HAVE_STEAM + if (chooser.num_scenarios() == 0) { chooser.add_directory(scenario_dir.GetPath()); @@ -498,14 +528,6 @@ void initialize_application(void) HTTPClient::Init(); -#ifdef HAVE_STEAM - if (!STEAMSHIM_init()) - { - alert_user("You must launch the Steam version of Classic Marathon using the Classic Marathon Launcher.", fatalError); - exit(1); - } -#endif - // Initialize everything mytm_initialize(); // initialize_fonts(); @@ -719,7 +741,7 @@ void main_event_loop(void) #ifdef HAVE_STEAM while (auto steam_event = STEAMSHIM_pump()) { switch (steam_event->type) { - case SHIMEVENT_ISOVERLAYACTIVATED: + case SHIMEVENT_IS_OVERLAY_ACTIVATED: if (steam_event->okay && get_game_state() == _game_in_progress && !game_is_networked) { pause_game(); diff --git a/Steam/steamshim_parent.cpp b/Steam/steamshim_parent.cpp index aee6f0542..349b20bcc 100755 --- a/Steam/steamshim_parent.cpp +++ b/Steam/steamshim_parent.cpp @@ -25,6 +25,7 @@ typedef int PipeType; namespace fs = boost::filesystem; #include "steam/steam_api.h" +#include #define DEBUGPIPE 1 #if DEBUGPIPE @@ -280,10 +281,123 @@ class SteamBridge; static ISteamUserStats *GSteamStats = NULL; static ISteamUtils *GSteamUtils = NULL; static ISteamUser *GSteamUser = NULL; +static ISteamUGC *GSteamUGC = NULL; static AppId_t GAppID = 0; static uint64 GUserID = 0; static SteamBridge *GSteamBridge = NULL; +namespace SteamItemTags +{ + constexpr const char* ItemType = "ItemType"; + constexpr const char* RequiredScenario = "RequiredScenario"; +} + +typedef enum ItemType { + Scenario, + Plugin, + Other +}; + +struct item_subscribed_query_result +{ + struct item + { + uint64_t id; + ItemType type; + std::string install_folder_path; + }; + + EResult result_code; + std::vector items; + + std::ostringstream shim_serialize() const + { + std::ostringstream data_stream; + data_stream.write(reinterpret_cast(&result_code), sizeof(result_code)); + + int number_items = items.size(); + data_stream.write(reinterpret_cast(&number_items), sizeof(number_items)); + + for (const auto& item : items) + { + data_stream.write(reinterpret_cast(&item.id), sizeof(item.id)); + data_stream.write(reinterpret_cast(&item.type), sizeof(item.type)); + data_stream << item.install_folder_path << '\0'; + } + + return data_stream; + } +}; + +struct item_owned_query_result +{ + struct item + { + uint64_t id; + ItemType type; + bool is_scenarios_compatible; + std::string title; + std::vector tags; + }; + + EResult result_code; + std::vector items; + + std::ostringstream shim_serialize() const + { + std::ostringstream data_stream; + data_stream.write(reinterpret_cast(&result_code), sizeof(result_code)); + + int number_items = items.size(); + data_stream.write(reinterpret_cast(&number_items), sizeof(number_items)); + + for (const auto& item : items) + { + data_stream.write(reinterpret_cast(&item.id), sizeof(item.id)); + data_stream.write(reinterpret_cast(&item.type), sizeof(item.type)); + data_stream.write(reinterpret_cast(&item.is_scenarios_compatible), sizeof(item.is_scenarios_compatible)); + data_stream << item.title << '\0'; + + for (const auto& tag : item.tags) + { + data_stream << tag << '\0'; + } + + data_stream << '\0'; + } + + return data_stream; + } +}; + +struct item_upload_data { + + uint64_t id; + ItemType type; + std::string directory_path; + std::string thumbnail_path; + std::string required_scenario; + std::vector tags; + + void shim_deserialize(const uint8* buf, unsigned int buflen) + { + std::istringstream iss(std::string((const char*)buf, buflen)); + iss.read(reinterpret_cast(&id), sizeof(id)); + iss.read(reinterpret_cast(&type), sizeof(type)); + std::getline(iss, directory_path, '\0'); + std::getline(iss, thumbnail_path, '\0'); + std::getline(iss, required_scenario, '\0'); + + while (true) + { + std::string tag; + std::getline(iss, tag, '\0'); + if (tag.empty()) break; + tags.push_back(tag); + } + } +}; + class SteamBridge { public: @@ -291,8 +405,25 @@ class SteamBridge STEAM_CALLBACK(SteamBridge, OnUserStatsReceived, UserStatsReceived_t, m_CallbackUserStatsReceived); STEAM_CALLBACK(SteamBridge, OnUserStatsStored, UserStatsStored_t, m_CallbackUserStatsStored); STEAM_CALLBACK(SteamBridge, OnOverlayActivated, GameOverlayActivated_t, m_CallbackOverlayActivated); + void set_item_created_callback(SteamAPICall_t api_call, const item_upload_data& item_data); + void set_item_updated_callback(SteamAPICall_t api_call, UGCUpdateHandle_t handle); + void set_item_owned_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name); + void set_item_mod_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name); + void set_item_scenario_queried_callback(SteamAPICall_t api_call); + void idle(); private: PipeType fd; + CCallResult m_CallbackItemCreatedResult; + CCallResult m_CallbackItemUpdatedResult; + CCallResult m_CallbackItemQueryCompleted; + void OnItemCreated(CreateItemResult_t* pCallback, bool bIOFailure); + void OnItemUpdated(SubmitItemUpdateResult_t* pCallback, bool bIOFailure); + void OnItemOwnedQueried(SteamUGCQueryCompleted_t* pCallback, bool bIOFailure); + void OnItemScenarioQueried(SteamUGCQueryCompleted_t* pCallback, bool bIOFailure); + void OnItemModQueried(SteamUGCQueryCompleted_t* pCallback, bool bIOFailure); + item_upload_data m_upload_item_data; + UGCUpdateHandle_t m_update_handle = 0xffffffffffffffffull; + std::string m_scenario_name; }; typedef enum ShimCmd @@ -308,6 +439,10 @@ typedef enum ShimCmd SHIMCMD_GETSTATI, SHIMCMD_SETSTATF, SHIMCMD_GETSTATF, + SHIMCMD_WORKSHOP_UPLOAD, + SHIMCMD_WORKSHOP_QUERY_ITEM_OWNED, + SHIMCMD_WORKSHOP_QUERY_ITEM_MOD, + SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO } ShimCmd; typedef enum ShimEvent @@ -322,24 +457,34 @@ typedef enum ShimEvent SHIMEVENT_GETSTATI, SHIMEVENT_SETSTATF, SHIMEVENT_GETSTATF, - SHIMEVENT_ISOVERLAYACTIVATED + SHIMEVENT_IS_OVERLAY_ACTIVATED, + SHIMEVENT_WORKSHOP_UPLOAD_RESULT, + SHIMEVENT_WORKSHOP_UPLOAD_PROGRESS, + SHIMEVENT_WORKSHOP_QUERY_OWNED_ITEM_RESULT, + SHIMEVENT_WORKSHOP_QUERY_SUBSCRIBED_ITEM_RESULT } ShimEvent; static bool write1ByteCmd(PipeType fd, const uint8 b1) { - const uint8 buf[] = { 1, b1 }; + uint16_t length = 1; + uint8* length_bytes = (uint8*)&length; + const uint8 buf[] = { length_bytes[0], length_bytes[1], b1 }; return writePipe(fd, buf, sizeof (buf)); } // write1ByteCmd static bool write2ByteCmd(PipeType fd, const uint8 b1, const uint8 b2) { - const uint8 buf[] = { 2, b1, b2 }; + uint16_t length = 2; + uint8* length_bytes = (uint8*)&length; + const uint8 buf[] = { length_bytes[0], length_bytes[1], b1, b2 }; return writePipe(fd, buf, sizeof (buf)); } // write2ByteCmd static bool write3ByteCmd(PipeType fd, const uint8 b1, const uint8 b2, const uint8 b3) { - const uint8 buf[] = { 3, b1, b2, b3 }; + uint16_t length = 3; + uint8* length_bytes = (uint8*)&length; + const uint8 buf[] = { length_bytes[0], length_bytes[1], b1, b2, b3 }; return writePipe(fd, buf, sizeof (buf)); } // write3ByteCmd @@ -364,28 +509,71 @@ static inline bool writeStatsStored(PipeType fd, const bool okay) static inline bool writeOverlayActivated(PipeType fd, const bool okay) { - dbgpipe("Parent sending SHIMEVENT_ISOVERLAYACTIVE(%sokay).\n", okay ? "" : "!"); - return write2ByteCmd(fd, SHIMEVENT_ISOVERLAYACTIVATED, okay ? 1 : 0); + dbgpipe("Parent sending SHIMEVENT_IS_OVERLAY_ACTIVATED(%sokay).\n", okay ? "" : "!"); + return write2ByteCmd(fd, SHIMEVENT_IS_OVERLAY_ACTIVATED, okay ? 1 : 0); +} // writeOverlayActivated + +static inline bool writeWorkshopUploadResult(PipeType fd, const EResult result) +{ + dbgpipe("Parent sending SHIMEVENT_WORKSHOP_UPLOAD_RESULT(%d result).\n", result); + return write2ByteCmd(fd, SHIMEVENT_WORKSHOP_UPLOAD_RESULT, result); +} // writeOverlayActivated + +static bool writeWorkshopItemOwnedQueriedResult(PipeType fd, const item_owned_query_result& query_result) +{ + dbgpipe("Parent sending SHIMEVENT_WORKSHOP_QUERY_OWNED_ITEM_RESULT(%d result).\n", query_result.result_code); + auto data_stream = query_result.shim_serialize(); + + data_stream = std::ostringstream() << (uint8)SHIMEVENT_WORKSHOP_QUERY_OWNED_ITEM_RESULT << data_stream.str(); + + std::ostringstream data_stream_shim; + + uint16_t length = data_stream.str().length(); + data_stream_shim.write(reinterpret_cast(&length), sizeof(length)); + data_stream_shim << data_stream.str(); + + auto buffer = data_stream_shim.str(); + return writePipe(fd, buffer.data(), buffer.length()); +} // writeOverlayActivated + +static bool writeWorkshopItemQueriedResult(PipeType fd, const item_subscribed_query_result& query_result) +{ + dbgpipe("Parent sending SHIMEVENT_WORKSHOP_QUERY_SUBSCRIBED_ITEM_RESULT(%d result).\n", query_result.result_code); + auto data_stream = query_result.shim_serialize(); + + data_stream = std::ostringstream() << (uint8)SHIMEVENT_WORKSHOP_QUERY_SUBSCRIBED_ITEM_RESULT << data_stream.str(); + + std::ostringstream data_stream_shim; + + uint16_t length = data_stream.str().length(); + data_stream_shim.write(reinterpret_cast(&length), sizeof(length)); + data_stream_shim << data_stream.str(); + + auto buffer = data_stream_shim.str(); + return writePipe(fd, buffer.data(), buffer.length()); } // writeOverlayActivated static bool writeAchievementSet(PipeType fd, const char *name, const bool enable, const bool okay) { uint8 buf[256]; - uint8 *ptr = buf+1; + uint8 *ptr = buf+2; dbgpipe("Parent sending SHIMEVENT_SETACHIEVEMENT('%s', %senable, %sokay).\n", name, enable ? "" : "!", okay ? "" : "!"); *(ptr++) = (uint8) SHIMEVENT_SETACHIEVEMENT; *(ptr++) = enable ? 1 : 0; *(ptr++) = okay ? 1 : 0; strcpy((char *) ptr, name); ptr += strlen(name) + 1; - buf[0] = (uint8) ((ptr-1) - buf); - return writePipe(fd, buf, buf[0] + 1); + uint16_t length = ((ptr - 1) - buf); + uint8* length_bytes = (uint8*)&length; + buf[0] = length_bytes[0]; + buf[1] = length_bytes[1]; + return writePipe(fd, buf, length + 2); } // writeAchievementSet static bool writeAchievementGet(PipeType fd, const char *name, const int status, const uint64 time) { uint8 buf[256]; - uint8 *ptr = buf+1; + uint8 *ptr = buf+2; dbgpipe("Parent sending SHIMEVENT_GETACHIEVEMENT('%s', status %d, time %llu).\n", name, status, (unsigned long long) time); *(ptr++) = (uint8) SHIMEVENT_GETACHIEVEMENT; *(ptr++) = (uint8) status; @@ -393,8 +581,11 @@ static bool writeAchievementGet(PipeType fd, const char *name, const int status, ptr += sizeof (time); strcpy((char *) ptr, name); ptr += strlen(name) + 1; - buf[0] = (uint8) ((ptr-1) - buf); - return writePipe(fd, buf, buf[0] + 1); + uint16_t length = ((ptr - 1) - buf); + uint8* length_bytes = (uint8*)&length; + buf[0] = length_bytes[0]; + buf[1] = length_bytes[1]; + return writePipe(fd, buf, length + 2); } // writeAchievementGet static inline bool writeResetStats(PipeType fd, const bool alsoAch, const bool okay) @@ -406,15 +597,18 @@ static inline bool writeResetStats(PipeType fd, const bool alsoAch, const bool o static bool writeStatThing(PipeType fd, const ShimEvent ev, const char *name, const void *val, const size_t vallen, const bool okay) { uint8 buf[256]; - uint8 *ptr = buf+1; + uint8 *ptr = buf+2; *(ptr++) = (uint8) ev; *(ptr++) = okay ? 1 : 0; memcpy(ptr, val, vallen); ptr += vallen; strcpy((char *) ptr, name); ptr += strlen(name) + 1; - buf[0] = (uint8) ((ptr-1) - buf); - return writePipe(fd, buf, buf[0] + 1); + uint16_t length = ((ptr - 1) - buf); + uint8* length_bytes = (uint8*)&length; + buf[0] = length_bytes[0]; + buf[1] = length_bytes[1]; + return writePipe(fd, buf, length + 2); } // writeStatThing static inline bool writeSetStatI(PipeType fd, const char *name, const int32 val, const bool okay) @@ -441,7 +635,39 @@ static inline bool writeGetStatF(PipeType fd, const char *name, const float val, return writeStatThing(fd, SHIMEVENT_GETSTATF, name, &val, sizeof (val), okay); } // writeGetStatF +static void UpdateItem(PublishedFileId_t item_id, item_upload_data& item_data) +{ + UGCUpdateHandle_t updateHandle = GSteamUGC->StartItemUpdate(GAppID, item_id); + + if (item_data.id) //existing item + GSteamUGC->RemoveItemKeyValueTags(updateHandle, SteamItemTags::RequiredScenario); + else //new item + { + std::string title = "New Item " + std::to_string(item_id); + std::string type = std::to_string(item_data.type); + GSteamUGC->SetItemTitle(updateHandle, title.c_str()); + GSteamUGC->AddItemKeyValueTag(updateHandle, SteamItemTags::ItemType, type.c_str()); + GSteamUGC->SetItemVisibility(updateHandle, k_ERemoteStoragePublishedFileVisibilityPrivate); + } + + if (!item_data.directory_path.empty()) + { + GSteamUGC->SetItemContent(updateHandle, item_data.directory_path.c_str()); + } + + if (!item_data.thumbnail_path.empty()) + { + GSteamUGC->SetItemPreview(updateHandle, item_data.thumbnail_path.c_str()); + } + + if (!item_data.required_scenario.empty()) + { + GSteamUGC->AddItemKeyValueTag(updateHandle, SteamItemTags::RequiredScenario, item_data.required_scenario.c_str()); + } + auto steam_api_call = GSteamUGC->SubmitItemUpdate(updateHandle, nullptr); + GSteamBridge->set_item_updated_callback(steam_api_call, updateHandle); +} SteamBridge::SteamBridge(PipeType _fd) : m_CallbackUserStatsReceived( this, &SteamBridge::OnUserStatsReceived ) @@ -470,6 +696,223 @@ void SteamBridge::OnOverlayActivated(GameOverlayActivated_t *pCallback) writeOverlayActivated(fd, pCallback->m_bActive); } // SteamBridge::OnOverlayActivated +void SteamBridge::set_item_created_callback(SteamAPICall_t api_call, const item_upload_data& item_data) +{ + m_upload_item_data = item_data; + m_CallbackItemCreatedResult.Set(api_call, this, &SteamBridge::OnItemCreated); +} + +void SteamBridge::set_item_updated_callback(SteamAPICall_t api_call, UGCUpdateHandle_t handle) +{ + m_update_handle = handle; + m_CallbackItemUpdatedResult.Set(api_call, this, &SteamBridge::OnItemUpdated); +} + +void SteamBridge::set_item_owned_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name) +{ + m_scenario_name = scenario_name; + m_CallbackItemQueryCompleted.Set(api_call, this, &SteamBridge::OnItemOwnedQueried); +} + +void SteamBridge::set_item_scenario_queried_callback(SteamAPICall_t api_call) +{ + m_CallbackItemQueryCompleted.Set(api_call, this, &SteamBridge::OnItemScenarioQueried); +} + +void SteamBridge::set_item_mod_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name) +{ + m_scenario_name = scenario_name; + m_CallbackItemQueryCompleted.Set(api_call, this, &SteamBridge::OnItemModQueried); +} + +void SteamBridge::idle() +{ + if (m_update_handle != 0xffffffffffffffffull) + { + uint64 total_bytes, uploaded_bytes; + auto status = GSteamUGC->GetItemUpdateProgress(m_update_handle, &uploaded_bytes, &total_bytes); + if (status != k_EItemUpdateStatusInvalid && total_bytes) + { + write3ByteCmd(fd, SHIMEVENT_WORKSHOP_UPLOAD_PROGRESS, status, (uploaded_bytes * 1.f / total_bytes) * 100); + } + } +} + +void SteamBridge::OnItemCreated(CreateItemResult_t* pCallback, bool bIOFailure) +{ + if (bIOFailure || pCallback->m_eResult != k_EResultOK) + writeWorkshopUploadResult(fd, pCallback->m_eResult); + else + UpdateItem(pCallback->m_nPublishedFileId, m_upload_item_data); +} + +void SteamBridge::OnItemUpdated(SubmitItemUpdateResult_t* pCallback, bool bIOFailure) +{ + if (bIOFailure || pCallback->m_eResult != k_EResultOK) + { + if (!m_upload_item_data.id) + { + GSteamUGC->DeleteItem(pCallback->m_nPublishedFileId); //won't care about callback and return value here + } + } + + m_update_handle = 0xffffffffffffffffull; + writeWorkshopUploadResult(fd, pCallback->m_eResult); +} + +void SteamBridge::OnItemOwnedQueried(SteamUGCQueryCompleted_t* pCallback, bool bIOFailure) +{ + item_owned_query_result items_result; + + if (!bIOFailure && pCallback->m_eResult == k_EResultOK) + { + for (int i = 0; i < pCallback->m_unNumResultsReturned; i++) + { + SteamUGCDetails_t item_details; + + if (!GSteamUGC->GetQueryUGCResult(pCallback->m_handle, i, &item_details) && !item_details.m_bBanned) + { + continue; + } + + item_owned_query_result::item item; + item.is_scenarios_compatible = true; + + char item_kv_tag[256]; + + if (!GSteamUGC->GetQueryUGCKeyValueTag(pCallback->m_handle, i, SteamItemTags::ItemType, item_kv_tag, sizeof(item_kv_tag))) + { + continue; //ignore item if we can't retrieve its type tag + } + + item.type = (ItemType)std::stoi(item_kv_tag); //we should probably check better here + + char item_scenario_tag[256]; + if (GSteamUGC->GetQueryUGCKeyValueTag(pCallback->m_handle, i, SteamItemTags::RequiredScenario, item_scenario_tag, sizeof(item_scenario_tag))) + { + if (std::strlen(item_scenario_tag) && m_scenario_name != item_scenario_tag) + { + continue; //not compatible item + } + + item.is_scenarios_compatible = false; + } + + auto number_tags = GSteamUGC->GetQueryUGCNumTags(pCallback->m_handle, i); + for (int k = 0; k < number_tags; k++) + { + char tag[256]; + if (GSteamUGC->GetQueryUGCTag(pCallback->m_handle, i, k, tag, sizeof(tag))) + { + item.tags.push_back(tag); + } + } + + item.title = item_details.m_rgchTitle; + item.id = item_details.m_nPublishedFileId; + items_result.items.push_back(item); + } + } + + items_result.result_code = pCallback->m_eResult; + GSteamUGC->ReleaseQueryUGCRequest(pCallback->m_handle); + writeWorkshopItemOwnedQueriedResult(fd, items_result); +} + +void SteamBridge::OnItemModQueried(SteamUGCQueryCompleted_t* pCallback, bool bIOFailure) +{ + item_subscribed_query_result items_result; + + if (!bIOFailure && pCallback->m_eResult == k_EResultOK) + { + for (int i = 0; i < pCallback->m_unNumResultsReturned; i++) + { + SteamUGCDetails_t item_details; + + if (!GSteamUGC->GetQueryUGCResult(pCallback->m_handle, i, &item_details)) + { + continue; + } + + char item_type_tag[256]; + if (!GSteamUGC->GetQueryUGCKeyValueTag(pCallback->m_handle, i, SteamItemTags::ItemType, item_type_tag, sizeof(item_type_tag))) + { + continue; //ignore item if we can't retrieve its type tag + } + + item_subscribed_query_result::item item; + item.type = (ItemType)std::stoi(item_type_tag); //we should probably check better here + + if (item.type == ItemType::Scenario) + { + continue; + } + + char item_scenario_tag[256]; + if (GSteamUGC->GetQueryUGCKeyValueTag(pCallback->m_handle, i, SteamItemTags::RequiredScenario, item_scenario_tag, sizeof(item_scenario_tag))) + { + if (std::strlen(item_scenario_tag) && m_scenario_name != item_scenario_tag) + { + continue; //not compatible item + } + } + + uint64 item_size; + char folder_path[256]; + uint32 time_stamp; + + if (!GSteamUGC->GetItemInstallInfo(item_details.m_nPublishedFileId, &item_size, folder_path, sizeof(folder_path), &time_stamp)) + { + continue; + } + + item.id = item_details.m_nPublishedFileId; + item.install_folder_path = folder_path; + items_result.items.push_back(item); + } + } + + items_result.result_code = pCallback->m_eResult; + GSteamUGC->ReleaseQueryUGCRequest(pCallback->m_handle); + writeWorkshopItemQueriedResult(fd, items_result); +} + +void SteamBridge::OnItemScenarioQueried(SteamUGCQueryCompleted_t* pCallback, bool bIOFailure) +{ + item_subscribed_query_result items_result; + + if (!bIOFailure && pCallback->m_eResult == k_EResultOK) + { + for (int i = 0; i < pCallback->m_unNumResultsReturned; i++) + { + SteamUGCDetails_t item_details; + + if (!GSteamUGC->GetQueryUGCResult(pCallback->m_handle, i, &item_details)) + { + continue; + } + + uint64 item_size; + char folder_path[256]; + uint32 time_stamp; + + if (!GSteamUGC->GetItemInstallInfo(item_details.m_nPublishedFileId, &item_size, folder_path, sizeof(folder_path), &time_stamp)) + { + continue; + } + + item_subscribed_query_result::item item; + item.id = item_details.m_nPublishedFileId; + item.type = ItemType::Scenario; + item.install_folder_path = folder_path; + items_result.items.push_back(item); + } + } + + items_result.result_code = pCallback->m_eResult; + GSteamUGC->ReleaseQueryUGCRequest(pCallback->m_handle); + writeWorkshopItemQueriedResult(fd, items_result); +} static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) { @@ -493,6 +936,9 @@ static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) PRINTGOTCMD(SHIMCMD_GETSTATI); PRINTGOTCMD(SHIMCMD_SETSTATF); PRINTGOTCMD(SHIMCMD_GETSTATF); + PRINTGOTCMD(SHIMCMD_WORKSHOP_UPLOAD); + PRINTGOTCMD(SHIMCMD_WORKSHOP_QUERY_ITEM_OWNED); + PRINTGOTCMD(SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO); #undef PRINTGOTCMD else printf("Parent got unknown shimcmd %d.\n", (int) cmd); #endif @@ -501,6 +947,7 @@ static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) { case SHIMCMD_PUMP: SteamAPI_RunCallbacks(); + GSteamBridge->idle(); break; case SHIMCMD_BYE: @@ -599,6 +1046,55 @@ static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) writeGetStatF(fd, name, 0.0f, false); } // if break; + + case SHIMCMD_WORKSHOP_UPLOAD: + if (buflen) + { + item_upload_data item = {}; + item.shim_deserialize(buf, buflen); + + if (item.id) + UpdateItem(item.id, item); + else + { + auto steam_api_call = GSteamUGC->CreateItem(GAppID, k_EWorkshopFileTypeCommunity); + GSteamBridge->set_item_created_callback(steam_api_call, item); + } + } // if + break; + + case SHIMCMD_WORKSHOP_QUERY_ITEM_OWNED: + if (buflen) + { + auto scenario = std::string((const char*)buf); + auto handle = GSteamUGC->CreateQueryUserUGCRequest(GUserID, k_EUserUGCList_Published, k_EUGCMatchingUGCType_Items, k_EUserUGCListSortOrder_TitleAsc, GAppID, 0, 1); + GSteamUGC->SetReturnKeyValueTags(handle, true); + auto steam_api_call = GSteamUGC->SendQueryUGCRequest(handle); + GSteamBridge->set_item_owned_queried_callback(steam_api_call, scenario); + } + break; + + case SHIMCMD_WORKSHOP_QUERY_ITEM_MOD: + if (buflen) + { + auto scenario = std::string((const char*)buf); + auto handle = GSteamUGC->CreateQueryUserUGCRequest(GUserID, k_EUserUGCList_Subscribed, k_EUGCMatchingUGCType_Items, k_EUserUGCListSortOrder_CreationOrderDesc, 0, GAppID, 1); + GSteamUGC->SetReturnKeyValueTags(handle, true); + auto steam_api_call = GSteamUGC->SendQueryUGCRequest(handle); + GSteamBridge->set_item_mod_queried_callback(steam_api_call, scenario); + } + break; + + case SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO: + { + auto scenario_tag = std::to_string(ItemType::Scenario); + auto handle = GSteamUGC->CreateQueryUserUGCRequest(GUserID, k_EUserUGCList_Subscribed, k_EUGCMatchingUGCType_Items, k_EUserUGCListSortOrder_CreationOrderDesc, 0, GAppID, 1); + GSteamUGC->SetReturnOnlyIDs(handle, true); + GSteamUGC->AddRequiredKeyValueTag(handle, SteamItemTags::ItemType, scenario_tag.c_str()); + auto steam_api_call = GSteamUGC->SendQueryUGCRequest(handle); + GSteamBridge->set_item_scenario_queried_callback(steam_api_call); + } + break; } // switch return true; // keep going. @@ -607,7 +1103,7 @@ static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) static void processCommands(PipeType pipeParentRead, PipeType pipeParentWrite) { bool quit = false; - uint8 buf[256]; + static uint8 buf[65536]; int br; // this read blocks. @@ -615,18 +1111,20 @@ static void processCommands(PipeType pipeParentRead, PipeType pipeParentWrite) { while (br > 0) { - const int cmdlen = (int) buf[0]; - if ((br-1) >= cmdlen) + int cmdlen; + const int rawdatalength = br - 2; + + if (rawdatalength >= 0 && rawdatalength >= (cmdlen = *reinterpret_cast(buf))) { - if (!processCommand(buf+1, cmdlen, pipeParentWrite)) + if (!processCommand(buf+2, cmdlen, pipeParentWrite)) { quit = true; break; } // if - br -= cmdlen + 1; + br -= cmdlen + 2; if (br > 0) - memmove(buf, buf+cmdlen+1, br); + memmove(buf, buf+cmdlen+2, br); } // if else // get more data. { @@ -656,18 +1154,19 @@ static bool setEnvironmentVars(PipeType pipeChildRead, PipeType pipeChildWrite) return true; } // setEnvironmentVars -static bool initSteamworks(PipeType fd) +static bool initSteamworks(PipeType fd, ESteamAPIInitResult* resultCode, SteamErrMsg* errorMessage) { // this can fail for many reasons: // - you forgot a steam_appid.txt in the current working directory. // - you don't have Steam running // - you don't own the game listed in steam_appid.txt - if (!SteamAPI_Init()) - return 0; + *resultCode = SteamAPI_InitEx(errorMessage); + if (*resultCode != k_ESteamAPIInitResult_OK) return 0; GSteamStats = SteamUserStats(); GSteamUtils = SteamUtils(); GSteamUser = SteamUser(); + GSteamUGC = SteamUGC(); GAppID = GSteamUtils ? GSteamUtils->GetAppID() : 0; GUserID = GSteamUser ? GSteamUser->GetSteamID().ConvertToUint64() : 0; @@ -684,6 +1183,7 @@ static void deinitSteamworks(void) GSteamStats = NULL; GSteamUtils= NULL; GSteamUser = NULL; + GSteamUGC = NULL; } // deinitSteamworks static int mainline(void) @@ -695,11 +1195,17 @@ static int mainline(void) ProcessType childPid; dbgpipe("Parent starting mainline.\n"); + ESteamAPIInitResult initResultCode; + SteamErrMsg initErrorMessage; if (!createPipes(&pipeParentRead, &pipeParentWrite, &pipeChildRead, &pipeChildWrite)) fail("Failed to create application pipes"); - else if (!initSteamworks(pipeParentWrite)) - fail("Failed to initialize Steamworks"); + else if (!initSteamworks(pipeParentWrite, &initResultCode, &initErrorMessage)) + { + char str[1200]; + sprintf(str, "Failed to initialize Steamworks: %s (error %d)", initErrorMessage, initResultCode); + fail(str); + } else if (!setEnvironmentVars(pipeChildRead, pipeChildWrite)) fail("Failed to set environment variables"); else if (!launchChild(&childPid)){ diff --git a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj index 4788d3bb1..22d45a838 100644 --- a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj +++ b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj @@ -491,7 +491,7 @@ - + true true diff --git a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj.filters b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj.filters index d4608fa2a..07a54e7a6 100644 --- a/VisualStudio/LibAlephOne/LibAlephOne.vcxproj.filters +++ b/VisualStudio/LibAlephOne/LibAlephOne.vcxproj.filters @@ -724,7 +724,7 @@ Lua\Source Files - + Misc\Source Files From d2d9c7df24056219406dcefd58a0670f1d92f8ce Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Fri, 9 Aug 2024 20:46:51 -0400 Subject: [PATCH 23/58] retrieve "Other" workshop items and populate the env selectors with them --- Source_Files/Misc/preferences_widgets_sdl.cpp | 57 ++++++++++++++++++- Source_Files/shell.cpp | 28 +++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/Source_Files/Misc/preferences_widgets_sdl.cpp b/Source_Files/Misc/preferences_widgets_sdl.cpp index 3f7166413..47c4d652c 100644 --- a/Source_Files/Misc/preferences_widgets_sdl.cpp +++ b/Source_Files/Misc/preferences_widgets_sdl.cpp @@ -29,9 +29,15 @@ */ #include "preferences_widgets_sdl.h" + +#include + #include "Crosshairs.h" #include "preferences.h" +#ifdef HAVE_STEAM +#include "steamshim_child.h" +#endif extern bool use_lua_hud_crosshairs; @@ -44,8 +50,58 @@ void w_env_select::select_item_callback(void* arg) { obj->select_item(obj->parent); } +#ifdef HAVE_STEAM +extern std::vector subscribed_workshop_items; + +static void add_workshop_items(Typecode type, std::vector& items) +{ + std::vector files; + FindAllFiles finder(files); + + for (auto& item : subscribed_workshop_items) + { + FileSpecifier dir = item.install_folder_path; + finder.Find(dir, type); + } + + if (files.size() == 0) + { + return; + } + + env_item title; + strcpy(title.name, "Steam Workshop"); + items.push_back(title); + + std::sort(files.begin(), files.end(), [](const FileSpecifier& a, const FileSpecifier& b) { + std::string tmp, a_name, b_name; + a.SplitPath(tmp, a_name); + b.SplitPath(tmp, b_name); + + return std::lexicographical_compare(a_name.begin(), + a_name.end(), + b_name.begin(), + b_name.end(), + [](const char& a, const char& b) { + return tolower(a) < tolower(b); + }); + }); + + for (auto& file : files) + { + items.push_back(env_item(file, 1, true)); + } +} +#endif + void w_env_select::select_item(dialog *parent) { + vector items; + +#ifdef HAVE_STEAM + add_workshop_items(type, items); +#endif + // Find available files vector files; if (type != _typecode_theme) { @@ -61,7 +117,6 @@ void w_env_select::select_item(dialog *parent) } // Create structured list of files - vector items; vector::const_iterator i = files.begin(), end = files.end(); string last_base; int indent_level = 0; diff --git a/Source_Files/shell.cpp b/Source_Files/shell.cpp index 07457e62d..48529acb7 100644 --- a/Source_Files/shell.cpp +++ b/Source_Files/shell.cpp @@ -140,6 +140,10 @@ DirectorySpecifier recordings_dir; // Directory for recordings (except film b DirectorySpecifier screenshots_dir; // Directory for screenshots DirectorySpecifier log_dir; // Directory for Aleph One Log.txt +#ifdef HAVE_STEAM +std::vector subscribed_workshop_items; +#endif + /* // Command-line options bool option_nogl = false; // Disable OpenGL @@ -461,6 +465,30 @@ void initialize_application(void) } } +#ifdef HAVE_STEAM + STEAMSHIM_queryWorkshopItemMod(Scenario::instance()->GetName()); + while (STEAMSHIM_alive()) + { + auto result = STEAMSHIM_pump(); + + if (result && result->type == SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT) + { + if (result->items_subscribed.result_code == 1) + { + for (const auto& item : result->items_subscribed.items) + { + if (item.type == ItemType::Other) + { + subscribed_workshop_items.push_back(item); + } + } + + break; + } + } + } +#endif + initialize_fonts(true); Plugins::instance()->enumerate(); From 935d0349092f2c9639e0b3772347caf3fafb9c75 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Fri, 9 Aug 2024 22:52:11 -0400 Subject: [PATCH 24/58] load plugins from the workshop --- Source_Files/Misc/preferences_widgets_sdl.cpp | 7 +++++-- Source_Files/XML/Plugins.cpp | 18 ++++++++++++++++++ Source_Files/shell.cpp | 5 +---- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Source_Files/Misc/preferences_widgets_sdl.cpp b/Source_Files/Misc/preferences_widgets_sdl.cpp index 47c4d652c..7fca75601 100644 --- a/Source_Files/Misc/preferences_widgets_sdl.cpp +++ b/Source_Files/Misc/preferences_widgets_sdl.cpp @@ -60,8 +60,11 @@ static void add_workshop_items(Typecode type, std::vector& items) for (auto& item : subscribed_workshop_items) { - FileSpecifier dir = item.install_folder_path; - finder.Find(dir, type); + if (item.type == ItemType::Other) + { + FileSpecifier dir = item.install_folder_path; + finder.Find(dir, type); + } } if (files.size() == 0) diff --git a/Source_Files/XML/Plugins.cpp b/Source_Files/XML/Plugins.cpp index 771bc9b41..37f1f8974 100644 --- a/Source_Files/XML/Plugins.cpp +++ b/Source_Files/XML/Plugins.cpp @@ -33,6 +33,9 @@ #include "InfoTree.h" #include "XML_ParseTreeRoot.h" #include "Scenario.h" +#ifdef HAVE_STEAM +#include "steamshim_child.h" +#endif #include @@ -483,10 +486,25 @@ bool PluginLoader::ParseDirectory(FileSpecifier& dir) extern std::vector data_search_path; +#ifdef HAVE_STEAM +extern std::vector subscribed_workshop_items; +#endif + void Plugins::enumerate() { logContext("parsing plugins"); PluginLoader loader; + +#ifdef HAVE_STEAM + for (const auto& item : subscribed_workshop_items) + { + if (item.type == ItemType::Plugin) + { + FileSpecifier dir(item.install_folder_path); + loader.ParseDirectory(dir); + } + } +#endif for (std::vector::const_iterator it = data_search_path.begin(); it != data_search_path.end(); ++it) { DirectorySpecifier path = *it + "Plugins"; diff --git a/Source_Files/shell.cpp b/Source_Files/shell.cpp index 48529acb7..26e7bc95d 100644 --- a/Source_Files/shell.cpp +++ b/Source_Files/shell.cpp @@ -477,10 +477,7 @@ void initialize_application(void) { for (const auto& item : result->items_subscribed.items) { - if (item.type == ItemType::Other) - { - subscribed_workshop_items.push_back(item); - } + subscribed_workshop_items.push_back(item); } break; From 9d6234bf05bf7fc78dfd1289d3a77ce06694cec6 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Fri, 9 Aug 2024 23:17:52 -0400 Subject: [PATCH 25/58] upload dialog improvements --- Source_Files/Misc/interface.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Source_Files/Misc/interface.cpp b/Source_Files/Misc/interface.cpp index 34129dd23..c29b2ce8a 100644 --- a/Source_Files/Misc/interface.cpp +++ b/Source_Files/Misc/interface.cpp @@ -1919,8 +1919,6 @@ static void display_steam_workshop_uploader_dialog(void* arg) table->dual_add(items_popup->label("Upload For"), d); table->dual_add(items_popup, d); - table->add_row(new w_spacer(), true); - static const std::vector item_types = { "Scenario", "Plugin", "Other"}; auto types_popup = new w_select_popup(); types_popup->set_labels(item_types); @@ -1929,20 +1927,19 @@ static void display_steam_workshop_uploader_dialog(void* arg) table->dual_add(types_popup->label("Item Type"), d); table->dual_add(types_popup, d); - table->add_row(new w_spacer(), true); - - auto custom_scenarios = new w_toggle(true); - table->dual_add(custom_scenarios->label("Scenarios Compatible"), d); + char label_off[128]; + const char* labels[] = { label_off, "Any Scenario", "", nullptr }; + snprintf(label_off, 128, "%s Only", Scenario::instance()->GetName().c_str()); + + auto custom_scenarios = new w_toggle(true, labels); + table->dual_add(custom_scenarios->label("Compatible With"), d); table->dual_add(custom_scenarios, d); - table->dual_add_row(new w_static_text("Uncheck if the item is only compatible with this scenario"), d); table->add_row(new w_spacer(), true); auto thumbnail_path = new w_file_chooser("Choose Preview Image", _typecode_unknown); table->dual_add(thumbnail_path->label("Preview Image"), d); table->dual_add(thumbnail_path, d); - table->add_row(new w_spacer(), true); - auto directory_path = new w_directory_chooser(); table->dual_add(directory_path->label("Item Directory"), d); table->dual_add(directory_path, d); @@ -1988,7 +1985,7 @@ static void display_steam_workshop_uploader_dialog(void* arg) ui_data.item_type = types_popup->get_selection(); bool is_scenario = static_cast(ui_data.item_type) == ItemType::Scenario; custom_scenarios->set_enabled(!is_scenario); - custom_scenarios->set_selection(!is_scenario); + custom_scenarios->set_selection(is_scenario ? 2 : 1); }, nullptr); From 6294d4e5ca8d9996a5e476b80528638022c01e35 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Sat, 10 Aug 2024 13:36:44 +0200 Subject: [PATCH 26/58] Add workshop legal agreement stuff --- Source_Files/Misc/interface.cpp | 9 ++++++++- Source_Files/Misc/steamshim_child.cpp | 1 + Source_Files/Misc/steamshim_child.h | 1 + Steam/steamshim_parent.cpp | 12 ++++++------ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Source_Files/Misc/interface.cpp b/Source_Files/Misc/interface.cpp index c29b2ce8a..8e85b1459 100644 --- a/Source_Files/Misc/interface.cpp +++ b/Source_Files/Misc/interface.cpp @@ -1832,7 +1832,9 @@ static void steam_workshop_upload_item_callback(void* arg) { if (result->okay) { - alert_user("Your item was correctly uploaded on Steam", infoNoError); + std::string message = "Your item was correctly uploaded on Steam."; + message += result->needs_to_accept_workshop_agreement ? " However, your item will remain hidden until you accept the Steam workshop legal agreement." : ""; + alert_user(message.c_str(), infoNoError); dialog->quit(0); } else @@ -1948,6 +1950,11 @@ static void display_steam_workshop_uploader_dialog(void* arg) placer->add(new w_spacer, true); + placer->dual_add(new w_hyperlink("https://steamcommunity.com/sharedfiles/workshoplegalagreement", + "By submitting this item, you agree to the workshop terms of service"), d); + + placer->add(new w_spacer, true); + auto button_placer = new horizontal_placer; auto callback_params = std::make_pair(&ui_data, &d); diff --git a/Source_Files/Misc/steamshim_child.cpp b/Source_Files/Misc/steamshim_child.cpp index d684f05dd..26b6e7779 100644 --- a/Source_Files/Misc/steamshim_child.cpp +++ b/Source_Files/Misc/steamshim_child.cpp @@ -318,6 +318,7 @@ static const STEAMSHIM_Event *processEvent(const uint8 *buf, size_t buflen) case SHIMEVENT_WORKSHOP_UPLOAD_RESULT: event.ivalue = (int)*(buf++); event.okay = event.ivalue == 1; + event.needs_to_accept_workshop_agreement = (bool)*(buf++); break; case SHIMEVENT_WORKSHOP_UPLOAD_PROGRESS: diff --git a/Source_Files/Misc/steamshim_child.h b/Source_Files/Misc/steamshim_child.h index 096a3c9af..d46186dca 100755 --- a/Source_Files/Misc/steamshim_child.h +++ b/Source_Files/Misc/steamshim_child.h @@ -164,6 +164,7 @@ struct STEAMSHIM_Event float fvalue; unsigned long long epochsecs; char name[256]; + bool needs_to_accept_workshop_agreement; item_owned_query_result items_owned; item_subscribed_query_result items_subscribed; }; diff --git a/Steam/steamshim_parent.cpp b/Steam/steamshim_parent.cpp index 349b20bcc..6137e94e3 100755 --- a/Steam/steamshim_parent.cpp +++ b/Steam/steamshim_parent.cpp @@ -513,10 +513,10 @@ static inline bool writeOverlayActivated(PipeType fd, const bool okay) return write2ByteCmd(fd, SHIMEVENT_IS_OVERLAY_ACTIVATED, okay ? 1 : 0); } // writeOverlayActivated -static inline bool writeWorkshopUploadResult(PipeType fd, const EResult result) +static inline bool writeWorkshopUploadResult(PipeType fd, const EResult result, bool needs_accept_workshop_agreement) { - dbgpipe("Parent sending SHIMEVENT_WORKSHOP_UPLOAD_RESULT(%d result).\n", result); - return write2ByteCmd(fd, SHIMEVENT_WORKSHOP_UPLOAD_RESULT, result); + dbgpipe("Parent sending SHIMEVENT_WORKSHOP_UPLOAD_RESULT(%d result %d workshop agreement).\n", result, needs_accept_workshop_agreement); + return write3ByteCmd(fd, SHIMEVENT_WORKSHOP_UPLOAD_RESULT, result, needs_accept_workshop_agreement); } // writeOverlayActivated static bool writeWorkshopItemOwnedQueriedResult(PipeType fd, const item_owned_query_result& query_result) @@ -635,7 +635,7 @@ static inline bool writeGetStatF(PipeType fd, const char *name, const float val, return writeStatThing(fd, SHIMEVENT_GETSTATF, name, &val, sizeof (val), okay); } // writeGetStatF -static void UpdateItem(PublishedFileId_t item_id, item_upload_data& item_data) +static void UpdateItem(PublishedFileId_t item_id, const item_upload_data& item_data) { UGCUpdateHandle_t updateHandle = GSteamUGC->StartItemUpdate(GAppID, item_id); @@ -741,7 +741,7 @@ void SteamBridge::idle() void SteamBridge::OnItemCreated(CreateItemResult_t* pCallback, bool bIOFailure) { if (bIOFailure || pCallback->m_eResult != k_EResultOK) - writeWorkshopUploadResult(fd, pCallback->m_eResult); + writeWorkshopUploadResult(fd, pCallback->m_eResult, pCallback->m_bUserNeedsToAcceptWorkshopLegalAgreement); else UpdateItem(pCallback->m_nPublishedFileId, m_upload_item_data); } @@ -757,7 +757,7 @@ void SteamBridge::OnItemUpdated(SubmitItemUpdateResult_t* pCallback, bool bIOFai } m_update_handle = 0xffffffffffffffffull; - writeWorkshopUploadResult(fd, pCallback->m_eResult); + writeWorkshopUploadResult(fd, pCallback->m_eResult, pCallback->m_bUserNeedsToAcceptWorkshopLegalAgreement); } void SteamBridge::OnItemOwnedQueried(SteamUGCQueryCompleted_t* pCallback, bool bIOFailure) From 131a996bac84bf354c1ff544654e5c5cba1b2499 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Sat, 10 Aug 2024 08:04:53 -0400 Subject: [PATCH 27/58] another attempt at clarifying the custom scenarios checkbox --- Source_Files/Misc/interface.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Source_Files/Misc/interface.cpp b/Source_Files/Misc/interface.cpp index 8e85b1459..b1ac31678 100644 --- a/Source_Files/Misc/interface.cpp +++ b/Source_Files/Misc/interface.cpp @@ -1929,12 +1929,11 @@ static void display_steam_workshop_uploader_dialog(void* arg) table->dual_add(types_popup->label("Item Type"), d); table->dual_add(types_popup, d); - char label_off[128]; - const char* labels[] = { label_off, "Any Scenario", "", nullptr }; - snprintf(label_off, 128, "%s Only", Scenario::instance()->GetName().c_str()); + char label[64]; + snprintf(label, 64, "%s Only", Scenario::instance()->GetName().c_str()); - auto custom_scenarios = new w_toggle(true, labels); - table->dual_add(custom_scenarios->label("Compatible With"), d); + auto custom_scenarios = new w_toggle(false); + table->dual_add(custom_scenarios->label(label), d); table->dual_add(custom_scenarios, d); table->add_row(new w_spacer(), true); @@ -1982,7 +1981,7 @@ static void display_steam_workshop_uploader_dialog(void* arg) directory_path->set_directory(ui_data.directory_path); thumbnail_path->set_file(ui_data.thumbnail_path); - custom_scenarios->set_selection(ui_data.is_scenarios_compatible); + custom_scenarios->set_selection(!ui_data.is_scenarios_compatible); custom_scenarios->set_enabled(static_cast(ui_data.item_type) != ItemType::Scenario); }, nullptr); @@ -1992,13 +1991,13 @@ static void display_steam_workshop_uploader_dialog(void* arg) ui_data.item_type = types_popup->get_selection(); bool is_scenario = static_cast(ui_data.item_type) == ItemType::Scenario; custom_scenarios->set_enabled(!is_scenario); - custom_scenarios->set_selection(is_scenario ? 2 : 1); + custom_scenarios->set_selection(false); }, nullptr); custom_scenarios->set_selection_changed_callback([&](void*) { - ui_data.is_scenarios_compatible = custom_scenarios->get_selection(); + ui_data.is_scenarios_compatible = !custom_scenarios->get_selection(); }); directory_path->set_callback([&]() From ed6772f571b67e307fb27e50c693a7c0159999ad Mon Sep 17 00:00:00 2001 From: Kolfering Date: Sat, 10 Aug 2024 15:00:35 +0200 Subject: [PATCH 28/58] Open overlay with item page when new workshop item is uploaded --- Steam/steamshim_parent.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Steam/steamshim_parent.cpp b/Steam/steamshim_parent.cpp index 6137e94e3..f8ec39e7b 100755 --- a/Steam/steamshim_parent.cpp +++ b/Steam/steamshim_parent.cpp @@ -282,6 +282,7 @@ static ISteamUserStats *GSteamStats = NULL; static ISteamUtils *GSteamUtils = NULL; static ISteamUser *GSteamUser = NULL; static ISteamUGC *GSteamUGC = NULL; +static ISteamFriends* GSteamFriends = NULL; static AppId_t GAppID = 0; static uint64 GUserID = 0; static SteamBridge *GSteamBridge = NULL; @@ -755,6 +756,14 @@ void SteamBridge::OnItemUpdated(SubmitItemUpdateResult_t* pCallback, bool bIOFai GSteamUGC->DeleteItem(pCallback->m_nPublishedFileId); //won't care about callback and return value here } } + else + { + if (!m_upload_item_data.id) + { + std::string url = "https://steamcommunity.com/sharedfiles/filedetails/?id=" + std::to_string(pCallback->m_nPublishedFileId); + GSteamFriends->ActivateGameOverlayToWebPage(url.c_str()); + } + } m_update_handle = 0xffffffffffffffffull; writeWorkshopUploadResult(fd, pCallback->m_eResult, pCallback->m_bUserNeedsToAcceptWorkshopLegalAgreement); @@ -1167,6 +1176,7 @@ static bool initSteamworks(PipeType fd, ESteamAPIInitResult* resultCode, SteamEr GSteamUtils = SteamUtils(); GSteamUser = SteamUser(); GSteamUGC = SteamUGC(); + GSteamFriends = SteamFriends(); GAppID = GSteamUtils ? GSteamUtils->GetAppID() : 0; GUserID = GSteamUser ? GSteamUser->GetSteamID().ConvertToUint64() : 0; @@ -1184,6 +1194,7 @@ static void deinitSteamworks(void) GSteamUtils= NULL; GSteamUser = NULL; GSteamUGC = NULL; + GSteamFriends = NULL; } // deinitSteamworks static int mainline(void) From 11fa8ced2c1e1fb4dac5ad0c510f384538f2e39e Mon Sep 17 00:00:00 2001 From: Kolfering Date: Sat, 10 Aug 2024 15:58:49 +0200 Subject: [PATCH 29/58] Update vcpkg baseline for steamworks sdk to disable rpath fixes on steam dylibs --- vcpkg-configuration.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json index dd2620414..3622040cb 100644 --- a/vcpkg-configuration.json +++ b/vcpkg-configuration.json @@ -7,7 +7,7 @@ { "kind": "git", "repository": "https://github.com/Aleph-One-Marathon/vcpkg-registry", - "baseline": "1e3dc0fb74e33ce0d5359df043cd048a27c17837", + "baseline": "136888395ab723ece5ff1acbf08ff0ed58b04fd5", "packages": [ "steamworks-sdk" ] } ] From 7b6a0292805e9e836ef3b0e7d52513bd00e57734 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Sun, 11 Aug 2024 16:00:43 +0200 Subject: [PATCH 30/58] Add tag management in steam workshop uploader --- Source_Files/Misc/interface.cpp | 130 +++++++++-- Source_Files/Misc/preferences_widgets_sdl.cpp | 2 +- Source_Files/Misc/steamshim_child.h | 72 ++++--- Source_Files/XML/Plugins.cpp | 2 +- Steam/steamshim_parent.cpp | 204 +++++++++++++----- 5 files changed, 312 insertions(+), 98 deletions(-) diff --git a/Source_Files/Misc/interface.cpp b/Source_Files/Misc/interface.cpp index b1ac31678..0e1c4ff5b 100644 --- a/Source_Files/Misc/interface.cpp +++ b/Source_Files/Misc/interface.cpp @@ -270,6 +270,7 @@ struct screen_data { struct steam_workshop_uploader_ui_data { uint64_t item_id; int item_type; + int content_type; FileSpecifier directory_path; FileSpecifier thumbnail_path; bool is_scenarios_compatible; @@ -1743,7 +1744,8 @@ static item_upload_data steam_workshop_prepare_upload(steam_workshop_uploader_ui } workshop_item.id = data.item_id; - workshop_item.type = (ItemType)data.item_type; + workshop_item.item_type = static_cast(data.item_type); + workshop_item.content_type = static_cast(data.content_type); workshop_item.directory_path = data.directory_path.GetPath(); workshop_item.thumbnail_path = data.thumbnail_path.GetPath(); return workshop_item; @@ -1883,7 +1885,8 @@ static void display_steam_workshop_uploader_dialog(void* arg) item_owned_query_result::item new_item; new_item.id = 0; new_item.title = "New Item"; - new_item.type = ItemType::Plugin; + new_item.item_type = ItemType::Plugin; + new_item.content_type = ContentType::Graphics; new_item.is_scenarios_compatible = true; item_list.items.insert(item_list.items.begin(), new_item); @@ -1901,7 +1904,7 @@ static void display_steam_workshop_uploader_dialog(void* arg) } steam_workshop_uploader_ui_data ui_data; - ui_data.item_type = static_cast(new_item.type); + ui_data.item_type = static_cast(new_item.item_type); ui_data.is_scenarios_compatible = new_item.is_scenarios_compatible; ui_data.item_id = new_item.id; @@ -1921,13 +1924,39 @@ static void display_steam_workshop_uploader_dialog(void* arg) table->dual_add(items_popup->label("Upload For"), d); table->dual_add(items_popup, d); - static const std::vector item_types = { "Scenario", "Plugin", "Other"}; - auto types_popup = new w_select_popup(); - types_popup->set_labels(item_types); - types_popup->set_selection(static_cast(new_item.type)); + auto get_content_types_tags = [&](ItemType item_type) -> std::vector + { + static const std::vector content_types_tags[] = { + { }, + { "Graphics", "HUD", "Music", "Script", "Theme" }, + { "Solo & Net", "Solo Only", "Net Only" } + }; + + switch (item_type) + { + case ItemType::Scenario: + return content_types_tags[0]; + case ItemType::Plugin: + return content_types_tags[1]; + default: + return content_types_tags[2]; + } + }; - table->dual_add(types_popup->label("Item Type"), d); - table->dual_add(types_popup, d); + static const std::vector item_types = { "Scenario", "Plugin", "Map", "Physics", "Script", "Sounds", "Shapes" }; + auto item_types_popup = new w_select_popup(); + item_types_popup->set_labels(item_types); + item_types_popup->set_selection(static_cast(new_item.item_type)); + + table->dual_add(item_types_popup->label("Item Type"), d); + table->dual_add(item_types_popup, d); + + auto content_types_popup = new w_select_popup(); + content_types_popup->set_labels(get_content_types_tags(new_item.item_type)); + content_types_popup->set_selection(0); + + table->dual_add(content_types_popup->label("Content Type"), d); + table->dual_add(content_types_popup, d); char label[64]; snprintf(label, 64, "%s Only", Scenario::instance()->GetName().c_str()); @@ -1964,34 +1993,97 @@ static void display_steam_workshop_uploader_dialog(void* arg) d.set_widget_placer(placer); + auto can_update_content_type = [&]() -> bool + { + switch (static_cast(ui_data.item_type)) + { + case ItemType::Plugin: + return !ui_data.item_id; + case ItemType::Map: + case ItemType::Script: + return true; + default: + return false; + } + }; + + auto update_content_type_value = [&]() + { + int start_enum_index; + switch (static_cast(ui_data.item_type)) + { + case ItemType::Scenario: + start_enum_index = static_cast(ContentType::START_SCENARIO); + break; + case ItemType::Plugin: + start_enum_index = static_cast(ContentType::START_PLUGIN); + break; + default: + start_enum_index = static_cast(ContentType::START_OTHER); + break; + } + + ui_data.content_type = start_enum_index + std::max(content_types_popup->get_selection(), 0); + }; + + auto get_selection_for_content_type = [&]() -> int + { + switch (static_cast(ui_data.item_type)) + { + case ItemType::Scenario: + return ui_data.content_type - static_cast(ContentType::START_SCENARIO); + case ItemType::Plugin: + return ui_data.content_type - static_cast(ContentType::START_PLUGIN); + default: + return ui_data.content_type - static_cast(ContentType::START_OTHER); + } + }; + + auto update_common_widgets = [&]() + { + bool is_scenario = static_cast(ui_data.item_type) == ItemType::Scenario; + custom_scenarios->set_enabled(!is_scenario); + custom_scenarios->set_selection(!ui_data.is_scenarios_compatible); + + content_types_popup->set_labels(get_content_types_tags(static_cast(ui_data.item_type))); + content_types_popup->set_enabled(can_update_content_type()); + }; + items_popup->set_popup_callback([&](void*) { auto item_index = items_popup->get_selection(); auto& item = item_list.items.at(item_index); ui_data.item_id = item.id; - ui_data.item_type = static_cast(item.type); + ui_data.item_type = static_cast(item.item_type); + ui_data.content_type = static_cast(item.content_type); ui_data.directory_path = ""; ui_data.thumbnail_path = ""; ui_data.is_scenarios_compatible = item.is_scenarios_compatible; - types_popup->set_selection(ui_data.item_type); - types_popup->set_enabled(!ui_data.item_id); + item_types_popup->set_selection(ui_data.item_type); + item_types_popup->set_enabled(!ui_data.item_id); directory_path->set_directory(ui_data.directory_path); thumbnail_path->set_file(ui_data.thumbnail_path); - custom_scenarios->set_selection(!ui_data.is_scenarios_compatible); - custom_scenarios->set_enabled(static_cast(ui_data.item_type) != ItemType::Scenario); + update_common_widgets(); + content_types_popup->set_selection(get_selection_for_content_type()); }, nullptr); - types_popup->set_popup_callback([&](void*) + item_types_popup->set_popup_callback([&](void*) { - ui_data.item_type = types_popup->get_selection(); - bool is_scenario = static_cast(ui_data.item_type) == ItemType::Scenario; - custom_scenarios->set_enabled(!is_scenario); - custom_scenarios->set_selection(false); + ui_data.item_type = item_types_popup->get_selection(); + update_common_widgets(); + content_types_popup->set_selection(0); + update_content_type_value(); + + }, nullptr); + + content_types_popup->set_popup_callback([&](void*) + { + update_content_type_value(); }, nullptr); diff --git a/Source_Files/Misc/preferences_widgets_sdl.cpp b/Source_Files/Misc/preferences_widgets_sdl.cpp index 7fca75601..4cff90aac 100644 --- a/Source_Files/Misc/preferences_widgets_sdl.cpp +++ b/Source_Files/Misc/preferences_widgets_sdl.cpp @@ -60,7 +60,7 @@ static void add_workshop_items(Typecode type, std::vector& items) for (auto& item : subscribed_workshop_items) { - if (item.type == ItemType::Other) + if (item.item_type != ItemType::Plugin) { FileSpecifier dir = item.install_folder_path; finder.Find(dir, type); diff --git a/Source_Files/Misc/steamshim_child.h b/Source_Files/Misc/steamshim_child.h index d46186dca..53cf4f495 100755 --- a/Source_Files/Misc/steamshim_child.h +++ b/Source_Files/Misc/steamshim_child.h @@ -7,35 +7,50 @@ enum class ItemType { Scenario, Plugin, - Other + Map, + Physics, + Script, + Sounds, + Shapes +}; + +enum class ContentType { + START_SCENARIO = 0, + None = 0, + + START_PLUGIN = 16, + Graphics = 16, + HUD, + Music, + Script, + Theme, + + START_OTHER = 64, + SoloAndNet = 64, + Solo, + Net }; struct item_upload_data { uint64_t id; - ItemType type; + ItemType item_type; + ContentType content_type; std::string directory_path; std::string thumbnail_path; std::string required_scenario; - std::vector tags; std::ostringstream shim_serialize() const { std::ostringstream data_stream; data_stream.write(reinterpret_cast(&id), sizeof(id)); - data_stream.write(reinterpret_cast(&type), sizeof(type)); + data_stream.write(reinterpret_cast(&item_type), sizeof(item_type)); + data_stream.write(reinterpret_cast(&content_type), sizeof(content_type)); data_stream << directory_path << '\0'; data_stream << thumbnail_path << '\0'; data_stream << required_scenario << '\0'; - for (const auto& tag : tags) - { - data_stream << tag << '\0'; - } - - data_stream << '\0'; - return data_stream; } }; @@ -45,10 +60,10 @@ struct item_owned_query_result struct item { uint64_t id; - ItemType type; + ItemType item_type; + ContentType content_type; bool is_scenarios_compatible; std::string title; - std::vector tags; }; int result_code; //steam code (EResult) where 1 is success @@ -69,21 +84,17 @@ struct item_owned_query_result iss.read(reinterpret_cast(&deserialized_item.id), sizeof(deserialized_item.id)); - int type; - iss.read(reinterpret_cast(&type), sizeof(type)); - deserialized_item.type = (ItemType)type; + int item_type; + iss.read(reinterpret_cast(&item_type), sizeof(item_type)); + deserialized_item.item_type = static_cast(item_type); + + int content_type; + iss.read(reinterpret_cast(&content_type), sizeof(content_type)); + deserialized_item.content_type = static_cast(content_type); iss.read(reinterpret_cast(&deserialized_item.is_scenarios_compatible), sizeof(deserialized_item.is_scenarios_compatible)); std::getline(iss, deserialized_item.title, '\0'); - while (true) - { - std::string tag; - std::getline(iss, tag, '\0'); - if (tag.empty()) break; - deserialized_item.tags.push_back(tag); - } - items.push_back(deserialized_item); } } @@ -94,7 +105,8 @@ struct item_subscribed_query_result struct item { uint64_t id; - ItemType type; + ItemType item_type; + ContentType content_type; std::string install_folder_path; }; @@ -115,9 +127,13 @@ struct item_subscribed_query_result item deserialized_item = {}; iss.read(reinterpret_cast(&deserialized_item.id), sizeof(deserialized_item.id)); - int type; - iss.read(reinterpret_cast(&type), sizeof(type)); - deserialized_item.type = (ItemType)type; + int item_type; + iss.read(reinterpret_cast(&item_type), sizeof(item_type)); + deserialized_item.item_type = static_cast(item_type); + + int content_type; + iss.read(reinterpret_cast(&content_type), sizeof(content_type)); + deserialized_item.content_type = static_cast(content_type); std::getline(iss, deserialized_item.install_folder_path, '\0'); diff --git a/Source_Files/XML/Plugins.cpp b/Source_Files/XML/Plugins.cpp index 37f1f8974..bffe2a939 100644 --- a/Source_Files/XML/Plugins.cpp +++ b/Source_Files/XML/Plugins.cpp @@ -498,7 +498,7 @@ void Plugins::enumerate() { #ifdef HAVE_STEAM for (const auto& item : subscribed_workshop_items) { - if (item.type == ItemType::Plugin) + if (item.item_type == ItemType::Plugin) { FileSpecifier dir(item.install_folder_path); loader.ParseDirectory(dir); diff --git a/Steam/steamshim_parent.cpp b/Steam/steamshim_parent.cpp index f8ec39e7b..a4fef884c 100755 --- a/Steam/steamshim_parent.cpp +++ b/Steam/steamshim_parent.cpp @@ -290,13 +290,35 @@ static SteamBridge *GSteamBridge = NULL; namespace SteamItemTags { constexpr const char* ItemType = "ItemType"; + constexpr const char* ContentType = "ContentType"; constexpr const char* RequiredScenario = "RequiredScenario"; } -typedef enum ItemType { +enum class ItemType { Scenario, Plugin, - Other + Map, + Physics, + Script, + Sounds, + Shapes +}; + +enum class ContentType { + START_SCENARIO = 0, + None = 0, + + START_PLUGIN = 16, + Graphics = 16, + HUD, + Music, + Script, + Theme, + + START_OTHER = 64, + SoloAndNet = 64, + Solo, + Net }; struct item_subscribed_query_result @@ -304,7 +326,8 @@ struct item_subscribed_query_result struct item { uint64_t id; - ItemType type; + ItemType item_type; + ContentType content_type; std::string install_folder_path; }; @@ -322,7 +345,8 @@ struct item_subscribed_query_result for (const auto& item : items) { data_stream.write(reinterpret_cast(&item.id), sizeof(item.id)); - data_stream.write(reinterpret_cast(&item.type), sizeof(item.type)); + data_stream.write(reinterpret_cast(&item.item_type), sizeof(item.item_type)); + data_stream.write(reinterpret_cast(&item.content_type), sizeof(item.content_type)); data_stream << item.install_folder_path << '\0'; } @@ -335,10 +359,10 @@ struct item_owned_query_result struct item { uint64_t id; - ItemType type; + ItemType item_type; + ContentType content_type; bool is_scenarios_compatible; std::string title; - std::vector tags; }; EResult result_code; @@ -355,16 +379,10 @@ struct item_owned_query_result for (const auto& item : items) { data_stream.write(reinterpret_cast(&item.id), sizeof(item.id)); - data_stream.write(reinterpret_cast(&item.type), sizeof(item.type)); + data_stream.write(reinterpret_cast(&item.item_type), sizeof(item.item_type)); + data_stream.write(reinterpret_cast(&item.content_type), sizeof(item.content_type)); data_stream.write(reinterpret_cast(&item.is_scenarios_compatible), sizeof(item.is_scenarios_compatible)); data_stream << item.title << '\0'; - - for (const auto& tag : item.tags) - { - data_stream << tag << '\0'; - } - - data_stream << '\0'; } return data_stream; @@ -374,28 +392,21 @@ struct item_owned_query_result struct item_upload_data { uint64_t id; - ItemType type; + ItemType item_type; + ContentType content_type; std::string directory_path; std::string thumbnail_path; std::string required_scenario; - std::vector tags; void shim_deserialize(const uint8* buf, unsigned int buflen) { std::istringstream iss(std::string((const char*)buf, buflen)); iss.read(reinterpret_cast(&id), sizeof(id)); - iss.read(reinterpret_cast(&type), sizeof(type)); + iss.read(reinterpret_cast(&item_type), sizeof(item_type)); + iss.read(reinterpret_cast(&content_type), sizeof(content_type)); std::getline(iss, directory_path, '\0'); std::getline(iss, thumbnail_path, '\0'); std::getline(iss, required_scenario, '\0'); - - while (true) - { - std::string tag; - std::getline(iss, tag, '\0'); - if (tag.empty()) break; - tags.push_back(tag); - } } }; @@ -407,7 +418,7 @@ class SteamBridge STEAM_CALLBACK(SteamBridge, OnUserStatsStored, UserStatsStored_t, m_CallbackUserStatsStored); STEAM_CALLBACK(SteamBridge, OnOverlayActivated, GameOverlayActivated_t, m_CallbackOverlayActivated); void set_item_created_callback(SteamAPICall_t api_call, const item_upload_data& item_data); - void set_item_updated_callback(SteamAPICall_t api_call, UGCUpdateHandle_t handle); + void set_item_updated_callback(SteamAPICall_t api_call, UGCUpdateHandle_t handle, const item_upload_data& item_data); void set_item_owned_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name); void set_item_mod_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name); void set_item_scenario_queried_callback(SteamAPICall_t api_call); @@ -636,21 +647,114 @@ static inline bool writeGetStatF(PipeType fd, const char *name, const float val, return writeStatThing(fd, SHIMEVENT_GETSTATF, name, &val, sizeof (val), okay); } // writeGetStatF +static std::vector GetTagsForItemType(ItemType item_type, ContentType content_type) +{ + std::vector tags; + + switch (item_type) + { + case ItemType::Scenario: + tags.push_back("Scenario"); + break; + case ItemType::Plugin: + tags.push_back("Plugin"); + switch (content_type) + { + case ContentType::Graphics: + tags.push_back("Graphics"); + break; + case ContentType::HUD: + tags.push_back("HUD"); + break; + case ContentType::Music: + tags.push_back("Music"); + break; + case ContentType::Script: + tags.push_back("Script"); + break; + case ContentType::Theme: + tags.push_back("Theme"); + break; + } + break; + case ItemType::Map: + switch (content_type) + { + case ContentType::Solo: + tags.push_back("Solo Map"); + break; + case ContentType::Net: + tags.push_back("Net Map"); + break; + case ContentType::SoloAndNet: + tags.push_back("Solo Map"); + tags.push_back("Net Map"); + break; + } + break; + case ItemType::Physics: + tags.push_back("Physics"); + break; + case ItemType::Script: + switch (content_type) + { + case ContentType::Solo: + tags.push_back("Solo Script"); + break; + case ContentType::Net: + tags.push_back("Net Script"); + break; + case ContentType::SoloAndNet: + tags.push_back("Solo Script"); + tags.push_back("Net Script"); + break; + } + break; + case ItemType::Sounds: + tags.push_back("Sounds"); + break; + case ItemType::Shapes: + tags.push_back("Shapes"); + break; + default: + break; + } + + return tags; +} + static void UpdateItem(PublishedFileId_t item_id, const item_upload_data& item_data) { UGCUpdateHandle_t updateHandle = GSteamUGC->StartItemUpdate(GAppID, item_id); if (item_data.id) //existing item + { GSteamUGC->RemoveItemKeyValueTags(updateHandle, SteamItemTags::RequiredScenario); + GSteamUGC->RemoveItemKeyValueTags(updateHandle, SteamItemTags::ContentType); //let at least users change solo/net stuff + } else //new item { std::string title = "New Item " + std::to_string(item_id); - std::string type = std::to_string(item_data.type); + std::string item_type = std::to_string(static_cast(item_data.item_type)); GSteamUGC->SetItemTitle(updateHandle, title.c_str()); - GSteamUGC->AddItemKeyValueTag(updateHandle, SteamItemTags::ItemType, type.c_str()); + GSteamUGC->AddItemKeyValueTag(updateHandle, SteamItemTags::ItemType, item_type.c_str()); GSteamUGC->SetItemVisibility(updateHandle, k_ERemoteStoragePublishedFileVisibilityPrivate); } + std::string content_type = std::to_string(static_cast(item_data.content_type)); + GSteamUGC->AddItemKeyValueTag(updateHandle, SteamItemTags::ContentType, content_type.c_str()); + + auto tags = GetTagsForItemType(item_data.item_type, item_data.content_type); + const char* tag_array[16]; + + for (auto i = 0; i < tags.size(); i++) + { + tag_array[i] = tags[i].c_str(); + } + + SteamParamStringArray_t steam_tags = { tag_array, tags.size() }; + GSteamUGC->SetItemTags(updateHandle, &steam_tags); + if (!item_data.directory_path.empty()) { GSteamUGC->SetItemContent(updateHandle, item_data.directory_path.c_str()); @@ -667,7 +771,7 @@ static void UpdateItem(PublishedFileId_t item_id, const item_upload_data& item_d } auto steam_api_call = GSteamUGC->SubmitItemUpdate(updateHandle, nullptr); - GSteamBridge->set_item_updated_callback(steam_api_call, updateHandle); + GSteamBridge->set_item_updated_callback(steam_api_call, updateHandle, item_data); } SteamBridge::SteamBridge(PipeType _fd) @@ -703,8 +807,9 @@ void SteamBridge::set_item_created_callback(SteamAPICall_t api_call, const item_ m_CallbackItemCreatedResult.Set(api_call, this, &SteamBridge::OnItemCreated); } -void SteamBridge::set_item_updated_callback(SteamAPICall_t api_call, UGCUpdateHandle_t handle) +void SteamBridge::set_item_updated_callback(SteamAPICall_t api_call, UGCUpdateHandle_t handle, const item_upload_data& item_data) { + m_upload_item_data = item_data; m_update_handle = handle; m_CallbackItemUpdatedResult.Set(api_call, this, &SteamBridge::OnItemUpdated); } @@ -791,10 +896,17 @@ void SteamBridge::OnItemOwnedQueried(SteamUGCQueryCompleted_t* pCallback, bool b if (!GSteamUGC->GetQueryUGCKeyValueTag(pCallback->m_handle, i, SteamItemTags::ItemType, item_kv_tag, sizeof(item_kv_tag))) { - continue; //ignore item if we can't retrieve its type tag + continue; //ignore item if we can't retrieve its item type tag + } + + item.item_type = static_cast(std::stoi(item_kv_tag)); //we should probably check better here + + if (!GSteamUGC->GetQueryUGCKeyValueTag(pCallback->m_handle, i, SteamItemTags::ContentType, item_kv_tag, sizeof(item_kv_tag))) + { + continue; //ignore item if we can't retrieve its content type tag } - item.type = (ItemType)std::stoi(item_kv_tag); //we should probably check better here + item.content_type = static_cast(std::stoi(item_kv_tag)); //we should probably check better here char item_scenario_tag[256]; if (GSteamUGC->GetQueryUGCKeyValueTag(pCallback->m_handle, i, SteamItemTags::RequiredScenario, item_scenario_tag, sizeof(item_scenario_tag))) @@ -807,16 +919,6 @@ void SteamBridge::OnItemOwnedQueried(SteamUGCQueryCompleted_t* pCallback, bool b item.is_scenarios_compatible = false; } - auto number_tags = GSteamUGC->GetQueryUGCNumTags(pCallback->m_handle, i); - for (int k = 0; k < number_tags; k++) - { - char tag[256]; - if (GSteamUGC->GetQueryUGCTag(pCallback->m_handle, i, k, tag, sizeof(tag))) - { - item.tags.push_back(tag); - } - } - item.title = item_details.m_rgchTitle; item.id = item_details.m_nPublishedFileId; items_result.items.push_back(item); @@ -849,14 +951,16 @@ void SteamBridge::OnItemModQueried(SteamUGCQueryCompleted_t* pCallback, bool bIO continue; //ignore item if we can't retrieve its type tag } - item_subscribed_query_result::item item; - item.type = (ItemType)std::stoi(item_type_tag); //we should probably check better here - - if (item.type == ItemType::Scenario) + char content_type_tag[256]; + if (!GSteamUGC->GetQueryUGCKeyValueTag(pCallback->m_handle, i, SteamItemTags::ContentType, content_type_tag, sizeof(content_type_tag))) { - continue; + continue; //ignore item if we can't retrieve its content type tag } + item_subscribed_query_result::item item; + item.item_type = static_cast(std::stoi(item_type_tag)); //we should probably check better here + item.content_type = static_cast(std::stoi(content_type_tag)); //we should probably check better here + char item_scenario_tag[256]; if (GSteamUGC->GetQueryUGCKeyValueTag(pCallback->m_handle, i, SteamItemTags::RequiredScenario, item_scenario_tag, sizeof(item_scenario_tag))) { @@ -912,7 +1016,8 @@ void SteamBridge::OnItemScenarioQueried(SteamUGCQueryCompleted_t* pCallback, boo item_subscribed_query_result::item item; item.id = item_details.m_nPublishedFileId; - item.type = ItemType::Scenario; + item.item_type = ItemType::Scenario; + item.content_type = ContentType::None; item.install_folder_path = folder_path; items_result.items.push_back(item); } @@ -1089,6 +1194,7 @@ static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) auto scenario = std::string((const char*)buf); auto handle = GSteamUGC->CreateQueryUserUGCRequest(GUserID, k_EUserUGCList_Subscribed, k_EUGCMatchingUGCType_Items, k_EUserUGCListSortOrder_CreationOrderDesc, 0, GAppID, 1); GSteamUGC->SetReturnKeyValueTags(handle, true); + GSteamUGC->AddExcludedTag(handle, "Scenario"); auto steam_api_call = GSteamUGC->SendQueryUGCRequest(handle); GSteamBridge->set_item_mod_queried_callback(steam_api_call, scenario); } @@ -1096,7 +1202,7 @@ static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) case SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO: { - auto scenario_tag = std::to_string(ItemType::Scenario); + auto scenario_tag = std::to_string(static_cast(ItemType::Scenario)); auto handle = GSteamUGC->CreateQueryUserUGCRequest(GUserID, k_EUserUGCList_Subscribed, k_EUGCMatchingUGCType_Items, k_EUserUGCListSortOrder_CreationOrderDesc, 0, GAppID, 1); GSteamUGC->SetReturnOnlyIDs(handle, true); GSteamUGC->AddRequiredKeyValueTag(handle, SteamItemTags::ItemType, scenario_tag.c_str()); From e45d50b3a2a7c66688e4d05ad7d576eec63f2d61 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Tue, 13 Aug 2024 20:19:21 -0400 Subject: [PATCH 31/58] fix clang compile error --- Steam/steamshim_parent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Steam/steamshim_parent.cpp b/Steam/steamshim_parent.cpp index a4fef884c..22d762cce 100755 --- a/Steam/steamshim_parent.cpp +++ b/Steam/steamshim_parent.cpp @@ -752,7 +752,7 @@ static void UpdateItem(PublishedFileId_t item_id, const item_upload_data& item_d tag_array[i] = tags[i].c_str(); } - SteamParamStringArray_t steam_tags = { tag_array, tags.size() }; + SteamParamStringArray_t steam_tags = { tag_array, static_cast(tags.size()) }; GSteamUGC->SetItemTags(updateHandle, &steam_tags); if (!item_data.directory_path.empty()) From a87a727cc1dfc941f0a31b4a6aee395b8014bd79 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Sat, 17 Aug 2024 11:29:15 -0400 Subject: [PATCH 32/58] move log_dir initialization to before Scenario Chooser, otherwise logs go to the wrong place --- Source_Files/shell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source_Files/shell.cpp b/Source_Files/shell.cpp index 26e7bc95d..cea0568d3 100644 --- a/Source_Files/shell.cpp +++ b/Source_Files/shell.cpp @@ -299,6 +299,7 @@ void initialize_application(void) SDL_EventState(SDL_DROPFILE, SDL_DISABLE); } + log_dir = get_data_path(kPathLogs); initialize_joystick(); const string default_data_env = a1_getenv("ALEPHONE_DEFAULT_DATA"); @@ -372,7 +373,6 @@ void initialize_application(void) #endif local_data_dir = get_data_path(kPathLocalData); - log_dir = get_data_path(kPathLogs); preferences_dir = get_data_path(kPathPreferences); saved_games_dir = get_data_path(kPathSavedGames); quick_saves_dir = get_data_path(kPathQuickSaves); From 1a974734c692c38311fca1f3bd66e60c7d552c10 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Sat, 17 Aug 2024 13:34:09 -0400 Subject: [PATCH 33/58] split solo and net maps/scripts in env selector --- Source_Files/Misc/preferences.cpp | 1 + Source_Files/Misc/preferences_widgets_sdl.cpp | 64 +++++++++++++++++-- Source_Files/Misc/preferences_widgets_sdl.h | 11 +++- Source_Files/Network/network_dialogs.cpp | 12 +++- 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/Source_Files/Misc/preferences.cpp b/Source_Files/Misc/preferences.cpp index f3a4dc7d6..70bff4ba7 100644 --- a/Source_Files/Misc/preferences.cpp +++ b/Source_Files/Misc/preferences.cpp @@ -3186,6 +3186,7 @@ static void environment_dialog(void *arg) table->dual_add(use_replay_net_lua_w, d); w_env_select *replay_net_lua_w = new w_env_select(network_preferences->netscript_file, "AVAILABLE NETSCRIPTS", _typecode_netscript, &d); + replay_net_lua_w->set_prefer_net(true); table->dual_add(replay_net_lua_w->label("Netscript File"), d); table->dual_add(replay_net_lua_w, d); use_replay_net_lua_w->add_dependent_widget(replay_net_lua_w); diff --git a/Source_Files/Misc/preferences_widgets_sdl.cpp b/Source_Files/Misc/preferences_widgets_sdl.cpp index 4cff90aac..f328a796f 100644 --- a/Source_Files/Misc/preferences_widgets_sdl.cpp +++ b/Source_Files/Misc/preferences_widgets_sdl.cpp @@ -31,6 +31,7 @@ #include "preferences_widgets_sdl.h" #include +#include #include "Crosshairs.h" @@ -53,14 +54,20 @@ void w_env_select::select_item_callback(void* arg) { #ifdef HAVE_STEAM extern std::vector subscribed_workshop_items; -static void add_workshop_items(Typecode type, std::vector& items) +static void add_workshop_items(std::vector& items, Typecode type, + ItemType item_type, + std::optional content_type, + const std::string& header) { std::vector files; FindAllFiles finder(files); - - for (auto& item : subscribed_workshop_items) + + for (const auto& item : subscribed_workshop_items) { - if (item.item_type != ItemType::Plugin) + if (item.item_type == item_type && + (!content_type.has_value() || + item.content_type == content_type.value() || + item.content_type == ContentType::SoloAndNet)) { FileSpecifier dir = item.install_folder_path; finder.Find(dir, type); @@ -73,7 +80,7 @@ static void add_workshop_items(Typecode type, std::vector& items) } env_item title; - strcpy(title.name, "Steam Workshop"); + strcpy(title.name, header.c_str()); items.push_back(title); std::sort(files.begin(), files.end(), [](const FileSpecifier& a, const FileSpecifier& b) { @@ -95,6 +102,51 @@ static void add_workshop_items(Typecode type, std::vector& items) items.push_back(env_item(file, 1, true)); } } + +static void add_workshop_items(std::vector& items, Typecode type, bool prefer_net) +{ + static const char* solo = "Steam Workshop (Solo)"; + static const char* net = "Steam Workshop (Net)"; + static const char* both = "Steam Workshop"; + switch (type) + { + case _typecode_scenario: + if (prefer_net) + { + add_workshop_items(items, type, ItemType::Map, ContentType::Net, net); + add_workshop_items(items, type, ItemType::Map, ContentType::Solo, solo); + } + else + { + add_workshop_items(items, type, ItemType::Map, ContentType::Solo, solo); + add_workshop_items(items, type, ItemType::Map, ContentType::Net, net); + } + break; + case _typecode_physics: + add_workshop_items(items, type, ItemType::Physics, std::nullopt, both); + break; + case _typecode_netscript: + if (prefer_net) + { + add_workshop_items(items, type, ItemType::Script, ContentType::Net, net); + add_workshop_items(items, type, ItemType::Script, ContentType::Solo, solo); + } + else + { + add_workshop_items(items, type, ItemType::Script, ContentType::Solo, solo); + add_workshop_items(items, type, ItemType::Script, ContentType::Net, net); + } + break; + case _typecode_sounds: + add_workshop_items(items, type, ItemType::Sounds, std::nullopt, both); + break; + case _typecode_shapes: + add_workshop_items(items, type, ItemType::Shapes, std::nullopt, both); + break; + default: + break; + } +} #endif void w_env_select::select_item(dialog *parent) @@ -102,7 +154,7 @@ void w_env_select::select_item(dialog *parent) vector items; #ifdef HAVE_STEAM - add_workshop_items(type, items); + add_workshop_items(items, type, prefer_net); #endif // Find available files diff --git a/Source_Files/Misc/preferences_widgets_sdl.h b/Source_Files/Misc/preferences_widgets_sdl.h index 6974e4924..034ebed84 100644 --- a/Source_Files/Misc/preferences_widgets_sdl.h +++ b/Source_Files/Misc/preferences_widgets_sdl.h @@ -115,7 +115,7 @@ class w_env_select : public w_select_button { public: w_env_select(const char *path, const char *m, Typecode t, dialog *d) : w_select_button(item_name, select_item_callback, NULL, true), - parent(d), menu_title(m), type(t), mCallback(NULL) + parent(d), menu_title(m), type(t), mCallback(NULL), prefer_net{false} { set_arg(this); set_path(path); @@ -145,6 +145,11 @@ w_env_select(const char *path, const char *m, Typecode t, dialog *d) return item; } + void set_prefer_net(bool prefer_net) + { + this->prefer_net = prefer_net; + } + private: void select_item(dialog *parent); static void select_item_callback(void *arg); @@ -157,6 +162,8 @@ w_env_select(const char *path, const char *m, Typecode t, dialog *d) char item_name[256]; // File name (excluding directory part) selection_made_callback_t mCallback; + + bool prefer_net; }; class EnvSelectWidget : public SDLWidgetWidget, public Bindable @@ -175,6 +182,8 @@ class EnvSelectWidget : public SDLWidgetWidget, public Bindable virtual FileSpecifier bind_export() { return get_file(); } virtual void bind_import(FileSpecifier f) { set_file(f); } + void set_prefer_net(bool prefer_net) { m_env_select->set_prefer_net(prefer_net); } + private: w_env_select* m_env_select; }; diff --git a/Source_Files/Network/network_dialogs.cpp b/Source_Files/Network/network_dialogs.cpp index c99978281..7e34c9dbf 100644 --- a/Source_Files/Network/network_dialogs.cpp +++ b/Source_Files/Network/network_dialogs.cpp @@ -1474,16 +1474,20 @@ void SetupNetgameDialog::setupForGameType () m_deadPlayersDropItemsWidget->set_value (true); m_aliensWidget->set_value (true); + + m_mapWidget->set_prefer_net(false); break; case _game_of_kill_monsters: case _game_of_king_of_the_hill: case _game_of_kill_man_with_ball: case _game_of_tag: - case _game_of_custom: + case _game_of_custom: m_allowTeamsWidget->activate (); m_deadPlayersDropItemsWidget->activate (); m_aliensWidget->activate (); + + m_mapWidget->set_prefer_net(true); break; case _game_of_capture_the_flag: @@ -1493,6 +1497,8 @@ void SetupNetgameDialog::setupForGameType () m_allowTeamsWidget->set_value (true); m_teamWidget->activate (); + + m_mapWidget->set_prefer_net(true); break; case _game_of_rugby: @@ -1502,6 +1508,8 @@ void SetupNetgameDialog::setupForGameType () m_allowTeamsWidget->set_value (true); m_teamWidget->activate (); + + m_mapWidget->set_prefer_net(true); break; default: @@ -2739,6 +2747,7 @@ class SdlSetupNetgameDialog : public SetupNetgameDialog // Could eventually store this path in network_preferences somewhere, so to have separate map file // prefs for single- and multi-player. w_env_select* map_w = new w_env_select ("", "AVAILABLE MAPS", _typecode_scenario, &m_dialog); + map_w->set_prefer_net(true); #ifndef MAC_APP_STORE player_table->dual_add(map_w->label("Map"), m_dialog); player_table->dual_add(map_w, m_dialog); @@ -2769,6 +2778,7 @@ class SdlSetupNetgameDialog : public SetupNetgameDialog #endif w_env_select* choose_script_w = new w_env_select ("", "AVAILABLE NETSCRIPTS", _typecode_netscript, &m_dialog); + choose_script_w->set_prefer_net(true); #ifndef MAC_APP_STORE network_table->add(new w_spacer(), true); network_table->dual_add(choose_script_w, m_dialog); From 96275feed814cfe0554471925c2594df45f6a14a Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Sat, 17 Aug 2024 13:39:43 -0400 Subject: [PATCH 34/58] explicitly fill scenario image crop background with black --- Source_Files/Misc/ScenarioChooser.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source_Files/Misc/ScenarioChooser.cpp b/Source_Files/Misc/ScenarioChooser.cpp index 0a4d170b7..bd0d009a4 100644 --- a/Source_Files/Misc/ScenarioChooser.cpp +++ b/Source_Files/Misc/ScenarioChooser.cpp @@ -505,6 +505,8 @@ void ScenarioChooser::optimize_image(ScenarioChooserScenario& scenario, SDL_Wind scenario.image.reset(SDL_CreateRGBSurface(0, scenario_width, scenario_height, format->BitsPerPixel, format->Rmask, format->Gmask, format->Bmask, format->Amask)); + SDL_FillRect(scenario.image.get(), nullptr, SDL_MapRGB(scenario.image->format, 0, 0, 0)); + SDL_SoftStretchLinear(optimized.get(), &src_rect, scenario.image.get(), &dst_rect); } From 52b7979459e7d5a3a67f790247de8b6056f0a874 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Sun, 18 Aug 2024 15:58:40 +0200 Subject: [PATCH 35/58] Enable scenario workshop item only for infinity and retrieve game install path --- Source_Files/Misc/interface.cpp | 43 +++++++++++++---- Source_Files/Misc/steamshim_child.cpp | 19 +++++++- Source_Files/Misc/steamshim_child.h | 18 ++++++- Source_Files/shell.cpp | 31 +++++++++---- Steam/steamshim_parent.cpp | 67 ++++++++++++++++++++++++--- 5 files changed, 152 insertions(+), 26 deletions(-) diff --git a/Source_Files/Misc/interface.cpp b/Source_Files/Misc/interface.cpp index 0e1c4ff5b..5c27d6567 100644 --- a/Source_Files/Misc/interface.cpp +++ b/Source_Files/Misc/interface.cpp @@ -267,6 +267,10 @@ struct screen_data { int32 duration; }; +#ifdef HAVE_STEAM + +#include + struct steam_workshop_uploader_ui_data { uint64_t item_id; int item_type; @@ -276,6 +280,10 @@ struct steam_workshop_uploader_ui_data { bool is_scenarios_compatible; }; +extern steam_game_information steam_game_info; + +#endif + /* -------------- constants */ struct screen_data display_screens[]= { { INTRO_SCREEN_BASE, NUMBER_OF_INTRO_SCREENS, INTRO_SCREEN_DURATION }, @@ -342,7 +350,6 @@ static void display_screen(short base_pict_id); static void display_introduction_screen_for_demo(void); static void display_epilogue(void); static void display_about_dialog(); -static void display_steam_workshop_uploader_dialog(void *arg); static void force_system_colors(void); static bool point_in_rectangle(short x, short y, screen_rectangle *rect); @@ -1725,13 +1732,13 @@ class w_authors_list : public w_string_list void item_selected(void) { } }; -#include +#ifdef HAVE_STEAM static item_upload_data steam_workshop_prepare_upload(steam_workshop_uploader_ui_data& data) { item_upload_data workshop_item; - if (!data.is_scenarios_compatible) + if (steam_game_info.support_workshop_item_scenario && !data.is_scenarios_compatible) { const auto scenario_name = Scenario::instance()->GetName(); @@ -1943,10 +1950,16 @@ static void display_steam_workshop_uploader_dialog(void* arg) } }; - static const std::vector item_types = { "Scenario", "Plugin", "Map", "Physics", "Script", "Sounds", "Shapes" }; + static std::vector item_types = { "Plugin", "Map", "Physics", "Script", "Sounds", "Shapes" }; + + if (steam_game_info.support_workshop_item_scenario) + { + item_types.insert(item_types.begin(), "Scenario"); + } + auto item_types_popup = new w_select_popup(); item_types_popup->set_labels(item_types); - item_types_popup->set_selection(static_cast(new_item.item_type)); + item_types_popup->set_selection(steam_game_info.support_workshop_item_scenario ? static_cast(new_item.item_type) : static_cast(new_item.item_type) - 1); table->dual_add(item_types_popup->label("Item Type"), d); table->dual_add(item_types_popup, d); @@ -1960,11 +1973,19 @@ static void display_steam_workshop_uploader_dialog(void* arg) char label[64]; snprintf(label, 64, "%s Only", Scenario::instance()->GetName().c_str()); - + auto custom_scenarios_label = new w_label(label); auto custom_scenarios = new w_toggle(false); - table->dual_add(custom_scenarios->label(label), d); + custom_scenarios->associate_label(custom_scenarios_label); + custom_scenarios->visible(steam_game_info.support_workshop_item_scenario); + custom_scenarios_label->visible(steam_game_info.support_workshop_item_scenario); + + table->dual_add(custom_scenarios_label, d); table->dual_add(custom_scenarios, d); - table->add_row(new w_spacer(), true); + + if (steam_game_info.support_workshop_item_scenario) + { + table->add_row(new w_spacer(), true); + } auto thumbnail_path = new w_file_chooser("Choose Preview Image", _typecode_unknown); table->dual_add(thumbnail_path->label("Preview Image"), d); @@ -2061,7 +2082,7 @@ static void display_steam_workshop_uploader_dialog(void* arg) ui_data.thumbnail_path = ""; ui_data.is_scenarios_compatible = item.is_scenarios_compatible; - item_types_popup->set_selection(ui_data.item_type); + item_types_popup->set_selection(steam_game_info.support_workshop_item_scenario ? ui_data.item_type : ui_data.item_type - 1); item_types_popup->set_enabled(!ui_data.item_id); directory_path->set_directory(ui_data.directory_path); @@ -2074,7 +2095,7 @@ static void display_steam_workshop_uploader_dialog(void* arg) item_types_popup->set_popup_callback([&](void*) { - ui_data.item_type = item_types_popup->get_selection(); + ui_data.item_type = steam_game_info.support_workshop_item_scenario ? item_types_popup->get_selection() : item_types_popup->get_selection() + 1; update_common_widgets(); content_types_popup->set_selection(0); update_content_type_value(); @@ -2107,6 +2128,8 @@ static void display_steam_workshop_uploader_dialog(void* arg) d.run(); } +#endif + static void display_about_dialog() { force_system_colors(); diff --git a/Source_Files/Misc/steamshim_child.cpp b/Source_Files/Misc/steamshim_child.cpp index 26b6e7779..b56e6bc1a 100644 --- a/Source_Files/Misc/steamshim_child.cpp +++ b/Source_Files/Misc/steamshim_child.cpp @@ -137,7 +137,8 @@ enum ShimCmd SHIMCMD_WORKSHOP_UPLOAD, SHIMCMD_WORKSHOP_QUERY_ITEM_OWNED, SHIMCMD_WORKSHOP_QUERY_ITEM_MOD, - SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO + SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO, + SHIMCMD_GET_GAME_INFO }; static int write1ByteCmd(const uint8 b1) @@ -260,6 +261,7 @@ static const STEAMSHIM_Event *processEvent(const uint8 *buf, size_t buflen) PRINTGOTEVENT(SHIMEVENT_WORKSHOP_UPLOAD_PROGRESS); PRINTGOTEVENT(SHIMEVENT_WORKSHOP_QUERY_ITEM_OWNED_RESULT); PRINTGOTEVENT(SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT); + PRINTGOTEVENT(SHIMEVENT_GET_GAME_INFO); #undef PRINTGOTEVENT else printf("Child got unknown shimevent %d.\n", (int) type); #endif @@ -342,6 +344,14 @@ static const STEAMSHIM_Event *processEvent(const uint8 *buf, size_t buflen) break; } + case SHIMEVENT_GET_GAME_INFO: + { + event.game_info = {}; + event.game_info.shim_deserialize(buf, buflen); + event.okay = true; + break; + } + default: /* uh oh */ return NULL; } /* switch */ @@ -495,6 +505,13 @@ void STEAMSHIM_queryWorkshopItemMod(const std::string& scenario_name) writePipe(GPipeWrite, buffer.data(), buffer.length()); } +void STEAMSHIM_getGameInfo() +{ + if (isDead()) return; + dbgpipe("Child sending SHIMCMD_GET_GAME_INFO.\n"); + write1ByteCmd(SHIMCMD_GET_GAME_INFO); +} + void STEAMSHIM_queryWorkshopItemScenario() { if (isDead()) return; diff --git a/Source_Files/Misc/steamshim_child.h b/Source_Files/Misc/steamshim_child.h index 53cf4f495..c6d8c6771 100755 --- a/Source_Files/Misc/steamshim_child.h +++ b/Source_Files/Misc/steamshim_child.h @@ -31,6 +31,19 @@ enum class ContentType { Net }; +struct steam_game_information +{ + std::string install_folder_path; + bool support_workshop_item_scenario; + + void shim_deserialize(const uint8* buf, unsigned int buflen) + { + std::istringstream iss(std::string((const char*)buf, buflen)); + std::getline(iss, install_folder_path, '\0'); + iss.read(reinterpret_cast(&support_workshop_item_scenario), sizeof(support_workshop_item_scenario)); + } +}; + struct item_upload_data { uint64_t id; @@ -158,7 +171,8 @@ enum STEAMSHIM_EventType SHIMEVENT_WORKSHOP_UPLOAD_RESULT, SHIMEVENT_WORKSHOP_UPLOAD_PROGRESS, SHIMEVENT_WORKSHOP_QUERY_ITEM_OWNED_RESULT, - SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT + SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT, + SHIMEVENT_GET_GAME_INFO }; enum STEAM_EItemUpdateStatus //from steam API @@ -183,6 +197,7 @@ struct STEAMSHIM_Event bool needs_to_accept_workshop_agreement; item_owned_query_result items_owned; item_subscribed_query_result items_subscribed; + steam_game_information game_info; }; int STEAMSHIM_init(void); /* non-zero on success, zero on failure. */ @@ -202,6 +217,7 @@ void STEAMSHIM_getStatF(const char *name); void STEAMSHIM_queryWorkshopItemOwned(const std::string& scenario_name); void STEAMSHIM_queryWorkshopItemMod(const std::string& scenario_name); void STEAMSHIM_queryWorkshopItemScenario(); +void STEAMSHIM_getGameInfo(); #endif /* include-once blocker */ /* end of steamshim_child.h ... */ diff --git a/Source_Files/shell.cpp b/Source_Files/shell.cpp index cea0568d3..33acc8b41 100644 --- a/Source_Files/shell.cpp +++ b/Source_Files/shell.cpp @@ -142,6 +142,7 @@ DirectorySpecifier log_dir; // Directory for Aleph One Log.txt #ifdef HAVE_STEAM std::vector subscribed_workshop_items; +steam_game_information steam_game_info; #endif /* @@ -466,22 +467,36 @@ void initialize_application(void) } #ifdef HAVE_STEAM + STEAMSHIM_getGameInfo(); STEAMSHIM_queryWorkshopItemMod(Scenario::instance()->GetName()); - while (STEAMSHIM_alive()) + + bool got_info = false, got_items = false; + while (STEAMSHIM_alive() && (!got_info || !got_items)) { auto result = STEAMSHIM_pump(); - if (result && result->type == SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT) + if (!result) { - if (result->items_subscribed.result_code == 1) - { - for (const auto& item : result->items_subscribed.items) + sleep_for_machine_ticks(30); + continue; + } + + switch (result->type) + { + case SHIMEVENT_GET_GAME_INFO: + steam_game_info = result->game_info; + got_info = true; + break; + case SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT: + if (result->items_subscribed.result_code == 1) { - subscribed_workshop_items.push_back(item); + for (const auto& item : result->items_subscribed.items) + { + subscribed_workshop_items.push_back(item); + } } - + got_items = true; break; - } } } #endif diff --git a/Steam/steamshim_parent.cpp b/Steam/steamshim_parent.cpp index 22d762cce..67297b414 100755 --- a/Steam/steamshim_parent.cpp +++ b/Steam/steamshim_parent.cpp @@ -321,6 +321,23 @@ enum class ContentType { Net }; +struct steam_game_information +{ + std::string install_folder_path; + bool support_workshop_item_scenario; + + std::ostringstream shim_serialize() const + { + std::ostringstream data_stream; + data_stream << install_folder_path << '\0'; + data_stream.write(reinterpret_cast(&support_workshop_item_scenario), sizeof(support_workshop_item_scenario)); + return data_stream; + } +}; + +static constexpr AppId_t MarathonInfinityAppId = 2398520; +static steam_game_information game_info; + struct item_subscribed_query_result { struct item @@ -454,7 +471,8 @@ typedef enum ShimCmd SHIMCMD_WORKSHOP_UPLOAD, SHIMCMD_WORKSHOP_QUERY_ITEM_OWNED, SHIMCMD_WORKSHOP_QUERY_ITEM_MOD, - SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO + SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO, + SHIMCMD_GET_GAME_INFO } ShimCmd; typedef enum ShimEvent @@ -473,7 +491,8 @@ typedef enum ShimEvent SHIMEVENT_WORKSHOP_UPLOAD_RESULT, SHIMEVENT_WORKSHOP_UPLOAD_PROGRESS, SHIMEVENT_WORKSHOP_QUERY_OWNED_ITEM_RESULT, - SHIMEVENT_WORKSHOP_QUERY_SUBSCRIBED_ITEM_RESULT + SHIMEVENT_WORKSHOP_QUERY_SUBSCRIBED_ITEM_RESULT, + SHIMEVENT_GET_GAME_INFO } ShimEvent; static bool write1ByteCmd(PipeType fd, const uint8 b1) @@ -529,7 +548,7 @@ static inline bool writeWorkshopUploadResult(PipeType fd, const EResult result, { dbgpipe("Parent sending SHIMEVENT_WORKSHOP_UPLOAD_RESULT(%d result %d workshop agreement).\n", result, needs_accept_workshop_agreement); return write3ByteCmd(fd, SHIMEVENT_WORKSHOP_UPLOAD_RESULT, result, needs_accept_workshop_agreement); -} // writeOverlayActivated +} static bool writeWorkshopItemOwnedQueriedResult(PipeType fd, const item_owned_query_result& query_result) { @@ -546,7 +565,7 @@ static bool writeWorkshopItemOwnedQueriedResult(PipeType fd, const item_owned_qu auto buffer = data_stream_shim.str(); return writePipe(fd, buffer.data(), buffer.length()); -} // writeOverlayActivated +} static bool writeWorkshopItemQueriedResult(PipeType fd, const item_subscribed_query_result& query_result) { @@ -563,7 +582,24 @@ static bool writeWorkshopItemQueriedResult(PipeType fd, const item_subscribed_qu auto buffer = data_stream_shim.str(); return writePipe(fd, buffer.data(), buffer.length()); -} // writeOverlayActivated +} + +static bool writeGameInfo(PipeType fd, const steam_game_information& game_info) +{ + dbgpipe("Parent sending SHIMEVENT_GET_GAME_INFO.\n"); + auto data_stream = game_info.shim_serialize(); + + data_stream = std::ostringstream() << (uint8)SHIMEVENT_GET_GAME_INFO << data_stream.str(); + + std::ostringstream data_stream_shim; + + uint16_t length = data_stream.str().length(); + data_stream_shim.write(reinterpret_cast(&length), sizeof(length)); + data_stream_shim << data_stream.str(); + + auto buffer = data_stream_shim.str(); + return writePipe(fd, buffer.data(), buffer.length()); +} static bool writeAchievementSet(PipeType fd, const char *name, const bool enable, const bool okay) { @@ -765,7 +801,7 @@ static void UpdateItem(PublishedFileId_t item_id, const item_upload_data& item_d GSteamUGC->SetItemPreview(updateHandle, item_data.thumbnail_path.c_str()); } - if (!item_data.required_scenario.empty()) + if (game_info.support_workshop_item_scenario && !item_data.required_scenario.empty()) { GSteamUGC->AddItemKeyValueTag(updateHandle, SteamItemTags::RequiredScenario, item_data.required_scenario.c_str()); } @@ -1053,6 +1089,7 @@ static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) PRINTGOTCMD(SHIMCMD_WORKSHOP_UPLOAD); PRINTGOTCMD(SHIMCMD_WORKSHOP_QUERY_ITEM_OWNED); PRINTGOTCMD(SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO); + PRINTGOTCMD(SHIMCMD_GET_GAME_INFO); #undef PRINTGOTCMD else printf("Parent got unknown shimcmd %d.\n", (int) cmd); #endif @@ -1171,6 +1208,12 @@ static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) UpdateItem(item.id, item); else { + if (item.item_type == ItemType::Scenario && !game_info.support_workshop_item_scenario) //double check + { + writeWorkshopUploadResult(fd, EResult::k_EResultFail, false); + break; + } + auto steam_api_call = GSteamUGC->CreateItem(GAppID, k_EWorkshopFileTypeCommunity); GSteamBridge->set_item_created_callback(steam_api_call, item); } @@ -1210,6 +1253,12 @@ static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) GSteamBridge->set_item_scenario_queried_callback(steam_api_call); } break; + + case SHIMCMD_GET_GAME_INFO: + { + writeGameInfo(fd, game_info); + } + break; } // switch return true; // keep going. @@ -1288,6 +1337,12 @@ static bool initSteamworks(PipeType fd, ESteamAPIInitResult* resultCode, SteamEr GUserID = GSteamUser ? GSteamUser->GetSteamID().ConvertToUint64() : 0; GSteamBridge = new SteamBridge(fd); + char folder_path[256]; + SteamApps()->GetAppInstallDir(GAppID, folder_path, sizeof(folder_path)); + game_info = {}; + game_info.install_folder_path = folder_path; + game_info.support_workshop_item_scenario = GAppID == MarathonInfinityAppId; + return 1; } // initSteamworks From eb69998e4d80e2917a92c8840211273d6b09ddc6 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Sun, 18 Aug 2024 16:31:18 +0200 Subject: [PATCH 36/58] Add support for 50+ workshop items queries --- Steam/steamshim_parent.cpp | 108 ++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/Steam/steamshim_parent.cpp b/Steam/steamshim_parent.cpp index 67297b414..1011a42dd 100755 --- a/Steam/steamshim_parent.cpp +++ b/Steam/steamshim_parent.cpp @@ -436,9 +436,9 @@ class SteamBridge STEAM_CALLBACK(SteamBridge, OnOverlayActivated, GameOverlayActivated_t, m_CallbackOverlayActivated); void set_item_created_callback(SteamAPICall_t api_call, const item_upload_data& item_data); void set_item_updated_callback(SteamAPICall_t api_call, UGCUpdateHandle_t handle, const item_upload_data& item_data); - void set_item_owned_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name); - void set_item_mod_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name); - void set_item_scenario_queried_callback(SteamAPICall_t api_call); + void set_item_owned_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name, int page_number); + void set_item_mod_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name, int page_number); + void set_item_scenario_queried_callback(SteamAPICall_t api_call, int page_number); void idle(); private: PipeType fd; @@ -453,6 +453,9 @@ class SteamBridge item_upload_data m_upload_item_data; UGCUpdateHandle_t m_update_handle = 0xffffffffffffffffull; std::string m_scenario_name; + item_subscribed_query_result m_items_subscribed_result_set = {}; + item_owned_query_result m_items_owned_result_set = {}; + int m_items_query_page_number; }; typedef enum ShimCmd @@ -810,6 +813,33 @@ static void UpdateItem(PublishedFileId_t item_id, const item_upload_data& item_d GSteamBridge->set_item_updated_callback(steam_api_call, updateHandle, item_data); } +static void workshopQueryItemScenario(int page_number) +{ + auto scenario_tag = std::to_string(static_cast(ItemType::Scenario)); + auto handle = GSteamUGC->CreateQueryUserUGCRequest(GUserID, k_EUserUGCList_Subscribed, k_EUGCMatchingUGCType_Items, k_EUserUGCListSortOrder_CreationOrderDesc, 0, GAppID, page_number); + GSteamUGC->SetReturnOnlyIDs(handle, true); + GSteamUGC->AddRequiredKeyValueTag(handle, SteamItemTags::ItemType, scenario_tag.c_str()); + auto steam_api_call = GSteamUGC->SendQueryUGCRequest(handle); + GSteamBridge->set_item_scenario_queried_callback(steam_api_call, page_number); +} + +static void workshopQueryItemMod(const std::string& scenario, int page_number) +{ + auto handle = GSteamUGC->CreateQueryUserUGCRequest(GUserID, k_EUserUGCList_Subscribed, k_EUGCMatchingUGCType_Items, k_EUserUGCListSortOrder_CreationOrderDesc, 0, GAppID, page_number); + GSteamUGC->SetReturnKeyValueTags(handle, true); + GSteamUGC->AddExcludedTag(handle, "Scenario"); + auto steam_api_call = GSteamUGC->SendQueryUGCRequest(handle); + GSteamBridge->set_item_mod_queried_callback(steam_api_call, scenario, page_number); +} + +static void workshopQueryItemOwned(const std::string& scenario, int page_number) +{ + auto handle = GSteamUGC->CreateQueryUserUGCRequest(GUserID, k_EUserUGCList_Published, k_EUGCMatchingUGCType_Items, k_EUserUGCListSortOrder_TitleAsc, GAppID, 0, page_number); + GSteamUGC->SetReturnKeyValueTags(handle, true); + auto steam_api_call = GSteamUGC->SendQueryUGCRequest(handle); + GSteamBridge->set_item_owned_queried_callback(steam_api_call, scenario, page_number); +} + SteamBridge::SteamBridge(PipeType _fd) : m_CallbackUserStatsReceived( this, &SteamBridge::OnUserStatsReceived ) , m_CallbackUserStatsStored( this, &SteamBridge::OnUserStatsStored ) @@ -850,19 +880,22 @@ void SteamBridge::set_item_updated_callback(SteamAPICall_t api_call, UGCUpdateHa m_CallbackItemUpdatedResult.Set(api_call, this, &SteamBridge::OnItemUpdated); } -void SteamBridge::set_item_owned_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name) +void SteamBridge::set_item_owned_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name, int page_number) { + m_items_query_page_number = page_number; m_scenario_name = scenario_name; m_CallbackItemQueryCompleted.Set(api_call, this, &SteamBridge::OnItemOwnedQueried); } -void SteamBridge::set_item_scenario_queried_callback(SteamAPICall_t api_call) +void SteamBridge::set_item_scenario_queried_callback(SteamAPICall_t api_call, int page_number) { + m_items_query_page_number = page_number; m_CallbackItemQueryCompleted.Set(api_call, this, &SteamBridge::OnItemScenarioQueried); } -void SteamBridge::set_item_mod_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name) +void SteamBridge::set_item_mod_queried_callback(SteamAPICall_t api_call, const std::string& scenario_name, int page_number) { + m_items_query_page_number = page_number; m_scenario_name = scenario_name; m_CallbackItemQueryCompleted.Set(api_call, this, &SteamBridge::OnItemModQueried); } @@ -912,8 +945,6 @@ void SteamBridge::OnItemUpdated(SubmitItemUpdateResult_t* pCallback, bool bIOFai void SteamBridge::OnItemOwnedQueried(SteamUGCQueryCompleted_t* pCallback, bool bIOFailure) { - item_owned_query_result items_result; - if (!bIOFailure && pCallback->m_eResult == k_EResultOK) { for (int i = 0; i < pCallback->m_unNumResultsReturned; i++) @@ -957,19 +988,24 @@ void SteamBridge::OnItemOwnedQueried(SteamUGCQueryCompleted_t* pCallback, bool b item.title = item_details.m_rgchTitle; item.id = item_details.m_nPublishedFileId; - items_result.items.push_back(item); + m_items_owned_result_set.items.push_back(item); } } - items_result.result_code = pCallback->m_eResult; + m_items_owned_result_set.result_code = pCallback->m_eResult; GSteamUGC->ReleaseQueryUGCRequest(pCallback->m_handle); - writeWorkshopItemOwnedQueriedResult(fd, items_result); + + if (pCallback->m_unNumResultsReturned >= kNumUGCResultsPerPage && pCallback->m_eResult == k_EResultOK) + workshopQueryItemOwned(m_scenario_name, m_items_query_page_number + 1); + else + { + writeWorkshopItemOwnedQueriedResult(fd, m_items_owned_result_set); + m_items_owned_result_set = {}; + } } void SteamBridge::OnItemModQueried(SteamUGCQueryCompleted_t* pCallback, bool bIOFailure) { - item_subscribed_query_result items_result; - if (!bIOFailure && pCallback->m_eResult == k_EResultOK) { for (int i = 0; i < pCallback->m_unNumResultsReturned; i++) @@ -1017,19 +1053,24 @@ void SteamBridge::OnItemModQueried(SteamUGCQueryCompleted_t* pCallback, bool bIO item.id = item_details.m_nPublishedFileId; item.install_folder_path = folder_path; - items_result.items.push_back(item); + m_items_subscribed_result_set.items.push_back(item); } } - items_result.result_code = pCallback->m_eResult; + m_items_subscribed_result_set.result_code = pCallback->m_eResult; GSteamUGC->ReleaseQueryUGCRequest(pCallback->m_handle); - writeWorkshopItemQueriedResult(fd, items_result); + + if (pCallback->m_unNumResultsReturned >= kNumUGCResultsPerPage && pCallback->m_eResult == k_EResultOK) + workshopQueryItemMod(m_scenario_name, m_items_query_page_number + 1); + else + { + writeWorkshopItemQueriedResult(fd, m_items_subscribed_result_set); + m_items_subscribed_result_set = {}; + } } void SteamBridge::OnItemScenarioQueried(SteamUGCQueryCompleted_t* pCallback, bool bIOFailure) { - item_subscribed_query_result items_result; - if (!bIOFailure && pCallback->m_eResult == k_EResultOK) { for (int i = 0; i < pCallback->m_unNumResultsReturned; i++) @@ -1055,13 +1096,20 @@ void SteamBridge::OnItemScenarioQueried(SteamUGCQueryCompleted_t* pCallback, boo item.item_type = ItemType::Scenario; item.content_type = ContentType::None; item.install_folder_path = folder_path; - items_result.items.push_back(item); + m_items_subscribed_result_set.items.push_back(item); } } - items_result.result_code = pCallback->m_eResult; + m_items_subscribed_result_set.result_code = pCallback->m_eResult; GSteamUGC->ReleaseQueryUGCRequest(pCallback->m_handle); - writeWorkshopItemQueriedResult(fd, items_result); + + if (pCallback->m_unNumResultsReturned >= kNumUGCResultsPerPage && pCallback->m_eResult == k_EResultOK) + workshopQueryItemScenario(m_items_query_page_number + 1); + else + { + writeWorkshopItemQueriedResult(fd, m_items_subscribed_result_set); + m_items_subscribed_result_set = {}; + } } static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) @@ -1224,10 +1272,7 @@ static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) if (buflen) { auto scenario = std::string((const char*)buf); - auto handle = GSteamUGC->CreateQueryUserUGCRequest(GUserID, k_EUserUGCList_Published, k_EUGCMatchingUGCType_Items, k_EUserUGCListSortOrder_TitleAsc, GAppID, 0, 1); - GSteamUGC->SetReturnKeyValueTags(handle, true); - auto steam_api_call = GSteamUGC->SendQueryUGCRequest(handle); - GSteamBridge->set_item_owned_queried_callback(steam_api_call, scenario); + workshopQueryItemOwned(scenario, 1); } break; @@ -1235,22 +1280,13 @@ static bool processCommand(const uint8 *buf, unsigned int buflen, PipeType fd) if (buflen) { auto scenario = std::string((const char*)buf); - auto handle = GSteamUGC->CreateQueryUserUGCRequest(GUserID, k_EUserUGCList_Subscribed, k_EUGCMatchingUGCType_Items, k_EUserUGCListSortOrder_CreationOrderDesc, 0, GAppID, 1); - GSteamUGC->SetReturnKeyValueTags(handle, true); - GSteamUGC->AddExcludedTag(handle, "Scenario"); - auto steam_api_call = GSteamUGC->SendQueryUGCRequest(handle); - GSteamBridge->set_item_mod_queried_callback(steam_api_call, scenario); + workshopQueryItemMod(scenario, 1); } break; case SHIMCMD_WORKSHOP_QUERY_ITEM_SCENARIO: { - auto scenario_tag = std::to_string(static_cast(ItemType::Scenario)); - auto handle = GSteamUGC->CreateQueryUserUGCRequest(GUserID, k_EUserUGCList_Subscribed, k_EUGCMatchingUGCType_Items, k_EUserUGCListSortOrder_CreationOrderDesc, 0, GAppID, 1); - GSteamUGC->SetReturnOnlyIDs(handle, true); - GSteamUGC->AddRequiredKeyValueTag(handle, SteamItemTags::ItemType, scenario_tag.c_str()); - auto steam_api_call = GSteamUGC->SendQueryUGCRequest(handle); - GSteamBridge->set_item_scenario_queried_callback(steam_api_call); + workshopQueryItemScenario(1); } break; From ba0594a04e0bf94205a813ffbafb84c601e36d66 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Sun, 18 Aug 2024 22:49:52 +0200 Subject: [PATCH 37/58] Fix a recent bug in steam uploader --- Source_Files/Misc/interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source_Files/Misc/interface.cpp b/Source_Files/Misc/interface.cpp index 5c27d6567..112502c56 100644 --- a/Source_Files/Misc/interface.cpp +++ b/Source_Files/Misc/interface.cpp @@ -1950,7 +1950,7 @@ static void display_steam_workshop_uploader_dialog(void* arg) } }; - static std::vector item_types = { "Plugin", "Map", "Physics", "Script", "Sounds", "Shapes" }; + std::vector item_types = { "Plugin", "Map", "Physics", "Script", "Sounds", "Shapes" }; if (steam_game_info.support_workshop_item_scenario) { From 8242ab9fa0d270da8c79a7890bc7eaaadbece96d Mon Sep 17 00:00:00 2001 From: Kolfering Date: Mon, 19 Aug 2024 01:35:54 +0200 Subject: [PATCH 38/58] Fix another bug in steam uploader --- Source_Files/Misc/interface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source_Files/Misc/interface.cpp b/Source_Files/Misc/interface.cpp index 112502c56..a68aad1ed 100644 --- a/Source_Files/Misc/interface.cpp +++ b/Source_Files/Misc/interface.cpp @@ -1912,6 +1912,7 @@ static void display_steam_workshop_uploader_dialog(void* arg) steam_workshop_uploader_ui_data ui_data; ui_data.item_type = static_cast(new_item.item_type); + ui_data.content_type = static_cast(new_item.content_type); ui_data.is_scenarios_compatible = new_item.is_scenarios_compatible; ui_data.item_id = new_item.id; From e7676a304a6c49745e6bc74f80122839a814763f Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Sun, 18 Aug 2024 22:23:39 -0400 Subject: [PATCH 39/58] save quick saves for workshop scenarios to a place recursive auto cloud will sync them --- Source_Files/Misc/ScenarioChooser.cpp | 12 ++-- Source_Files/Misc/ScenarioChooser.h | 8 ++- Source_Files/shell.cpp | 79 +++++++++++++++++---------- 3 files changed, 63 insertions(+), 36 deletions(-) diff --git a/Source_Files/Misc/ScenarioChooser.cpp b/Source_Files/Misc/ScenarioChooser.cpp index bd0d009a4..d46454bf9 100644 --- a/Source_Files/Misc/ScenarioChooser.cpp +++ b/Source_Files/Misc/ScenarioChooser.cpp @@ -33,6 +33,8 @@ class ScenarioChooserScenario std::string name; std::shared_ptr image; + bool is_workshop; + bool is_primary; bool load(const std::string& path); void find_image(); @@ -173,11 +175,13 @@ ScenarioChooser::~ScenarioChooser() } -void ScenarioChooser::add_scenario(const std::string& path) +void ScenarioChooser::add_scenario(const std::string& path, bool is_primary, bool is_workshop) { ScenarioChooserScenario scenario; if (scenario.load(path)) { + scenario.is_primary = is_primary; + scenario.is_workshop = is_workshop; scenarios_.push_back(scenario); } } @@ -194,7 +198,7 @@ void ScenarioChooser::add_directory(const std::string& path) { if (entry.is_directory) { - add_scenario((d + entry.name).GetPath()); + add_scenario((d + entry.name).GetPath(), false, false); } } } @@ -205,7 +209,7 @@ int ScenarioChooser::num_scenarios() const return static_cast(scenarios_.size()); } -std::string ScenarioChooser::run() +std::pair ScenarioChooser::run() { std::sort(scenarios_.begin(), scenarios_.end()); @@ -244,7 +248,7 @@ std::string ScenarioChooser::run() SDL_Delay(30); } - return scenarios_[selection_].path; + return std::make_pair(scenarios_[selection_].path, scenarios_[selection_].is_workshop); } void ScenarioChooser::determine_cols_rows() diff --git a/Source_Files/Misc/ScenarioChooser.h b/Source_Files/Misc/ScenarioChooser.h index e0f913ed4..9a46b199f 100644 --- a/Source_Files/Misc/ScenarioChooser.h +++ b/Source_Files/Misc/ScenarioChooser.h @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -41,12 +42,14 @@ class ScenarioChooser ScenarioChooser(); ~ScenarioChooser(); - void add_scenario(const std::string& path); + void add_primary_scenario(const std::string& path) { add_scenario(path, true, false); } + void add_workshop_scenario(const std::string& path) { add_scenario(path, false, true); } void add_directory(const std::string& path); int num_scenarios() const; - std::string run(); + // returns path to scenario, is_workshop + std::pair run(); private: bool done_; @@ -68,6 +71,7 @@ class ScenarioChooser std::vector scenarios_; + void add_scenario(const std::string& path, bool is_primary, bool is_workshop); void determine_cols_rows(); void ensure_selection_visible(); void handle_event(SDL_Event& e); diff --git a/Source_Files/shell.cpp b/Source_Files/shell.cpp index 33acc8b41..1022a509f 100644 --- a/Source_Files/shell.cpp +++ b/Source_Files/shell.cpp @@ -317,7 +317,7 @@ void initialize_application(void) } ScenarioChooser chooser; - chooser.add_scenario(scenario_dir.GetPath()); + chooser.add_primary_scenario(scenario_dir.GetPath()); #ifdef HAVE_STEAM if (!STEAMSHIM_init()) @@ -326,26 +326,39 @@ void initialize_application(void) exit(1); } + STEAMSHIM_getGameInfo(); STEAMSHIM_queryWorkshopItemScenario(); - - while (STEAMSHIM_alive()) + + bool got_info = false, got_items = false; + while (STEAMSHIM_alive() && (!got_info || !got_items)) { auto result = STEAMSHIM_pump(); - if (result && result->type == SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT) + if (!result) { - if (result->items_subscribed.result_code == 1) - { - for (const auto& steam_scenario : result->items_subscribed.items) + sleep_for_machine_ticks(30); + continue; + } + + switch (result->type) + { + case SHIMEVENT_GET_GAME_INFO: + steam_game_info = result->game_info; + got_info = true; + break; + case SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT: + if (result->items_subscribed.result_code == 1) { - chooser.add_scenario(steam_scenario.install_folder_path); + for (const auto& steam_scenario : result->items_subscribed.items) + { + chooser.add_workshop_scenario(steam_scenario.install_folder_path); + } } - } - - break; + got_items = true; + break; + default: + break; } - - sleep_for_machine_ticks(30); } #endif // HAVE_STEAM @@ -358,9 +371,12 @@ void initialize_application(void) chooser.add_directory((scenario_dir + "Scenarios").GetPath()); } + auto is_workshop_scenario = false; if (chooser.num_scenarios() > 1) { - auto chosen_path = chooser.run(); + std::string chosen_path; + std::tie(chosen_path, is_workshop_scenario) = chooser.run(); + // ugh shell_options.directory = chosen_path; } @@ -368,7 +384,7 @@ void initialize_application(void) // Find data directories, construct search path InitDefaultStringSets(); - + #ifndef SCENARIO_IS_BUNDLED default_data_dir = get_data_path(kPathDefaultData); #endif @@ -377,6 +393,17 @@ void initialize_application(void) preferences_dir = get_data_path(kPathPreferences); saved_games_dir = get_data_path(kPathSavedGames); quick_saves_dir = get_data_path(kPathQuickSaves); + +#ifdef HAVE_STEAM + if (is_workshop_scenario) + { + quick_saves_dir += "Marathon Infinity"; + quick_saves_dir.CreateDirectory(); + quick_saves_dir += "Workshop"; + quick_saves_dir.CreateDirectory(); + } +#endif + image_cache_dir = get_data_path(kPathImageCache); recordings_dir = get_data_path(kPathRecordings); screenshots_dir = get_data_path(kPathScreenshots); @@ -467,11 +494,9 @@ void initialize_application(void) } #ifdef HAVE_STEAM - STEAMSHIM_getGameInfo(); STEAMSHIM_queryWorkshopItemMod(Scenario::instance()->GetName()); - bool got_info = false, got_items = false; - while (STEAMSHIM_alive() && (!got_info || !got_items)) + while (STEAMSHIM_alive()) { auto result = STEAMSHIM_pump(); @@ -481,22 +506,16 @@ void initialize_application(void) continue; } - switch (result->type) + if (result->type == SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT) { - case SHIMEVENT_GET_GAME_INFO: - steam_game_info = result->game_info; - got_info = true; - break; - case SHIMEVENT_WORKSHOP_QUERY_ITEM_SUBSCRIBED_RESULT: - if (result->items_subscribed.result_code == 1) - { - for (const auto& item : result->items_subscribed.items) + if (result->items_subscribed.result_code == 1) + { + for (const auto& item : result->items_subscribed.items) { subscribed_workshop_items.push_back(item); } - } - got_items = true; - break; + } + break; } } #endif From 370fb30d0e783a67cf5081c15c3ed14ca94df193 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Sun, 18 Aug 2024 22:25:06 -0400 Subject: [PATCH 40/58] always list the primary scenario first --- Source_Files/Misc/ScenarioChooser.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source_Files/Misc/ScenarioChooser.cpp b/Source_Files/Misc/ScenarioChooser.cpp index d46454bf9..e86e38764 100644 --- a/Source_Files/Misc/ScenarioChooser.cpp +++ b/Source_Files/Misc/ScenarioChooser.cpp @@ -74,6 +74,11 @@ class TitleScreenFinder : public FileFinder bool ScenarioChooserScenario::operator<(const ScenarioChooserScenario& other) const { + if (is_primary != other.is_primary) + { + return is_primary; + } + return std::lexicographical_compare(name.begin(), name.end(), other.name.begin(), From a6136924b04448aac006d88e68d1520e2726b86a Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Mon, 19 Aug 2024 18:52:49 -0400 Subject: [PATCH 41/58] press button A to choose a scenario --- Source_Files/Misc/ScenarioChooser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source_Files/Misc/ScenarioChooser.cpp b/Source_Files/Misc/ScenarioChooser.cpp index e86e38764..a0d928ce4 100644 --- a/Source_Files/Misc/ScenarioChooser.cpp +++ b/Source_Files/Misc/ScenarioChooser.cpp @@ -327,6 +327,12 @@ void ScenarioChooser::handle_event(SDL_Event& e) case SDL_CONTROLLERBUTTONDOWN: switch (e.cbutton.button) { + case SDL_CONTROLLER_BUTTON_A: + if (selection_ >= 0) + { + done_ = true; + } + break; case SDL_CONTROLLER_BUTTON_B: exit(0); case SDL_CONTROLLER_BUTTON_DPAD_DOWN: From 8897d3b5ad559046d2c7c8070f4ae27b05c2d701 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Mon, 19 Aug 2024 19:10:10 -0400 Subject: [PATCH 42/58] add missing header --- Source_Files/Misc/steamshim_child.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source_Files/Misc/steamshim_child.h b/Source_Files/Misc/steamshim_child.h index c6d8c6771..37fbefdd6 100755 --- a/Source_Files/Misc/steamshim_child.h +++ b/Source_Files/Misc/steamshim_child.h @@ -1,6 +1,7 @@ #ifndef _INCL_STEAMSHIM_CHILD_H_ #define _INCL_STEAMSHIM_CHILD_H_ +#include #include #include From 40b25b01f9b32c81fcd6136019ea13b0ef9f2284 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Mon, 19 Aug 2024 19:24:11 -0400 Subject: [PATCH 43/58] search the workshop subscriptions when finding maps/physics by checksum or shapes/sounds by date --- Source_Files/Files/wad_sdl.cpp | 59 ++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/Source_Files/Files/wad_sdl.cpp b/Source_Files/Files/wad_sdl.cpp index d53921400..fd52803bc 100644 --- a/Source_Files/Files/wad_sdl.cpp +++ b/Source_Files/Files/wad_sdl.cpp @@ -31,6 +31,10 @@ #include +#ifdef HAVE_STEAM +#include "steamshim_child.h" +#endif + // From shell_sdl.cpp extern vector data_search_path; @@ -66,9 +70,47 @@ class FindByChecksum : public FileFinder { uint32 look_for_checksum; }; +#ifdef HAVE_STEAM +extern std::vector subscribed_workshop_items; + +ItemType typecode_to_item_type(Typecode file_type) +{ + switch (file_type) + { + case _typecode_scenario: + return ItemType::Map; + case _typecode_physics: + return ItemType::Physics; + case _typecode_shapes: + return ItemType::Shapes; + case _typecode_sounds: + return ItemType::Sounds; + default: + assert(false); + } +} +#endif + bool find_wad_file_that_has_checksum(FileSpecifier &matching_file, Typecode file_type, short path_resource_id, uint32 checksum) { FindByChecksum finder(checksum); + +#ifdef HAVE_STEAM + auto item_type = typecode_to_item_type(file_type); + for (const auto& item : subscribed_workshop_items) + { + if (item_type == item.item_type) + { + FileSpecifier dir(item.install_folder_path); + if (finder.Find(dir, file_type)) + { + matching_file = finder.found_what; + return true; + } + } + } +#endif + vector::const_iterator i = data_search_path.begin(), end = data_search_path.end(); while (i != end) { FileSpecifier dir = *i; @@ -109,6 +151,23 @@ class FindByDate : public FileFinder { bool find_file_with_modification_date(FileSpecifier &matching_file, Typecode file_type, short path_resource_id, TimeType modification_date) { FindByDate finder(modification_date); + +#ifdef HAVE_STEAM + auto item_type = typecode_to_item_type(file_type); + for (const auto& item : subscribed_workshop_items) + { + if (item_type == item.item_type) + { + FileSpecifier dir(item.install_folder_path); + if (finder.Find(dir, file_type)) + { + matching_file = finder.found_what; + return true; + } + } + } +#endif + vector::const_iterator i = data_search_path.begin(), end = data_search_path.end(); while (i != end) { FileSpecifier dir = *i; From 1d84234c42d6e7fab998fb7dd6ef566831609156 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Mon, 19 Aug 2024 21:09:59 -0400 Subject: [PATCH 44/58] give out Vid Buoy to players who come in with the Slings and Arrows fusion --- Source_Files/Misc/m2_achievements.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source_Files/Misc/m2_achievements.lua b/Source_Files/Misc/m2_achievements.lua index 4808d3695..2c525beb4 100644 --- a/Source_Files/Misc/m2_achievements.lua +++ b/Source_Files/Misc/m2_achievements.lua @@ -44,8 +44,13 @@ function Triggers.init(restored) end if Level.index == 5 then + if Players[0]._fusion_pistols == nil then + Players[0]._fusion_pistols = Players[0].items["fusion pistol"] + end Triggers.terminal_enter = we_terminal_enter Triggers.idle = we_idle + else + Players[0]._fusion_pistols = nil end if Level.index == 9 then @@ -103,7 +108,7 @@ function catym_terminal_enter(terminal) end function we_terminal_enter() - if Players[0].items["fusion pistol"] == 0 then + if Players[0].items["fusion pistol"] == Players[0]._fusion_pistols then got_achievement("ACH_VID_BUOY") Triggers.terminal_enter = nil end From d9973603fdc16ff332ef21224d88891a7a224665 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Mon, 19 Aug 2024 21:20:17 -0400 Subject: [PATCH 45/58] disallow getting Surf's Up by opening airlocks, saving, resuming, and grabbing the SPNKR --- Source_Files/Misc/m2_achievements.lua | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Source_Files/Misc/m2_achievements.lua b/Source_Files/Misc/m2_achievements.lua index 2c525beb4..5ee7576cc 100644 --- a/Source_Files/Misc/m2_achievements.lua +++ b/Source_Files/Misc/m2_achievements.lua @@ -58,9 +58,13 @@ function Triggers.init(restored) end if Level.index == 13 then - Triggers.idle = iiharl_idle - Triggers.platform_activated = iiharl_platform_activated - Triggers.projectile_created = iiharl_projectile_created + if not Level._surfs_up_over then + Triggers.idle = iiharl_idle + Triggers.platform_activated = iiharl_platform_activated + Triggers.projectile_created = iiharl_projectile_created + end + else + Level._surfs_up_over = nil end if Level.index == 16 then @@ -170,6 +174,7 @@ function iiharl_projectile_created(projectile) projectile.owner.player and projectile.type ~= "fist" then + Level._surfs_up_over = true Triggers.idle = nil Triggers.projectile_created = nil Triggers.platform_activated = nil @@ -181,6 +186,7 @@ function iiharl_platform_activated(polygon) polygon.index == 33 or polygon.index == 64 then + Level._surfs_up_over = true Triggers.idle = nil Triggers.projectile_created = nil Triggers.platform_activated = nil From 65afcd2bdb19873a5d0ab5ed532a07a64d606895 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Tue, 20 Aug 2024 21:03:43 -0400 Subject: [PATCH 46/58] revise run/walk labels a little --- Source_Files/Misc/preferences.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source_Files/Misc/preferences.cpp b/Source_Files/Misc/preferences.cpp index 70bff4ba7..4042e2b93 100644 --- a/Source_Files/Misc/preferences.cpp +++ b/Source_Files/Misc/preferences.cpp @@ -2588,14 +2588,14 @@ static void controls_dialog(void *arg) static const char* run_option_labels[] = { "Hold to Run", - "Hold to Walk", - "Tap to Toggle", + "Always Run", + "Toggle", nullptr }; static const char* swim_option_labels[] = { "Hold to Swim", - "Hold to Sink", + "Always Swim", nullptr }; From d5ccdf50384b260218d46a90cf9e19485fa7a040 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Tue, 20 Aug 2024 21:19:09 -0400 Subject: [PATCH 47/58] indicate when w_env_select files are missing, Thoth style; display a placeholder when the w_env_select path is completely empty --- Source_Files/Misc/preferences_widgets_sdl.h | 22 +++++++++++++++++++-- Source_Files/Misc/sdl_widgets.cpp | 2 +- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Source_Files/Misc/preferences_widgets_sdl.h b/Source_Files/Misc/preferences_widgets_sdl.h index 034ebed84..5d915147e 100644 --- a/Source_Files/Misc/preferences_widgets_sdl.h +++ b/Source_Files/Misc/preferences_widgets_sdl.h @@ -111,6 +111,8 @@ class w_env_list : public w_list { class w_env_select; using selection_made_callback_t = std::function; +extern const char* const sFileChooserInvalidFileString; + class w_env_select : public w_select_button { public: w_env_select(const char *path, const char *m, Typecode t, dialog *d) @@ -131,8 +133,24 @@ w_env_select(const char *path, const char *m, Typecode t, dialog *d) item = p; item.GetName(item_name); std::string filename = item_name; - strncpy(item_name, FileSpecifier::HideExtension(filename).c_str(), 256); - set_selection(item_name); + + if (*p) + { + if (item.Exists()) + { + strncpy(item_name, FileSpecifier::HideExtension(filename).c_str(), 256); + } + else + { + snprintf(item_name, 256, "[?%s]", FileSpecifier::HideExtension(filename).c_str(), 256); + } + + set_selection(item_name); + } + else + { + set_selection(sFileChooserInvalidFileString); + } } const char *get_path(void) const diff --git a/Source_Files/Misc/sdl_widgets.cpp b/Source_Files/Misc/sdl_widgets.cpp index e72400c60..58a18c9cf 100644 --- a/Source_Files/Misc/sdl_widgets.cpp +++ b/Source_Files/Misc/sdl_widgets.cpp @@ -2350,7 +2350,7 @@ void w_select_popup::gotSelected () } -static const char* const sFileChooserInvalidFileString = "(no valid selection)"; +const char* const sFileChooserInvalidFileString = "(no valid selection)"; w_file_chooser::w_file_chooser(const char* inDialogPrompt, Typecode inTypecode) : w_select_button("", NULL, NULL, true), typecode(inTypecode) From 828df44d6706db6f3aec2be125fd17b6ce24d1b4 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Tue, 20 Aug 2024 21:25:46 -0400 Subject: [PATCH 48/58] remove one too many 256es --- Source_Files/Misc/preferences_widgets_sdl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source_Files/Misc/preferences_widgets_sdl.h b/Source_Files/Misc/preferences_widgets_sdl.h index 5d915147e..baad2a6d8 100644 --- a/Source_Files/Misc/preferences_widgets_sdl.h +++ b/Source_Files/Misc/preferences_widgets_sdl.h @@ -142,7 +142,7 @@ w_env_select(const char *path, const char *m, Typecode t, dialog *d) } else { - snprintf(item_name, 256, "[?%s]", FileSpecifier::HideExtension(filename).c_str(), 256); + snprintf(item_name, 256, "[?%s]", FileSpecifier::HideExtension(filename).c_str()); } set_selection(item_name); From 807d33c33d58ac8700cb646c35737751072a040a Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Wed, 21 Aug 2024 17:15:26 -0400 Subject: [PATCH 49/58] add a --no-chooser options; make --editor also skip the chooser --- Source_Files/shell.cpp | 46 +++++++++++++++++++++------------- Source_Files/shell_options.cpp | 3 ++- Source_Files/shell_options.h | 2 ++ 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/Source_Files/shell.cpp b/Source_Files/shell.cpp index 1022a509f..aaa1db8b2 100644 --- a/Source_Files/shell.cpp +++ b/Source_Files/shell.cpp @@ -326,10 +326,17 @@ void initialize_application(void) exit(1); } - STEAMSHIM_getGameInfo(); - STEAMSHIM_queryWorkshopItemScenario(); - bool got_info = false, got_items = false; + STEAMSHIM_getGameInfo(); + if (shell_options.editor || shell_options.no_chooser) + { + got_items = true; + } + else + { + STEAMSHIM_queryWorkshopItemScenario(); + } + while (STEAMSHIM_alive() && (!got_info || !got_items)) { auto result = STEAMSHIM_pump(); @@ -362,23 +369,26 @@ void initialize_application(void) } #endif // HAVE_STEAM - if (chooser.num_scenarios() == 0) - { - chooser.add_directory(scenario_dir.GetPath()); - } - else if (chooser.num_scenarios() == 1) - { - chooser.add_directory((scenario_dir + "Scenarios").GetPath()); - } - auto is_workshop_scenario = false; - if (chooser.num_scenarios() > 1) + if (!shell_options.editor && !shell_options.no_chooser) { - std::string chosen_path; - std::tie(chosen_path, is_workshop_scenario) = chooser.run(); - - // ugh - shell_options.directory = chosen_path; + if (chooser.num_scenarios() == 0) + { + chooser.add_directory(scenario_dir.GetPath()); + } + else if (chooser.num_scenarios() == 1) + { + chooser.add_directory((scenario_dir + "Scenarios").GetPath()); + } + + if (chooser.num_scenarios() > 1) + { + std::string chosen_path; + std::tie(chosen_path, is_workshop_scenario) = chooser.run(); + + // ugh + shell_options.directory = chosen_path; + } } #endif diff --git a/Source_Files/shell_options.cpp b/Source_Files/shell_options.cpp index c37a0102e..fb87956e0 100644 --- a/Source_Files/shell_options.cpp +++ b/Source_Files/shell_options.cpp @@ -96,7 +96,8 @@ static const std::vector shell_options_flags { {"j", "nojoystick", "Do not initialize joysticks", shell_options.nojoystick}, {"i", "insecure_lua", "", shell_options.insecure_lua}, {"Q", "skip-intro", "Skip intro screens", shell_options.skip_intro}, - {"e", "editor", "Use editor prefs; jump directly to map", shell_options.editor} + {"e", "editor", "Use editor prefs; jump directly to map", shell_options.editor}, + {"", "no-chooser", "Disable the scenario chooser", shell_options.no_chooser} }; static const std::vector shell_options_strings { diff --git a/Source_Files/shell_options.h b/Source_Files/shell_options.h index d6481ee0b..1ebef8402 100644 --- a/Source_Files/shell_options.h +++ b/Source_Files/shell_options.h @@ -23,6 +23,8 @@ struct ShellOptions { bool skip_intro; bool editor; + bool no_chooser; + std::string replay_directory; std::string directory; From e1d14578aa2afbb57a563c98728b169ffec81ce4 Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Wed, 21 Aug 2024 18:00:25 -0400 Subject: [PATCH 50/58] version 1.10 --- Source_Files/Misc/alephversion.h | 8 ++++---- docs/Lua_HUD.html | 2 +- docs/Lua_HUD.xml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source_Files/Misc/alephversion.h b/Source_Files/Misc/alephversion.h index c8a2c732a..d58e46272 100644 --- a/Source_Files/Misc/alephversion.h +++ b/Source_Files/Misc/alephversion.h @@ -24,12 +24,12 @@ ALEPHVERSION.H #define A1_DISPLAY_NAME "Aleph One" -#define A1_DISPLAY_VERSION "1.9" -#define A1_DISPLAY_DATE_VERSION "2024-07-12" -#define A1_DATE_VERSION "20240712" +#define A1_DISPLAY_VERSION "1.10" +#define A1_DISPLAY_DATE_VERSION "2024-08-22" +#define A1_DATE_VERSION "20240822" #ifdef _WIN32 -#define WIN_VERSION_STRING 0,2024,7,12 // <-- don't forget to update that for windows releases +#define WIN_VERSION_STRING 0,2024,8,22 // <-- don't forget to update that for windows releases #define A1_DISPLAY_PLATFORM "Windows" #define A1_UPDATE_PLATFORM "windows" #elif defined (__APPLE__) && defined(__MACH__) diff --git a/docs/Lua_HUD.html b/docs/Lua_HUD.html index 0a3089f6f..0a96cf31c 100644 --- a/docs/Lua_HUD.html +++ b/docs/Lua_HUD.html @@ -339,7 +339,7 @@

the current scoring mode (if the gametype is "custom")

.ticks

ticks since game started

-
.interpolated_ticks git +
.interpolated_ticks 20240822

ticks since game started, including fractional ticks if running at greater than 30 fps

.type
diff --git a/docs/Lua_HUD.xml b/docs/Lua_HUD.xml index 100e64149..df796d8c5 100644 --- a/docs/Lua_HUD.xml +++ b/docs/Lua_HUD.xml @@ -519,7 +519,7 @@ end ticks since game started time - + ticks since game started, including fractional ticks if running at greater than 30 fps number From 5912e464cf96148896d415f67a279315c0f070d1 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Thu, 22 Aug 2024 21:12:31 +0200 Subject: [PATCH 51/58] Update dedicated server version --- Source_Files/Network/StandaloneHub/StandaloneHub.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source_Files/Network/StandaloneHub/StandaloneHub.h b/Source_Files/Network/StandaloneHub/StandaloneHub.h index 280dd94a0..fcc06add0 100644 --- a/Source_Files/Network/StandaloneHub/StandaloneHub.h +++ b/Source_Files/Network/StandaloneHub/StandaloneHub.h @@ -22,7 +22,7 @@ #include "MessageInflater.h" #include "network_messages.h" -#define STANDALONE_HUB_VERSION "01.00" +#define STANDALONE_HUB_VERSION "01.01" class StandaloneHub { private: From 3aef2ef5df2d145102f60278d47d8f6ca5913ccf Mon Sep 17 00:00:00 2001 From: Kolfering Date: Fri, 23 Aug 2024 02:38:15 +0200 Subject: [PATCH 52/58] Push standalone hub docker image to github registry --- .github/workflows/release-standalone-hub.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-standalone-hub.yml b/.github/workflows/release-standalone-hub.yml index ecb760297..51bc21ee8 100644 --- a/.github/workflows/release-standalone-hub.yml +++ b/.github/workflows/release-standalone-hub.yml @@ -4,22 +4,33 @@ on: [workflow_dispatch, workflow_call] jobs: release-standalone-hub: + permissions: + packages: write runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - name: Get Standalone Hub Version run: echo "standalone_hub_version=$(awk -F'"' '/#define STANDALONE_HUB_VERSION/ {print $2}' Source_Files/Network/StandaloneHub/StandaloneHub.h)" >> $GITHUB_ENV - + + - name: Get Repository Owner + run: echo "repository_owner=${GITHUB_REPOSITORY_OWNER@L}" >> "${GITHUB_ENV}" + - name: Build Docker image run: docker buildx build -t alephone/standalone-hub:${{env.standalone_hub_version}} . -f Dockerfile.hub --load - name: Save Docker image run: docker save -o alephone-standalone-hub-${{env.standalone_hub_version}}.tar alephone/standalone-hub:${{env.standalone_hub_version}} - + - name: Upload uses: actions/upload-artifact@v4 with: name: alephone-standalone-hub if-no-files-found: error - path: alephone-standalone-hub-${{env.standalone_hub_version}}.tar \ No newline at end of file + path: alephone-standalone-hub-${{env.standalone_hub_version}}.tar + + - name: Push to Github Container Registry + run: | + echo ${{ github.token }} | docker login --username ${{ github.actor }} --password-stdin ghcr.io + docker tag alephone/standalone-hub:${{env.standalone_hub_version}} ghcr.io/${{env.repository_owner}}/standalone-hub:${{env.standalone_hub_version}} + docker push ghcr.io/${{env.repository_owner}}/standalone-hub:${{env.standalone_hub_version}} \ No newline at end of file From 8298d3176982b7ae2a87d4d62feec6b9f0ea3af6 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Sat, 24 Aug 2024 11:58:51 +0200 Subject: [PATCH 53/58] Update vcpkg.json alephone version for 1.10 release --- vcpkg.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcpkg.json b/vcpkg.json index 47ae838ed..ee00aa05b 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,6 +1,6 @@ { "name":"alephone", - "version-date":"2024-07-12", + "version-date":"2024-08-22", "dependencies":[ { "name":"boost-algorithm" From 2825da5e84e06390f0038f1e3037ad825df40c6f Mon Sep 17 00:00:00 2001 From: Gregory Smith Date: Sat, 3 Aug 2024 13:48:34 -0400 Subject: [PATCH 54/58] fix vacbobs spoiling the ACCIVI achievement --- Source_Files/Misc/inf_achievements.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source_Files/Misc/inf_achievements.lua b/Source_Files/Misc/inf_achievements.lua index 97de0789d..ff218dfa9 100644 --- a/Source_Files/Misc/inf_achievements.lua +++ b/Source_Files/Misc/inf_achievements.lua @@ -83,7 +83,7 @@ function Triggers.init(restored) if Level.index == 19 then if not Players[0]._accivi_over then - Triggers.platform_activated = accivi_platform_activated + Triggers.idle = accivi_idle Triggers.platform_switch = accivi_platform_switch Triggers.projectile_switch = accivi_projectile_switch Triggers.tag_switch = accivi_tag_switch @@ -170,15 +170,15 @@ end function accivi_over() Players[0]._accivi_over = true - Triggers.platform_activated = nil + Triggers.idle = nil Triggers.platform_switch = nil Triggers.projectile_switch = nil Triggers.tag_switch = nil end -function accivi_platform_activated(polygon) - if polygon.index == 638 then - accivi_over() +function accivi_idle() + if Players[0].monster.polygon.index == 639 then + accivi_over() end end From fe206069c77f52e0b8cb54fc76f1f3a41fa4e742 Mon Sep 17 00:00:00 2001 From: Hopper262 Date: Wed, 28 Aug 2024 22:41:02 -0400 Subject: [PATCH 55/58] Avoid destructive recalculations during poly height changes; fixes #492 --- Source_Files/GameWorld/map.h | 4 ++-- Source_Files/GameWorld/map_constructors.cpp | 23 ++++++++++++++------- Source_Files/Lua/lua_map.cpp | 13 ++++++------ 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Source_Files/GameWorld/map.h b/Source_Files/GameWorld/map.h index a05104ca7..a2366475c 100644 --- a/Source_Files/GameWorld/map.h +++ b/Source_Files/GameWorld/map.h @@ -1292,8 +1292,8 @@ void precalculate_map_indexes(void); void touch_polygon(short polygon_index); void recalculate_redundant_polygon_data(short polygon_index); -void recalculate_redundant_endpoint_data(short endpoint_index); -void recalculate_redundant_line_data(short line_index); +void recalculate_redundant_endpoint_data(short endpoint_index, bool only_for_heights = false); +void recalculate_redundant_line_data(short line_index, bool only_for_heights = false); void recalculate_redundant_side_data(short side_index, short line_index); void calculate_endpoint_polygon_owners(short endpoint_index, short *first_index, short *index_count); diff --git a/Source_Files/GameWorld/map_constructors.cpp b/Source_Files/GameWorld/map_constructors.cpp index ff72795d5..4922669cd 100644 --- a/Source_Files/GameWorld/map_constructors.cpp +++ b/Source_Files/GameWorld/map_constructors.cpp @@ -227,7 +227,8 @@ void recalculate_redundant_polygon_data( /* calculates solidity, highest adjacent floor and lowest adjacent ceiling; not to be called at runtime. */ void recalculate_redundant_endpoint_data( - short endpoint_index) + short endpoint_index, + bool only_for_heights) { struct endpoint_data *endpoint= get_endpoint_data(endpoint_index); world_distance highest_adjacent_floor_height= INT16_MIN; @@ -278,9 +279,12 @@ void recalculate_redundant_endpoint_data( } } - SET_ENDPOINT_SOLIDITY(endpoint, solid); - SET_ENDPOINT_TRANSPARENCY(endpoint, transparent); - SET_ENDPOINT_ELEVATION(endpoint, elevation); + if (!only_for_heights) + { + SET_ENDPOINT_SOLIDITY(endpoint, solid); + SET_ENDPOINT_TRANSPARENCY(endpoint, transparent); + SET_ENDPOINT_ELEVATION(endpoint, elevation); + } endpoint->highest_adjacent_floor_height= highest_adjacent_floor_height; endpoint->lowest_adjacent_ceiling_height= lowest_adjacent_ceiling_height; endpoint->supporting_polygon_index= supporting_polygon_index; @@ -289,7 +293,8 @@ void recalculate_redundant_endpoint_data( /* calculates line length, highest adjacent floor and lowest adjacent ceiling and calls recalculate_redundant_side_data() on the line’s sides */ void recalculate_redundant_line_data( - short line_index) + short line_index, + bool only_for_heights) { struct line_data *line= get_line_data(line_index); struct side_data *clockwise_side= NULL, *counterclockwise_side= NULL; @@ -299,8 +304,9 @@ void recalculate_redundant_line_data( bool transparent_texture= false; /* recalculate line length */ - line->length= distance2d(&(get_endpoint_data(line->endpoint_indexes[0])->vertex), - &(get_endpoint_data(line->endpoint_indexes[1])->vertex)); + if (only_for_heights) + line->length= distance2d(&(get_endpoint_data(line->endpoint_indexes[0])->vertex), + &(get_endpoint_data(line->endpoint_indexes[1])->vertex)); /* find highest adjacent floor and lowest adjacent ceiling */ { @@ -341,6 +347,9 @@ void recalculate_redundant_line_data( } } + if (only_for_heights) + return; + if (line->clockwise_polygon_side_index!=NONE) { recalculate_redundant_side_data(line->clockwise_polygon_side_index, line_index); diff --git a/Source_Files/Lua/lua_map.cpp b/Source_Files/Lua/lua_map.cpp index 0a76f5846..1e7f7eb7d 100644 --- a/Source_Files/Lua/lua_map.cpp +++ b/Source_Files/Lua/lua_map.cpp @@ -739,8 +739,8 @@ static int Lua_Polygon_Floor_Set_Height(lua_State *L) polygon->floor_height = static_cast(lua_tonumber(L,2)*WORLD_ONE); for (short i = 0; i < polygon->vertex_count; ++i) { - recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i]); - recalculate_redundant_line_data(polygon->line_indexes[i]); + recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i], true); + recalculate_redundant_line_data(polygon->line_indexes[i], true); } return 0; } @@ -893,8 +893,8 @@ static int Lua_Polygon_Ceiling_Set_Height(lua_State *L) polygon->ceiling_height = static_cast(lua_tonumber(L,2)*WORLD_ONE); for (short i = 0; i < polygon->vertex_count; ++i) { - recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i]); - recalculate_redundant_line_data(polygon->line_indexes[i]); + recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i], true); + recalculate_redundant_line_data(polygon->line_indexes[i], true); } return 0; } @@ -1270,6 +1270,7 @@ const luaL_Reg Lua_Polygon_Sides_Metatable[] = { {0, 0} }; +static void update_line_redundancy(short line_index); int Lua_Polygon_Change_Height(lua_State* L) { if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3)) @@ -1287,8 +1288,8 @@ int Lua_Polygon_Change_Height(lua_State* L) auto polygon = get_polygon_data(polygon_index); for (auto i = 0; i < polygon->vertex_count; ++i) { - recalculate_redundant_line_data(polygon->line_indexes[i]); - recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i]); + recalculate_redundant_line_data(polygon->line_indexes[i], true); + recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i], true); } } From bd8f25a429a34dea20302468b7e688addc11252b Mon Sep 17 00:00:00 2001 From: Hopper262 Date: Wed, 28 Aug 2024 23:16:50 -0400 Subject: [PATCH 56/58] enable Lua .empty for all side textures; closes #514 --- Source_Files/Lua/lua_map.cpp | 46 ++++++++++++++++++++++++++++++++++++ docs/Lua.html | 4 ++-- docs/Lua.xml | 4 ++-- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/Source_Files/Lua/lua_map.cpp b/Source_Files/Lua/lua_map.cpp index 1e7f7eb7d..90107f641 100644 --- a/Source_Files/Lua/lua_map.cpp +++ b/Source_Files/Lua/lua_map.cpp @@ -1892,6 +1892,12 @@ static int Lua_Primary_Side_Get_Collection(lua_State *L) return 1; } +static int Lua_Primary_Side_Get_Empty(lua_State *L) +{ + lua_pushboolean(L, get_side_data(Lua_Primary_Side::Index(L, 1))->primary_texture.texture == UNONE); + return 1; +} + static int Lua_Primary_Side_Get_Light(lua_State *L) { Lua_Light::Push(L, get_side_data(Lua_Primary_Side::Index(L, 1))->primary_lightsource_index); @@ -1966,6 +1972,21 @@ static int Lua_Primary_Side_Set_Collection(lua_State *L) return 0; } +static int Lua_Primary_Side_Set_Empty(lua_State *L) +{ + short side_index = Lua_Primary_Side::Index(L, 1); + if (!lua_isboolean(L, 2)) + return luaL_error(L, "empty: incorrect argument type"); + + if (lua_toboolean(L, 2)) + { + side_data *side = get_side_data(side_index); + side->primary_texture.texture = UNONE; + update_line_redundancy(side->line_index); + } + return 0; +} + static int Lua_Primary_Side_Set_Light(lua_State *L) { short light_index; @@ -2026,6 +2047,7 @@ static int Lua_Primary_Side_Set_Transfer_Mode(lua_State *L) } const luaL_Reg Lua_Primary_Side_Get[] = { {"collection", Lua_Primary_Side_Get_Collection}, + {"empty", Lua_Primary_Side_Get_Empty}, {"light", Lua_Primary_Side_Get_Light}, {"texture_index", Lua_Primary_Side_Get_Texture_Index}, {"texture_x", Lua_Primary_Side_Get_Texture_X}, @@ -2036,6 +2058,7 @@ const luaL_Reg Lua_Primary_Side_Get[] = { const luaL_Reg Lua_Primary_Side_Set[] = { {"collection", Lua_Primary_Side_Set_Collection}, + {"empty", Lua_Primary_Side_Set_Empty}, {"light", Lua_Primary_Side_Set_Light}, {"texture_index", Lua_Primary_Side_Set_Texture_Index}, {"texture_x", Lua_Primary_Side_Set_Texture_X}, @@ -2053,6 +2076,12 @@ static int Lua_Secondary_Side_Get_Collection(lua_State *L) return 1; } +static int Lua_Secondary_Side_Get_Empty(lua_State *L) +{ + lua_pushboolean(L, get_side_data(Lua_Secondary_Side::Index(L, 1))->secondary_texture.texture == UNONE); + return 1; +} + static int Lua_Secondary_Side_Get_Light(lua_State *L) { Lua_Light::Push(L, get_side_data(Lua_Secondary_Side::Index(L, 1))->secondary_lightsource_index); @@ -2094,6 +2123,21 @@ static int Lua_Secondary_Side_Set_Collection(lua_State *L) return 0; } +static int Lua_Secondary_Side_Set_Empty(lua_State *L) +{ + short side_index = Lua_Secondary_Side::Index(L, 1); + if (!lua_isboolean(L, 2)) + return luaL_error(L, "empty: incorrect argument type"); + + if (lua_toboolean(L, 2)) + { + side_data *side = get_side_data(side_index); + side->secondary_texture.texture = UNONE; + update_line_redundancy(side->line_index); + } + return 0; +} + static int Lua_Secondary_Side_Set_Light(lua_State *L) { short light_index; @@ -2154,6 +2198,7 @@ static int Lua_Secondary_Side_Set_Transfer_Mode(lua_State *L) } const luaL_Reg Lua_Secondary_Side_Get[] = { {"collection", Lua_Secondary_Side_Get_Collection}, + {"empty", Lua_Secondary_Side_Get_Empty}, {"light", Lua_Secondary_Side_Get_Light}, {"texture_index", Lua_Secondary_Side_Get_Texture_Index}, {"texture_x", Lua_Secondary_Side_Get_Texture_X}, @@ -2164,6 +2209,7 @@ const luaL_Reg Lua_Secondary_Side_Get[] = { const luaL_Reg Lua_Secondary_Side_Set[] = { {"collection", Lua_Secondary_Side_Set_Collection}, + {"empty", Lua_Secondary_Side_Set_Empty}, {"light", Lua_Secondary_Side_Set_Light}, {"texture_index", Lua_Secondary_Side_Set_Texture_Index}, {"texture_x", Lua_Secondary_Side_Set_Texture_X}, diff --git a/docs/Lua.html b/docs/Lua.html index 1001b26d2..9d7b02eeb 100644 --- a/docs/Lua.html +++ b/docs/Lua.html @@ -2100,8 +2100,8 @@

texture collection

.empty
-

whether transparent side is empty

-

transparent side only

+

whether side is empty

+

transparent sides only in earlier versions Git

setting empty to false is a no-op; set collection and texture_index instead

.light
diff --git a/docs/Lua.xml b/docs/Lua.xml index da7c38952..3f7c9b8ab 100644 --- a/docs/Lua.xml +++ b/docs/Lua.xml @@ -2097,9 +2097,9 @@ end collection - whether transparent side is empty + whether side is empty boolean - transparent side only + transparent sides only in earlier versions setting empty to false is a no-op; set collection and texture_index instead From 836bcfd880f21d037fe1e25458dbc99bf3029750 Mon Sep 17 00:00:00 2001 From: Kolfering Date: Fri, 30 Aug 2024 16:11:45 +0200 Subject: [PATCH 57/58] Don't let people send empty messages in game gathering/joining dialogs too --- Source_Files/Network/Metaserver/network_metaserver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source_Files/Network/Metaserver/network_metaserver.cpp b/Source_Files/Network/Metaserver/network_metaserver.cpp index 1a1709abf..0697e7fd5 100644 --- a/Source_Files/Network/Metaserver/network_metaserver.cpp +++ b/Source_Files/Network/Metaserver/network_metaserver.cpp @@ -515,6 +515,7 @@ MetaserverClient::pumpAll() void MetaserverClient::sendChatMessage(const std::string& message) { + if (message.empty()) return; if (message == ".available" || message == ".avail") { if(m_notificationAdapter) { string players = "Available Players: "; From f54650be32dbf40e148ea0324699f65fd8cd11b1 Mon Sep 17 00:00:00 2001 From: Hopper262 Date: Fri, 30 Aug 2024 15:26:22 -0400 Subject: [PATCH 58/58] Revert "Avoid destructive recalculations during poly height changes; fixes #492" This reverts commit fe206069c77f52e0b8cb54fc76f1f3a41fa4e742. --- Source_Files/GameWorld/map.h | 4 ++-- Source_Files/GameWorld/map_constructors.cpp | 23 +++++++-------------- Source_Files/Lua/lua_map.cpp | 13 ++++++------ 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/Source_Files/GameWorld/map.h b/Source_Files/GameWorld/map.h index a2366475c..a05104ca7 100644 --- a/Source_Files/GameWorld/map.h +++ b/Source_Files/GameWorld/map.h @@ -1292,8 +1292,8 @@ void precalculate_map_indexes(void); void touch_polygon(short polygon_index); void recalculate_redundant_polygon_data(short polygon_index); -void recalculate_redundant_endpoint_data(short endpoint_index, bool only_for_heights = false); -void recalculate_redundant_line_data(short line_index, bool only_for_heights = false); +void recalculate_redundant_endpoint_data(short endpoint_index); +void recalculate_redundant_line_data(short line_index); void recalculate_redundant_side_data(short side_index, short line_index); void calculate_endpoint_polygon_owners(short endpoint_index, short *first_index, short *index_count); diff --git a/Source_Files/GameWorld/map_constructors.cpp b/Source_Files/GameWorld/map_constructors.cpp index 4922669cd..ff72795d5 100644 --- a/Source_Files/GameWorld/map_constructors.cpp +++ b/Source_Files/GameWorld/map_constructors.cpp @@ -227,8 +227,7 @@ void recalculate_redundant_polygon_data( /* calculates solidity, highest adjacent floor and lowest adjacent ceiling; not to be called at runtime. */ void recalculate_redundant_endpoint_data( - short endpoint_index, - bool only_for_heights) + short endpoint_index) { struct endpoint_data *endpoint= get_endpoint_data(endpoint_index); world_distance highest_adjacent_floor_height= INT16_MIN; @@ -279,12 +278,9 @@ void recalculate_redundant_endpoint_data( } } - if (!only_for_heights) - { - SET_ENDPOINT_SOLIDITY(endpoint, solid); - SET_ENDPOINT_TRANSPARENCY(endpoint, transparent); - SET_ENDPOINT_ELEVATION(endpoint, elevation); - } + SET_ENDPOINT_SOLIDITY(endpoint, solid); + SET_ENDPOINT_TRANSPARENCY(endpoint, transparent); + SET_ENDPOINT_ELEVATION(endpoint, elevation); endpoint->highest_adjacent_floor_height= highest_adjacent_floor_height; endpoint->lowest_adjacent_ceiling_height= lowest_adjacent_ceiling_height; endpoint->supporting_polygon_index= supporting_polygon_index; @@ -293,8 +289,7 @@ void recalculate_redundant_endpoint_data( /* calculates line length, highest adjacent floor and lowest adjacent ceiling and calls recalculate_redundant_side_data() on the line’s sides */ void recalculate_redundant_line_data( - short line_index, - bool only_for_heights) + short line_index) { struct line_data *line= get_line_data(line_index); struct side_data *clockwise_side= NULL, *counterclockwise_side= NULL; @@ -304,9 +299,8 @@ void recalculate_redundant_line_data( bool transparent_texture= false; /* recalculate line length */ - if (only_for_heights) - line->length= distance2d(&(get_endpoint_data(line->endpoint_indexes[0])->vertex), - &(get_endpoint_data(line->endpoint_indexes[1])->vertex)); + line->length= distance2d(&(get_endpoint_data(line->endpoint_indexes[0])->vertex), + &(get_endpoint_data(line->endpoint_indexes[1])->vertex)); /* find highest adjacent floor and lowest adjacent ceiling */ { @@ -347,9 +341,6 @@ void recalculate_redundant_line_data( } } - if (only_for_heights) - return; - if (line->clockwise_polygon_side_index!=NONE) { recalculate_redundant_side_data(line->clockwise_polygon_side_index, line_index); diff --git a/Source_Files/Lua/lua_map.cpp b/Source_Files/Lua/lua_map.cpp index 90107f641..836dcba6e 100644 --- a/Source_Files/Lua/lua_map.cpp +++ b/Source_Files/Lua/lua_map.cpp @@ -739,8 +739,8 @@ static int Lua_Polygon_Floor_Set_Height(lua_State *L) polygon->floor_height = static_cast(lua_tonumber(L,2)*WORLD_ONE); for (short i = 0; i < polygon->vertex_count; ++i) { - recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i], true); - recalculate_redundant_line_data(polygon->line_indexes[i], true); + recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i]); + recalculate_redundant_line_data(polygon->line_indexes[i]); } return 0; } @@ -893,8 +893,8 @@ static int Lua_Polygon_Ceiling_Set_Height(lua_State *L) polygon->ceiling_height = static_cast(lua_tonumber(L,2)*WORLD_ONE); for (short i = 0; i < polygon->vertex_count; ++i) { - recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i], true); - recalculate_redundant_line_data(polygon->line_indexes[i], true); + recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i]); + recalculate_redundant_line_data(polygon->line_indexes[i]); } return 0; } @@ -1270,7 +1270,6 @@ const luaL_Reg Lua_Polygon_Sides_Metatable[] = { {0, 0} }; -static void update_line_redundancy(short line_index); int Lua_Polygon_Change_Height(lua_State* L) { if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3)) @@ -1288,8 +1287,8 @@ int Lua_Polygon_Change_Height(lua_State* L) auto polygon = get_polygon_data(polygon_index); for (auto i = 0; i < polygon->vertex_count; ++i) { - recalculate_redundant_line_data(polygon->line_indexes[i], true); - recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i], true); + recalculate_redundant_line_data(polygon->line_indexes[i]); + recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i]); } }