From 8fa95a9f24d4caeb21e21ed9a2ed7f7e64a6512b Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 25 Jan 2025 15:42:24 -0800 Subject: [PATCH] plugins and plugin-settings windows are now screen-size-responsive. Race minigame is now a cheap unlock for new accounts but already unlocked for existing ones. --- .efrocachemap | 60 ++++++------ CHANGELOG.md | 2 +- .../ba_data/python/baclassic/_appsubsystem.py | 36 ++++---- src/assets/ba_data/python/baclassic/_store.py | 24 +++-- src/assets/ba_data/python/baenv.py | 2 +- .../ba_data/python/bauiv1lib/coop/browser.py | 74 ++++++++++----- .../python/bauiv1lib/settings/plugins.py | 91 +++++++++++-------- .../bauiv1lib/settings/pluginsettings.py | 60 +++++++----- src/ballistica/shared/ballistica.cc | 2 +- 9 files changed, 209 insertions(+), 142 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 57cd3537..9f577b30 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -432,12 +432,12 @@ "build/assets/ba_data/audio/zoeOw.ogg": "b2d705c31c9dcc1efdc71394764c3beb", "build/assets/ba_data/audio/zoePickup01.ogg": "e9366dc2d2b8ab8b0c4e2c14c02d0789", "build/assets/ba_data/audio/zoeScream01.ogg": "903e0e45ee9b3373e9d9ce20c814374e", - "build/assets/ba_data/data/langdata.json": "8d49fa91845f43ec8bff3ad3f4895e69", - "build/assets/ba_data/data/languages/arabic.json": "32b9849fb8389b8c7798f0b744620318", + "build/assets/ba_data/data/langdata.json": "1155a380ac3dafb994b4f7438a6efa4f", + "build/assets/ba_data/data/languages/arabic.json": "955758fcbd6ceaa19c8984ec04dc409b", "build/assets/ba_data/data/languages/belarussian.json": "009b452aa308bf2b2f7e92d9b78ba5ff", "build/assets/ba_data/data/languages/chinese.json": "5363a79f843e6be7ef47a840f47cc17d", "build/assets/ba_data/data/languages/chinesetraditional.json": "bea0f9c17324591b8261015cbd80a265", - "build/assets/ba_data/data/languages/croatian.json": "66be7ada024c5d5cf813a07b75217e48", + "build/assets/ba_data/data/languages/croatian.json": "1ad9d43f30c6d7ed3b39e2a0e8bfae0b", "build/assets/ba_data/data/languages/czech.json": "3418bee44e69be13b7f72996abe96921", "build/assets/ba_data/data/languages/danish.json": "8e57db30c5250df2abff14a822f83ea7", "build/assets/ba_data/data/languages/dutch.json": "4ba5bbcc0fecddd0aac6ee2c165d1e40", @@ -451,7 +451,7 @@ "build/assets/ba_data/data/languages/hindi.json": "567e6976b3c72f891431ad7fcc62ab16", "build/assets/ba_data/data/languages/hungarian.json": "af801baffb2c06460635dfb04c34bb3e", "build/assets/ba_data/data/languages/indonesian.json": "607ba358179185f032096ea1978e4448", - "build/assets/ba_data/data/languages/italian.json": "8ed7e5b3a277ed1576af100fc944ef7e", + "build/assets/ba_data/data/languages/italian.json": "656dbe1c77d0d4776f3b095384e8dda2", "build/assets/ba_data/data/languages/korean.json": "360760d72832863e1a3451b0a514cb08", "build/assets/ba_data/data/languages/malay.json": "0212e18e54efa202c17505376e5b82fb", "build/assets/ba_data/data/languages/persian.json": "517217e679c768fff4ffec7f8000ab77", @@ -459,10 +459,10 @@ "build/assets/ba_data/data/languages/polish.json": "993b612c5854fc42a78726ed09c65251", "build/assets/ba_data/data/languages/portuguese.json": "99eaba2900ab66b05f0e9f22da4792a2", "build/assets/ba_data/data/languages/romanian.json": "b04345d8c7631d657a69c73eb7be755a", - "build/assets/ba_data/data/languages/russian.json": "780d1857df77ef59104d5dac75415bd6", + "build/assets/ba_data/data/languages/russian.json": "f2d5569c5924f21d02cfa45eabac758c", "build/assets/ba_data/data/languages/serbian.json": "623fa4129a1154c2f32ed7867e56ff6a", "build/assets/ba_data/data/languages/slovak.json": "c11c29708b3742cdc2a92b4fa0d6d29f", - "build/assets/ba_data/data/languages/spanish.json": "83baf596f8d29ebb965051bf280424c6", + "build/assets/ba_data/data/languages/spanish.json": "1e429102b451ccb8c392a352624e8a6c", "build/assets/ba_data/data/languages/swedish.json": "3b179e7333183c70adb0811246b09959", "build/assets/ba_data/data/languages/tamil.json": "ead39b864228696a9b0d19344bc4b5ec", "build/assets/ba_data/data/languages/thai.json": "383540a1e9c7c131ac579f51afc87471", @@ -4174,22 +4174,22 @@ "build/assets/windows/Win32/ucrtbased.dll": "bfd1180c269d3950b76f35a63655e9e1", "build/assets/windows/Win32/vc_redist.x86.exe": "15a5f1f876503885adbdf5b3989b3718", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "92bd286969030fdcc3f0b8ebad115c74", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "711ea2ab6d63356b03ea7a29899afcef", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "513f33f187e85b909793ddd2aa9732a5", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "8e9824b44c359d404e2ad8fcf0f448f8", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "3409817015ddf936d5fc293d9d71c706", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "cb054db65cddf26f667d1842b17f2b7d", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "c97f0757f6282a46aad165ab2411818e", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "8302bf0d0ee175ae28c8fd2e24c71628", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "3f05bbbc8434cafe12b6692344cf5b6a", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "e367580ee6a85f7baf70f13f3e1b4867", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "cdf23977be0849e7e944e0a44cdaf140", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "23e305bc449464c6eef46867cd8c5363", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "0e5fc0e3f78ecc0a1cb382f00690829f", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "afcd6f10eca27f891a3c000fbfe80231", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "1c75953b11ccd3efe5396f2c0add5c9e", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "8d6c40f72e7d1abc922a0567c858b14f", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "e24bb1259608c728a356750e81c536e6", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "2f34a75859192d79062ddcef8b53959a", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "188c2627da68618f1757d7c6264c631a", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "a5e1677bee69b8cdc49a34009dd100c1", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "48991687444dd243c6031e3cee4a1fa8", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "6d664808b8c7644b32c41b25eeca0143", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "6c0ba3f4be9540c30fc09f13e8524fa4", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "378faae22a13d5ef4446fc3c6bb1ef90", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "407e1f9508f9cfeb72bea651c231e66f", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "b23c4ad8cc56228d58dab66e1387b615", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "a6c73f1589742e19c0e9fd19a8bb4e52", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "48fed8f481ad390c12b094a41a0d07ac", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "e5f1362531bab5b937545e149b6d4135", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "8d83a22f2fedcebc2b6327a81e02e7c8", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "fc2cf0933aaee17916c46cec57bff439", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "dc5927b762d684df558dfedf25e4fb70", "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "2ee184af9b80d60afea7f97aba29cb16", "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "37c5f795ccbaeffeb5d6ede4fe9f3c19", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "2ee184af9b80d60afea7f97aba29cb16", @@ -4202,14 +4202,14 @@ "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "d258789fd7bdc5092aab87ccb4601921", "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "314516411d5ac8e991a6f742f399d4de", "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "d258789fd7bdc5092aab87ccb4601921", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "5393242850af9d26c0ee050765ee71cf", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "887c497ef3462b454bd00891e10da33b", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "37afc11cbb5bb3d8d5c617d285fd2ccf", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "36ef12603f477db495d4be42ae8428dc", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "9a935afd3302e43b8c8da97a901ee736", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "d02591202dd1201d6dd2c631344c2396", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "b079ea523eceb09c63f9269e1f2096dd", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "15693ffb865e33c99820ee4d4962a39c", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "728e7999dec1017d1e9f0e9e521885e4", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "6052cd644522f3e174f27db3d51396b1", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "2fe7bf4e33e98872e9f52c71fc061134", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "692d2b8e0e68ded67a935fa72f17f8d2", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "a94e443fe7d96eb9d9e1684fc3a7af0b", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "e8323acf80bcc48b27beab167f4f70f9", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "76645f01806e43775d376e45c84ef855", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "594f4d538e9e910a21c73a8b71e8aaab", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/enums.py": "794d258d59fd17a61752843a9a0551ad", "src/ballistica/base/mgen/pyembed/binding_base.inc": "06042d31df0ff9af96b99477162e2a91", diff --git a/CHANGELOG.md b/CHANGELOG.md index bd3d9988..5efcda5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.37 (build 22248, api 9, 2025-01-23) +### 1.7.37 (build 22251, api 9, 2025-01-25) - Bumping api version to 9. As you'll see below, there's some UI changes that will require a bit of work for any UI mods to adapt to. If your mods don't touch UI stuff at all you can simply bump your api version and call it a day. diff --git a/src/assets/ba_data/python/baclassic/_appsubsystem.py b/src/assets/ba_data/python/baclassic/_appsubsystem.py index a5cec9d0..6a4d0785 100644 --- a/src/assets/ba_data/python/baclassic/_appsubsystem.py +++ b/src/assets/ba_data/python/baclassic/_appsubsystem.py @@ -897,7 +897,7 @@ class ClassicAppSubsystem(babase.AppSubsystem): return babase.Lstr(resource=rsrc) - def required_purchase_for_game(self, game: str) -> str | None: + def required_purchases_for_game(self, game: str) -> list[str]: """Return which purchase (if any) is required for a game.""" # pylint: disable=too-many-return-statements @@ -907,9 +907,9 @@ class ClassicAppSubsystem(babase.AppSubsystem): ): # Special case: Pro used to unlock this. return ( - None + [] if self.accounts.have_pro() - else 'upgrades.infinite_runaround' + else ['upgrades.infinite_runaround'] ) if game in ( 'Challenges:Infinite Onslaught', @@ -917,48 +917,52 @@ class ClassicAppSubsystem(babase.AppSubsystem): ): # Special case: Pro used to unlock this. return ( - None + [] if self.accounts.have_pro() - else 'upgrades.infinite_onslaught' + else ['upgrades.infinite_onslaught'] ) if game in ( 'Challenges:Meteor Shower', 'Challenges:Epic Meteor Shower', ): - return 'games.meteor_shower' + return ['games.meteor_shower'] if game in ( 'Challenges:Target Practice', 'Challenges:Target Practice B', ): - return 'games.target_practice' + return ['games.target_practice'] if game in ( 'Challenges:Ninja Fight', 'Challenges:Pro Ninja Fight', ): - return 'games.ninja_fight' + return ['games.ninja_fight'] + + if game in ('Challenges:Race', 'Challenges:Pro Race'): + return ['games.race'] if game in ('Challenges:Lake Frigid Race',): - return 'maps.lake_frigid' + return ['games.race', 'maps.lake_frigid'] if game in ( 'Challenges:Easter Egg Hunt', 'Challenges:Pro Easter Egg Hunt', ): - return 'games.easter_egg_hunt' + return ['games.easter_egg_hunt'] - return None + return [] def is_game_unlocked(self, game: str) -> bool: """Is a particular game unlocked?""" plus = babase.app.plus assert plus is not None - purchase = self.required_purchase_for_game(game) - if purchase is None: + purchases = self.required_purchases_for_game(game) + if not purchases: return True - out = plus.get_v1_account_product_purchased(purchase) - assert isinstance(out, bool) - return out + for purchase in purchases: + if not plus.get_v1_account_product_purchased(purchase): + return False + return True diff --git a/src/assets/ba_data/python/baclassic/_store.py b/src/assets/ba_data/python/baclassic/_store.py index d316263b..ed5098b7 100644 --- a/src/assets/ba_data/python/baclassic/_store.py +++ b/src/assets/ba_data/python/baclassic/_store.py @@ -90,10 +90,11 @@ class StoreSubsystem: assert babase.app.classic is not None if babase.app.classic.store_items is None: - from bascenev1lib.game import ninjafight - from bascenev1lib.game import meteorshower - from bascenev1lib.game import targetpractice - from bascenev1lib.game import easteregghunt + from bascenev1lib.game.race import RaceGame + from bascenev1lib.game.ninjafight import NinjaFightGame + from bascenev1lib.game.meteorshower import MeteorShowerGame + from bascenev1lib.game.targetpractice import TargetPracticeGame + from bascenev1lib.game.easteregghunt import EasterEggHuntGame # IMPORTANT - need to keep this synced with the master server. # (doing so manually for now) @@ -122,24 +123,28 @@ class StoreSubsystem: 'merch': {}, 'pro': {}, 'maps.lake_frigid': {'map_type': maps.LakeFrigid}, + 'games.race': { + 'gametype': RaceGame, + 'previewTex': 'bigGPreview', + }, 'games.ninja_fight': { - 'gametype': ninjafight.NinjaFightGame, + 'gametype': NinjaFightGame, 'previewTex': 'courtyardPreview', }, 'games.meteor_shower': { - 'gametype': meteorshower.MeteorShowerGame, + 'gametype': MeteorShowerGame, 'previewTex': 'rampagePreview', }, 'games.infinite_onslaught': { - 'gametype': meteorshower.MeteorShowerGame, + 'gametype': MeteorShowerGame, 'previewTex': 'rampagePreview', }, 'games.target_practice': { - 'gametype': targetpractice.TargetPracticeGame, + 'gametype': TargetPracticeGame, 'previewTex': 'doomShroomPreview', }, 'games.easter_egg_hunt': { - 'gametype': easteregghunt.EasterEggHuntGame, + 'gametype': EasterEggHuntGame, 'previewTex': 'towerDPreview', }, 'icons.flag_us': { @@ -380,6 +385,7 @@ class StoreSubsystem: store_layout['minigames'] = [ { 'items': [ + 'games.race', 'games.ninja_fight', 'games.meteor_shower', 'games.target_practice', diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 40416921..907068d2 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -53,7 +53,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 22248 +TARGET_BALLISTICA_BUILD = 22251 TARGET_BALLISTICA_VERSION = '1.7.37' diff --git a/src/assets/ba_data/python/bauiv1lib/coop/browser.py b/src/assets/ba_data/python/bauiv1lib/coop/browser.py index 4b9433b0..d2a144a4 100644 --- a/src/assets/ba_data/python/bauiv1lib/coop/browser.py +++ b/src/assets/ba_data/python/bauiv1lib/coop/browser.py @@ -1022,19 +1022,33 @@ class CoopBrowserWindow(bui.MainWindow): ) return - required_purchase = bui.app.classic.required_purchase_for_game(game) + required_purchases = bui.app.classic.required_purchases_for_game(game) - if ( - required_purchase is not None - and not plus.get_v1_account_product_purchased(required_purchase) - ): - if plus.get_v1_account_state() != 'signed_in': - show_sign_in_prompt() - else: - PurchaseWindow( - items=[required_purchase], origin_widget=origin_widget - ) - return + # Show pop-up to allow purchasing any required stuff we don't have. + for purchase in required_purchases: + if not plus.get_v1_account_product_purchased(purchase): + if plus.get_v1_account_state() != 'signed_in': + show_sign_in_prompt() + else: + PurchaseWindow( + items=[purchase], origin_widget=origin_widget + ) + return + + # if required_purchases and not all( + # plus.get_v1_account_product_purchased(p) + # for p in required_purchases + # ): + # if plus.get_v1_account_state() != 'signed_in': + # show_sign_in_prompt() + # else: + # # Hmm just ask about the first I guess.. They can pop + # # this window back up to the next if they purchase the + # # first. + # PurchaseWindow( + # items=[required_purchases[0]], origin_widget=origin_widget + # ) + # return self._save_state() @@ -1107,18 +1121,34 @@ class CoopBrowserWindow(bui.MainWindow): if tournament_button.game is not None and not classic.is_game_unlocked( tournament_button.game ): - required_purchase = classic.required_purchase_for_game( + required_purchases = classic.required_purchases_for_game( tournament_button.game ) - assert required_purchase is not None - if plus.get_v1_account_state() != 'signed_in': - show_sign_in_prompt() - else: - PurchaseWindow( - items=[required_purchase], - origin_widget=tournament_button.button, - ) - return + # We gotta be missing *something* if its locked. + assert required_purchases + + for purchase in required_purchases: + if not plus.get_v1_account_product_purchased(purchase): + if plus.get_v1_account_state() != 'signed_in': + show_sign_in_prompt() + else: + PurchaseWindow( + items=[purchase], + origin_widget=tournament_button.button, + ) + return + + # assert required_purchases + # if plus.get_v1_account_state() != 'signed_in': + # show_sign_in_prompt() + # else: + # # Hmm; just show the first requirement. They can come + # # back to see more after they purchase the first. + # PurchaseWindow( + # items=[required_purchases[0]], + # origin_widget=tournament_button.button, + # ) + # return if tournament_button.time_remaining <= 0: bui.screenmessage( diff --git a/src/assets/ba_data/python/bauiv1lib/settings/plugins.py b/src/assets/ba_data/python/bauiv1lib/settings/plugins.py index 40d2f26c..283e371a 100644 --- a/src/assets/ba_data/python/bauiv1lib/settings/plugins.py +++ b/src/assets/ba_data/python/bauiv1lib/settings/plugins.py @@ -36,46 +36,58 @@ class PluginWindow(bui.MainWindow): transition: str | None = 'in_right', origin_widget: bui.Widget | None = None, ): + # pylint: disable=too-many-locals app = bui.app self._category = Category.ALL assert bui.app.classic is not None uiscale = bui.app.ui_v1.uiscale - self._width = 870.0 if uiscale is bui.UIScale.SMALL else 670.0 - x_inset = 100 if uiscale is bui.UIScale.SMALL else 0 - yoffs = -55.0 if uiscale is bui.UIScale.SMALL else 0 + self._width = 1200.0 if uiscale is bui.UIScale.SMALL else 670.0 self._height = ( - 450.0 + 900.0 if uiscale is bui.UIScale.SMALL else 450.0 if uiscale is bui.UIScale.MEDIUM else 520.0 ) - top_extra = 0 if uiscale is bui.UIScale.SMALL else 0 + + # Do some fancy math to fill all available screen area up to the + # size of our backing container. This lets us fit to the exact + # screen shape at small ui scale. + screensize = bui.get_virtual_screen_size() + scale = ( + 1.9 + if uiscale is bui.UIScale.SMALL + else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0 + ) + # Calc screen size in our local container space and clamp to a + # bit smaller than our container size. + target_width = min(self._width - 80, screensize[0] / scale) + target_height = min(self._height - 80, screensize[1] / scale) + + # To get top/left coords, go to the center of our window and + # offset by half the width/height of our target area. + yoffs = 0.5 * self._height + 0.5 * target_height + 20.0 + + self._scroll_width = target_width + self._scroll_height = target_height - 40 + self._scroll_bottom = yoffs - 64 - self._scroll_height + super().__init__( root_widget=bui.containerwidget( - size=(self._width, self._height + top_extra), + size=(self._width, self._height), toolbar_visibility=( 'menu_minimal' if uiscale is bui.UIScale.SMALL else 'menu_full' ), - scale=( - 1.9 - if uiscale is bui.UIScale.SMALL - else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0 - ), - stack_offset=( - (0, 0) if uiscale is bui.UIScale.SMALL else (0, 0) - ), + scale=scale, ), transition=transition, origin_widget=origin_widget, + # We're affected by screen size only at small ui-scale. + refresh_on_screen_size_changes=uiscale is bui.UIScale.SMALL, ) - self._scroll_width = self._width - (100 + 2 * x_inset) - self._scroll_height = self._height - ( - 200.0 if uiscale is bui.UIScale.SMALL else 115.0 - ) self._sub_width = self._scroll_width * 0.95 self._sub_height = 724.0 @@ -88,12 +100,12 @@ class PluginWindow(bui.MainWindow): else: self._back_button = bui.buttonwidget( parent=self._root_widget, - position=(53 + x_inset, self._height - 60 + yoffs), - size=(140, 60), + position=(53, yoffs - 49), + size=(60, 60), scale=0.8, autoselect=True, - label=bui.Lstr(resource='backText'), - button_type='back', + label=bui.charstr(bui.SpecialChar.BACK), + button_type='backSmall', on_activate_call=self.main_window_back, ) bui.containerwidget( @@ -102,7 +114,10 @@ class PluginWindow(bui.MainWindow): self._title_text = bui.textwidget( parent=self._root_widget, - position=(self._width * 0.5, self._height - 41 + yoffs), + position=( + self._width * 0.5, + yoffs - (42 if uiscale is bui.UIScale.SMALL else 30), + ), size=(0, 0), text=bui.Lstr(resource='pluginsText'), color=app.ui_v1.title_color, @@ -111,19 +126,16 @@ class PluginWindow(bui.MainWindow): v_align='center', ) - if self._back_button is not None: - bui.buttonwidget( - edit=self._back_button, - button_type='backSmall', - size=(60, 60), - label=bui.charstr(bui.SpecialChar.BACK), - ) - - settings_button_x = 670 if uiscale is bui.UIScale.SMALL else 570 + settings_button_x = ( + self._width * 0.5 + + self._scroll_width * 0.5 + - (100 if uiscale is bui.UIScale.SMALL else 40) + ) + button_row_yoffs = yoffs + (-2 if uiscale is bui.UIScale.SMALL else 10) self._num_plugins_text = bui.textwidget( parent=self._root_widget, - position=(settings_button_x - 130, self._height - 41 + yoffs), + position=(settings_button_x - 130, button_row_yoffs - 41), size=(0, 0), text='', h_align='center', @@ -133,7 +145,7 @@ class PluginWindow(bui.MainWindow): self._category_button = bui.buttonwidget( parent=self._root_widget, scale=0.7, - position=(settings_button_x - 105, self._height - 60 + yoffs), + position=(settings_button_x - 105, button_row_yoffs - 60), size=(130, 60), label=bui.Lstr(resource='allText'), autoselect=True, @@ -144,7 +156,7 @@ class PluginWindow(bui.MainWindow): self._settings_button = bui.buttonwidget( parent=self._root_widget, - position=(settings_button_x, self._height - 58 + yoffs), + position=(settings_button_x, button_row_yoffs - 58), size=(40, 40), label='', on_activate_call=self._open_settings, @@ -152,7 +164,7 @@ class PluginWindow(bui.MainWindow): bui.imagewidget( parent=self._root_widget, - position=(settings_button_x + 3, self._height - 57 + yoffs), + position=(settings_button_x + 3, button_row_yoffs - 57), draw_controller=self._settings_button, size=(35, 35), texture=bui.gettexture('settingsIcon'), @@ -166,15 +178,16 @@ class PluginWindow(bui.MainWindow): self._scrollwidget = bui.scrollwidget( parent=self._root_widget, + size=(self._scroll_width, self._scroll_height), position=( - 50 + x_inset, - (135 if uiscale is bui.UIScale.SMALL else 50) + yoffs, + self._width * 0.5 - self._scroll_width * 0.5, + self._scroll_bottom, ), simple_culling_v=20.0, highlight=False, - size=(self._scroll_width, self._scroll_height), selection_loops_to_parent=True, claims_left_right=True, + border_opacity=0.4, ) bui.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) diff --git a/src/assets/ba_data/python/bauiv1lib/settings/pluginsettings.py b/src/assets/ba_data/python/bauiv1lib/settings/pluginsettings.py index 19024b6b..9d3344ce 100644 --- a/src/assets/ba_data/python/bauiv1lib/settings/pluginsettings.py +++ b/src/assets/ba_data/python/bauiv1lib/settings/pluginsettings.py @@ -21,42 +21,52 @@ class PluginSettingsWindow(bui.MainWindow): assert bui.app.classic is not None uiscale = bui.app.ui_v1.uiscale - width = 750.0 if uiscale is bui.UIScale.SMALL else 470.0 - height = 400.0 if uiscale is bui.UIScale.SMALL else 300.0 - yoffs = -20 if uiscale is bui.UIScale.SMALL else 0 + self._width = 1200.0 if uiscale is bui.UIScale.SMALL else 470.0 + self._height = 900.0 if uiscale is bui.UIScale.SMALL else 360.0 + + # Do some fancy math to fill all available screen area up to the + # size of our backing container. This lets us fit to the exact + # screen shape at small ui scale. + screensize = bui.get_virtual_screen_size() + scale = ( + 2.06 + if uiscale is bui.UIScale.SMALL + else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0 + ) + # Calc screen size in our local container space and clamp to a + # bit smaller than our container size. + # target_width = min(self._width - 60, screensize[0] / scale) + target_height = min(self._height - 100, screensize[1] / scale) + + # To get top/left coords, go to the center of our window and + # offset by half the width/height of our target area. + self._yoffs = 0.5 * self._height + 0.5 * target_height + 30.0 super().__init__( root_widget=bui.containerwidget( - size=(width, height), + size=(self._width, self._height), toolbar_visibility=( 'menu_minimal' if uiscale is bui.UIScale.SMALL else 'menu_full' ), - scale=( - 2.06 - if uiscale is bui.UIScale.SMALL - else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0 - ), - stack_offset=( - (0, 0) if uiscale is bui.UIScale.SMALL else (0, 0) - ), + scale=scale, ), transition=transition, origin_widget=origin_widget, + # We're affected by screen size only at small ui-scale. + refresh_on_screen_size_changes=uiscale is bui.UIScale.SMALL, ) if uiscale is bui.UIScale.SMALL: - xoffs = 135 self._back_button = bui.get_special_widget('back_button') bui.containerwidget( edit=self._root_widget, on_cancel_call=self.main_window_back ) else: - xoffs = 0 self._back_button = bui.buttonwidget( parent=self._root_widget, - position=(53, height - 60 + yoffs), + position=(55, self._yoffs - 33), size=(60, 60), scale=0.8, autoselect=True, @@ -71,20 +81,24 @@ class PluginSettingsWindow(bui.MainWindow): self._title_text = bui.textwidget( parent=self._root_widget, position=( - width * 0.5, - height - (55 if uiscale is bui.UIScale.SMALL else 35) + yoffs, + self._width * 0.5, + self._yoffs - (55 if uiscale is bui.UIScale.SMALL else 10), ), size=(0, 0), text=bui.Lstr(resource='pluginSettingsText'), + maxwidth=230, color=bui.app.ui_v1.title_color, h_align='center', v_align='center', ) - self._y_position = height - 140 + yoffs + # Roughly center our few bits of content. + x = self._width * 0.5 - 175 + y = self._height * 0.5 + 30 + self._enable_plugins_button = bui.buttonwidget( parent=self._root_widget, - position=(xoffs + 65, self._y_position + yoffs), + position=(x, y), size=(350, 60), autoselect=True, label=bui.Lstr(resource='pluginsEnableAllText'), @@ -94,10 +108,10 @@ class PluginSettingsWindow(bui.MainWindow): ), ) - self._y_position -= 70 + y -= 70 self._disable_plugins_button = bui.buttonwidget( parent=self._root_widget, - position=(xoffs + 65, self._y_position + yoffs), + position=(x, y), size=(350, 60), autoselect=True, label=bui.Lstr(resource='pluginsDisableAllText'), @@ -107,10 +121,10 @@ class PluginSettingsWindow(bui.MainWindow): ), ) - self._y_position -= 70 + y -= 70 self._enable_new_plugins_check_box = bui.checkboxwidget( parent=self._root_widget, - position=(xoffs + 65, self._y_position + yoffs), + position=(x, y), size=(350, 60), value=bui.app.config.get( bui.app.plugins.AUTO_ENABLE_NEW_PLUGINS_CONFIG_KEY, diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index f74b2305..362f69c3 100644 --- a/src/ballistica/shared/ballistica.cc +++ b/src/ballistica/shared/ballistica.cc @@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int { namespace ballistica { // These are set automatically via script; don't modify them here. -const int kEngineBuildNumber = 22248; +const int kEngineBuildNumber = 22251; const char* kEngineVersion = "1.7.37"; const int kEngineApiVersion = 9;