mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-19 13:25:31 +08:00
Lots of stuff. Chests now functional for tourneys
This commit is contained in:
parent
690da5a3da
commit
2190568baf
111
.efrocachemap
generated
111
.efrocachemap
generated
@ -53,6 +53,7 @@
|
||||
"build/assets/ba_data/audio/assassinFall.ogg": "201d192debe8bda9e9dead28e9cc6939",
|
||||
"build/assets/ba_data/audio/assassinHit1.ogg": "caaab755b159e399b121be1aec8f61b9",
|
||||
"build/assets/ba_data/audio/assassinHit2.ogg": "a08ac94f02040af67bc46eff6a691a84",
|
||||
"build/assets/ba_data/audio/aww.ogg": "80cf7a35a58ec6633d3c5440764de3f5",
|
||||
"build/assets/ba_data/audio/bear1.ogg": "acddcf643e9fbf8d92eacf50992c81d0",
|
||||
"build/assets/ba_data/audio/bear2.ogg": "74f7ce4f64e0fb943ab4ec34fdc83779",
|
||||
"build/assets/ba_data/audio/bear3.ogg": "142d1f3d021c8639fbbc1a2ed0f3dc93",
|
||||
@ -95,6 +96,7 @@
|
||||
"build/assets/ba_data/audio/cheer.ogg": "b9f1cce825ca00295b61b088f353715b",
|
||||
"build/assets/ba_data/audio/click01.ogg": "204f93a3eb7d82cf8ca9172ee5f01c11",
|
||||
"build/assets/ba_data/audio/corkPop.ogg": "7b0bdbb0cdaf40ec5adf3311ecfe620a",
|
||||
"build/assets/ba_data/audio/corkPop2.ogg": "1ad5aff84af244acb2f3eaf95ddb7f6a",
|
||||
"build/assets/ba_data/audio/cowboy1.ogg": "e12671599d7f6fa7e246b3ad4d83ad7d",
|
||||
"build/assets/ba_data/audio/cowboy2.ogg": "0cd227e165a76bf829ac0e3ac129929c",
|
||||
"build/assets/ba_data/audio/cowboy3.ogg": "9ce2c947a9ddcf9c6e793721d5b1eb66",
|
||||
@ -121,6 +123,7 @@
|
||||
"build/assets/ba_data/audio/dingSmallHigh.ogg": "73ce9e68ef59847dc7621d38ed019c42",
|
||||
"build/assets/ba_data/audio/dripity.ogg": "db450cee4e5241fbaa80a2874cb3cf7f",
|
||||
"build/assets/ba_data/audio/drumRoll.ogg": "8d8234c10e7b9dee277a4e26aec3c9e1",
|
||||
"build/assets/ba_data/audio/drumRollShort.ogg": "b4273cdd69c0b09bd1da5146a6b1bc76",
|
||||
"build/assets/ba_data/audio/error.ogg": "a39731636b92282052e15eb5b9413816",
|
||||
"build/assets/ba_data/audio/explosion01.ogg": "51bba8fc738410a61da8d535d8485a20",
|
||||
"build/assets/ba_data/audio/explosion02.ogg": "b4ce0ea7abd1c5b52ad7a868f1029a2d",
|
||||
@ -147,6 +150,7 @@
|
||||
"build/assets/ba_data/audio/frostyHit02.ogg": "c608e2ce52c872d701110367fa447656",
|
||||
"build/assets/ba_data/audio/frostyHit03.ogg": "20860a3e0acd4104d2b62ac4a624749f",
|
||||
"build/assets/ba_data/audio/fuse01.ogg": "f24744d8b4590b5898015dd98b2b9374",
|
||||
"build/assets/ba_data/audio/gasp.ogg": "91b267abf7015cf36d263e961f83856b",
|
||||
"build/assets/ba_data/audio/gladiator1.ogg": "528596df10aec80417a4df83325fc09d",
|
||||
"build/assets/ba_data/audio/gladiator2.ogg": "a0f42843c7a73523e90ed32d766959f1",
|
||||
"build/assets/ba_data/audio/gladiator3.ogg": "b3fa702291a4da6f439e72481177a5c2",
|
||||
@ -218,6 +222,7 @@
|
||||
"build/assets/ba_data/audio/menuMusic.ogg": "b25ee0041baf71b08c7650ae9f4daab0",
|
||||
"build/assets/ba_data/audio/metalHit.ogg": "ced0188b46245cd60b248fc7bc13b706",
|
||||
"build/assets/ba_data/audio/metalSkid.ogg": "a069f5022be74229c008a19b3e00e64c",
|
||||
"build/assets/ba_data/audio/nice.ogg": "fb362c97a244ed3a2c2f98c38691fb00",
|
||||
"build/assets/ba_data/audio/ninjaAttack1.ogg": "82c98bc81f3e3e224ddd3151be918dd6",
|
||||
"build/assets/ba_data/audio/ninjaAttack2.ogg": "1f0952bb9df1877fbb9e05b8649b63da",
|
||||
"build/assets/ba_data/audio/ninjaAttack3.ogg": "e5edefe727e4fe2bcb16ab90edc36c39",
|
||||
@ -287,6 +292,7 @@
|
||||
"build/assets/ba_data/audio/raceBeep1.ogg": "2d271c487cefbd67f15a21a0904b3e1f",
|
||||
"build/assets/ba_data/audio/raceBeep2.ogg": "47cf9d039e19a3446444bfeb82b394b6",
|
||||
"build/assets/ba_data/audio/refWhistle.ogg": "8ebbde5488b834e73f1d8ee4dad8b1f3",
|
||||
"build/assets/ba_data/audio/revUp.ogg": "19862620186556029821e41b403f3a11",
|
||||
"build/assets/ba_data/audio/robot1.ogg": "feed97d9abb23097d659b10c6276bab8",
|
||||
"build/assets/ba_data/audio/robot2.ogg": "d9fc996427452f76b0527d5ca84983af",
|
||||
"build/assets/ba_data/audio/robot3.ogg": "bf766b82d438323f89fe4688dd78f5ef",
|
||||
@ -395,7 +401,11 @@
|
||||
"build/assets/ba_data/audio/wizardFall.ogg": "e422bd05ae30a28b02b1c55fb0c1fa00",
|
||||
"build/assets/ba_data/audio/wizardHit1.ogg": "7686120c658c811064efda94ac3e90ca",
|
||||
"build/assets/ba_data/audio/wizardHit2.ogg": "d245e07803be7158da49d4962ccf483a",
|
||||
"build/assets/ba_data/audio/woo.ogg": "e84ef95cb1d97b65ff529687d6076da9",
|
||||
"build/assets/ba_data/audio/woo2.ogg": "5dfb2e489f406d11772f96ded5611c4f",
|
||||
"build/assets/ba_data/audio/woo3.ogg": "637878bb31decb36e6db7a5295eea933",
|
||||
"build/assets/ba_data/audio/woodDebrisFall.ogg": "e163c84d87821e3e19ec8b0bf1fef9a7",
|
||||
"build/assets/ba_data/audio/wow.ogg": "581d224d771195bde72548509cc1cc32",
|
||||
"build/assets/ba_data/audio/wrestler1.ogg": "7486e02349206e8082b44105d0a1195c",
|
||||
"build/assets/ba_data/audio/wrestler2.ogg": "0f197b1d7e6c2e0cc86e57d1b53581aa",
|
||||
"build/assets/ba_data/audio/wrestler3.ogg": "911ad7c64018e8d5fa5f722a04de8837",
|
||||
@ -404,6 +414,7 @@
|
||||
"build/assets/ba_data/audio/wrestlerFall.ogg": "3c6bb84fb09a0829fd60066b1807a16c",
|
||||
"build/assets/ba_data/audio/wrestlerHit1.ogg": "1950d463514448069f0d3c0f00108eaa",
|
||||
"build/assets/ba_data/audio/wrestlerHit2.ogg": "5b549fb2406fd72d1d0947fc8173cc08",
|
||||
"build/assets/ba_data/audio/yeah.ogg": "2c55f21c39cf5f41a81317dec3f5d7fa",
|
||||
"build/assets/ba_data/audio/zoeAttack01.ogg": "0b0536b8afba7cb773beffeaa2e4bb90",
|
||||
"build/assets/ba_data/audio/zoeAttack02.ogg": "931a5b3d78e2322443fe1e51e6c25b99",
|
||||
"build/assets/ba_data/audio/zoeAttack03.ogg": "e1d1f58f038bedda8c22fc518aa37c7e",
|
||||
@ -421,21 +432,21 @@
|
||||
"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": "ce2f76ab5f36cbc0212d1b3c424eb954",
|
||||
"build/assets/ba_data/data/langdata.json": "dbbd8f26d2f85c0b649d461e991b80cb",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "3c22e7b6d7b09a812a2e28b35c9e9241",
|
||||
"build/assets/ba_data/data/languages/belarussian.json": "0b60a9d4496d1213c2d0b647d346ce30",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "fc45d2838b834889c06920ae7c2102fa",
|
||||
"build/assets/ba_data/data/languages/chinesetraditional.json": "904b35b656c53f9830e406565edd5120",
|
||||
"build/assets/ba_data/data/languages/croatian.json": "1e541070309ff6be95b0c39940aa7e99",
|
||||
"build/assets/ba_data/data/languages/croatian.json": "e131a87cf5783e0fbb3d211a927efe1a",
|
||||
"build/assets/ba_data/data/languages/czech.json": "d18b7d1c6bf51fc81af4084ef0e69e3e",
|
||||
"build/assets/ba_data/data/languages/danish.json": "8e57db30c5250df2abff14a822f83ea7",
|
||||
"build/assets/ba_data/data/languages/dutch.json": "f4e1e8e9231cda9d1bcc7e87a7f8821e",
|
||||
"build/assets/ba_data/data/languages/english.json": "b5917c3b975155e35fedb655dbd7568c",
|
||||
"build/assets/ba_data/data/languages/dutch.json": "4085dec5af362cf068b494524ced3872",
|
||||
"build/assets/ba_data/data/languages/english.json": "527d106870b0690cc39a80b88e60ab7a",
|
||||
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "3d9269a90a2fee164d0a7513c4f130a3",
|
||||
"build/assets/ba_data/data/languages/french.json": "6d20655730b1017ef187fd828b91d43c",
|
||||
"build/assets/ba_data/data/languages/german.json": "a150dbb5c0f43984757f7db295d96203",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "df76e851aee59657b69e34efd54fee06",
|
||||
"build/assets/ba_data/data/languages/german.json": "b92ec951b5a0ce4f73677051ca59a06b",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "2569fe1b2f686670f825e2faaa8c5dc3",
|
||||
"build/assets/ba_data/data/languages/greek.json": "d28d1092fbb00ed857cbd53124c0dc78",
|
||||
"build/assets/ba_data/data/languages/hindi.json": "567e6976b3c72f891431ad7fcc62ab16",
|
||||
"build/assets/ba_data/data/languages/hungarian.json": "9d88004a98f0fbe2ea72edd5e0b3002e",
|
||||
@ -451,7 +462,7 @@
|
||||
"build/assets/ba_data/data/languages/russian.json": "fc64ed6b6356ea11385ee5c20748425a",
|
||||
"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": "499b464318a8c9d1fb271cf480862b57",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "f8ab976d219e579546bb98b6d7fd12ce",
|
||||
"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",
|
||||
@ -1362,10 +1373,18 @@
|
||||
"build/assets/ba_data/textures/chestIconMulti.ktx": "c026aa573aab141044b503437ffdaeea",
|
||||
"build/assets/ba_data/textures/chestIconMulti.pvr": "3f41eaa108068751ba40e08964c45ec0",
|
||||
"build/assets/ba_data/textures/chestIconMulti_preview.png": "47b6839bdc19ad9e3d3d6282ce0138dd",
|
||||
"build/assets/ba_data/textures/chestIconTint.dds": "04c079c1a79d548ca02969e9934d591b",
|
||||
"build/assets/ba_data/textures/chestIconTint.ktx": "ff39e97211bb71f59091aac2f51ebbed",
|
||||
"build/assets/ba_data/textures/chestIconTint.pvr": "129b44259f8b62c0e1d4c08612b9c691",
|
||||
"build/assets/ba_data/textures/chestIconTint_preview.png": "022f3f8bb8bc9c082dbb21958ec8722f",
|
||||
"build/assets/ba_data/textures/chestIcon_preview.png": "d3046ccf2fedefa9ad766054e350a5d6",
|
||||
"build/assets/ba_data/textures/chestOpenIcon.dds": "325e93c7147c3bf098857d0e3eff4a73",
|
||||
"build/assets/ba_data/textures/chestOpenIcon.ktx": "562afa582aa621b946c22460e0caca61",
|
||||
"build/assets/ba_data/textures/chestOpenIcon.pvr": "703c88d07b9ab22cbab647677eb05370",
|
||||
"build/assets/ba_data/textures/chestOpenIconTint.dds": "c3003ed402d46da9d5c8351f028c5d95",
|
||||
"build/assets/ba_data/textures/chestOpenIconTint.ktx": "d32fe2152a1bf6feff1f2416627b2023",
|
||||
"build/assets/ba_data/textures/chestOpenIconTint.pvr": "bd665e8289bfd5c369c473e973dd2d65",
|
||||
"build/assets/ba_data/textures/chestOpenIconTint_preview.png": "e5a2377c127998faaef83e06d4cc2584",
|
||||
"build/assets/ba_data/textures/chestOpenIcon_preview.png": "40ae165451f052265d07ea62f7d08713",
|
||||
"build/assets/ba_data/textures/circle.dds": "0f4c08ab481dcadce164227a146fdb62",
|
||||
"build/assets/ba_data/textures/circle.ktx": "a6ff1b802324d1874aaa9c24050cfcf3",
|
||||
@ -2359,6 +2378,10 @@
|
||||
"build/assets/ba_data/textures/sparks.ktx": "919af9b0b1b2e756c232c34bc15d506a",
|
||||
"build/assets/ba_data/textures/sparks.pvr": "249e98bbadad09b59f0e8bdd46b1c9b1",
|
||||
"build/assets/ba_data/textures/sparks_preview.png": "9b6b74000a0f56899dd09a956a864ec9",
|
||||
"build/assets/ba_data/textures/spinner.dds": "54b0a3a695689974defcb7d0ddc40101",
|
||||
"build/assets/ba_data/textures/spinner.ktx": "9e47f8b7dcca8f061bff6a04a30a2833",
|
||||
"build/assets/ba_data/textures/spinner.pvr": "312c7ffa74c39d262d00971881ecd93b",
|
||||
"build/assets/ba_data/textures/spinner_preview.png": "680af969ab856865098dfcf4fb8b6845",
|
||||
"build/assets/ba_data/textures/star.dds": "e799668a604f3e680f7676994e894c1d",
|
||||
"build/assets/ba_data/textures/star.ktx": "725da9d09a93c636bd825788f859c62d",
|
||||
"build/assets/ba_data/textures/star.pvr": "bb68b74f455c36dcd7a40f9d38b5c74f",
|
||||
@ -4103,47 +4126,47 @@
|
||||
"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": "390472d8d44b0a650796bfd6022d0549",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "23f27d6f139c653f23a15a0af7f7e02c",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "097b082f8f5abb18d824b2044da1de78",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "c027478f038af2faedcc4103e75bc39d",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "5c7f18d5ff9eb14421fe3743550ddf57",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "cef0bc0d149a4c433c2e4bee5b47414a",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "25546af5cf64a0e1e1d1f46b38298820",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "7f172d6c531c371837302f370f77db08",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "0d79db47846defaffaa0bf97ec6b23fc",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "45373e10bb60989787e415ae938756fe",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "0cc3834e81761efdc50babed9e5c7151",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "4e28c4abb0e7128d08f2b84a87d8a765",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "96b856d3db5d061527383b42e588a333",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "124afb5eec04365e42b059b0c2ec98e7",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "0271c53794bdb4a762ae7210d9828fb7",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "f8b3744f90503502618130c8d28f1aa4",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "33a0ae6f1ea5a0b0c60055ce01478488",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "aad882eaf2230b89973e2cf4f13c9759",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "33a0ae6f1ea5a0b0c60055ce01478488",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "aad882eaf2230b89973e2cf4f13c9759",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "c20929c73caa78445525c5788b6963e0",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "0f21a43d99552df99e0d21c646e6e698",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "c20929c73caa78445525c5788b6963e0",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "0f21a43d99552df99e0d21c646e6e698",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "01dab862a43d9e7c4ee4e49212442d42",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "ae4e3f563892f6b9311c4b7284f28c11",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "01dab862a43d9e7c4ee4e49212442d42",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "ae4e3f563892f6b9311c4b7284f28c11",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "2f581e3dead7038e5b94bc096a7b8c80",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "4538ad0d6b4794de96fb78742ebcdc84",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "0d1a2f2066ae412549034e981ae39e2c",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "55180e66455f91d3af8f15c0c81607a4",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "bb2c15187840ef373ae79cdf1623d3b5",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "8ee1bb4440c364f9fa91791276d64b87",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "863f70d88ab9b3c7c6910d94e26b6f35",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "bb928df1aa05c84889b45f2a00544e64",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "2444899f2f36667dc27fcf5537fc76b6",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "efebe5318abe421031108d9908b4cb84",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "9b4928361ff7e3aa85ea6cca5f3903d8",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "9fad073f6fd49702ceb1ee5057c4f9de",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "ac52ed0994f33ea4997da21d0a7f6877",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "43f429f37c145fc2bf80c01dfd095a7e",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "ea87a5838b465c40b60ff911cccbe189",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "3cafa3287637bba5e56b363bb4fc8f9a",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "1fbe4ab96f25d20b421c8206c9230948",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "0a4dbc635f8e9b3f42e89dd2027bd9d3",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "6114856f2ab42ef6b20a1affdf53032d",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "bfa75071d993efc3853fa350c1de2bcb",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "3971d8deb2c33cfd18c4e3b338d48ec3",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "bd0c352337d72f020b431feca7974c3a",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "073b3690cfb03847ac3b3fe9c017e520",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "c7f0d9c4db7a67b4d72f3c406c585897",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "1c375e8003442dd3d059bc0baa260e61",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "40daac4bbc8990d5140f97e792bc4fb1",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "1c375e8003442dd3d059bc0baa260e61",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "40daac4bbc8990d5140f97e792bc4fb1",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "19af08729bed7249eaf9acd697966f3f",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "97d2486072bf3a83edb0250ea2d3e69e",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "19af08729bed7249eaf9acd697966f3f",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "97d2486072bf3a83edb0250ea2d3e69e",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "51884d81e2d7bdeb6b59a72f0247c8e1",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "36bb6f32ab12e2a46b82155a93b2e527",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "51884d81e2d7bdeb6b59a72f0247c8e1",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "36bb6f32ab12e2a46b82155a93b2e527",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "f629e97c70198ab3688f11ab4a2d1e97",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "a868c0116adf9f48f503b50b50c70cd8",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "04216607232edde485d139e9e96c6612",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "bdc158a2dfd592cd8dcb235a162a82fe",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "4a0340814c6034b39b2c08287935e26a",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "546ccf01f342463d46302b05c0171044",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "67bb2ff991e00433c1abba2044a0d21e",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "8653a52a8fd75c527c976abb9d223e90",
|
||||
"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",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base_app.inc": "2d228e7c5578261d394f9c407f4becb1",
|
||||
"src/ballistica/classic/mgen/pyembed/binding_classic.inc": "fc09126750304b2761049aa9d93a951e",
|
||||
"src/ballistica/classic/mgen/pyembed/binding_classic.inc": "8ab156122cde23d9718923abe1b4ae5b",
|
||||
"src/ballistica/core/mgen/pyembed/binding_core.inc": "217c84a30f866aaca3a4373e82af7db2",
|
||||
"src/ballistica/core/mgen/pyembed/env.inc": "f015d726b44d2922112fc14d9f146d8b",
|
||||
"src/ballistica/core/mgen/python_modules_monolithic.h": "fb967ed1c7db0c77d8deb4f00a7103c5",
|
||||
|
||||
17
CHANGELOG.md
17
CHANGELOG.md
@ -1,4 +1,4 @@
|
||||
### 1.7.37 (build 22155, api 9, 2024-12-31)
|
||||
### 1.7.37 (build 22178, api 9, 2025-01-11)
|
||||
- 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.
|
||||
@ -176,6 +176,21 @@
|
||||
should use arrow keys for navigation. To update any old UI code, search for
|
||||
and remove any 'claims_tab' arguments to UI calls since that argument no
|
||||
longer exists.
|
||||
- Added a `get_unknown_type_fallback()` method to `dataclassio.IOMultiType`.
|
||||
This be defined to allow multi-type data to be loadable even in the presence
|
||||
of new types it doesn't recognize.
|
||||
- Added a `lossy` arg to `dataclassio.dataclass_from_dict()` and
|
||||
`dataclassio.dataclass_from_json()`. Enum value fallbacks and the new
|
||||
multitype fallbacks are now only applied when `lossy` is True. This also flags
|
||||
the returned dataclass to prevent it from being serialized back out. Fallbacks
|
||||
are useful for forward compatibility, but they are also dangerous in that they
|
||||
can silently modify/destroy data, so this mechanism will hopefully help keep
|
||||
them used safely.
|
||||
- Added a spinner widget (creatable via `bauiv1.spinnerwidget()`). This should
|
||||
help things look more alive than the static 'loading...' text I've been using
|
||||
in various places.
|
||||
- Tournament now award chests instead of tickets.
|
||||
- Tournaments are now free to enter if you are running this build or newer.
|
||||
|
||||
### 1.7.36 (build 21944, api 8, 2024-07-26)
|
||||
- Wired up Tokens, BombSquad's new purchasable currency. The first thing these
|
||||
|
||||
@ -772,6 +772,8 @@ set(BALLISTICA_SOURCES
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/widget/row_widget.h
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/widget/scroll_widget.cc
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/widget/scroll_widget.h
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/widget/spinner_widget.cc
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/widget/spinner_widget.h
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/widget/stack_widget.cc
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/widget/stack_widget.h
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/widget/text_widget.cc
|
||||
|
||||
@ -764,6 +764,8 @@
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\widget\row_widget.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\scroll_widget.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\widget\scroll_widget.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\spinner_widget.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\widget\spinner_widget.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\stack_widget.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\widget\stack_widget.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\text_widget.cc" />
|
||||
|
||||
@ -1726,6 +1726,12 @@
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\widget\scroll_widget.h">
|
||||
<Filter>ballistica\ui_v1\widget</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\spinner_widget.cc">
|
||||
<Filter>ballistica\ui_v1\widget</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\widget\spinner_widget.h">
|
||||
<Filter>ballistica\ui_v1\widget</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\stack_widget.cc">
|
||||
<Filter>ballistica\ui_v1\widget</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@ -759,6 +759,8 @@
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\widget\row_widget.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\scroll_widget.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\widget\scroll_widget.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\spinner_widget.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\widget\spinner_widget.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\stack_widget.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\widget\stack_widget.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\text_widget.cc" />
|
||||
|
||||
@ -1726,6 +1726,12 @@
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\widget\scroll_widget.h">
|
||||
<Filter>ballistica\ui_v1\widget</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\spinner_widget.cc">
|
||||
<Filter>ballistica\ui_v1\widget</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\widget\spinner_widget.h">
|
||||
<Filter>ballistica\ui_v1\widget</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\stack_widget.cc">
|
||||
<Filter>ballistica\ui_v1\widget</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cpplint==2.0.0
|
||||
dmgbuild==1.6.2
|
||||
dmgbuild==1.6.4
|
||||
filelock==3.16.1
|
||||
furo==2024.8.6
|
||||
mypy==1.14.1
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
"ba_data/audio/assassinFall.ogg",
|
||||
"ba_data/audio/assassinHit1.ogg",
|
||||
"ba_data/audio/assassinHit2.ogg",
|
||||
"ba_data/audio/aww.ogg",
|
||||
"ba_data/audio/bear1.ogg",
|
||||
"ba_data/audio/bear2.ogg",
|
||||
"ba_data/audio/bear3.ogg",
|
||||
@ -94,6 +95,7 @@
|
||||
"ba_data/audio/cheer.ogg",
|
||||
"ba_data/audio/click01.ogg",
|
||||
"ba_data/audio/corkPop.ogg",
|
||||
"ba_data/audio/corkPop2.ogg",
|
||||
"ba_data/audio/cowboy1.ogg",
|
||||
"ba_data/audio/cowboy2.ogg",
|
||||
"ba_data/audio/cowboy3.ogg",
|
||||
@ -120,6 +122,7 @@
|
||||
"ba_data/audio/dingSmallHigh.ogg",
|
||||
"ba_data/audio/dripity.ogg",
|
||||
"ba_data/audio/drumRoll.ogg",
|
||||
"ba_data/audio/drumRollShort.ogg",
|
||||
"ba_data/audio/error.ogg",
|
||||
"ba_data/audio/explosion01.ogg",
|
||||
"ba_data/audio/explosion02.ogg",
|
||||
@ -146,6 +149,7 @@
|
||||
"ba_data/audio/frostyHit02.ogg",
|
||||
"ba_data/audio/frostyHit03.ogg",
|
||||
"ba_data/audio/fuse01.ogg",
|
||||
"ba_data/audio/gasp.ogg",
|
||||
"ba_data/audio/gladiator1.ogg",
|
||||
"ba_data/audio/gladiator2.ogg",
|
||||
"ba_data/audio/gladiator3.ogg",
|
||||
@ -217,6 +221,7 @@
|
||||
"ba_data/audio/menuMusic.ogg",
|
||||
"ba_data/audio/metalHit.ogg",
|
||||
"ba_data/audio/metalSkid.ogg",
|
||||
"ba_data/audio/nice.ogg",
|
||||
"ba_data/audio/ninjaAttack1.ogg",
|
||||
"ba_data/audio/ninjaAttack2.ogg",
|
||||
"ba_data/audio/ninjaAttack3.ogg",
|
||||
@ -286,6 +291,7 @@
|
||||
"ba_data/audio/raceBeep1.ogg",
|
||||
"ba_data/audio/raceBeep2.ogg",
|
||||
"ba_data/audio/refWhistle.ogg",
|
||||
"ba_data/audio/revUp.ogg",
|
||||
"ba_data/audio/robot1.ogg",
|
||||
"ba_data/audio/robot2.ogg",
|
||||
"ba_data/audio/robot3.ogg",
|
||||
@ -394,7 +400,11 @@
|
||||
"ba_data/audio/wizardFall.ogg",
|
||||
"ba_data/audio/wizardHit1.ogg",
|
||||
"ba_data/audio/wizardHit2.ogg",
|
||||
"ba_data/audio/woo.ogg",
|
||||
"ba_data/audio/woo2.ogg",
|
||||
"ba_data/audio/woo3.ogg",
|
||||
"ba_data/audio/woodDebrisFall.ogg",
|
||||
"ba_data/audio/wow.ogg",
|
||||
"ba_data/audio/wrestler1.ogg",
|
||||
"ba_data/audio/wrestler2.ogg",
|
||||
"ba_data/audio/wrestler3.ogg",
|
||||
@ -403,6 +413,7 @@
|
||||
"ba_data/audio/wrestlerFall.ogg",
|
||||
"ba_data/audio/wrestlerHit1.ogg",
|
||||
"ba_data/audio/wrestlerHit2.ogg",
|
||||
"ba_data/audio/yeah.ogg",
|
||||
"ba_data/audio/zoeAttack01.ogg",
|
||||
"ba_data/audio/zoeAttack02.ogg",
|
||||
"ba_data/audio/zoeAttack03.ogg",
|
||||
@ -1401,10 +1412,18 @@
|
||||
"ba_data/textures/chestIconMulti.ktx",
|
||||
"ba_data/textures/chestIconMulti.pvr",
|
||||
"ba_data/textures/chestIconMulti_preview.png",
|
||||
"ba_data/textures/chestIconTint.dds",
|
||||
"ba_data/textures/chestIconTint.ktx",
|
||||
"ba_data/textures/chestIconTint.pvr",
|
||||
"ba_data/textures/chestIconTint_preview.png",
|
||||
"ba_data/textures/chestIcon_preview.png",
|
||||
"ba_data/textures/chestOpenIcon.dds",
|
||||
"ba_data/textures/chestOpenIcon.ktx",
|
||||
"ba_data/textures/chestOpenIcon.pvr",
|
||||
"ba_data/textures/chestOpenIconTint.dds",
|
||||
"ba_data/textures/chestOpenIconTint.ktx",
|
||||
"ba_data/textures/chestOpenIconTint.pvr",
|
||||
"ba_data/textures/chestOpenIconTint_preview.png",
|
||||
"ba_data/textures/chestOpenIcon_preview.png",
|
||||
"ba_data/textures/circle.dds",
|
||||
"ba_data/textures/circle.ktx",
|
||||
@ -2398,6 +2417,10 @@
|
||||
"ba_data/textures/sparks.ktx",
|
||||
"ba_data/textures/sparks.pvr",
|
||||
"ba_data/textures/sparks_preview.png",
|
||||
"ba_data/textures/spinner.dds",
|
||||
"ba_data/textures/spinner.ktx",
|
||||
"ba_data/textures/spinner.pvr",
|
||||
"ba_data/textures/spinner_preview.png",
|
||||
"ba_data/textures/star.dds",
|
||||
"ba_data/textures/star.ktx",
|
||||
"ba_data/textures/star.pvr",
|
||||
|
||||
@ -77,6 +77,8 @@
|
||||
"ba_data/python/baclassic/__pycache__/_appmode.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_appsubsystem.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_benchmark.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_chest.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_clienteffect.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_input.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_music.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_net.cpython-312.opt-1.pyc",
|
||||
@ -93,6 +95,8 @@
|
||||
"ba_data/python/baclassic/_appmode.py",
|
||||
"ba_data/python/baclassic/_appsubsystem.py",
|
||||
"ba_data/python/baclassic/_benchmark.py",
|
||||
"ba_data/python/baclassic/_chest.py",
|
||||
"ba_data/python/baclassic/_clienteffect.py",
|
||||
"ba_data/python/baclassic/_input.py",
|
||||
"ba_data/python/baclassic/_music.py",
|
||||
"ba_data/python/baclassic/_net.py",
|
||||
@ -107,6 +111,7 @@
|
||||
"ba_data/python/bacommon/__pycache__/app.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bacommon/__pycache__/assets.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bacommon/__pycache__/bacloud.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bacommon/__pycache__/bs.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bacommon/__pycache__/build.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bacommon/__pycache__/cloud.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bacommon/__pycache__/loggercontrol.cpython-312.opt-1.pyc",
|
||||
@ -118,6 +123,7 @@
|
||||
"ba_data/python/bacommon/app.py",
|
||||
"ba_data/python/bacommon/assets.py",
|
||||
"ba_data/python/bacommon/bacloud.py",
|
||||
"ba_data/python/bacommon/bs.py",
|
||||
"ba_data/python/bacommon/build.py",
|
||||
"ba_data/python/bacommon/cloud.py",
|
||||
"ba_data/python/bacommon/loggercontrol.py",
|
||||
@ -603,6 +609,7 @@
|
||||
"ba_data/python/efro/dataclassio/__pycache__/_pathcapture.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/efro/dataclassio/__pycache__/_prep.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/efro/dataclassio/__pycache__/extras.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/efro/dataclassio/__pycache__/templatemultitype.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/efro/dataclassio/_api.py",
|
||||
"ba_data/python/efro/dataclassio/_base.py",
|
||||
"ba_data/python/efro/dataclassio/_inputter.py",
|
||||
@ -610,6 +617,7 @@
|
||||
"ba_data/python/efro/dataclassio/_pathcapture.py",
|
||||
"ba_data/python/efro/dataclassio/_prep.py",
|
||||
"ba_data/python/efro/dataclassio/extras.py",
|
||||
"ba_data/python/efro/dataclassio/templatemultitype.py",
|
||||
"ba_data/python/efro/debug.py",
|
||||
"ba_data/python/efro/error.py",
|
||||
"ba_data/python/efro/logging.py",
|
||||
|
||||
@ -206,6 +206,8 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_appmode.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_appsubsystem.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_benchmark.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_chest.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_clienteffect.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_input.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_music.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_net.py \
|
||||
@ -486,6 +488,8 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_appmode.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_appsubsystem.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_benchmark.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_chest.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_clienteffect.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_input.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_music.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_net.cpython-312.opt-1.pyc \
|
||||
@ -738,6 +742,7 @@ SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/app.py \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/assets.py \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/bacloud.py \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/bs.py \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/build.py \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/cloud.py \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/loggercontrol.py \
|
||||
@ -759,6 +764,7 @@ SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \
|
||||
$(BUILD_DIR)/ba_data/python/efro/dataclassio/_pathcapture.py \
|
||||
$(BUILD_DIR)/ba_data/python/efro/dataclassio/_prep.py \
|
||||
$(BUILD_DIR)/ba_data/python/efro/dataclassio/extras.py \
|
||||
$(BUILD_DIR)/ba_data/python/efro/dataclassio/templatemultitype.py \
|
||||
$(BUILD_DIR)/ba_data/python/efro/debug.py \
|
||||
$(BUILD_DIR)/ba_data/python/efro/error.py \
|
||||
$(BUILD_DIR)/ba_data/python/efro/logging.py \
|
||||
@ -778,6 +784,7 @@ SCRIPT_TARGETS_PYC_PUBLIC_TOOLS = \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/app.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/assets.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/bacloud.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/bs.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/build.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/cloud.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/loggercontrol.cpython-312.opt-1.pyc \
|
||||
@ -799,6 +806,7 @@ SCRIPT_TARGETS_PYC_PUBLIC_TOOLS = \
|
||||
$(BUILD_DIR)/ba_data/python/efro/dataclassio/__pycache__/_pathcapture.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/efro/dataclassio/__pycache__/_prep.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/efro/dataclassio/__pycache__/extras.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/efro/dataclassio/__pycache__/templatemultitype.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/efro/__pycache__/debug.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/efro/__pycache__/error.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/efro/__pycache__/logging.cpython-312.opt-1.pyc \
|
||||
@ -5259,6 +5267,7 @@ AUDIO_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/audio/assassinFall.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/assassinHit1.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/assassinHit2.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/aww.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/bear1.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/bear2.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/bear3.ogg \
|
||||
@ -5301,6 +5310,7 @@ AUDIO_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/audio/cheer.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/click01.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/corkPop.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/corkPop2.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/cowboy1.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/cowboy2.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/cowboy3.ogg \
|
||||
@ -5327,6 +5337,7 @@ AUDIO_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/audio/dingSmallHigh.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/dripity.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/drumRoll.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/drumRollShort.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/error.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/explosion01.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/explosion02.ogg \
|
||||
@ -5353,6 +5364,7 @@ AUDIO_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/audio/frostyHit02.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/frostyHit03.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/fuse01.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/gasp.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/gladiator1.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/gladiator2.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/gladiator3.ogg \
|
||||
@ -5424,6 +5436,7 @@ AUDIO_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/audio/menuMusic.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/metalHit.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/metalSkid.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/nice.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/ninjaAttack1.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/ninjaAttack2.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/ninjaAttack3.ogg \
|
||||
@ -5493,6 +5506,7 @@ AUDIO_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/audio/raceBeep1.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/raceBeep2.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/refWhistle.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/revUp.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/robot1.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/robot2.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/robot3.ogg \
|
||||
@ -5601,7 +5615,11 @@ AUDIO_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/audio/wizardFall.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/wizardHit1.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/wizardHit2.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/woo.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/woo2.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/woo3.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/woodDebrisFall.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/wow.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/wrestler1.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/wrestler2.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/wrestler3.ogg \
|
||||
@ -5610,6 +5628,7 @@ AUDIO_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/audio/wrestlerFall.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/wrestlerHit1.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/wrestlerHit2.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/yeah.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/zoeAttack01.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/zoeAttack02.ogg \
|
||||
$(BUILD_DIR)/ba_data/audio/zoeAttack03.ogg \
|
||||
@ -5723,7 +5742,9 @@ TEX2D_DDS_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIcon.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIconEmpty.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIconMulti.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIconTint.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/chestOpenIcon.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/chestOpenIconTint.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/circle.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/circleNoAlpha.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/circleOutline.dds \
|
||||
@ -5972,6 +5993,7 @@ TEX2D_DDS_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/textures/softRect2.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/softRectVertical.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/sparks.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/spinner.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/star.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/startButton.dds \
|
||||
$(BUILD_DIR)/ba_data/textures/stepRightUpLevelColor.dds \
|
||||
@ -6135,7 +6157,9 @@ TEX2D_PVR_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIcon.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIconEmpty.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIconMulti.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIconTint.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/chestOpenIcon.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/chestOpenIconTint.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/circle.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/circleNoAlpha.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/circleOutline.pvr \
|
||||
@ -6384,6 +6408,7 @@ TEX2D_PVR_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/textures/softRect2.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/softRectVertical.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/sparks.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/spinner.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/star.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/startButton.pvr \
|
||||
$(BUILD_DIR)/ba_data/textures/stepRightUpLevelColor.pvr \
|
||||
@ -6547,7 +6572,9 @@ TEX2D_KTX_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIcon.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIconEmpty.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIconMulti.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIconTint.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/chestOpenIcon.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/chestOpenIconTint.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/circle.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/circleNoAlpha.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/circleOutline.ktx \
|
||||
@ -6796,6 +6823,7 @@ TEX2D_KTX_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/textures/softRect2.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/softRectVertical.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/sparks.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/spinner.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/star.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/startButton.ktx \
|
||||
$(BUILD_DIR)/ba_data/textures/stepRightUpLevelColor.ktx \
|
||||
@ -6958,7 +6986,9 @@ TEX2D_PREVIEW_PNG_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/textures/characterIconMask_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIconEmpty_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIconMulti_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIconTint_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/chestIcon_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/chestOpenIconTint_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/chestOpenIcon_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/circleNoAlpha_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/circleOutlineNoAlpha_preview.png \
|
||||
@ -7208,6 +7238,7 @@ TEX2D_PREVIEW_PNG_TARGETS = \
|
||||
$(BUILD_DIR)/ba_data/textures/softRectVertical_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/softRect_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/sparks_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/spinner_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/star_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/startButton_preview.png \
|
||||
$(BUILD_DIR)/ba_data/textures/stepRightUpLevelColor_preview.png \
|
||||
|
||||
@ -68,9 +68,10 @@ class App:
|
||||
health_monitor: AppHealthMonitor
|
||||
|
||||
# How long we allow shutdown tasks to run before killing them.
|
||||
# Currently the entire app hard-exits if shutdown takes 10 seconds,
|
||||
# so we need to keep it under that.
|
||||
SHUTDOWN_TASK_TIMEOUT_SECONDS = 5
|
||||
# Currently the entire app hard-exits if shutdown takes 15 seconds,
|
||||
# so we need to keep it under that. Staying above 10 should allow
|
||||
# 10 second network timeouts to happen though.
|
||||
SHUTDOWN_TASK_TIMEOUT_SECONDS = 12
|
||||
|
||||
class State(Enum):
|
||||
"""High level state the app can be in."""
|
||||
|
||||
@ -30,7 +30,9 @@ def utc_now_cloud() -> datetime.datetime:
|
||||
|
||||
Applies offsets pulled from server communication/etc.
|
||||
"""
|
||||
# FIXME - do something smart here.
|
||||
# TODO: wire this up. Just using local time for now. Make sure that
|
||||
# BaseFeatureSet::TimeSinceEpochCloudSeconds() and this are synced
|
||||
# up.
|
||||
return utc_now()
|
||||
|
||||
|
||||
|
||||
@ -2,18 +2,11 @@
|
||||
#
|
||||
"""Components for the classic BombSquad experience.
|
||||
|
||||
This package is used as a dumping ground for functionality that is
|
||||
necessary to keep classic BombSquad working, but which may no longer be
|
||||
the best way to do things going forward.
|
||||
|
||||
New code should try to avoid using code from here when possible.
|
||||
|
||||
Functionality in this package should be exposed through the
|
||||
ClassicAppSubsystem. This allows type-checked code to go through the
|
||||
babase.app.classic singleton which forces it to explicitly handle the
|
||||
possibility of babase.app.classic being None. When code instead imports
|
||||
classic submodules directly, it is much harder to make it cleanly handle
|
||||
classic not being present.
|
||||
This package/feature-set contains functionality related to the classic
|
||||
BombSquad experience. Note that much legacy BombSquad code is still a
|
||||
bit tangled and thus this feature-set is largely inseperable from
|
||||
scenev1 and uiv1. Future feature-sets will be designed in a more modular
|
||||
way.
|
||||
"""
|
||||
|
||||
# ba_meta require api 9
|
||||
@ -29,8 +22,16 @@ from efro.util import set_canonical_module_names
|
||||
from baclassic._appmode import ClassicAppMode
|
||||
from baclassic._appsubsystem import ClassicAppSubsystem
|
||||
from baclassic._achievement import Achievement, AchievementSubsystem
|
||||
from baclassic._chest import (
|
||||
ChestAppearanceDisplayInfo,
|
||||
CHEST_APPEARANCE_DISPLAY_INFO_DEFAULT,
|
||||
CHEST_APPEARANCE_DISPLAY_INFOS,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'ChestAppearanceDisplayInfo',
|
||||
'CHEST_APPEARANCE_DISPLAY_INFO_DEFAULT',
|
||||
'CHEST_APPEARANCE_DISPLAY_INFOS',
|
||||
'ClassicAppMode',
|
||||
'ClassicAppSubsystem',
|
||||
'Achievement',
|
||||
|
||||
@ -197,9 +197,9 @@ class ClassicAppMode(babase.AppMode):
|
||||
if account is None:
|
||||
self._account_data_sub = None
|
||||
_baclassic.set_root_ui_account_values(
|
||||
tickets_text='',
|
||||
tokens_text='',
|
||||
league_rank_text='',
|
||||
tickets=-1,
|
||||
tokens=-1,
|
||||
league_rank=-1,
|
||||
league_type='',
|
||||
achievements_percent_text='',
|
||||
level_text='',
|
||||
@ -250,7 +250,7 @@ class ClassicAppMode(babase.AppMode):
|
||||
print(f'GOT SUB TEST UPDATE: {val}')
|
||||
|
||||
def _on_classic_account_data_change(
|
||||
self, val: bacommon.cloud.BSClassicAccountLiveData
|
||||
self, val: bacommon.bs.ClassicAccountLiveData
|
||||
) -> None:
|
||||
# print('ACCOUNT CHANGED:', val)
|
||||
achp = round(val.achievements / max(val.achievements_total, 1) * 100.0)
|
||||
@ -264,11 +264,9 @@ class ClassicAppMode(babase.AppMode):
|
||||
chest3 = val.chests.get('3')
|
||||
|
||||
_baclassic.set_root_ui_account_values(
|
||||
tickets_text=str(val.tickets),
|
||||
tokens_text=str(val.tokens),
|
||||
league_rank_text=(
|
||||
'-' if val.league_rank is None else f'#{val.league_rank}'
|
||||
),
|
||||
tickets=val.tickets,
|
||||
tokens=val.tokens,
|
||||
league_rank=(-1 if val.league_rank is None else val.league_rank),
|
||||
league_type=(
|
||||
'' if val.league_type is None else val.league_type.value
|
||||
),
|
||||
@ -292,17 +290,35 @@ class ClassicAppMode(babase.AppMode):
|
||||
chest_0_unlock_time=(
|
||||
-1.0 if chest0 is None else chest0.unlock_time.timestamp()
|
||||
),
|
||||
chest_1_unlock_time=-1.0,
|
||||
chest_2_unlock_time=-1.0,
|
||||
chest_3_unlock_time=-1.0,
|
||||
chest_1_unlock_time=(
|
||||
-1.0 if chest1 is None else chest1.unlock_time.timestamp()
|
||||
),
|
||||
chest_2_unlock_time=(
|
||||
-1.0 if chest2 is None else chest2.unlock_time.timestamp()
|
||||
),
|
||||
chest_3_unlock_time=(
|
||||
-1.0 if chest3 is None else chest3.unlock_time.timestamp()
|
||||
),
|
||||
chest_0_ad_allow_time=(
|
||||
-1.0
|
||||
if chest0 is None or chest0.ad_allow_time is None
|
||||
else chest0.ad_allow_time.timestamp()
|
||||
),
|
||||
chest_1_ad_allow_time=-1.0,
|
||||
chest_2_ad_allow_time=-1.0,
|
||||
chest_3_ad_allow_time=-1.0,
|
||||
chest_1_ad_allow_time=(
|
||||
-1.0
|
||||
if chest1 is None or chest1.ad_allow_time is None
|
||||
else chest1.ad_allow_time.timestamp()
|
||||
),
|
||||
chest_2_ad_allow_time=(
|
||||
-1.0
|
||||
if chest2 is None or chest2.ad_allow_time is None
|
||||
else chest2.ad_allow_time.timestamp()
|
||||
),
|
||||
chest_3_ad_allow_time=(
|
||||
-1.0
|
||||
if chest3 is None or chest3.ad_allow_time is None
|
||||
else chest3.ad_allow_time.timestamp()
|
||||
),
|
||||
)
|
||||
|
||||
# Note that we have values and updated faded state accordingly.
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
"""Provides classic app subsystem."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, override
|
||||
import random
|
||||
import logging
|
||||
import weakref
|
||||
from typing import TYPE_CHECKING, override, assert_never
|
||||
|
||||
from efro.dataclassio import dataclass_from_dict
|
||||
import babase
|
||||
@ -26,6 +26,7 @@ from baclassic import _input
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any, Sequence
|
||||
|
||||
import bacommon.bs
|
||||
from bascenev1lib.actor import spazappearance
|
||||
from bauiv1lib.party import PartyWindow
|
||||
|
||||
@ -509,11 +510,36 @@ class ClassicAppSubsystem(babase.AppSubsystem):
|
||||
request, 'post', data, callback, response_type
|
||||
).start()
|
||||
|
||||
def get_tournament_prize_strings(self, entry: dict[str, Any]) -> list[str]:
|
||||
def set_tournament_prize_image(
|
||||
self, entry: dict[str, Any], index: int, image: bauiv1.Widget
|
||||
) -> None:
|
||||
"""Given a tournament entry, return strings for its prize levels."""
|
||||
from baclassic import _tournament
|
||||
|
||||
return _tournament.get_tournament_prize_strings(entry)
|
||||
return _tournament.set_tournament_prize_chest_image(entry, index, image)
|
||||
|
||||
def create_in_game_tournament_prize_image(
|
||||
self,
|
||||
entry: dict[str, Any],
|
||||
index: int,
|
||||
position: tuple[float, float],
|
||||
) -> None:
|
||||
"""Given a tournament entry, return strings for its prize levels."""
|
||||
from baclassic import _tournament
|
||||
|
||||
_tournament.create_in_game_tournament_prize_image(
|
||||
entry, index, position
|
||||
)
|
||||
|
||||
def get_tournament_prize_strings(
|
||||
self, entry: dict[str, Any], include_tickets: bool
|
||||
) -> list[str]:
|
||||
"""Given a tournament entry, return strings for its prize levels."""
|
||||
from baclassic import _tournament
|
||||
|
||||
return _tournament.get_tournament_prize_strings(
|
||||
entry, include_tickets=include_tickets
|
||||
)
|
||||
|
||||
def getcampaign(self, name: str) -> bascenev1.Campaign:
|
||||
"""Return a campaign by name."""
|
||||
@ -852,3 +878,48 @@ class ClassicAppSubsystem(babase.AppSubsystem):
|
||||
is_top_level=True,
|
||||
suppress_warning=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def run_bs_client_effects(effects: list[bacommon.bs.ClientEffect]) -> None:
|
||||
"""Run client effects sent from the master server."""
|
||||
from baclassic._clienteffect import run_bs_client_effects
|
||||
|
||||
run_bs_client_effects(effects)
|
||||
|
||||
@staticmethod
|
||||
def basic_client_ui_button_label_str(
|
||||
label: bacommon.bs.BasicClientUI.ButtonLabel,
|
||||
) -> babase.Lstr:
|
||||
"""Given a client-ui label, return an Lstr."""
|
||||
import bacommon.bs
|
||||
|
||||
cls = bacommon.bs.BasicClientUI.ButtonLabel
|
||||
if label is cls.UNKNOWN:
|
||||
# Server should not be sending us unknown stuff; make noise
|
||||
# if they do.
|
||||
logging.error(
|
||||
'Got BasicClientUI.ButtonLabel.UNKNOWN; should not happen.'
|
||||
)
|
||||
return babase.Lstr(value='<error>')
|
||||
|
||||
rsrc: str | None = None
|
||||
if label is cls.OK:
|
||||
rsrc = 'okText'
|
||||
elif label is cls.APPLY:
|
||||
rsrc = 'applyText'
|
||||
elif label is cls.CANCEL:
|
||||
rsrc = 'cancelText'
|
||||
elif label is cls.ACCEPT:
|
||||
rsrc = 'gatherWindow.partyInviteAcceptText'
|
||||
elif label is cls.DECLINE:
|
||||
rsrc = 'gatherWindow.partyInviteDeclineText'
|
||||
elif label is cls.IGNORE:
|
||||
rsrc = 'gatherWindow.partyInviteIgnoreText'
|
||||
elif label is cls.CLAIM:
|
||||
rsrc = 'claimText'
|
||||
elif label is cls.DISCARD:
|
||||
rsrc = 'discardText'
|
||||
else:
|
||||
assert_never(label)
|
||||
|
||||
return babase.Lstr(resource=rsrc)
|
||||
|
||||
91
src/assets/ba_data/python/baclassic/_chest.py
Normal file
91
src/assets/ba_data/python/baclassic/_chest.py
Normal file
@ -0,0 +1,91 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Chest related functionality."""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bacommon.bs import ClassicChestAppearance
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class ChestAppearanceDisplayInfo:
|
||||
"""Info about how to locally display chest appearances."""
|
||||
|
||||
# NOTE TO SELF: Don't rename these attrs; the C++ layer is hard
|
||||
# coded to look for them.
|
||||
|
||||
texclosed: str
|
||||
texclosedtint: str
|
||||
texopen: str
|
||||
texopentint: str
|
||||
color: tuple[float, float, float]
|
||||
tint: tuple[float, float, float]
|
||||
tint2: tuple[float, float, float]
|
||||
|
||||
|
||||
# Info for chest types we know how to draw. Anything not found in here
|
||||
# should fall back to the DEFAULT entry.
|
||||
CHEST_APPEARANCE_DISPLAY_INFO_DEFAULT = ChestAppearanceDisplayInfo(
|
||||
texclosed='chestIcon',
|
||||
texclosedtint='chestIconTint',
|
||||
texopen='chestOpenIcon',
|
||||
texopentint='chestOpenIconTint',
|
||||
color=(1, 1, 1),
|
||||
tint=(1, 1, 1),
|
||||
tint2=(1, 1, 1),
|
||||
)
|
||||
|
||||
CHEST_APPEARANCE_DISPLAY_INFOS: dict[
|
||||
ClassicChestAppearance, ChestAppearanceDisplayInfo
|
||||
] = {
|
||||
ClassicChestAppearance.L2: ChestAppearanceDisplayInfo(
|
||||
texclosed='chestIcon',
|
||||
texclosedtint='chestIconTint',
|
||||
texopen='chestOpenIcon',
|
||||
texopentint='chestOpenIconTint',
|
||||
color=(0.8, 1.0, 0.93),
|
||||
tint=(0.65, 1.0, 0.8),
|
||||
tint2=(0.65, 1.0, 0.8),
|
||||
),
|
||||
ClassicChestAppearance.L3: ChestAppearanceDisplayInfo(
|
||||
texclosed='chestIcon',
|
||||
texclosedtint='chestIconTint',
|
||||
texopen='chestOpenIcon',
|
||||
texopentint='chestOpenIconTint',
|
||||
color=(0.75, 0.9, 1.3),
|
||||
tint=(0.7, 1, 1.9),
|
||||
tint2=(0.7, 1, 1.9),
|
||||
),
|
||||
ClassicChestAppearance.L4: ChestAppearanceDisplayInfo(
|
||||
texclosed='chestIcon',
|
||||
texclosedtint='chestIconTint',
|
||||
texopen='chestOpenIcon',
|
||||
texopentint='chestOpenIconTint',
|
||||
color=(0.7, 1.0, 1.4),
|
||||
tint=(1.4, 1.6, 2.0),
|
||||
tint2=(1.4, 1.6, 2.0),
|
||||
),
|
||||
ClassicChestAppearance.L5: ChestAppearanceDisplayInfo(
|
||||
texclosed='chestIcon',
|
||||
texclosedtint='chestIconTint',
|
||||
texopen='chestOpenIcon',
|
||||
texopentint='chestOpenIconTint',
|
||||
color=(0.75, 0.5, 2.4),
|
||||
tint=(1.0, 0.8, 0.0),
|
||||
tint2=(1.0, 0.8, 0.0),
|
||||
),
|
||||
ClassicChestAppearance.L6: ChestAppearanceDisplayInfo(
|
||||
texclosed='chestIcon',
|
||||
texclosedtint='chestIconTint',
|
||||
texopen='chestOpenIcon',
|
||||
texopentint='chestOpenIconTint',
|
||||
color=(1.1, 0.8, 0.0),
|
||||
tint=(2, 2, 2),
|
||||
tint2=(2, 2, 2),
|
||||
),
|
||||
}
|
||||
77
src/assets/ba_data/python/baclassic/_clienteffect.py
Normal file
77
src/assets/ba_data/python/baclassic/_clienteffect.py
Normal file
@ -0,0 +1,77 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Functionality related to running client-effects from the master server."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, assert_never
|
||||
|
||||
from efro.util import strict_partial
|
||||
|
||||
import bacommon.bs
|
||||
import bauiv1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
def run_bs_client_effects(effects: list[bacommon.bs.ClientEffect]) -> None:
|
||||
"""Run effects."""
|
||||
# pylint: disable=too-many-branches
|
||||
|
||||
delay = 0.0
|
||||
for effect in effects:
|
||||
if isinstance(effect, bacommon.bs.ClientEffectScreenMessage):
|
||||
textfin = bauiv1.Lstr(
|
||||
translate=('serverResponses', effect.message)
|
||||
).evaluate()
|
||||
if effect.subs is not None:
|
||||
# Should always be even.
|
||||
assert len(effect.subs) % 2 == 0
|
||||
for j in range(0, len(effect.subs) - 1, 2):
|
||||
textfin = textfin.replace(
|
||||
effect.subs[j],
|
||||
effect.subs[j + 1],
|
||||
)
|
||||
bauiv1.apptimer(
|
||||
delay,
|
||||
strict_partial(
|
||||
bauiv1.screenmessage, textfin, color=effect.color
|
||||
),
|
||||
)
|
||||
|
||||
elif isinstance(effect, bacommon.bs.ClientEffectSound):
|
||||
smcls = bacommon.bs.ClientEffectSound.Sound
|
||||
soundfile: str | None = None
|
||||
if effect.sound is smcls.UNKNOWN:
|
||||
# Server should avoid sending us sounds we don't
|
||||
# support. Make some noise if it happens.
|
||||
logging.error('Got unrecognized bacommon.bs.ClientEffectSound.')
|
||||
elif effect.sound is smcls.CASH_REGISTER:
|
||||
soundfile = 'cashRegister'
|
||||
elif effect.sound is smcls.ERROR:
|
||||
soundfile = 'error'
|
||||
elif effect.sound is smcls.POWER_DOWN:
|
||||
soundfile = 'powerdown01'
|
||||
elif effect.sound is smcls.GUN_COCKING:
|
||||
soundfile = 'gunCocking'
|
||||
else:
|
||||
assert_never(effect.sound)
|
||||
if soundfile is not None:
|
||||
bauiv1.apptimer(
|
||||
delay,
|
||||
strict_partial(
|
||||
bauiv1.getsound(soundfile).play, volume=effect.volume
|
||||
),
|
||||
)
|
||||
|
||||
elif isinstance(effect, bacommon.bs.ClientEffectDelay):
|
||||
delay += effect.seconds
|
||||
else:
|
||||
# Server should not send us stuff we can't digest. Make
|
||||
# some noise if it happens.
|
||||
logging.error(
|
||||
'Got unrecognized bacommon.bs.ClientEffect;'
|
||||
' should not happen.'
|
||||
)
|
||||
@ -6,13 +6,23 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bacommon.bs import ClassicChestAppearance
|
||||
import babase
|
||||
import bauiv1
|
||||
import bascenev1
|
||||
|
||||
from baclassic._chest import (
|
||||
CHEST_APPEARANCE_DISPLAY_INFOS,
|
||||
CHEST_APPEARANCE_DISPLAY_INFO_DEFAULT,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
|
||||
def get_tournament_prize_strings(entry: dict[str, Any]) -> list[str]:
|
||||
def get_tournament_prize_strings(
|
||||
entry: dict[str, Any], include_tickets: bool
|
||||
) -> list[str]:
|
||||
"""Given a tournament entry, return strings for its prize levels."""
|
||||
# pylint: disable=too-many-locals
|
||||
from bascenev1 import get_trophy_string
|
||||
@ -27,7 +37,7 @@ def get_tournament_prize_strings(entry: dict[str, Any]) -> list[str]:
|
||||
trophy_type_2 = entry.get('prizeTrophy2')
|
||||
trophy_type_3 = entry.get('prizeTrophy3')
|
||||
out_vals = []
|
||||
for rng, prize, trophy_type in (
|
||||
for rng, ticket_prize, trophy_type in (
|
||||
(range1, prize1, trophy_type_1),
|
||||
(range2, prize2, trophy_type_2),
|
||||
(range3, prize3, trophy_type_3),
|
||||
@ -45,14 +55,100 @@ def get_tournament_prize_strings(entry: dict[str, Any]) -> list[str]:
|
||||
if trophy_type is not None:
|
||||
pvval += get_trophy_string(trophy_type)
|
||||
|
||||
# If we've got trophies but not for this entry, throw some space
|
||||
# in to compensate so the ticket counts line up.
|
||||
if prize is not None:
|
||||
if ticket_prize is not None and include_tickets:
|
||||
pvval = (
|
||||
babase.charstr(babase.SpecialChar.TICKET_BACKING)
|
||||
+ str(prize)
|
||||
+ str(ticket_prize)
|
||||
+ pvval
|
||||
)
|
||||
out_vals.append(prval)
|
||||
out_vals.append(pvval)
|
||||
return out_vals
|
||||
|
||||
|
||||
def set_tournament_prize_chest_image(
|
||||
entry: dict[str, Any], index: int, image: bauiv1.Widget
|
||||
) -> None:
|
||||
"""Set image attrs representing a tourney prize chest."""
|
||||
ranges = [
|
||||
entry.get('prizeRange1'),
|
||||
entry.get('prizeRange2'),
|
||||
entry.get('prizeRange3'),
|
||||
]
|
||||
chests = [
|
||||
entry.get('prizeChest1'),
|
||||
entry.get('prizeChest2'),
|
||||
entry.get('prizeChest3'),
|
||||
]
|
||||
|
||||
assert 0 <= index < 3
|
||||
|
||||
# If tourney doesn't include this prize, just hide the image.
|
||||
if ranges[index] is None:
|
||||
bauiv1.imagewidget(edit=image, opacity=0.0)
|
||||
return
|
||||
|
||||
try:
|
||||
appearance = ClassicChestAppearance(chests[index])
|
||||
except ValueError:
|
||||
appearance = ClassicChestAppearance.DEFAULT
|
||||
chestdisplayinfo = CHEST_APPEARANCE_DISPLAY_INFOS.get(
|
||||
appearance, CHEST_APPEARANCE_DISPLAY_INFO_DEFAULT
|
||||
)
|
||||
bauiv1.imagewidget(
|
||||
edit=image,
|
||||
opacity=1.0,
|
||||
color=chestdisplayinfo.color,
|
||||
texture=bauiv1.gettexture(chestdisplayinfo.texclosed),
|
||||
tint_texture=bauiv1.gettexture(chestdisplayinfo.texclosedtint),
|
||||
tint_color=chestdisplayinfo.tint,
|
||||
tint2_color=chestdisplayinfo.tint2,
|
||||
)
|
||||
|
||||
|
||||
def create_in_game_tournament_prize_image(
|
||||
entry: dict[str, Any], index: int, position: tuple[float, float]
|
||||
) -> None:
|
||||
"""Create a display for the prize chest (if any) in-game."""
|
||||
from bascenev1lib.actor.image import Image
|
||||
|
||||
ranges = [
|
||||
entry.get('prizeRange1'),
|
||||
entry.get('prizeRange2'),
|
||||
entry.get('prizeRange3'),
|
||||
]
|
||||
chests = [
|
||||
entry.get('prizeChest1'),
|
||||
entry.get('prizeChest2'),
|
||||
entry.get('prizeChest3'),
|
||||
]
|
||||
|
||||
# If tourney doesn't include this prize, no-op.
|
||||
if ranges[index] is None:
|
||||
return
|
||||
|
||||
try:
|
||||
appearance = ClassicChestAppearance(chests[index])
|
||||
except ValueError:
|
||||
appearance = ClassicChestAppearance.DEFAULT
|
||||
chestdisplayinfo = CHEST_APPEARANCE_DISPLAY_INFOS.get(
|
||||
appearance, CHEST_APPEARANCE_DISPLAY_INFO_DEFAULT
|
||||
)
|
||||
Image(
|
||||
# Provide magical extended dict version of texture that Image
|
||||
# actor supports.
|
||||
texture={
|
||||
'texture': bascenev1.gettexture(chestdisplayinfo.texclosed),
|
||||
'tint_texture': bascenev1.gettexture(
|
||||
chestdisplayinfo.texclosedtint
|
||||
),
|
||||
'tint_color': chestdisplayinfo.tint,
|
||||
'tint2_color': chestdisplayinfo.tint2,
|
||||
'mask_texture': None,
|
||||
},
|
||||
color=chestdisplayinfo.color + (1.0,),
|
||||
position=position,
|
||||
scale=(48.0, 48.0),
|
||||
transition=Image.Transition.FADE_IN,
|
||||
transition_delay=2.0,
|
||||
).autoretain()
|
||||
|
||||
@ -53,7 +53,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 22155
|
||||
TARGET_BALLISTICA_BUILD = 22178
|
||||
TARGET_BALLISTICA_VERSION = '1.7.37'
|
||||
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import _baplus
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any
|
||||
|
||||
import bacommon.bs
|
||||
from babase import AccountV2Subsystem
|
||||
|
||||
from baplus._cloud import CloudSubsystem
|
||||
|
||||
@ -15,6 +15,7 @@ if TYPE_CHECKING:
|
||||
|
||||
from efro.message import Message, Response
|
||||
import bacommon.cloud
|
||||
import bacommon.bs
|
||||
|
||||
|
||||
# TODO: Should make it possible to define a protocol in bacommon.cloud and
|
||||
@ -120,45 +121,45 @@ class CloudSubsystem(babase.AppSubsystem):
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.BSPrivatePartyMessage,
|
||||
msg: bacommon.bs.PrivatePartyMessage,
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.BSPrivatePartyResponse | Exception], None
|
||||
[bacommon.bs.PrivatePartyResponse | Exception], None
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.BSInboxRequestMessage,
|
||||
msg: bacommon.bs.InboxRequestMessage,
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.BSInboxRequestResponse | Exception], None
|
||||
[bacommon.bs.InboxRequestResponse | Exception], None
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.BSInboxEntryProcessMessage,
|
||||
msg: bacommon.bs.ClientUIActionMessage,
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.BSInboxEntryProcessResponse | Exception], None
|
||||
[bacommon.bs.ClientUIActionResponse | Exception], None
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.BSChestInfoMessage,
|
||||
msg: bacommon.bs.ChestInfoMessage,
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.BSChestInfoResponse | Exception], None
|
||||
[bacommon.bs.ChestInfoResponse | Exception], None
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.BSChestActionMessage,
|
||||
msg: bacommon.bs.ChestActionMessage,
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.BSChestActionResponse | Exception], None
|
||||
[bacommon.bs.ChestActionResponse | Exception], None
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
@ -229,7 +230,7 @@ class CloudSubsystem(babase.AppSubsystem):
|
||||
|
||||
def subscribe_classic_account_data(
|
||||
self,
|
||||
updatecall: Callable[[bacommon.cloud.BSClassicAccountLiveData], None],
|
||||
updatecall: Callable[[bacommon.bs.ClassicAccountLiveData], None],
|
||||
) -> babase.CloudSubscription:
|
||||
"""Subscribe to classic account data."""
|
||||
raise NotImplementedError(
|
||||
|
||||
@ -357,6 +357,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
|
||||
h_offs = 7.0
|
||||
v_offs = -280.0
|
||||
v_offs2 = -236.0
|
||||
|
||||
# We wanna prevent controllers users from popping up browsers
|
||||
# or game-center widgets in cases where they can't easily get back
|
||||
@ -384,7 +385,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
bui.buttonwidget(
|
||||
parent=rootc,
|
||||
color=(0.45, 0.4, 0.5),
|
||||
position=(160, v_offs + 439),
|
||||
position=(240, v_offs2 + 439),
|
||||
size=(350, 62),
|
||||
label=(
|
||||
bui.Lstr(resource='tournamentStandingsText')
|
||||
@ -406,7 +407,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
show_next_button = self._is_more_levels and not (env.demo or env.arcade)
|
||||
|
||||
if not show_next_button:
|
||||
h_offs += 70
|
||||
h_offs += 60
|
||||
|
||||
# Due to virtual-bounds changes, have to squish buttons a bit to
|
||||
# avoid overlapping with tips at bottom. Could look nicer to
|
||||
@ -614,7 +615,6 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
|
||||
@override
|
||||
def on_begin(self) -> None:
|
||||
# FIXME: Clean this up.
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-locals
|
||||
@ -882,7 +882,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
# If we're not doing the world's-best button, just show a title
|
||||
# instead.
|
||||
ts_height = 300
|
||||
ts_h_offs = 210
|
||||
ts_h_offs = 290
|
||||
v_offs = 40
|
||||
txt = Text(
|
||||
(
|
||||
@ -956,7 +956,6 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
if display_scores[i][1] is None:
|
||||
name_str = '-'
|
||||
else:
|
||||
# noinspection PyUnresolvedReferences
|
||||
name_str = ', '.join(
|
||||
[p['name'] for p in display_scores[i][1]['players']]
|
||||
)
|
||||
@ -1025,9 +1024,8 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
ts_h_offs = -480
|
||||
v_offs = 40
|
||||
|
||||
# Only make this if we don't have the button
|
||||
# (never want clients to see it so no need for client-only
|
||||
# version, etc).
|
||||
# Only make this if we don't have the button (never want clients
|
||||
# to see it so no need for client-only version, etc).
|
||||
if self._have_achievements:
|
||||
if not self._account_has_achievements:
|
||||
Text(
|
||||
@ -1069,7 +1067,6 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
).autoretain()
|
||||
|
||||
def _got_friend_score_results(self, results: list[Any] | None) -> None:
|
||||
# FIXME: tidy this up
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
@ -1205,7 +1202,6 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
).autoretain()
|
||||
|
||||
def _got_score_results(self, results: dict[str, Any] | None) -> None:
|
||||
# FIXME: tidy this up
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
@ -1222,11 +1218,12 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
# Delay a bit if results come in too fast.
|
||||
assert self._begin_time is not None
|
||||
base_delay = max(0, 2.7 - (bs.time() - self._begin_time))
|
||||
v_offs = 20
|
||||
# v_offs = 20
|
||||
v_offs = 64
|
||||
if results is None:
|
||||
self._score_loading_status = Text(
|
||||
bs.Lstr(resource='worldScoresUnavailableText'),
|
||||
position=(230, 150 + v_offs),
|
||||
position=(280, 130 + v_offs),
|
||||
color=(1, 1, 1, 0.4),
|
||||
transition=Text.Transition.FADE_IN,
|
||||
transition_delay=base_delay + 0.3,
|
||||
@ -1271,7 +1268,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
(1.5 + base_delay),
|
||||
bs.WeakCall(self._show_world_rank, offs_x),
|
||||
)
|
||||
ts_h_offs = 200
|
||||
ts_h_offs = 280
|
||||
ts_height = 300
|
||||
|
||||
# Show world tops.
|
||||
@ -1299,7 +1296,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
transition_delay=base_delay + 0.3,
|
||||
).autoretain()
|
||||
else:
|
||||
v_offs += 20
|
||||
v_offs += 40
|
||||
|
||||
h_offs_extra = 0
|
||||
v_offs_names = 0
|
||||
@ -1326,6 +1323,37 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
random.randrange(0, len(times) + 1),
|
||||
(base_delay + i * 0.05, base_delay + 0.4 + i * 0.05),
|
||||
)
|
||||
|
||||
# Conundrum: We want to place line numbers to the
|
||||
# left of our score column based on the largest
|
||||
# score width. However scores may use Lstrs and thus
|
||||
# may have different widths in different languages.
|
||||
# We don't want to bake down the Lstrs we display
|
||||
# because then clients can't view scores in their
|
||||
# own language. So as a compromise lets measure
|
||||
# max-width based on baked down Lstrs but then
|
||||
# display regular Lstrs with max-width set based on
|
||||
# that. Hopefully that'll look reasonable for most
|
||||
# languages.
|
||||
max_score_width = 10.0
|
||||
for tval in self._show_info['tops']:
|
||||
score = int(tval[0])
|
||||
name_str = tval[1]
|
||||
if name_str != '-':
|
||||
max_score_width = max(
|
||||
max_score_width,
|
||||
bui.get_string_width(
|
||||
(
|
||||
str(score)
|
||||
if self._score_type == 'points'
|
||||
else bs.timestring(
|
||||
(score * 10) / 1000.0
|
||||
).evaluate()
|
||||
),
|
||||
suppress_warning=True,
|
||||
),
|
||||
)
|
||||
|
||||
for i, tval in enumerate(self._show_info['tops']):
|
||||
score = int(tval[0])
|
||||
name_str = tval[1]
|
||||
@ -1347,12 +1375,37 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
tdelay2 = times[i][1]
|
||||
|
||||
if name_str != '-':
|
||||
Text(
|
||||
(
|
||||
sstr = (
|
||||
str(score)
|
||||
if self._score_type == 'points'
|
||||
else bs.timestring((score * 10) / 1000.0)
|
||||
)
|
||||
|
||||
# Line number.
|
||||
Text(
|
||||
str(i + 1),
|
||||
position=(
|
||||
ts_h_offs
|
||||
+ 20
|
||||
+ h_offs_extra
|
||||
- max_score_width
|
||||
- 8.0,
|
||||
ts_height / 2
|
||||
+ -ts_height * (i + 1) / 10
|
||||
+ v_offs
|
||||
- 30.0,
|
||||
),
|
||||
scale=0.5,
|
||||
h_align=Text.HAlign.RIGHT,
|
||||
v_align=Text.VAlign.CENTER,
|
||||
color=(0.3, 0.3, 0.3),
|
||||
transition=Text.Transition.IN_LEFT,
|
||||
transition_delay=tdelay1,
|
||||
).autoretain()
|
||||
|
||||
# Score.
|
||||
Text(
|
||||
sstr,
|
||||
position=(
|
||||
ts_h_offs + 20 + h_offs_extra,
|
||||
ts_height / 2
|
||||
@ -1360,6 +1413,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
+ v_offs
|
||||
- 30.0,
|
||||
),
|
||||
maxwidth=max_score_width,
|
||||
h_align=Text.HAlign.RIGHT,
|
||||
v_align=Text.VAlign.CENTER,
|
||||
color=color0,
|
||||
@ -1367,6 +1421,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
transition=Text.Transition.IN_LEFT,
|
||||
transition_delay=tdelay1,
|
||||
).autoretain()
|
||||
# Player name.
|
||||
Text(
|
||||
bs.Lstr(value=name_str),
|
||||
position=(
|
||||
@ -1470,16 +1525,12 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
]
|
||||
# pylint: disable=useless-suppression
|
||||
# pylint: disable=unbalanced-tuple-unpacking
|
||||
(
|
||||
pr1,
|
||||
pv1,
|
||||
pr2,
|
||||
pv2,
|
||||
pr3,
|
||||
pv3,
|
||||
) = bs.app.classic.get_tournament_prize_strings(
|
||||
tourney_info
|
||||
(pr1, pv1, pr2, pv2, pr3, pv3) = (
|
||||
bs.app.classic.get_tournament_prize_strings(
|
||||
tourney_info, include_tickets=False
|
||||
)
|
||||
)
|
||||
|
||||
# pylint: enable=unbalanced-tuple-unpacking
|
||||
# pylint: enable=useless-suppression
|
||||
|
||||
@ -1495,10 +1546,14 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
transition_delay=2.0,
|
||||
).autoretain()
|
||||
vval = -107 + 70
|
||||
for rng, val in ((pr1, pv1), (pr2, pv2), (pr3, pv3)):
|
||||
for i, rng, val in (
|
||||
(0, pr1, pv1),
|
||||
(1, pr2, pv2),
|
||||
(2, pr3, pv3),
|
||||
):
|
||||
Text(
|
||||
rng,
|
||||
position=(-410 + 10, vval),
|
||||
position=(-430 + 10, vval),
|
||||
color=(1, 1, 1, 0.7),
|
||||
h_align=Text.HAlign.RIGHT,
|
||||
v_align=Text.VAlign.CENTER,
|
||||
@ -1509,7 +1564,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
).autoretain()
|
||||
Text(
|
||||
val,
|
||||
position=(-390 + 10, vval),
|
||||
position=(-410 + 10, vval),
|
||||
color=(0.7, 0.7, 0.7, 1.0),
|
||||
h_align=Text.HAlign.LEFT,
|
||||
v_align=Text.VAlign.CENTER,
|
||||
@ -1518,6 +1573,9 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
maxwidth=300,
|
||||
transition_delay=2.0,
|
||||
).autoretain()
|
||||
bs.app.classic.create_in_game_tournament_prize_image(
|
||||
tourney_info, i, (-410 + 70, vval)
|
||||
)
|
||||
vval -= 35
|
||||
except Exception:
|
||||
logging.exception('Error showing prize ranges.')
|
||||
|
||||
@ -56,15 +56,21 @@ class Image(bs.Actor):
|
||||
# pylint: disable=too-many-locals
|
||||
super().__init__()
|
||||
|
||||
# If they provided a dict as texture, assume its an icon.
|
||||
# otherwise its just a texture value itself.
|
||||
# If they provided a dict as texture, use it to wire up extended
|
||||
# stuff like tints and masks.
|
||||
mask_texture: bs.Texture | None
|
||||
if isinstance(texture, dict):
|
||||
tint_color = texture['tint_color']
|
||||
tint2_color = texture['tint2_color']
|
||||
tint_texture = texture['tint_texture']
|
||||
|
||||
# Assume we're dealing with a character icon but allow
|
||||
# overriding.
|
||||
mask_tex_name = texture.get('mask_texture', 'characterIconMask')
|
||||
mask_texture = (
|
||||
None if mask_tex_name is None else bs.gettexture(mask_tex_name)
|
||||
)
|
||||
texture = texture['texture']
|
||||
mask_texture = bs.gettexture('characterIconMask')
|
||||
else:
|
||||
tint_color = (1, 1, 1)
|
||||
tint2_color = None
|
||||
|
||||
@ -114,9 +114,12 @@ from _bauiv1 import (
|
||||
hscrollwidget,
|
||||
imagewidget,
|
||||
Mesh,
|
||||
root_ui_pause_updates,
|
||||
root_ui_resume_updates,
|
||||
rowwidget,
|
||||
scrollwidget,
|
||||
set_party_window_open,
|
||||
spinnerwidget,
|
||||
Sound,
|
||||
Texture,
|
||||
textwidget,
|
||||
@ -218,6 +221,8 @@ __all__ = [
|
||||
'quit',
|
||||
'QuitType',
|
||||
'request_permission',
|
||||
'root_ui_pause_updates',
|
||||
'root_ui_resume_updates',
|
||||
'rowwidget',
|
||||
'safecolor',
|
||||
'screenmessage',
|
||||
@ -228,6 +233,7 @@ __all__ = [
|
||||
'set_ui_input_device',
|
||||
'Sound',
|
||||
'SpecialChar',
|
||||
'spinnerwidget',
|
||||
'supports_max_fps',
|
||||
'supports_vsync',
|
||||
'supports_unicode_display',
|
||||
|
||||
@ -100,17 +100,20 @@ class AccountViewerWindow(PopupWindow):
|
||||
)
|
||||
bui.widget(edit=self._scrollwidget, autoselect=True)
|
||||
|
||||
# Note to self: Make sure to always update loading text and
|
||||
# spinner visibility together.
|
||||
self._loading_text = bui.textwidget(
|
||||
parent=self._scrollwidget,
|
||||
scale=0.5,
|
||||
text=bui.Lstr(
|
||||
value='${A}...',
|
||||
subs=[('${A}', bui.Lstr(resource='loadingText'))],
|
||||
),
|
||||
text='',
|
||||
size=(self._width - 60, 100),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
self._loading_spinner = bui.spinnerwidget(
|
||||
parent=self.root_widget,
|
||||
position=(self._width * 0.5, self._height * 0.5),
|
||||
)
|
||||
|
||||
# In cases where the user most likely has a browser/email, lets
|
||||
# offer a 'report this user' button.
|
||||
@ -227,9 +230,11 @@ class AccountViewerWindow(PopupWindow):
|
||||
edit=self._loading_text,
|
||||
text=bui.Lstr(resource='internal.unavailableNoConnectionText'),
|
||||
)
|
||||
bui.spinnerwidget(edit=self._loading_spinner, visible=False)
|
||||
else:
|
||||
try:
|
||||
self._loading_text.delete()
|
||||
self._loading_spinner.delete()
|
||||
trophystr = ''
|
||||
try:
|
||||
trophystr = data['trophies']
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -57,7 +57,7 @@ class WaitForConnectivityWindow(bui.Window):
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height * 0.65),
|
||||
position=(self._width * 0.5, self._height * 0.7),
|
||||
size=(0, 0),
|
||||
scale=1.2,
|
||||
h_align='center',
|
||||
@ -65,9 +65,15 @@ class WaitForConnectivityWindow(bui.Window):
|
||||
text=bui.Lstr(resource='internal.connectingToPartyText'),
|
||||
maxwidth=self._width * 0.9,
|
||||
)
|
||||
|
||||
self._spinner = bui.spinnerwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height * 0.54),
|
||||
)
|
||||
|
||||
self._info_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height * 0.45),
|
||||
position=(self._width * 0.5, self._height * 0.4),
|
||||
size=(0, 0),
|
||||
color=(0.6, 0.5, 0.6),
|
||||
flatness=1.0,
|
||||
@ -115,6 +121,15 @@ class WaitForConnectivityWindow(bui.Window):
|
||||
def _connected(self) -> None:
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
# Show 'connected.' and kill the spinner for the brief moment
|
||||
# we're visible on our way out.
|
||||
bui.textwidget(
|
||||
edit=self._info_text, text=bui.Lstr(resource='remote_app.connected')
|
||||
)
|
||||
if self._spinner:
|
||||
self._spinner.delete()
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget,
|
||||
transition=('out_scale'),
|
||||
|
||||
@ -231,11 +231,11 @@ class CoopBrowserWindow(bui.MainWindow):
|
||||
# Don't want initial construction affecting our last-selected.
|
||||
self._do_selection_callbacks = False
|
||||
v = self._height - 95
|
||||
txt = bui.textwidget(
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
self._width * 0.5,
|
||||
v + 40 - (0 if uiscale is bui.UIScale.SMALL else 0),
|
||||
v + 40 - (25 if uiscale is bui.UIScale.SMALL else 0),
|
||||
),
|
||||
size=(0, 0),
|
||||
text=bui.Lstr(
|
||||
@ -244,14 +244,11 @@ class CoopBrowserWindow(bui.MainWindow):
|
||||
),
|
||||
h_align='center',
|
||||
color=app.ui_v1.title_color,
|
||||
scale=1.5,
|
||||
maxwidth=500,
|
||||
scale=0.85 if uiscale is bui.UIScale.SMALL else 1.5,
|
||||
maxwidth=280 if uiscale is bui.UIScale.SMALL else 500,
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.textwidget(edit=txt, text='')
|
||||
|
||||
self._selected_row = cfg.get('Selected Coop Row', None)
|
||||
|
||||
self._scroll_width = self._width - (130 + 2 * x_inset)
|
||||
|
||||
@ -12,6 +12,11 @@ import bauiv1 as bui
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
||||
# As of 1.7.37, no longer charging entry fees for tourneys (tourneys now
|
||||
# reward chests and the game now makes its money from tokens/ads used to
|
||||
# speed up chest openings).
|
||||
USE_ENTRY_FEES = False
|
||||
|
||||
|
||||
class TournamentButton:
|
||||
"""Button showing a tournament in coop window."""
|
||||
@ -25,6 +30,7 @@ class TournamentButton:
|
||||
on_pressed: Callable[[TournamentButton], None],
|
||||
) -> None:
|
||||
# pylint: disable=too-many-positional-arguments
|
||||
# pylint: disable=too-many-statements
|
||||
self._r = 'coopSelectWindow'
|
||||
sclx = 300
|
||||
scly = 195.0
|
||||
@ -37,6 +43,7 @@ class TournamentButton:
|
||||
self.has_time_remaining: bool = False
|
||||
self.leader: Any = None
|
||||
self.required_league: str | None = None
|
||||
self._base_x_offs = 0 if USE_ENTRY_FEES else -45.0
|
||||
self.button = btn = bui.buttonwidget(
|
||||
parent=parent,
|
||||
position=(x + 23, y + 4),
|
||||
@ -96,7 +103,10 @@ class TournamentButton:
|
||||
header_color = (0.43, 0.4, 0.5, 1)
|
||||
value_color = (0.6, 0.6, 0.6, 1)
|
||||
|
||||
x_offs = 0
|
||||
x_offs = self._base_x_offs
|
||||
|
||||
# No longer using entry fees.
|
||||
if USE_ENTRY_FEES:
|
||||
bui.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
@ -180,8 +190,8 @@ class TournamentButton:
|
||||
self.button_y = y
|
||||
self.button_scale_y = scly
|
||||
|
||||
xo2 = 0
|
||||
prize_value_scale = 1.5
|
||||
# Offset for prize range/values.
|
||||
xo2 = 0.0
|
||||
|
||||
self.prize_range_1_text = bui.textwidget(
|
||||
parent=parent,
|
||||
@ -191,7 +201,7 @@ class TournamentButton:
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
maxwidth=50,
|
||||
text='-',
|
||||
text='',
|
||||
scale=0.8,
|
||||
color=header_color,
|
||||
flatness=1.0,
|
||||
@ -202,13 +212,21 @@ class TournamentButton:
|
||||
position=(x + 380 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='left',
|
||||
text='-',
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=100,
|
||||
scale=prize_value_scale,
|
||||
color=value_color,
|
||||
flatness=1.0,
|
||||
)
|
||||
self._chestsz = 50
|
||||
self.prize_chest_1_image = bui.imagewidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
texture=bui.gettexture('white'),
|
||||
position=(x + 380 + xo2 + x_offs, y + scly - 93),
|
||||
size=(self._chestsz, self._chestsz),
|
||||
opacity=0.0,
|
||||
)
|
||||
|
||||
self.prize_range_2_text = bui.textwidget(
|
||||
parent=parent,
|
||||
@ -216,6 +234,7 @@ class TournamentButton:
|
||||
position=(x + 355 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='right',
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=50,
|
||||
scale=0.8,
|
||||
@ -231,10 +250,17 @@ class TournamentButton:
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=100,
|
||||
scale=prize_value_scale,
|
||||
color=value_color,
|
||||
flatness=1.0,
|
||||
)
|
||||
self.prize_chest_2_image = bui.imagewidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
texture=bui.gettexture('white'),
|
||||
position=(x + 380 + xo2 + x_offs, y + scly - 93),
|
||||
size=(self._chestsz, self._chestsz),
|
||||
opacity=0.0,
|
||||
)
|
||||
|
||||
self.prize_range_3_text = bui.textwidget(
|
||||
parent=parent,
|
||||
@ -242,6 +268,7 @@ class TournamentButton:
|
||||
position=(x + 355 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='right',
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=50,
|
||||
scale=0.8,
|
||||
@ -257,15 +284,22 @@ class TournamentButton:
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=100,
|
||||
scale=prize_value_scale,
|
||||
color=value_color,
|
||||
flatness=1.0,
|
||||
)
|
||||
self.prize_chest_3_image = bui.imagewidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
texture=bui.gettexture('white'),
|
||||
position=(x + 380 + xo2 + x_offs, y + scly - 93),
|
||||
size=(self._chestsz, self._chestsz),
|
||||
opacity=0.0,
|
||||
)
|
||||
|
||||
bui.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 620 + x_offs, y + scly - 20),
|
||||
position=(x + 625 + x_offs, y + scly - 20),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text=bui.Lstr(resource=f'{self._r}.currentBestText'),
|
||||
@ -279,7 +313,7 @@ class TournamentButton:
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(
|
||||
x + 620 + x_offs - (170 / 1.4) * 0.5,
|
||||
x + 625 + x_offs - (170 / 1.4) * 0.5,
|
||||
y + scly - 60 - 40 * 0.5,
|
||||
),
|
||||
selectable=True,
|
||||
@ -299,7 +333,7 @@ class TournamentButton:
|
||||
self.current_leader_score_text = bui.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 620 + x_offs, y + scly - 113 + 10),
|
||||
position=(x + 625 + x_offs, y + scly - 113 + 10),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
@ -312,7 +346,7 @@ class TournamentButton:
|
||||
|
||||
self.more_scores_button = bui.buttonwidget(
|
||||
parent=parent,
|
||||
position=(x + 620 + x_offs - 60, y + scly - 50 - 125),
|
||||
position=(x + 625 + x_offs - 60, y + scly - 50 - 125),
|
||||
color=(0.5, 0.5, 0.6),
|
||||
textcolor=(0.7, 0.7, 0.8),
|
||||
label='-',
|
||||
@ -330,7 +364,7 @@ class TournamentButton:
|
||||
bui.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 820 + x_offs, y + scly - 20),
|
||||
position=(x + 840 + x_offs, y + scly - 20),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text=bui.Lstr(resource=f'{self._r}.timeRemainingText'),
|
||||
@ -343,7 +377,7 @@ class TournamentButton:
|
||||
self.time_remaining_value_text = bui.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 820 + x_offs, y + scly - 68),
|
||||
position=(x + 840 + x_offs, y + scly - 68),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
@ -356,7 +390,7 @@ class TournamentButton:
|
||||
self.time_remaining_out_of_text = bui.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 820 + x_offs, y + scly - 110),
|
||||
position=(x + 840 + x_offs, y + scly - 110),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
@ -415,26 +449,26 @@ class TournamentButton:
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
assert bui.app.classic is not None
|
||||
classic = bui.app.classic
|
||||
assert classic is not None
|
||||
|
||||
prize_y_offs = (
|
||||
34
|
||||
if 'prizeRange3' in entry
|
||||
else 20 if 'prizeRange2' in entry else 12
|
||||
)
|
||||
x_offs = 90
|
||||
x_offs = self._base_x_offs + 90
|
||||
|
||||
# pylint: disable=useless-suppression
|
||||
# pylint: disable=unbalanced-tuple-unpacking
|
||||
(
|
||||
pr1,
|
||||
pv1,
|
||||
pr2,
|
||||
pv2,
|
||||
pr3,
|
||||
pv3,
|
||||
) = bui.app.classic.get_tournament_prize_strings(entry)
|
||||
# pylint: enable=unbalanced-tuple-unpacking
|
||||
# pylint: enable=useless-suppression
|
||||
# Special offset for prize ranges/vals.
|
||||
x_offs2 = x_offs - 20.0
|
||||
|
||||
# Special offset for prize chests.
|
||||
x_offs2c = x_offs2 + 50
|
||||
|
||||
# Fetch prize range and trophy strings.
|
||||
(pr1, pv1, pr2, pv2, pr3, pv3) = classic.get_tournament_prize_strings(
|
||||
entry, include_tickets=False
|
||||
)
|
||||
|
||||
enabled = 'requiredLeague' not in entry
|
||||
bui.buttonwidget(
|
||||
@ -446,74 +480,91 @@ class TournamentButton:
|
||||
edit=self.prize_range_1_text,
|
||||
text='-' if pr1 == '' else pr1,
|
||||
position=(
|
||||
self.button_x + 365 + x_offs,
|
||||
self.button_x + 365 + x_offs2,
|
||||
self.button_y + self.button_scale_y - 93 + prize_y_offs,
|
||||
),
|
||||
)
|
||||
|
||||
# We want to draw values containing tickets a bit smaller
|
||||
# (scratch that; we now draw medals a bit bigger).
|
||||
ticket_char = bui.charstr(bui.SpecialChar.TICKET_BACKING)
|
||||
prize_value_scale_large = 1.0
|
||||
prize_value_scale_small = 1.0
|
||||
|
||||
bui.textwidget(
|
||||
edit=self.prize_value_1_text,
|
||||
text='-' if pv1 == '' else pv1,
|
||||
scale=(
|
||||
prize_value_scale_large
|
||||
if ticket_char not in pv1
|
||||
else prize_value_scale_small
|
||||
),
|
||||
position=(
|
||||
self.button_x + 380 + x_offs,
|
||||
self.button_x + 380 + x_offs2,
|
||||
self.button_y + self.button_scale_y - 93 + prize_y_offs,
|
||||
),
|
||||
)
|
||||
bui.imagewidget(
|
||||
edit=self.prize_chest_1_image,
|
||||
position=(
|
||||
self.button_x + 380 + x_offs2c,
|
||||
self.button_y
|
||||
+ self.button_scale_y
|
||||
- 93
|
||||
+ prize_y_offs
|
||||
- 0.5 * self._chestsz,
|
||||
),
|
||||
)
|
||||
classic.set_tournament_prize_image(entry, 0, self.prize_chest_1_image)
|
||||
|
||||
bui.textwidget(
|
||||
edit=self.prize_range_2_text,
|
||||
text=pr2,
|
||||
position=(
|
||||
self.button_x + 365 + x_offs,
|
||||
self.button_x + 365 + x_offs2,
|
||||
self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
|
||||
),
|
||||
)
|
||||
bui.textwidget(
|
||||
edit=self.prize_value_2_text,
|
||||
text=pv2,
|
||||
scale=(
|
||||
prize_value_scale_large
|
||||
if ticket_char not in pv2
|
||||
else prize_value_scale_small
|
||||
),
|
||||
position=(
|
||||
self.button_x + 380 + x_offs,
|
||||
self.button_x + 380 + x_offs2,
|
||||
self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
|
||||
),
|
||||
)
|
||||
bui.imagewidget(
|
||||
edit=self.prize_chest_2_image,
|
||||
position=(
|
||||
self.button_x + 380 + x_offs2c,
|
||||
self.button_y
|
||||
+ self.button_scale_y
|
||||
- 93
|
||||
- 45
|
||||
+ prize_y_offs
|
||||
- 0.5 * self._chestsz,
|
||||
),
|
||||
)
|
||||
classic.set_tournament_prize_image(entry, 1, self.prize_chest_2_image)
|
||||
|
||||
bui.textwidget(
|
||||
edit=self.prize_range_3_text,
|
||||
text=pr3,
|
||||
position=(
|
||||
self.button_x + 365 + x_offs,
|
||||
self.button_x + 365 + x_offs2,
|
||||
self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
|
||||
),
|
||||
)
|
||||
bui.textwidget(
|
||||
edit=self.prize_value_3_text,
|
||||
text=pv3,
|
||||
scale=(
|
||||
prize_value_scale_large
|
||||
if ticket_char not in pv3
|
||||
else prize_value_scale_small
|
||||
),
|
||||
position=(
|
||||
self.button_x + 380 + x_offs,
|
||||
self.button_x + 380 + x_offs2,
|
||||
self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
|
||||
),
|
||||
)
|
||||
bui.imagewidget(
|
||||
edit=self.prize_chest_3_image,
|
||||
position=(
|
||||
self.button_x + 380 + x_offs2c,
|
||||
self.button_y
|
||||
+ self.button_scale_y
|
||||
- 93
|
||||
- 90
|
||||
+ prize_y_offs
|
||||
- 0.5 * self._chestsz,
|
||||
),
|
||||
)
|
||||
classic.set_tournament_prize_image(entry, 2, self.prize_chest_3_image)
|
||||
|
||||
leader_name = '-'
|
||||
leader_score: str | bui.Lstr = '-'
|
||||
@ -599,6 +650,7 @@ class TournamentButton:
|
||||
)
|
||||
|
||||
fee = entry['fee']
|
||||
assert isinstance(fee, int | None)
|
||||
|
||||
if fee is None:
|
||||
fee_var = None
|
||||
@ -610,18 +662,23 @@ class TournamentButton:
|
||||
fee_var = 'price.tournament_entry_2'
|
||||
elif fee == 1:
|
||||
fee_var = 'price.tournament_entry_1'
|
||||
elif fee == -1:
|
||||
fee_var = None
|
||||
else:
|
||||
if fee != 0:
|
||||
print('Unknown fee value:', fee)
|
||||
fee_var = 'price.tournament_entry_0'
|
||||
|
||||
self.allow_ads = allow_ads = entry['allowAds']
|
||||
self.allow_ads = allow_ads = (
|
||||
entry['allowAds'] if USE_ENTRY_FEES else False
|
||||
)
|
||||
|
||||
final_fee: int | None = (
|
||||
final_fee = (
|
||||
None
|
||||
if fee_var is None
|
||||
else plus.get_v1_account_misc_read_val(fee_var, '?')
|
||||
)
|
||||
assert isinstance(final_fee, int | None)
|
||||
|
||||
final_fee_str: str | bui.Lstr
|
||||
if fee_var is None:
|
||||
@ -638,12 +695,15 @@ class TournamentButton:
|
||||
ad_tries_remaining = bui.app.classic.accounts.tournament_info[
|
||||
self.tournament_id
|
||||
]['adTriesRemaining']
|
||||
assert isinstance(ad_tries_remaining, int | None)
|
||||
free_tries_remaining = bui.app.classic.accounts.tournament_info[
|
||||
self.tournament_id
|
||||
]['freeTriesRemaining']
|
||||
assert isinstance(free_tries_remaining, int | None)
|
||||
|
||||
# Now, if this fee allows ads and we support video ads, show
|
||||
# the 'or ad' version.
|
||||
if USE_ENTRY_FEES:
|
||||
if allow_ads and plus.has_video_ads():
|
||||
ads_enabled = plus.have_incentivized_ad()
|
||||
bui.imagewidget(
|
||||
@ -651,7 +711,9 @@ class TournamentButton:
|
||||
opacity=1.0 if ads_enabled else 0.25,
|
||||
)
|
||||
or_text = (
|
||||
bui.Lstr(resource='orText', subs=[('${A}', ''), ('${B}', '')])
|
||||
bui.Lstr(
|
||||
resource='orText', subs=[('${A}', ''), ('${B}', '')]
|
||||
)
|
||||
.evaluate()
|
||||
.strip()
|
||||
)
|
||||
|
||||
@ -62,7 +62,7 @@ class PrivateGatherTab(GatherTab):
|
||||
self._state: State = State()
|
||||
self._last_datacode_refresh_time: float | None = None
|
||||
self._hostingstate = PrivateHostingState()
|
||||
self._v2state: bacommon.cloud.BSPrivatePartyResponse | None = None
|
||||
self._v2state: bacommon.bs.PrivatePartyResponse | None = None
|
||||
self._join_sub_tab_text: bui.Widget | None = None
|
||||
self._host_sub_tab_text: bui.Widget | None = None
|
||||
self._update_timer: bui.AppTimer | None = None
|
||||
@ -339,7 +339,7 @@ class PrivateGatherTab(GatherTab):
|
||||
if plus.accounts.primary is not None:
|
||||
with plus.accounts.primary:
|
||||
plus.cloud.send_message_cb(
|
||||
bacommon.cloud.BSPrivatePartyMessage(
|
||||
bacommon.bs.PrivatePartyMessage(
|
||||
need_datacode=(
|
||||
self._last_datacode_refresh_time is None
|
||||
or time.monotonic()
|
||||
@ -355,7 +355,7 @@ class PrivateGatherTab(GatherTab):
|
||||
self._last_v2_state_query_time = now
|
||||
|
||||
def _on_private_party_query_response(
|
||||
self, response: bacommon.cloud.BSPrivatePartyResponse | Exception
|
||||
self, response: bacommon.bs.PrivatePartyResponse | Exception
|
||||
) -> None:
|
||||
if isinstance(response, Exception):
|
||||
self._debug_server_comm('got pp v2 state response (err)')
|
||||
|
||||
@ -367,6 +367,7 @@ class PublicGatherTab(GatherTab):
|
||||
self._last_server_list_query_time: float | None = None
|
||||
self._join_list_column: bui.Widget | None = None
|
||||
self._join_status_text: bui.Widget | None = None
|
||||
self._join_status_spinner: bui.Widget | None = None
|
||||
self._no_servers_found_text: bui.Widget | None = None
|
||||
self._host_max_party_size_value: bui.Widget | None = None
|
||||
self._host_max_party_size_minus_button: bui.Widget | None = None
|
||||
@ -665,6 +666,9 @@ class PublicGatherTab(GatherTab):
|
||||
size=(400, 400),
|
||||
claims_left_right=True,
|
||||
)
|
||||
|
||||
# Create join status text and join spinner. Always make sure to
|
||||
# update both of these together.
|
||||
self._join_status_text = bui.textwidget(
|
||||
parent=self._container,
|
||||
text='',
|
||||
@ -678,6 +682,10 @@ class PublicGatherTab(GatherTab):
|
||||
color=(0.6, 0.6, 0.6),
|
||||
position=(c_width * 0.5, c_height * 0.5),
|
||||
)
|
||||
self._join_status_spinner = bui.spinnerwidget(
|
||||
parent=self._container, position=(c_width * 0.5, c_height * 0.5)
|
||||
)
|
||||
|
||||
self._no_servers_found_text = bui.textwidget(
|
||||
parent=self._container,
|
||||
text='',
|
||||
@ -944,37 +952,51 @@ class PublicGatherTab(GatherTab):
|
||||
name = cast(str, bui.textwidget(query=self._host_name_text))
|
||||
bs.set_public_party_name(name)
|
||||
|
||||
# Update status text.
|
||||
status_text = self._join_status_text
|
||||
if status_text:
|
||||
# Update status text and loading spinner.
|
||||
if self._join_status_text:
|
||||
assert self._join_status_spinner
|
||||
if not signed_in:
|
||||
bui.textwidget(
|
||||
edit=status_text, text=bui.Lstr(resource='notSignedInText')
|
||||
edit=self._join_status_text,
|
||||
text=bui.Lstr(resource='notSignedInText'),
|
||||
)
|
||||
bui.spinnerwidget(edit=self._join_status_spinner, visible=False)
|
||||
else:
|
||||
# If we have a valid list, show no status; just the list.
|
||||
# Otherwise show either 'loading...' or 'error' depending
|
||||
# on whether this is our first go-round.
|
||||
if self._have_valid_server_list:
|
||||
bui.textwidget(edit=status_text, text='')
|
||||
bui.textwidget(edit=self._join_status_text, text='')
|
||||
bui.spinnerwidget(
|
||||
edit=self._join_status_spinner, visible=False
|
||||
)
|
||||
else:
|
||||
if self._have_server_list_response:
|
||||
bui.textwidget(
|
||||
edit=status_text,
|
||||
edit=self._join_status_text,
|
||||
text=bui.Lstr(resource='errorText'),
|
||||
)
|
||||
else:
|
||||
bui.textwidget(
|
||||
edit=status_text,
|
||||
text=bui.Lstr(
|
||||
value='${A}...',
|
||||
subs=[
|
||||
(
|
||||
'${A}',
|
||||
bui.Lstr(resource='store.loadingText'),
|
||||
bui.spinnerwidget(
|
||||
edit=self._join_status_spinner, visible=False
|
||||
)
|
||||
],
|
||||
),
|
||||
else:
|
||||
# Show our loading spinner.
|
||||
bui.textwidget(edit=self._join_status_text, text='')
|
||||
# bui.textwidget(
|
||||
# edit=self._join_status_text,
|
||||
# text=bui.Lstr(
|
||||
# value='${A}...',
|
||||
# subs=[
|
||||
# (
|
||||
# '${A}',
|
||||
#
|
||||
# bui.Lstr(resource='store.loadingText'),
|
||||
# )
|
||||
# ],
|
||||
# ),
|
||||
# )
|
||||
bui.spinnerwidget(
|
||||
edit=self._join_status_spinner, visible=True
|
||||
)
|
||||
|
||||
self._update_party_rows()
|
||||
@ -1005,12 +1027,7 @@ class PublicGatherTab(GatherTab):
|
||||
self._ui_rows = self._ui_rows[:-clipcount]
|
||||
|
||||
# If we have no parties to show, we're done.
|
||||
if not self._parties_displayed:
|
||||
text = self._join_status_text
|
||||
if (
|
||||
plus.get_v1_account_state() == 'signed_in'
|
||||
and cast(str, bui.textwidget(query=text)) == ''
|
||||
):
|
||||
if self._have_valid_server_list and not self._parties_displayed:
|
||||
bui.textwidget(
|
||||
edit=self._no_servers_found_text,
|
||||
text=bui.Lstr(resource='noServersFoundText'),
|
||||
|
||||
@ -863,7 +863,7 @@ def show_get_tokens_prompt() -> None:
|
||||
if bool(True):
|
||||
ConfirmWindow(
|
||||
bui.Lstr(resource='tokens.notEnoughTokensText'),
|
||||
GetTokensWindow,
|
||||
_show_get_tokens,
|
||||
ok_text=bui.Lstr(resource='tokens.getTokensText'),
|
||||
width=460,
|
||||
height=130,
|
||||
@ -875,3 +875,30 @@ def show_get_tokens_prompt() -> None:
|
||||
width=460,
|
||||
height=130,
|
||||
)
|
||||
|
||||
|
||||
def _show_get_tokens() -> None:
|
||||
|
||||
# NOTE TO USERS: The code below is not the proper way to do things;
|
||||
# whenever possible one should use a MainWindow's
|
||||
# main_window_replace() or main_window_back() methods. We just need
|
||||
# to do things a bit more manually in this case.
|
||||
|
||||
prev_main_window = bui.app.ui_v1.get_main_window()
|
||||
|
||||
# Special-case: If it seems we're already in the account window, do
|
||||
# nothing.
|
||||
if isinstance(prev_main_window, GetTokensWindow):
|
||||
return
|
||||
|
||||
# Set our new main window.
|
||||
bui.app.ui_v1.set_main_window(
|
||||
GetTokensWindow(),
|
||||
from_window=False,
|
||||
is_auxiliary=True,
|
||||
suppress_warning=True,
|
||||
)
|
||||
|
||||
# Transition out any previous main window.
|
||||
if prev_main_window is not None:
|
||||
prev_main_window.main_window_close()
|
||||
|
||||
@ -6,30 +6,100 @@ from __future__ import annotations
|
||||
|
||||
import weakref
|
||||
from dataclasses import dataclass
|
||||
from typing import override
|
||||
from typing import override, assert_never
|
||||
|
||||
from efro.error import CommunicationError
|
||||
import bacommon.cloud
|
||||
import bacommon.bs
|
||||
import bauiv1 as bui
|
||||
|
||||
# Messages with format versions higher than this will show up as
|
||||
# 'app needs to be updated to view this'
|
||||
SUPPORTED_INBOX_MESSAGE_FORMAT_VERSION = 1
|
||||
|
||||
class _Section:
|
||||
def get_height(self) -> float:
|
||||
"""Return section height."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def draw(self, subcontainer: bui.Widget, y: float) -> None:
|
||||
"""Draw the section."""
|
||||
|
||||
|
||||
class _TextSection(_Section):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sub_width: float,
|
||||
text: str,
|
||||
*,
|
||||
subs: list[str],
|
||||
spacing_top: float = 0.0,
|
||||
spacing_bottom: float = 0.0,
|
||||
scale: float = 0.6,
|
||||
color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0),
|
||||
) -> None:
|
||||
self.sub_width = sub_width
|
||||
self.spacing_top = spacing_top
|
||||
self.spacing_bottom = spacing_bottom
|
||||
self.color = color
|
||||
|
||||
self.textfin = bui.Lstr(translate=('serverResponses', text)).evaluate()
|
||||
assert len(subs) % 2 == 0 # Should always be even.
|
||||
for j in range(0, len(subs) - 1, 2):
|
||||
self.textfin = self.textfin.replace(subs[j], subs[j + 1])
|
||||
|
||||
# Calc scale to fit width and then see what height we need at
|
||||
# that scale.
|
||||
t_width = max(
|
||||
10.0,
|
||||
bui.get_string_width(self.textfin, suppress_warning=True) * scale,
|
||||
)
|
||||
self.text_scale = scale * min(1.0, (sub_width * 0.9) / t_width)
|
||||
|
||||
self.text_height = (
|
||||
0.0
|
||||
if not self.textfin
|
||||
else bui.get_string_height(self.textfin, suppress_warning=True)
|
||||
) * self.text_scale
|
||||
|
||||
self.full_height = self.text_height + spacing_top + spacing_bottom
|
||||
|
||||
@override
|
||||
def get_height(self) -> float:
|
||||
return self.full_height
|
||||
|
||||
@override
|
||||
def draw(self, subcontainer: bui.Widget, y: float) -> None:
|
||||
bui.textwidget(
|
||||
parent=subcontainer,
|
||||
position=(
|
||||
self.sub_width * 0.5,
|
||||
y - self.spacing_top - self.text_height * 0.5,
|
||||
# y - self.height * 0.5 - 23.0,
|
||||
),
|
||||
color=self.color,
|
||||
scale=self.text_scale,
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
text=self.textfin,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class _MessageEntry:
|
||||
type: bacommon.cloud.BSInboxEntryType
|
||||
class _EntryDisplay:
|
||||
interaction_style: bacommon.bs.BasicClientUI.InteractionStyle
|
||||
button_label_positive: bacommon.bs.BasicClientUI.ButtonLabel
|
||||
button_label_negative: bacommon.bs.BasicClientUI.ButtonLabel
|
||||
sections: list[_Section]
|
||||
id: str
|
||||
height: float
|
||||
text_height: float
|
||||
scale: float
|
||||
text: str
|
||||
total_height: float
|
||||
color: tuple[float, float, float]
|
||||
backing: bui.Widget | None = None
|
||||
button_positive: bui.Widget | None = None
|
||||
button_spinner_positive: bui.Widget | None = None
|
||||
button_negative: bui.Widget | None = None
|
||||
message_text: bui.Widget | None = None
|
||||
button_spinner_negative: bui.Widget | None = None
|
||||
# message_text: bui.Widget | None = None
|
||||
processing_complete: bool = False
|
||||
|
||||
|
||||
@ -45,15 +115,15 @@ class InboxWindow(bui.MainWindow):
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
|
||||
self._message_entries: list[_MessageEntry] = []
|
||||
self._entry_displays: list[_EntryDisplay] = []
|
||||
|
||||
self._width = 600 if uiscale is bui.UIScale.SMALL else 450
|
||||
self._width = 800 if uiscale is bui.UIScale.SMALL else 500
|
||||
self._height = (
|
||||
375
|
||||
455
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 370 if uiscale is bui.UIScale.MEDIUM else 450
|
||||
)
|
||||
yoffs = -47 if uiscale is bui.UIScale.SMALL else 0
|
||||
yoffs = -42 if uiscale is bui.UIScale.SMALL else 0
|
||||
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
@ -62,9 +132,9 @@ class InboxWindow(bui.MainWindow):
|
||||
'menu_full' if uiscale is bui.UIScale.SMALL else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
2.3
|
||||
1.7
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.65 if uiscale is bui.UIScale.MEDIUM else 1.23
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.15
|
||||
),
|
||||
stack_offset=(
|
||||
(0, 0)
|
||||
@ -101,7 +171,7 @@ class InboxWindow(bui.MainWindow):
|
||||
position=(
|
||||
self._width * 0.5,
|
||||
self._height
|
||||
- (27 if uiscale is bui.UIScale.SMALL else 20)
|
||||
- (24 if uiscale is bui.UIScale.SMALL else 20)
|
||||
+ yoffs,
|
||||
),
|
||||
size=(0, 0),
|
||||
@ -122,11 +192,15 @@ class InboxWindow(bui.MainWindow):
|
||||
flatness=1.0,
|
||||
color=(0.4, 0.4, 0.5),
|
||||
shadow=0.0,
|
||||
text=bui.Lstr(resource='loadingText'),
|
||||
text='',
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
self._loading_spinner = bui.spinnerwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height * 0.5),
|
||||
)
|
||||
self._scrollwidget = bui.scrollwidget(
|
||||
parent=self._root_widget,
|
||||
size=(
|
||||
@ -141,6 +215,7 @@ class InboxWindow(bui.MainWindow):
|
||||
simple_culling_v=200,
|
||||
claims_left_right=True,
|
||||
claims_up_down=True,
|
||||
center_small_content_horizontally=True,
|
||||
)
|
||||
bui.widget(edit=self._scrollwidget, autoselect=True)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
@ -163,7 +238,7 @@ class InboxWindow(bui.MainWindow):
|
||||
|
||||
with plus.accounts.primary:
|
||||
plus.cloud.send_message_cb(
|
||||
bacommon.cloud.BSInboxRequestMessage(),
|
||||
bacommon.bs.InboxRequestMessage(),
|
||||
on_response=bui.WeakCall(self._on_inbox_request_response),
|
||||
)
|
||||
|
||||
@ -179,26 +254,33 @@ class InboxWindow(bui.MainWindow):
|
||||
|
||||
def _error(self, errmsg: bui.Lstr | str) -> None:
|
||||
"""Put ourself in a permanent error state."""
|
||||
bui.spinnerwidget(edit=self._loading_spinner, visible=False)
|
||||
bui.textwidget(
|
||||
edit=self._infotext,
|
||||
color=(1, 0, 0),
|
||||
text=errmsg,
|
||||
)
|
||||
|
||||
def _on_message_entry_press(
|
||||
def _on_entry_display_press(
|
||||
self,
|
||||
entry_weak: weakref.ReferenceType[_MessageEntry],
|
||||
process_type: bacommon.cloud.BSInboxEntryProcessType,
|
||||
display_weak: weakref.ReferenceType[_EntryDisplay],
|
||||
action: bacommon.bs.ClientUIAction,
|
||||
) -> None:
|
||||
entry = entry_weak()
|
||||
if entry is None:
|
||||
display = display_weak()
|
||||
if display is None:
|
||||
return
|
||||
|
||||
self._neuter_message_entry(entry)
|
||||
bui.getsound('click01').play()
|
||||
|
||||
# We don't do anything for invalid messages.
|
||||
if entry.type is bacommon.cloud.BSInboxEntryType.UNKNOWN:
|
||||
entry.processing_complete = True
|
||||
self._neuter_entry_display(display)
|
||||
|
||||
# We currently only recognize basic entries and their possible
|
||||
# interaction types.
|
||||
if (
|
||||
display.interaction_style
|
||||
is bacommon.bs.BasicClientUI.InteractionStyle.UNKNOWN
|
||||
):
|
||||
display.processing_complete = True
|
||||
self._close_soon_if_all_processed()
|
||||
return
|
||||
|
||||
@ -211,38 +293,43 @@ class InboxWindow(bui.MainWindow):
|
||||
bui.getsound('error').play()
|
||||
return
|
||||
|
||||
# Message the master-server to process the entry.
|
||||
# Ask the master-server to run our action.
|
||||
with plus.accounts.primary:
|
||||
plus.cloud.send_message_cb(
|
||||
bacommon.cloud.BSInboxEntryProcessMessage(
|
||||
entry.id, process_type
|
||||
),
|
||||
bacommon.bs.ClientUIActionMessage(display.id, action),
|
||||
on_response=bui.WeakCall(
|
||||
self._on_inbox_entry_process_response,
|
||||
entry_weak,
|
||||
process_type,
|
||||
self._on_client_ui_action_response,
|
||||
display_weak,
|
||||
action,
|
||||
),
|
||||
)
|
||||
|
||||
# Tweak the button to show this is in progress.
|
||||
# Tweak the UI to show that things are in motion.
|
||||
button = (
|
||||
entry.button_positive
|
||||
if process_type is bacommon.cloud.BSInboxEntryProcessType.POSITIVE
|
||||
else entry.button_negative
|
||||
display.button_positive
|
||||
if action is bacommon.bs.ClientUIAction.BUTTON_PRESS_POSITIVE
|
||||
else display.button_negative
|
||||
)
|
||||
button_spinner = (
|
||||
display.button_spinner_positive
|
||||
if action is bacommon.bs.ClientUIAction.BUTTON_PRESS_POSITIVE
|
||||
else display.button_spinner_negative
|
||||
)
|
||||
if button is not None:
|
||||
bui.buttonwidget(edit=button, label='...')
|
||||
bui.buttonwidget(edit=button, label='')
|
||||
if button_spinner is not None:
|
||||
bui.spinnerwidget(edit=button_spinner, visible=True)
|
||||
|
||||
def _close_soon_if_all_processed(self) -> None:
|
||||
bui.apptimer(0.25, bui.WeakCall(self._close_if_all_processed))
|
||||
|
||||
def _close_if_all_processed(self) -> None:
|
||||
if not all(m.processing_complete for m in self._message_entries):
|
||||
if not all(m.processing_complete for m in self._entry_displays):
|
||||
return
|
||||
|
||||
self.main_window_back()
|
||||
|
||||
def _neuter_message_entry(self, entry: _MessageEntry) -> None:
|
||||
def _neuter_entry_display(self, entry: _EntryDisplay) -> None:
|
||||
errsound = bui.getsound('error')
|
||||
if entry.button_positive is not None:
|
||||
bui.buttonwidget(
|
||||
@ -260,22 +347,20 @@ class InboxWindow(bui.MainWindow):
|
||||
)
|
||||
if entry.backing is not None:
|
||||
bui.imagewidget(edit=entry.backing, color=(0.4, 0.4, 0.4))
|
||||
if entry.message_text is not None:
|
||||
bui.textwidget(edit=entry.message_text, color=(0.5, 0.5, 0.5, 0.5))
|
||||
|
||||
def _on_inbox_entry_process_response(
|
||||
def _on_client_ui_action_response(
|
||||
self,
|
||||
entry_weak: weakref.ReferenceType[_MessageEntry],
|
||||
process_type: bacommon.cloud.BSInboxEntryProcessType,
|
||||
response: bacommon.cloud.BSInboxEntryProcessResponse | Exception,
|
||||
display_weak: weakref.ReferenceType[_EntryDisplay],
|
||||
action: bacommon.bs.ClientUIAction,
|
||||
response: bacommon.bs.ClientUIActionResponse | Exception,
|
||||
) -> None:
|
||||
# pylint: disable=too-many-branches
|
||||
entry = entry_weak()
|
||||
if entry is None:
|
||||
display = display_weak()
|
||||
if display is None:
|
||||
return
|
||||
|
||||
assert not entry.processing_complete
|
||||
entry.processing_complete = True
|
||||
assert not display.processing_complete
|
||||
display.processing_complete = True
|
||||
self._close_soon_if_all_processed()
|
||||
|
||||
# No-op if our UI is dead or on its way out.
|
||||
@ -284,10 +369,18 @@ class InboxWindow(bui.MainWindow):
|
||||
|
||||
# Tweak the button to show results.
|
||||
button = (
|
||||
entry.button_positive
|
||||
if process_type is bacommon.cloud.BSInboxEntryProcessType.POSITIVE
|
||||
else entry.button_negative
|
||||
display.button_positive
|
||||
if action is bacommon.bs.ClientUIAction.BUTTON_PRESS_POSITIVE
|
||||
else display.button_negative
|
||||
)
|
||||
button_spinner = (
|
||||
display.button_spinner_positive
|
||||
if action is bacommon.bs.ClientUIAction.BUTTON_PRESS_POSITIVE
|
||||
else display.button_spinner_negative
|
||||
)
|
||||
# Always hide spinner at this point.
|
||||
if button_spinner is not None:
|
||||
bui.spinnerwidget(edit=button_spinner, visible=False)
|
||||
|
||||
# See if we should show an error message.
|
||||
if isinstance(response, Exception):
|
||||
@ -297,9 +390,11 @@ class InboxWindow(bui.MainWindow):
|
||||
)
|
||||
else:
|
||||
error_message = bui.Lstr(resource='errorText')
|
||||
elif response.error is not None:
|
||||
elif response.error_type is not None:
|
||||
# If error_type is set, error should be also.
|
||||
assert response.error_message is not None
|
||||
error_message = bui.Lstr(
|
||||
translate=('serverResponses', response.error)
|
||||
translate=('serverResponses', response.error_message)
|
||||
)
|
||||
else:
|
||||
error_message = None
|
||||
@ -314,31 +409,25 @@ class InboxWindow(bui.MainWindow):
|
||||
)
|
||||
return
|
||||
|
||||
# Success!
|
||||
assert not isinstance(response, Exception)
|
||||
|
||||
# Run any bundled effects.
|
||||
assert bui.app.classic is not None
|
||||
bui.app.classic.run_bs_client_effects(response.effects)
|
||||
|
||||
# Whee; no error. Mark as done.
|
||||
if button is not None:
|
||||
# If we have full unicode, just show a checkmark in all cases.
|
||||
label: str | bui.Lstr
|
||||
if bui.supports_unicode_display():
|
||||
label = '✓'
|
||||
else:
|
||||
# For positive claim buttons, say 'success'.
|
||||
# Otherwise default to 'done.'
|
||||
if (
|
||||
entry.type
|
||||
in {
|
||||
bacommon.cloud.BSInboxEntryType.CLAIM,
|
||||
bacommon.cloud.BSInboxEntryType.CLAIM_DISCARD,
|
||||
}
|
||||
and process_type
|
||||
is bacommon.cloud.BSInboxEntryProcessType.POSITIVE
|
||||
):
|
||||
label = bui.Lstr(resource='successText')
|
||||
else:
|
||||
label = bui.Lstr(resource='doneText')
|
||||
bui.buttonwidget(edit=button, label=label)
|
||||
|
||||
def _on_inbox_request_response(
|
||||
self, response: bacommon.cloud.BSInboxRequestResponse | Exception
|
||||
self, response: bacommon.bs.InboxRequestResponse | Exception
|
||||
) -> None:
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
@ -364,11 +453,12 @@ class InboxWindow(bui.MainWindow):
|
||||
self._error(errmsg)
|
||||
return
|
||||
|
||||
assert isinstance(response, bacommon.cloud.BSInboxRequestResponse)
|
||||
assert isinstance(response, bacommon.bs.InboxRequestResponse)
|
||||
|
||||
# If we got no messages, don't touch anything. This keeps
|
||||
# keyboard control working in the empty case.
|
||||
if not response.entries:
|
||||
if not response.wrappers:
|
||||
bui.spinnerwidget(edit=self._loading_spinner, visible=False)
|
||||
bui.textwidget(
|
||||
edit=self._infotext,
|
||||
color=(0.4, 0.4, 0.5),
|
||||
@ -376,63 +466,96 @@ class InboxWindow(bui.MainWindow):
|
||||
)
|
||||
return
|
||||
|
||||
bui.spinnerwidget(edit=self._loading_spinner, visible=False)
|
||||
bui.textwidget(edit=self._infotext, text='')
|
||||
|
||||
sub_width = self._width - 90
|
||||
# Even though our window size varies with uiscale, we want
|
||||
# notifications to target a fixed width.
|
||||
sub_width = 400.0
|
||||
sub_height = 0.0
|
||||
|
||||
# Run the math on row heights/etc.
|
||||
for i, entry in enumerate(response.entries):
|
||||
# Construct entries for everything we'll display.
|
||||
for i, wrapper in enumerate(response.wrappers):
|
||||
|
||||
# We need to flatten text here so we can measure it.
|
||||
textfin: str
|
||||
# textfin: str
|
||||
color: tuple[float, float, float]
|
||||
|
||||
# Messages with either newer formatting or unrecognized
|
||||
# types show up as 'upgrade your app to see this'.
|
||||
if (
|
||||
entry.format_version > SUPPORTED_INBOX_MESSAGE_FORMAT_VERSION
|
||||
or entry.type is bacommon.cloud.BSInboxEntryType.UNKNOWN
|
||||
):
|
||||
textfin = bui.Lstr(
|
||||
translate=(
|
||||
'serverResponses',
|
||||
'You must update the app to view this.',
|
||||
)
|
||||
).evaluate()
|
||||
color = (0.6, 0.6, 0.6)
|
||||
else:
|
||||
# Translate raw response and apply any replacements.
|
||||
textfin = bui.Lstr(
|
||||
translate=('serverResponses', entry.message)
|
||||
).evaluate()
|
||||
assert len(entry.subs) % 2 == 0 # Should always be even.
|
||||
for j in range(0, len(entry.subs) - 1, 2):
|
||||
textfin = textfin.replace(entry.subs[j], entry.subs[j + 1])
|
||||
color = (0.55, 0.5, 0.7)
|
||||
interaction_style: bacommon.bs.BasicClientUI.InteractionStyle
|
||||
button_label_positive: bacommon.bs.BasicClientUI.ButtonLabel
|
||||
button_label_negative: bacommon.bs.BasicClientUI.ButtonLabel
|
||||
|
||||
# Calc scale to fit width and then see what height we need
|
||||
# at that scale.
|
||||
t_width = max(
|
||||
10.0, bui.get_string_width(textfin, suppress_warning=True)
|
||||
sections: list[_Section] = []
|
||||
total_height = 90.0
|
||||
|
||||
# Display only entries where we recognize all style/label
|
||||
# values and ui component types.
|
||||
if (
|
||||
isinstance(wrapper.ui, bacommon.bs.BasicClientUI)
|
||||
and not wrapper.ui.contains_unknown_elements()
|
||||
):
|
||||
color = (0.55, 0.5, 0.7)
|
||||
interaction_style = wrapper.ui.interaction_style
|
||||
button_label_positive = wrapper.ui.button_label_positive
|
||||
button_label_negative = wrapper.ui.button_label_negative
|
||||
|
||||
idcls = bacommon.bs.BasicClientUIComponentTypeID
|
||||
for component in wrapper.ui.components:
|
||||
ctypeid = component.get_type_id()
|
||||
if ctypeid is idcls.TEXT:
|
||||
assert isinstance(
|
||||
component, bacommon.bs.BasicClientUIComponentText
|
||||
)
|
||||
scale = min(0.6, (sub_width * 0.9) / t_width)
|
||||
t_height = (
|
||||
max(10.0, bui.get_string_height(textfin, suppress_warning=True))
|
||||
* scale
|
||||
section = _TextSection(
|
||||
sub_width=sub_width,
|
||||
text=component.text,
|
||||
subs=component.subs,
|
||||
color=component.color,
|
||||
scale=component.scale,
|
||||
spacing_top=component.spacing_top,
|
||||
spacing_bottom=component.spacing_bottom,
|
||||
)
|
||||
entry_height = 90.0 + t_height
|
||||
self._message_entries.append(
|
||||
_MessageEntry(
|
||||
type=entry.type,
|
||||
id=entry.id,
|
||||
height=entry_height,
|
||||
text_height=t_height,
|
||||
scale=scale,
|
||||
text=textfin,
|
||||
total_height += section.get_height()
|
||||
sections.append(section)
|
||||
|
||||
elif ctypeid is idcls.UNKNOWN:
|
||||
raise RuntimeError('Should not get here.')
|
||||
else:
|
||||
# Make sure we handle all types.
|
||||
assert_never(ctypeid)
|
||||
else:
|
||||
|
||||
# Display anything with unknown components as an
|
||||
# 'upgrade your app to see this' message.
|
||||
color = (0.6, 0.6, 0.6)
|
||||
interaction_style = (
|
||||
bacommon.bs.BasicClientUI.InteractionStyle.UNKNOWN
|
||||
)
|
||||
button_label_positive = bacommon.bs.BasicClientUI.ButtonLabel.OK
|
||||
button_label_negative = (
|
||||
bacommon.bs.BasicClientUI.ButtonLabel.CANCEL
|
||||
)
|
||||
|
||||
section = _TextSection(
|
||||
sub_width=sub_width,
|
||||
text='You must update the app to view this.',
|
||||
subs=[],
|
||||
)
|
||||
total_height += section.get_height()
|
||||
sections.append(section)
|
||||
|
||||
self._entry_displays.append(
|
||||
_EntryDisplay(
|
||||
interaction_style=interaction_style,
|
||||
button_label_positive=button_label_positive,
|
||||
button_label_negative=button_label_negative,
|
||||
id=wrapper.id,
|
||||
sections=sections,
|
||||
total_height=total_height,
|
||||
color=color,
|
||||
)
|
||||
)
|
||||
sub_height += entry_height
|
||||
sub_height += total_height
|
||||
|
||||
subcontainer = bui.containerwidget(
|
||||
id='inboxsub',
|
||||
@ -446,98 +569,116 @@ class InboxWindow(bui.MainWindow):
|
||||
|
||||
backing_tex = bui.gettexture('buttonSquareWide')
|
||||
|
||||
assert bui.app.classic is not None
|
||||
|
||||
buttonrows: list[list[bui.Widget]] = []
|
||||
y = sub_height
|
||||
for i, _entry in enumerate(response.entries):
|
||||
message_entry = self._message_entries[i]
|
||||
message_entry_weak = weakref.ref(message_entry)
|
||||
for i, _wrapper in enumerate(response.wrappers):
|
||||
entry_display = self._entry_displays[i]
|
||||
entry_display_weak = weakref.ref(entry_display)
|
||||
bwidth = 140
|
||||
bheight = 40
|
||||
|
||||
ysection = y - 23.0
|
||||
|
||||
# Backing.
|
||||
message_entry.backing = img = bui.imagewidget(
|
||||
entry_display.backing = img = bui.imagewidget(
|
||||
parent=subcontainer,
|
||||
position=(-0.022 * sub_width, y - message_entry.height * 1.09),
|
||||
position=(
|
||||
-0.022 * sub_width,
|
||||
y - entry_display.total_height * 1.09,
|
||||
),
|
||||
texture=backing_tex,
|
||||
size=(sub_width * 1.07, message_entry.height * 1.15),
|
||||
color=message_entry.color,
|
||||
size=(sub_width * 1.07, entry_display.total_height * 1.15),
|
||||
color=entry_display.color,
|
||||
opacity=0.9,
|
||||
)
|
||||
bui.widget(edit=img, depth_range=(0, 0.1))
|
||||
|
||||
# Section contents.
|
||||
for sec in entry_display.sections:
|
||||
sec.draw(subcontainer, ysection)
|
||||
ysection -= sec.get_height()
|
||||
|
||||
buttonrow: list[bui.Widget] = []
|
||||
have_negative_button = (
|
||||
message_entry.type
|
||||
is bacommon.cloud.BSInboxEntryType.CLAIM_DISCARD
|
||||
entry_display.interaction_style
|
||||
is (
|
||||
bacommon.bs.BasicClientUI
|
||||
).InteractionStyle.BUTTON_POSITIVE_NEGATIVE
|
||||
)
|
||||
|
||||
message_entry.button_positive = btn = bui.buttonwidget(
|
||||
parent=subcontainer,
|
||||
position=(
|
||||
bpos = (
|
||||
(
|
||||
(sub_width - bwidth - 25)
|
||||
if have_negative_button
|
||||
else ((sub_width - bwidth) * 0.5)
|
||||
),
|
||||
y - message_entry.height + 15.0,
|
||||
),
|
||||
size=(bwidth, bheight),
|
||||
label=bui.Lstr(
|
||||
resource=(
|
||||
'claimText'
|
||||
if message_entry.type
|
||||
in {
|
||||
bacommon.cloud.BSInboxEntryType.CLAIM,
|
||||
bacommon.cloud.BSInboxEntryType.CLAIM_DISCARD,
|
||||
}
|
||||
else 'okText'
|
||||
y - entry_display.total_height + 15.0,
|
||||
)
|
||||
entry_display.button_positive = btn = bui.buttonwidget(
|
||||
parent=subcontainer,
|
||||
position=bpos,
|
||||
size=(bwidth, bheight),
|
||||
label=bui.app.classic.basic_client_ui_button_label_str(
|
||||
entry_display.button_label_positive
|
||||
),
|
||||
color=message_entry.color,
|
||||
color=entry_display.color,
|
||||
textcolor=(0, 1, 0),
|
||||
on_activate_call=bui.WeakCall(
|
||||
self._on_message_entry_press,
|
||||
message_entry_weak,
|
||||
bacommon.cloud.BSInboxEntryProcessType.POSITIVE,
|
||||
self._on_entry_display_press,
|
||||
entry_display_weak,
|
||||
bacommon.bs.ClientUIAction.BUTTON_PRESS_POSITIVE,
|
||||
),
|
||||
enable_sound=False,
|
||||
)
|
||||
bui.widget(edit=btn, depth_range=(0.1, 1.0))
|
||||
buttonrow.append(btn)
|
||||
spinner = entry_display.button_spinner_positive = bui.spinnerwidget(
|
||||
parent=subcontainer,
|
||||
position=(
|
||||
bpos[0] + 0.5 * bwidth,
|
||||
bpos[1] + 0.5 * bheight,
|
||||
),
|
||||
visible=False,
|
||||
)
|
||||
bui.widget(edit=spinner, depth_range=(0.1, 1.0))
|
||||
|
||||
if have_negative_button:
|
||||
message_entry.button_negative = btn2 = bui.buttonwidget(
|
||||
bpos = (25, y - entry_display.total_height + 15.0)
|
||||
entry_display.button_negative = btn2 = bui.buttonwidget(
|
||||
parent=subcontainer,
|
||||
position=(25, y - message_entry.height + 15.0),
|
||||
position=bpos,
|
||||
size=(bwidth, bheight),
|
||||
label=bui.Lstr(resource='discardText'),
|
||||
label=bui.app.classic.basic_client_ui_button_label_str(
|
||||
entry_display.button_label_negative
|
||||
),
|
||||
color=(0.85, 0.5, 0.7),
|
||||
textcolor=(1, 0.4, 0.4),
|
||||
on_activate_call=bui.WeakCall(
|
||||
self._on_message_entry_press,
|
||||
message_entry_weak,
|
||||
bacommon.cloud.BSInboxEntryProcessType.NEGATIVE,
|
||||
self._on_entry_display_press,
|
||||
entry_display_weak,
|
||||
(bacommon.bs.ClientUIAction).BUTTON_PRESS_NEGATIVE,
|
||||
),
|
||||
enable_sound=False,
|
||||
)
|
||||
bui.widget(edit=btn2, depth_range=(0.1, 1.0))
|
||||
buttonrow.append(btn2)
|
||||
spinner = entry_display.button_spinner_negative = (
|
||||
bui.spinnerwidget(
|
||||
parent=subcontainer,
|
||||
position=(
|
||||
bpos[0] + 0.5 * bwidth,
|
||||
bpos[1] + 0.5 * bheight,
|
||||
),
|
||||
visible=False,
|
||||
)
|
||||
)
|
||||
bui.widget(edit=spinner, depth_range=(0.1, 1.0))
|
||||
|
||||
buttonrows.append(buttonrow)
|
||||
|
||||
message_entry.message_text = bui.textwidget(
|
||||
parent=subcontainer,
|
||||
position=(
|
||||
sub_width * 0.5,
|
||||
y - message_entry.text_height * 0.5 - 23.0,
|
||||
),
|
||||
scale=message_entry.scale,
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
text=message_entry.text,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
y -= message_entry.height
|
||||
y -= entry_display.total_height
|
||||
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
above_widget = (
|
||||
|
||||
@ -39,6 +39,7 @@ class LeagueRankWindow(bui.MainWindow):
|
||||
self._league_text: bui.Widget | None = None
|
||||
self._league_number_text: bui.Widget | None = None
|
||||
self._your_power_ranking_text: bui.Widget | None = None
|
||||
self._loading_spinner: bui.Widget | None = None
|
||||
self._season_ends_text: bui.Widget | None = None
|
||||
self._power_ranking_rank_text: bui.Widget | None = None
|
||||
self._to_ranked_text: bui.Widget | None = None
|
||||
@ -150,7 +151,7 @@ class LeagueRankWindow(bui.MainWindow):
|
||||
self._doing_power_ranking_query = False
|
||||
|
||||
self._subcontainer: bui.Widget | None = None
|
||||
self._subcontainerwidth = 800
|
||||
self._subcontainerwidth = max(800, self._scroll_width)
|
||||
self._subcontainerheight = 483
|
||||
self._power_ranking_score_widgets: list[bui.Widget] = []
|
||||
|
||||
@ -330,13 +331,8 @@ class LeagueRankWindow(bui.MainWindow):
|
||||
bui.textwidget(edit=self._league_title_text, text='')
|
||||
bui.textwidget(edit=self._league_text, text='')
|
||||
bui.textwidget(edit=self._league_number_text, text='')
|
||||
bui.textwidget(
|
||||
edit=self._your_power_ranking_text,
|
||||
text=bui.Lstr(
|
||||
value='${A}...',
|
||||
subs=[('${A}', bui.Lstr(resource='loadingText'))],
|
||||
),
|
||||
)
|
||||
bui.textwidget(edit=self._your_power_ranking_text, text='')
|
||||
bui.spinnerwidget(edit=self._loading_spinner, visible=True)
|
||||
bui.textwidget(edit=self._to_ranked_text, text='')
|
||||
bui.textwidget(edit=self._power_ranking_rank_text, text='')
|
||||
bui.textwidget(edit=self._season_ends_text, text='')
|
||||
@ -618,6 +614,14 @@ class LeagueRankWindow(bui.MainWindow):
|
||||
flatness=1.0,
|
||||
)
|
||||
|
||||
self._loading_spinner = bui.spinnerwidget(
|
||||
parent=w_parent,
|
||||
position=(
|
||||
self._subcontainerwidth * 0.5,
|
||||
self._subcontainerheight * 0.5,
|
||||
),
|
||||
size=64,
|
||||
)
|
||||
self._your_power_ranking_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(self._xoffs + 470, v - 142 - 70),
|
||||
@ -968,6 +972,7 @@ class LeagueRankWindow(bui.MainWindow):
|
||||
else ''
|
||||
),
|
||||
)
|
||||
bui.spinnerwidget(edit=self._loading_spinner, visible=False)
|
||||
|
||||
bui.textwidget(
|
||||
edit=self._power_ranking_rank_text,
|
||||
|
||||
@ -431,7 +431,6 @@ class MainMenuWindow(bui.MainWindow):
|
||||
)
|
||||
|
||||
# Credits button.
|
||||
# self._tdelay += self._t_delay_inc
|
||||
thistdelay = self._tdelay + td5 * self._t_delay_inc
|
||||
|
||||
h += side_button_width * side_button_scale * 0.5 + hspace2
|
||||
@ -454,15 +453,16 @@ class MainMenuWindow(bui.MainWindow):
|
||||
transition_delay=thistdelay,
|
||||
on_activate_call=self._credits,
|
||||
)
|
||||
# self._tdelay += self._t_delay_inc
|
||||
|
||||
self._quit_button: bui.Widget | None
|
||||
if self._have_quit_button:
|
||||
v -= 1.1 * side_button_2_height * side_button_2_scale
|
||||
# Nudge this a tiny bit right so we can press right from the
|
||||
# credits button to get to it.
|
||||
self._quit_button = quit_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=self._use_autoselect,
|
||||
position=(h, v),
|
||||
position=(h + 4.0, v),
|
||||
size=(side_button_2_width, side_button_2_height),
|
||||
scale=side_button_2_scale,
|
||||
label=bui.Lstr(
|
||||
|
||||
@ -579,6 +579,10 @@ class PartyQueueWindow(bui.Window):
|
||||
|
||||
if plus.get_v1_account_ticket_count() < self._boost_tickets:
|
||||
bui.getsound('error').play()
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='notEnoughTicketsText'),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
# gettickets.show_get_tickets_prompt()
|
||||
return
|
||||
|
||||
|
||||
@ -42,9 +42,9 @@ class PlayWindow(bui.MainWindow):
|
||||
self._playlist_select_context = playlist_select_context
|
||||
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
width = 1100 if uiscale is bui.UIScale.SMALL else 800
|
||||
x_offs = 150 if uiscale is bui.UIScale.SMALL else 0
|
||||
y_offs = -60 if uiscale is bui.UIScale.SMALL else 0
|
||||
width = 1100 if uiscale is bui.UIScale.SMALL else 1000
|
||||
x_offs = 150 if uiscale is bui.UIScale.SMALL else 90
|
||||
y_offs = -60 if uiscale is bui.UIScale.SMALL else 45
|
||||
height = 650 if uiscale is bui.UIScale.SMALL else 550
|
||||
button_width = 400
|
||||
|
||||
@ -89,7 +89,7 @@ class PlayWindow(bui.MainWindow):
|
||||
else:
|
||||
self._back_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(55 + x_offs, height - 132 + y_offs),
|
||||
position=(5 + x_offs, height - 162 + y_offs),
|
||||
size=(60, 60),
|
||||
scale=1.1,
|
||||
text_res_scale=1.5,
|
||||
@ -103,11 +103,12 @@ class PlayWindow(bui.MainWindow):
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
)
|
||||
|
||||
txt = bui.textwidget(
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(width * 0.5, height - 101 + y_offs),
|
||||
# position=(width * 0.5, height -
|
||||
# (101 if main_menu else 61)),
|
||||
position=(
|
||||
width * 0.5,
|
||||
height - (83 if uiscale is bui.UIScale.SMALL else 131) + y_offs,
|
||||
),
|
||||
size=(0, 0),
|
||||
text=bui.Lstr(
|
||||
resource=(
|
||||
@ -116,17 +117,13 @@ class PlayWindow(bui.MainWindow):
|
||||
else 'playlistsText'
|
||||
)
|
||||
),
|
||||
scale=1.7,
|
||||
scale=1.2 if uiscale is bui.UIScale.SMALL else 1.7,
|
||||
res_scale=2.0,
|
||||
maxwidth=400,
|
||||
color=bui.app.ui_v1.heading_color,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.textwidget(edit=txt, text='')
|
||||
|
||||
v = (
|
||||
height
|
||||
- (110 if self._playlist_select_context is None else 90)
|
||||
@ -134,14 +131,14 @@ class PlayWindow(bui.MainWindow):
|
||||
)
|
||||
v -= 100
|
||||
clr = (0.6, 0.7, 0.6, 1.0)
|
||||
v -= 280 if self._playlist_select_context is None else 180
|
||||
v += 30 if uiscale is bui.UIScale.SMALL else 0
|
||||
v -= 270 if self._playlist_select_context is None else 280
|
||||
v += 65 if uiscale is bui.UIScale.SMALL else 0
|
||||
hoffs = (
|
||||
x_offs + 80
|
||||
x_offs - 45
|
||||
if self._playlist_select_context is None
|
||||
else x_offs - 100
|
||||
)
|
||||
scl = 1.13 if self._playlist_select_context is None else 0.68
|
||||
scl = 0.75 if self._playlist_select_context is None else 0.68
|
||||
|
||||
self._lineup_tex = bui.gettexture('playerLineup')
|
||||
angry_computer_transparent_mesh = bui.getmesh(
|
||||
@ -167,16 +164,15 @@ class PlayWindow(bui.MainWindow):
|
||||
if self._playlist_select_context is None:
|
||||
self._coop_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(hoffs, v + (scl * 15)),
|
||||
position=(hoffs, v),
|
||||
size=(
|
||||
scl * button_width,
|
||||
scl * 300,
|
||||
scl * 360,
|
||||
),
|
||||
extra_touch_border_scale=0.1,
|
||||
autoselect=True,
|
||||
label='',
|
||||
button_type='square',
|
||||
text_scale=1.13,
|
||||
on_activate_call=self._coop,
|
||||
)
|
||||
|
||||
@ -247,7 +243,7 @@ class PlayWindow(bui.MainWindow):
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
color=(0.7, 0.9, 0.7, 1.0),
|
||||
scale=scl * 2.3,
|
||||
scale=scl * 1.5,
|
||||
)
|
||||
|
||||
bui.textwidget(
|
||||
@ -264,34 +260,29 @@ class PlayWindow(bui.MainWindow):
|
||||
color=clr,
|
||||
)
|
||||
|
||||
scl = 0.5 if self._playlist_select_context is None else 0.68
|
||||
hoffs += 440 if self._playlist_select_context is None else 216
|
||||
v += 180 if self._playlist_select_context is None else -68
|
||||
scl = 0.75 if self._playlist_select_context is None else 0.68
|
||||
hoffs += 300 if self._playlist_select_context is None else 216
|
||||
# v += 0 if self._playlist_select_context is None else -68
|
||||
|
||||
self._teams_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
hoffs,
|
||||
v + (scl * 15 if self._playlist_select_context is None else 0),
|
||||
v,
|
||||
# v + (scl * 15 if
|
||||
# self._playlist_select_context is None else 0),
|
||||
),
|
||||
size=(
|
||||
scl * button_width,
|
||||
scl * (300 if self._playlist_select_context is None else 360),
|
||||
scl * (360 if self._playlist_select_context is None else 360),
|
||||
),
|
||||
extra_touch_border_scale=0.1,
|
||||
autoselect=True,
|
||||
label='',
|
||||
button_type='square',
|
||||
text_scale=1.13,
|
||||
on_activate_call=self._team_tourney,
|
||||
)
|
||||
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
up_widget=bui.get_special_widget('get_tokens_button'),
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
|
||||
xxx = -14
|
||||
self._draw_dude(
|
||||
2,
|
||||
@ -381,7 +372,7 @@ class PlayWindow(bui.MainWindow):
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
color=(0.7, 0.9, 0.7, 1.0),
|
||||
scale=scl * 2.3,
|
||||
scale=scl * 1.5,
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -392,29 +383,30 @@ class PlayWindow(bui.MainWindow):
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
res_scale=1.5,
|
||||
scale=0.9 * scl,
|
||||
scale=0.83 * scl,
|
||||
flatness=1.0,
|
||||
maxwidth=scl * button_width * 0.7,
|
||||
color=clr,
|
||||
)
|
||||
|
||||
hoffs += 0 if self._playlist_select_context is None else 300
|
||||
v -= 155 if self._playlist_select_context is None else 0
|
||||
hoffs += 300 if self._playlist_select_context is None else 300
|
||||
# v -= 0 if self._playlist_select_context is None else 0
|
||||
self._free_for_all_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
hoffs,
|
||||
v + (scl * 15 if self._playlist_select_context is None else 0),
|
||||
v,
|
||||
# v + (scl * 15
|
||||
# if self._playlist_select_context is None else 0),
|
||||
),
|
||||
size=(
|
||||
scl * button_width,
|
||||
scl * (300 if self._playlist_select_context is None else 360),
|
||||
scl * (360 if self._playlist_select_context is None else 360),
|
||||
),
|
||||
extra_touch_border_scale=0.1,
|
||||
autoselect=True,
|
||||
label='',
|
||||
button_type='square',
|
||||
text_scale=1.13,
|
||||
on_activate_call=self._free_for_all,
|
||||
)
|
||||
|
||||
@ -505,7 +497,7 @@ class PlayWindow(bui.MainWindow):
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
color=(0.7, 0.9, 0.7, 1.0),
|
||||
scale=scl * 1.9,
|
||||
scale=scl * 1.5,
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -515,7 +507,7 @@ class PlayWindow(bui.MainWindow):
|
||||
text=bui.Lstr(resource=f'{self._r}.twoToEightPlayersText'),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
scale=0.9 * scl,
|
||||
scale=0.83 * scl,
|
||||
flatness=1.0,
|
||||
maxwidth=scl * button_width * 0.7,
|
||||
color=clr,
|
||||
|
||||
@ -17,6 +17,8 @@ if TYPE_CHECKING:
|
||||
|
||||
from bauiv1lib.play import PlaylistSelectContext
|
||||
|
||||
REQUIRE_PRO = False
|
||||
|
||||
|
||||
class PlayOptionsWindow(PopupWindow):
|
||||
"""A popup window for configuring play options."""
|
||||
@ -316,7 +318,7 @@ class PlayOptionsWindow(PopupWindow):
|
||||
label=bui.Lstr(resource='teamNamesColorText'),
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
if not bui.app.classic.accounts.have_pro():
|
||||
if REQUIRE_PRO and not bui.app.classic.accounts.have_pro():
|
||||
bui.imagewidget(
|
||||
parent=self.root_widget,
|
||||
size=(30, 30),
|
||||
@ -440,7 +442,7 @@ class PlayOptionsWindow(PopupWindow):
|
||||
assert plus is not None
|
||||
|
||||
assert bui.app.classic is not None
|
||||
if not bui.app.classic.accounts.have_pro():
|
||||
if REQUIRE_PRO and not bui.app.classic.accounts.have_pro():
|
||||
if plus.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
else:
|
||||
|
||||
@ -205,7 +205,10 @@ class ProfileUpgradeWindow(bui.Window):
|
||||
tickets = plus.get_v1_account_ticket_count()
|
||||
if tickets < self._cost:
|
||||
bui.getsound('error').play()
|
||||
print('FIXME - show not-enough-tickets msg.')
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='notEnoughTicketsText'),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
# gettickets.show_get_tickets_prompt()
|
||||
return
|
||||
bui.screenmessage(
|
||||
|
||||
@ -162,7 +162,6 @@ class PurchaseWindow(bui.Window):
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
|
||||
def _purchase(self) -> None:
|
||||
# from bauiv1lib import gettickets
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
@ -176,9 +175,12 @@ class PurchaseWindow(bui.Window):
|
||||
except Exception:
|
||||
ticket_count = None
|
||||
if ticket_count is not None and ticket_count < self._price:
|
||||
# gettickets.show_get_tickets_prompt()
|
||||
print('FIXME - show not-enough-tickets msg')
|
||||
bui.getsound('error').play()
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='notEnoughTicketsText'),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
# gettickets.show_get_tickets_prompt()
|
||||
return
|
||||
|
||||
def do_it() -> None:
|
||||
|
||||
@ -53,24 +53,25 @@ class ResourceTypeInfoWindow(PopupWindow):
|
||||
iconscale=1.2,
|
||||
)
|
||||
|
||||
yoffs = self._height - 150
|
||||
yoffs = self._height - 145
|
||||
|
||||
if resource_type == 'tickets':
|
||||
rdesc = (
|
||||
'Tickets can be used to unlock characters,\n'
|
||||
'maps, minigames, and more in the store.\n'
|
||||
'\n'
|
||||
'Earn tickets by completing achievements\n'
|
||||
'or by opening chests won in the game.'
|
||||
'Tickets can be found in chests won through\n'
|
||||
'campaigns, tournaments, and achievements.'
|
||||
)
|
||||
texname = 'tickets'
|
||||
elif resource_type == 'tokens':
|
||||
rdesc = (
|
||||
'Tokens have various uses in the game such as\n'
|
||||
'speeding up chest unlocks.\n'
|
||||
'Tokens are used to speed up chest unlocks\n'
|
||||
'and for other game and account features.\n'
|
||||
'\n'
|
||||
'You can buy packs of tokens or you can buy a\n'
|
||||
'Gold Pass to get unlimited tokens.\n'
|
||||
'You can win tokens in the game or buy them\n'
|
||||
'in packs. Or buy a Gold Pass to get infinite\n'
|
||||
'tokens forever and never hear of them again.'
|
||||
)
|
||||
texname = 'coin'
|
||||
elif resource_type == 'trophies':
|
||||
|
||||
@ -10,7 +10,7 @@ import logging
|
||||
import bauiv1 as bui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
from typing import Callable
|
||||
|
||||
|
||||
class AllSettingsWindow(bui.MainWindow):
|
||||
@ -21,7 +21,6 @@ class AllSettingsWindow(bui.MainWindow):
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-locals
|
||||
|
||||
# Preload some modules we use in a background thread so we won't
|
||||
@ -31,12 +30,12 @@ class AllSettingsWindow(bui.MainWindow):
|
||||
bui.set_analytics_screen('Settings Window')
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
width = 1000 if uiscale is bui.UIScale.SMALL else 580
|
||||
width = 1000 if uiscale is bui.UIScale.SMALL else 900
|
||||
x_inset = 125 if uiscale is bui.UIScale.SMALL else 0
|
||||
height = 500 if uiscale is bui.UIScale.SMALL else 435
|
||||
height = 500 if uiscale is bui.UIScale.SMALL else 450
|
||||
self._r = 'settingsWindow'
|
||||
top_extra = 20 if uiscale is bui.UIScale.SMALL else 0
|
||||
yoffs = -30 if uiscale is bui.UIScale.SMALL else 0
|
||||
yoffs = -30 if uiscale is bui.UIScale.SMALL else -30
|
||||
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
super().__init__(
|
||||
@ -50,10 +49,7 @@ class AllSettingsWindow(bui.MainWindow):
|
||||
scale=(
|
||||
1.5
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.25 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, 0) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
else 1.1 if uiscale is bui.UIScale.MEDIUM else 0.8
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
@ -69,12 +65,12 @@ class AllSettingsWindow(bui.MainWindow):
|
||||
self._back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
position=(40 + x_inset, height - 55 + yoffs),
|
||||
size=(130, 60),
|
||||
position=(40 + x_inset, height - 60 + yoffs),
|
||||
size=(70, 70),
|
||||
scale=0.8,
|
||||
text_scale=1.2,
|
||||
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(edit=self._root_widget, cancel_button=btn)
|
||||
@ -87,131 +83,116 @@ class AllSettingsWindow(bui.MainWindow):
|
||||
color=bui.app.ui_v1.title_color,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
scale=1.1,
|
||||
maxwidth=130,
|
||||
)
|
||||
|
||||
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),
|
||||
bwidth = 200
|
||||
bheight = 230
|
||||
margin = 1
|
||||
all_buttons_width = 4.0 * bwidth + 3.0 * margin
|
||||
|
||||
x = width * 0.5 - all_buttons_width * 0.5
|
||||
y = height + yoffs - 320.0
|
||||
|
||||
def _button(
|
||||
position: tuple[float, float],
|
||||
label: bui.Lstr,
|
||||
call: Callable[[], None],
|
||||
texture: bui.Texture,
|
||||
imgsize: float,
|
||||
*,
|
||||
color: tuple[float, float, float] = (1.0, 1.0, 1.0),
|
||||
imgoffs: tuple[float, float] = (0.0, 0.0),
|
||||
) -> bui.Widget:
|
||||
x, y = position
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
position=(x, y),
|
||||
size=(bwidth, bheight),
|
||||
button_type='square',
|
||||
label='',
|
||||
on_activate_call=call,
|
||||
)
|
||||
|
||||
v = height - 80 + yoffs
|
||||
v -= 145
|
||||
|
||||
basew = 280 if uiscale is bui.UIScale.SMALL else 230
|
||||
baseh = 170
|
||||
x_offs = (
|
||||
x_inset + (105 if uiscale is bui.UIScale.SMALL else 72) - basew
|
||||
) # now unused
|
||||
x_offs2 = x_offs + basew - 7
|
||||
x_offs3 = x_offs + 2 * (basew - 7)
|
||||
x_offs4 = x_offs2
|
||||
x_offs5 = x_offs3
|
||||
|
||||
def _b_title(
|
||||
x: float, y: float, button: bui.Widget, text: str | bui.Lstr
|
||||
) -> None:
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
text=text,
|
||||
position=(x + basew * 0.47, y + baseh * 0.22),
|
||||
maxwidth=basew * 0.7,
|
||||
text=label,
|
||||
position=(x + bwidth * 0.5, y + bheight * 0.25),
|
||||
maxwidth=bwidth * 0.7,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
draw_controller=button,
|
||||
draw_controller=btn,
|
||||
color=(0.7, 0.9, 0.7, 1.0),
|
||||
)
|
||||
|
||||
ctb = self._controllers_button = bui.buttonwidget(
|
||||
bui.imagewidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
position=(x_offs2, v),
|
||||
size=(basew, baseh),
|
||||
button_type='square',
|
||||
label='',
|
||||
on_activate_call=self._do_controllers,
|
||||
position=(
|
||||
x + bwidth * 0.5 - imgsize * 0.5 + imgoffs[0],
|
||||
y + bheight * 0.56 - imgsize * 0.5 + imgoffs[1],
|
||||
),
|
||||
size=(imgsize, imgsize),
|
||||
texture=texture,
|
||||
draw_controller=btn,
|
||||
color=color,
|
||||
)
|
||||
return btn
|
||||
|
||||
self._controllers_button = _button(
|
||||
position=(x, y),
|
||||
label=bui.Lstr(resource=f'{self._r}.controllersText'),
|
||||
call=self._do_controllers,
|
||||
texture=bui.gettexture('controllerIcon'),
|
||||
imgsize=150,
|
||||
imgoffs=(-2.0, 2.0),
|
||||
)
|
||||
x += bwidth + margin
|
||||
|
||||
self._graphics_button = _button(
|
||||
position=(x, y),
|
||||
label=bui.Lstr(resource=f'{self._r}.graphicsText'),
|
||||
call=self._do_graphics,
|
||||
texture=bui.gettexture('graphicsIcon'),
|
||||
imgsize=135,
|
||||
imgoffs=(0, 4.0),
|
||||
)
|
||||
x += bwidth + margin
|
||||
|
||||
self._audio_button = _button(
|
||||
position=(x, y),
|
||||
label=bui.Lstr(resource=f'{self._r}.audioText'),
|
||||
call=self._do_audio,
|
||||
texture=bui.gettexture('audioIcon'),
|
||||
imgsize=150,
|
||||
color=(1, 1, 0),
|
||||
)
|
||||
x += bwidth + margin
|
||||
|
||||
self._advanced_button = _button(
|
||||
position=(x, y),
|
||||
label=bui.Lstr(resource=f'{self._r}.advancedText'),
|
||||
call=self._do_advanced,
|
||||
texture=bui.gettexture('advancedIcon'),
|
||||
imgsize=150,
|
||||
color=(0.8, 0.95, 1),
|
||||
imgoffs=(0, 5.0),
|
||||
)
|
||||
|
||||
# Hmm; we're now wide enough that being limited to pressing up
|
||||
# might be ok.
|
||||
if bool(False):
|
||||
# Left from our leftmost button should go to back button.
|
||||
if self._back_button is None:
|
||||
bbtn = bui.get_special_widget('back_button')
|
||||
bui.widget(edit=ctb, left_widget=bbtn)
|
||||
_b_title(
|
||||
x_offs2, v, ctb, bui.Lstr(resource=f'{self._r}.controllersText')
|
||||
)
|
||||
imgw = imgh = 130
|
||||
bui.imagewidget(
|
||||
parent=self._root_widget,
|
||||
position=(x_offs2 + basew * 0.49 - imgw * 0.5, v + 35),
|
||||
size=(imgw, imgh),
|
||||
texture=bui.gettexture('controllerIcon'),
|
||||
draw_controller=ctb,
|
||||
bui.widget(edit=self._controllers_button, left_widget=bbtn)
|
||||
|
||||
# Right from our rightmost widget should go to squad button.
|
||||
bui.widget(
|
||||
edit=self._advanced_button,
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
|
||||
gfxb = self._graphics_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
position=(x_offs3, v),
|
||||
size=(basew, baseh),
|
||||
button_type='square',
|
||||
label='',
|
||||
on_activate_call=self._do_graphics,
|
||||
)
|
||||
pbtn = bui.get_special_widget('squad_button')
|
||||
bui.widget(edit=gfxb, up_widget=pbtn, right_widget=pbtn)
|
||||
_b_title(x_offs3, v, gfxb, bui.Lstr(resource=f'{self._r}.graphicsText'))
|
||||
imgw = imgh = 110
|
||||
bui.imagewidget(
|
||||
parent=self._root_widget,
|
||||
position=(x_offs3 + basew * 0.49 - imgw * 0.5, v + 42),
|
||||
size=(imgw, imgh),
|
||||
texture=bui.gettexture('graphicsIcon'),
|
||||
draw_controller=gfxb,
|
||||
)
|
||||
|
||||
v -= baseh - 5
|
||||
|
||||
abtn = self._audio_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
position=(x_offs4, v),
|
||||
size=(basew, baseh),
|
||||
button_type='square',
|
||||
label='',
|
||||
on_activate_call=self._do_audio,
|
||||
)
|
||||
_b_title(x_offs4, v, abtn, bui.Lstr(resource=f'{self._r}.audioText'))
|
||||
imgw = imgh = 120
|
||||
bui.imagewidget(
|
||||
parent=self._root_widget,
|
||||
position=(x_offs4 + basew * 0.49 - imgw * 0.5 + 5, v + 35),
|
||||
size=(imgw, imgh),
|
||||
color=(1, 1, 0),
|
||||
texture=bui.gettexture('audioIcon'),
|
||||
draw_controller=abtn,
|
||||
)
|
||||
|
||||
avb = self._advanced_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
position=(x_offs5, v),
|
||||
size=(basew, baseh),
|
||||
button_type='square',
|
||||
label='',
|
||||
on_activate_call=self._do_advanced,
|
||||
)
|
||||
_b_title(x_offs5, v, avb, bui.Lstr(resource=f'{self._r}.advancedText'))
|
||||
imgw = imgh = 120
|
||||
bui.imagewidget(
|
||||
parent=self._root_widget,
|
||||
position=(x_offs5 + basew * 0.49 - imgw * 0.5 + 5, v + 35),
|
||||
size=(imgw, imgh),
|
||||
color=(0.8, 0.95, 1),
|
||||
texture=bui.gettexture('advancedIcon'),
|
||||
draw_controller=avb,
|
||||
)
|
||||
self._restore_state()
|
||||
|
||||
@override
|
||||
|
||||
@ -34,7 +34,10 @@ class AudioSettingsWindow(bui.MainWindow):
|
||||
|
||||
spacing = 50.0
|
||||
width = 460.0
|
||||
height = 210.0
|
||||
height = 240.0
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
|
||||
yoffs = -5.0
|
||||
|
||||
# Update: hard-coding head-relative audio to true now,
|
||||
# so not showing options.
|
||||
@ -49,11 +52,10 @@ class AudioSettingsWindow(bui.MainWindow):
|
||||
show_soundtracks = True
|
||||
height += spacing * 2.0
|
||||
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
base_scale = (
|
||||
2.05
|
||||
1.9
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.6 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
)
|
||||
popup_menu_scale = base_scale * 1.2
|
||||
|
||||
@ -61,9 +63,6 @@ class AudioSettingsWindow(bui.MainWindow):
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height),
|
||||
scale=base_scale,
|
||||
stack_offset=(
|
||||
(0, -20) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
toolbar_visibility=(
|
||||
None if uiscale is bui.UIScale.SMALL else 'menu_full'
|
||||
),
|
||||
@ -74,21 +73,20 @@ class AudioSettingsWindow(bui.MainWindow):
|
||||
|
||||
self._back_button = back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(35, height - 55),
|
||||
size=(120, 60),
|
||||
position=(35, height + yoffs - 55),
|
||||
size=(60, 60),
|
||||
scale=0.8,
|
||||
text_scale=1.2,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
button_type='backSmall',
|
||||
on_activate_call=self.main_window_back,
|
||||
autoselect=True,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
v = height - 60
|
||||
v -= spacing * 1.0
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(width * 0.5, height - 32),
|
||||
position=(width * 0.5, height + yoffs - 32),
|
||||
size=(0, 0),
|
||||
text=bui.Lstr(resource=f'{self._r}.titleText'),
|
||||
color=bui.app.ui_v1.title_color,
|
||||
@ -97,12 +95,8 @@ class AudioSettingsWindow(bui.MainWindow):
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
bui.buttonwidget(
|
||||
edit=self._back_button,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
v = height + yoffs - 60
|
||||
v -= spacing * 1.0
|
||||
|
||||
self._sound_volume_numedit = svne = ConfigNumberEdit(
|
||||
parent=self._root_widget,
|
||||
|
||||
@ -141,11 +141,11 @@ class StoreBrowserWindow(bui.MainWindow):
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
self._width * 0.5,
|
||||
self._height - (53 if uiscale is bui.UIScale.SMALL else 44),
|
||||
self._height - (55 if uiscale is bui.UIScale.SMALL else 44),
|
||||
),
|
||||
size=(0, 0),
|
||||
color=app.ui_v1.title_color,
|
||||
scale=1.5,
|
||||
scale=1.1 if uiscale is bui.UIScale.SMALL else 1.5,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
text=bui.Lstr(resource='storeText'),
|
||||
@ -536,7 +536,10 @@ class StoreBrowserWindow(bui.MainWindow):
|
||||
our_tickets = plus.get_v1_account_ticket_count()
|
||||
if price is not None and our_tickets < price:
|
||||
bui.getsound('error').play()
|
||||
print('FIXME - show not-enough-tickets info.')
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='notEnoughTicketsText'),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
# gettickets.show_get_tickets_prompt()
|
||||
else:
|
||||
|
||||
|
||||
@ -33,6 +33,8 @@ class TournamentEntryWindow(PopupWindow):
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
|
||||
from bauiv1lib.coop.tournamentbutton import USE_ENTRY_FEES
|
||||
|
||||
assert bui.app.classic is not None
|
||||
assert bui.app.plus
|
||||
bui.set_analytics_screen('Tournament Entry Window')
|
||||
@ -42,9 +44,15 @@ class TournamentEntryWindow(PopupWindow):
|
||||
self._tournament_id
|
||||
]
|
||||
|
||||
self._purchase_name: str | None
|
||||
self._purchase_price_name: str | None
|
||||
|
||||
# Set a few vars depending on the tourney fee.
|
||||
self._fee = self._tournament_info['fee']
|
||||
self._allow_ads = self._tournament_info['allowAds']
|
||||
assert isinstance(self._fee, int | None)
|
||||
self._allow_ads = (
|
||||
self._tournament_info['allowAds'] if USE_ENTRY_FEES else False
|
||||
)
|
||||
if self._fee == 4:
|
||||
self._purchase_name = 'tournament_entry_4'
|
||||
self._purchase_price_name = 'price.tournament_entry_4'
|
||||
@ -57,6 +65,9 @@ class TournamentEntryWindow(PopupWindow):
|
||||
elif self._fee == 1:
|
||||
self._purchase_name = 'tournament_entry_1'
|
||||
self._purchase_price_name = 'price.tournament_entry_1'
|
||||
elif self._fee is None or self._fee == -1:
|
||||
self._purchase_name = None
|
||||
self._purchase_price_name = 'FREE-WOOT'
|
||||
else:
|
||||
if self._fee != 0:
|
||||
raise ValueError('invalid fee: ' + str(self._fee))
|
||||
@ -218,7 +229,7 @@ class TournamentEntryWindow(PopupWindow):
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
scale=0.6,
|
||||
# Note: AdMob now requires rewarded ad usage
|
||||
# Note to self: AdMob requires rewarded ad usage
|
||||
# specifically says 'Ad' in it.
|
||||
text=bui.Lstr(resource='watchAnAdText'),
|
||||
maxwidth=95,
|
||||
@ -439,29 +450,52 @@ class TournamentEntryWindow(PopupWindow):
|
||||
)
|
||||
|
||||
# Keep price up-to-date and update the button with it.
|
||||
self._purchase_price = plus.get_v1_account_misc_read_val(
|
||||
if self._purchase_price_name is not None:
|
||||
self._purchase_price = (
|
||||
0
|
||||
if self._purchase_price_name == 'FREE-WOOT'
|
||||
else plus.get_v1_account_misc_read_val(
|
||||
self._purchase_price_name, None
|
||||
)
|
||||
)
|
||||
|
||||
# HACK - this is always free now, so just have this say 'PLAY'
|
||||
bui.textwidget(
|
||||
edit=self._ticket_cost_text,
|
||||
text=(
|
||||
bui.Lstr(resource='getTicketsWindow.freeText')
|
||||
if self._purchase_price == 0
|
||||
else bui.Lstr(
|
||||
resource='getTicketsWindow.ticketsText',
|
||||
subs=[
|
||||
(
|
||||
'${COUNT}',
|
||||
(
|
||||
str(self._purchase_price)
|
||||
if self._purchase_price is not None
|
||||
else '?'
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
bui.Lstr(resource='playText')
|
||||
# if self._purchase_price == 0
|
||||
# else bui.Lstr(
|
||||
# resource='getTicketsWindow.ticketsText',
|
||||
# subs=[
|
||||
# (
|
||||
# '${COUNT}',
|
||||
# (
|
||||
# str(self._purchase_price)
|
||||
# if self._purchase_price is not None
|
||||
# else '?'
|
||||
# ),
|
||||
# )
|
||||
# ],
|
||||
# )
|
||||
),
|
||||
# text=(
|
||||
# bui.Lstr(resource='getTicketsWindow.freeText')
|
||||
# if self._purchase_price == 0
|
||||
# else bui.Lstr(
|
||||
# resource='getTicketsWindow.ticketsText',
|
||||
# subs=[
|
||||
# (
|
||||
# '${COUNT}',
|
||||
# (
|
||||
# str(self._purchase_price)
|
||||
# if self._purchase_price is not None
|
||||
# else '?'
|
||||
# ),
|
||||
# )
|
||||
# ],
|
||||
# )
|
||||
# ),
|
||||
position=(
|
||||
self._ticket_cost_text_position_free
|
||||
if self._purchase_price == 0
|
||||
@ -472,19 +506,20 @@ class TournamentEntryWindow(PopupWindow):
|
||||
|
||||
bui.textwidget(
|
||||
edit=self._free_plays_remaining_text,
|
||||
text=(
|
||||
''
|
||||
if (
|
||||
self._tournament_info['freeTriesRemaining'] in [None, 0]
|
||||
or self._purchase_price != 0
|
||||
)
|
||||
else '' + str(self._tournament_info['freeTriesRemaining'])
|
||||
),
|
||||
# text=(
|
||||
# ''
|
||||
# if (
|
||||
# self._tournament_info['freeTriesRemaining'] in [None, 0]
|
||||
# or self._purchase_price != 0
|
||||
# )
|
||||
# else '' + str(self._tournament_info['freeTriesRemaining'])
|
||||
# ),
|
||||
text='', # No longer relevant.
|
||||
)
|
||||
|
||||
bui.imagewidget(
|
||||
edit=self._ticket_img,
|
||||
opacity=0.2 if self._purchase_price == 0 else 1.0,
|
||||
opacity=0.0 if self._purchase_price == 0 else 1.0,
|
||||
position=(
|
||||
self._ticket_img_pos_free
|
||||
if self._purchase_price == 0
|
||||
@ -547,15 +582,16 @@ class TournamentEntryWindow(PopupWindow):
|
||||
self._launched = True
|
||||
launched = False
|
||||
|
||||
# If they gave us an existing, non-consistent
|
||||
# practice activity, just restart it.
|
||||
# If they gave us an existing, non-consistent practice activity,
|
||||
# just restart it.
|
||||
if (
|
||||
self._tournament_activity is not None
|
||||
and not practice == self._tournament_activity.session.submit_score
|
||||
):
|
||||
try:
|
||||
if not practice:
|
||||
bui.apptimer(0.1, bui.getsound('cashRegister').play)
|
||||
bui.apptimer(0.1, bui.getsound('drumRollShort').play)
|
||||
# bui.apptimer(0.1, bui.getsound('cashRegister').play)
|
||||
bui.screenmessage(
|
||||
bui.Lstr(
|
||||
translate=(
|
||||
@ -584,7 +620,8 @@ class TournamentEntryWindow(PopupWindow):
|
||||
# launch a new session.
|
||||
if not launched:
|
||||
if not practice:
|
||||
bui.apptimer(0.1, bui.getsound('cashRegister').play)
|
||||
bui.apptimer(0.1, bui.getsound('drumRollShort').play)
|
||||
# bui.apptimer(0.1, bui.getsound('cashRegister').play)
|
||||
bui.screenmessage(
|
||||
bui.Lstr(
|
||||
translate=('serverResponses', 'Entering tournament...')
|
||||
@ -653,14 +690,19 @@ class TournamentEntryWindow(PopupWindow):
|
||||
ticket_count = None
|
||||
ticket_cost = self._purchase_price
|
||||
if ticket_count is not None and ticket_count < ticket_cost:
|
||||
# gettickets.show_get_tickets_prompt()
|
||||
print('FIXME - show not-enough-tickets msg.')
|
||||
bui.getsound('error').play()
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='notEnoughTicketsText'),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
# gettickets.show_get_tickets_prompt()
|
||||
self._transition_out()
|
||||
return
|
||||
|
||||
cur_time = bui.apptime()
|
||||
self._last_ticket_press_time = cur_time
|
||||
|
||||
if self._purchase_name is not None:
|
||||
assert isinstance(ticket_cost, int)
|
||||
plus.in_game_purchase(self._purchase_name, ticket_cost)
|
||||
|
||||
@ -759,30 +801,20 @@ class TournamentEntryWindow(PopupWindow):
|
||||
plus.run_v1_account_transactions()
|
||||
self._launch()
|
||||
|
||||
# def _on_get_tickets_press(self) -> None:
|
||||
# from bauiv1lib import gettickets
|
||||
|
||||
# # If we're already entering, ignore presses.
|
||||
# if self._entering:
|
||||
# return
|
||||
|
||||
# # Bring up get-tickets window and then kill ourself (we're on the
|
||||
# # overlay layer so we'd show up above it).
|
||||
# gettickets.GetTicketsWindow(
|
||||
# modal=True, origin_widget=self._get_tickets_button
|
||||
# )
|
||||
# self._transition_out()
|
||||
|
||||
def _on_cancel(self) -> None:
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
# Don't allow canceling for several seconds after poking an enter
|
||||
# button if it looks like we're waiting on a purchase or entering
|
||||
# the tournament.
|
||||
if (bui.apptime() - self._last_ticket_press_time < 6.0) and (
|
||||
if (
|
||||
(bui.apptime() - self._last_ticket_press_time < 6.0)
|
||||
and self._purchase_name is not None
|
||||
and (
|
||||
plus.have_outstanding_v1_account_transactions()
|
||||
or plus.get_v1_account_product_purchased(self._purchase_name)
|
||||
or self._entering
|
||||
)
|
||||
):
|
||||
bui.getsound('error').play()
|
||||
return
|
||||
|
||||
@ -138,7 +138,7 @@ auto AppAdapterApple::TryRender() -> bool {
|
||||
|
||||
// Keep on drawing until the drawn window size
|
||||
// matches what we have (or until we try for too long or fail at drawing).
|
||||
seconds_t start_time = g_core->GetAppTimeSeconds();
|
||||
seconds_t start_time = g_core->AppTimeSeconds();
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
bool size_differs =
|
||||
((std::abs(resize_target_resolution_.x
|
||||
@ -147,7 +147,7 @@ auto AppAdapterApple::TryRender() -> bool {
|
||||
|| (std::abs(resize_target_resolution_.y
|
||||
- g_base->graphics_server->screen_pixel_height())
|
||||
> 0.01f));
|
||||
if (size_differs && g_core->GetAppTimeSeconds() - start_time < 0.1
|
||||
if (size_differs && g_core->AppTimeSeconds() - start_time < 0.1
|
||||
&& result) {
|
||||
result = g_base->graphics_server->TryRender();
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ void AppAdapterSDL::RunMainThreadEventLoopToCompletion() {
|
||||
assert(g_core->InMainThread());
|
||||
|
||||
while (!done_) {
|
||||
microsecs_t cycle_start_time = g_core->GetAppTimeMicrosecs();
|
||||
microsecs_t cycle_start_time = g_core->AppTimeMicrosecs();
|
||||
|
||||
// Events.
|
||||
SDL_Event event;
|
||||
@ -274,7 +274,7 @@ void AppAdapterSDL::SleepUntilNextEventCycle_(microsecs_t cycle_start_time) {
|
||||
|
||||
// Normally we just calc when our next draw should happen and sleep 'til
|
||||
// then.
|
||||
microsecs_t now = g_core->GetAppTimeMicrosecs();
|
||||
microsecs_t now = g_core->AppTimeMicrosecs();
|
||||
auto used_max_fps = max_fps_;
|
||||
millisecs_t millisecs_per_frame = 1000000 / used_max_fps;
|
||||
|
||||
@ -319,7 +319,7 @@ void AppAdapterSDL::SleepUntilNextEventCycle_(microsecs_t cycle_start_time) {
|
||||
// Maintain an 'oversleep' amount to compensate for the timer not being
|
||||
// exact. This should keep us exactly at our target frame-rate in the
|
||||
// end.
|
||||
now = g_core->GetAppTimeMicrosecs();
|
||||
now = g_core->AppTimeMicrosecs();
|
||||
oversleep_ = now - target_time;
|
||||
|
||||
// Prevent oversleep from compensating by more than a few millisecs per
|
||||
@ -438,7 +438,7 @@ void AppAdapterSDL::HandleSDLEvent_(const SDL_Event& event) {
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
if (g_core->GetAppTimeSeconds() - last_windowevent_close_time_ < 0.1) {
|
||||
if (g_core->AppTimeSeconds() - last_windowevent_close_time_ < 0.1) {
|
||||
// If they hit the window close button, skip the confirm.
|
||||
g_base->QuitApp(false);
|
||||
} else {
|
||||
@ -459,7 +459,7 @@ void AppAdapterSDL::HandleSDLEvent_(const SDL_Event& event) {
|
||||
case SDL_WINDOWEVENT_CLOSE: {
|
||||
// Simply note that this happened. We use this to adjust our
|
||||
// SDL_QUIT behavior (quit is called right after this).
|
||||
last_windowevent_close_time_ = g_core->GetAppTimeSeconds();
|
||||
last_windowevent_close_time_ = g_core->AppTimeSeconds();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ namespace ballistica::base {
|
||||
Asset::Asset() {
|
||||
assert(g_base);
|
||||
assert(g_base->InLogicThread());
|
||||
last_used_time_ = g_core->GetAppTimeMillisecs();
|
||||
last_used_time_ = g_core->AppTimeMillisecs();
|
||||
}
|
||||
|
||||
auto Asset::AssetTypeName(AssetType assettype) -> const char* {
|
||||
@ -65,9 +65,9 @@ void Asset::Preload(bool already_locked) {
|
||||
return std::string("preloading ") + AssetTypeName(GetAssetType()) + " "
|
||||
+ GetName();
|
||||
});
|
||||
preload_start_time_ = g_core->GetAppTimeMillisecs();
|
||||
preload_start_time_ = g_core->AppTimeMillisecs();
|
||||
DoPreload();
|
||||
preload_end_time_ = g_core->GetAppTimeMillisecs();
|
||||
preload_end_time_ = g_core->AppTimeMillisecs();
|
||||
preloaded_ = true;
|
||||
}
|
||||
}
|
||||
@ -87,9 +87,9 @@ void Asset::Load(bool already_locked) {
|
||||
return std::string("loading ") + AssetTypeName(GetAssetType()) + " "
|
||||
+ GetName();
|
||||
});
|
||||
load_start_time_ = g_core->GetAppTimeMillisecs();
|
||||
load_start_time_ = g_core->AppTimeMillisecs();
|
||||
DoLoad();
|
||||
load_end_time_ = g_core->GetAppTimeMillisecs();
|
||||
load_end_time_ = g_core->AppTimeMillisecs();
|
||||
BA_DEBUG_FUNCTION_TIMER_END_THREAD_EX(50, GetName());
|
||||
loaded_ = true;
|
||||
}
|
||||
|
||||
@ -165,6 +165,7 @@ void Assets::StartLoading() {
|
||||
LoadSystemTexture(SysTextureID::kCharacterIconMask, "characterIconMask");
|
||||
LoadSystemTexture(SysTextureID::kBlack, "black");
|
||||
LoadSystemTexture(SysTextureID::kWings, "wings");
|
||||
LoadSystemTexture(SysTextureID::kSpinner, "spinner");
|
||||
|
||||
// System cube map textures:
|
||||
LoadSystemCubeMapTexture(SysCubeMapTextureID::kReflectionChar,
|
||||
@ -479,7 +480,7 @@ auto Assets::GetAsset(const std::string& file_name,
|
||||
have_pending_loads_[static_cast<int>(d->GetAssetType())] = true;
|
||||
MarkAssetForLoad(d.get());
|
||||
}
|
||||
d->set_last_used_time(g_core->GetAppTimeMillisecs());
|
||||
d->set_last_used_time(g_core->AppTimeMillisecs());
|
||||
return Object::Ref<T>(d);
|
||||
}
|
||||
}
|
||||
@ -499,7 +500,7 @@ auto Assets::GetTexture(TextPacker* packer) -> Object::Ref<TextureAsset> {
|
||||
have_pending_loads_[static_cast<int>(d->GetAssetType())] = true;
|
||||
MarkAssetForLoad(d.get());
|
||||
}
|
||||
d->set_last_used_time(g_core->GetAppTimeMillisecs());
|
||||
d->set_last_used_time(g_core->AppTimeMillisecs());
|
||||
return Object::Ref<TextureAsset>(d);
|
||||
}
|
||||
}
|
||||
@ -519,7 +520,7 @@ auto Assets::GetQRCodeTexture(const std::string& url)
|
||||
have_pending_loads_[static_cast<int>(d->GetAssetType())] = true;
|
||||
MarkAssetForLoad(d.get());
|
||||
}
|
||||
d->set_last_used_time(g_core->GetAppTimeMillisecs());
|
||||
d->set_last_used_time(g_core->AppTimeMillisecs());
|
||||
return Object::Ref<TextureAsset>(d);
|
||||
}
|
||||
}
|
||||
@ -542,7 +543,7 @@ auto Assets::GetCubeMapTexture(const std::string& file_name)
|
||||
have_pending_loads_[static_cast<int>(d->GetAssetType())] = true;
|
||||
MarkAssetForLoad(d.get());
|
||||
}
|
||||
d->set_last_used_time(g_core->GetAppTimeMillisecs());
|
||||
d->set_last_used_time(g_core->AppTimeMillisecs());
|
||||
return Object::Ref<TextureAsset>(d);
|
||||
}
|
||||
}
|
||||
@ -598,7 +599,7 @@ auto Assets::GetTexture(const std::string& file_name)
|
||||
have_pending_loads_[static_cast<int>(d->GetAssetType())] = true;
|
||||
MarkAssetForLoad(d.get());
|
||||
}
|
||||
d->set_last_used_time(g_core->GetAppTimeMillisecs());
|
||||
d->set_last_used_time(g_core->AppTimeMillisecs());
|
||||
return Object::Ref<TextureAsset>(d);
|
||||
}
|
||||
}
|
||||
@ -750,7 +751,7 @@ auto Assets::RunPendingLoadsLogicThread() -> bool {
|
||||
template <typename T>
|
||||
auto Assets::RunPendingLoadList(std::vector<Object::Ref<T>*>* c_list) -> bool {
|
||||
bool flush = false;
|
||||
millisecs_t starttime = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t starttime = g_core->AppTimeMillisecs();
|
||||
|
||||
std::vector<Object::Ref<T>*> l;
|
||||
std::vector<Object::Ref<T>*> l_unfinished;
|
||||
@ -760,8 +761,7 @@ auto Assets::RunPendingLoadList(std::vector<Object::Ref<T>*>* c_list) -> bool {
|
||||
|
||||
// If we're already out of time.
|
||||
if (!flush
|
||||
&& g_core->GetAppTimeMillisecs() - starttime
|
||||
> PENDING_LOAD_PROCESS_TIME) {
|
||||
&& g_core->AppTimeMillisecs() - starttime > PENDING_LOAD_PROCESS_TIME) {
|
||||
bool return_val = (!c_list->empty());
|
||||
return return_val;
|
||||
}
|
||||
@ -790,8 +790,7 @@ auto Assets::RunPendingLoadList(std::vector<Object::Ref<T>*>* c_list) -> bool {
|
||||
// If the load finished, pop it on our "done-loading" list.. otherwise
|
||||
// keep it around.
|
||||
l_finished.push_back(*i); // else l_unfinished.push_back(*i);
|
||||
if (g_core->GetAppTimeMillisecs() - starttime
|
||||
> PENDING_LOAD_PROCESS_TIME
|
||||
if (g_core->AppTimeMillisecs() - starttime > PENDING_LOAD_PROCESS_TIME
|
||||
&& !flush) {
|
||||
out_of_time = true;
|
||||
}
|
||||
@ -832,7 +831,7 @@ auto Assets::RunPendingLoadList(std::vector<Object::Ref<T>*>* c_list) -> bool {
|
||||
|
||||
void Assets::Prune(int level) {
|
||||
assert(g_base->InLogicThread());
|
||||
millisecs_t current_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t current_time = g_core->AppTimeMillisecs();
|
||||
|
||||
// Need lists locked while accessing/modifying them.
|
||||
AssetListLock lock;
|
||||
@ -1168,11 +1167,11 @@ auto Assets::FindAssetFile(FileType type, const std::string& name)
|
||||
// We wanna fail gracefully for some types.
|
||||
if (type == FileType::kSound && name != "blank") {
|
||||
g_core->Log(LogName::kBaAssets, LogLevel::kError,
|
||||
"Unable to load audio: '" + name + "'; trying fallback...");
|
||||
"Unable to load audio: '" + name + "'.");
|
||||
return FindAssetFile(type, "blank");
|
||||
} else if (type == FileType::kTexture && name != "white") {
|
||||
g_core->Log(LogName::kBaAssets, LogLevel::kError,
|
||||
"Unable to load texture: '" + name + "'; trying fallback...");
|
||||
"Unable to load texture: '" + name + "'.");
|
||||
return FindAssetFile(type, "white");
|
||||
}
|
||||
|
||||
@ -1560,8 +1559,8 @@ auto DoCompileResourceString(cJSON* obj) -> std::string {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto Assets::CompileResourceString(const std::string& s, const std::string& loc,
|
||||
bool* valid) -> std::string {
|
||||
auto Assets::CompileResourceString(const std::string& s, bool* valid)
|
||||
-> std::string {
|
||||
bool dummyvalid;
|
||||
if (valid == nullptr) {
|
||||
valid = &dummyvalid;
|
||||
@ -1577,8 +1576,7 @@ auto Assets::CompileResourceString(const std::string& s, const std::string& loc,
|
||||
cJSON* root = cJSON_Parse(s.c_str());
|
||||
if (root == nullptr) {
|
||||
g_core->Log(LogName::kBaAssets, LogLevel::kError,
|
||||
"CompileResourceString failed (loc " + loc
|
||||
+ "); invalid json: '" + s + "'");
|
||||
"CompileResourceString failed; invalid json: '" + s + "'");
|
||||
*valid = false;
|
||||
return "";
|
||||
}
|
||||
@ -1588,8 +1586,8 @@ auto Assets::CompileResourceString(const std::string& s, const std::string& loc,
|
||||
*valid = true;
|
||||
} catch (const std::exception& e) {
|
||||
g_core->Log(LogName::kBaAssets, LogLevel::kError,
|
||||
"CompileResourceString failed (loc " + loc
|
||||
+ "): " + std::string(e.what()) + "; str='" + s + "'");
|
||||
"CompileResourceString failed: " + std::string(e.what())
|
||||
+ "; str='" + s + "'");
|
||||
result = "<error>";
|
||||
*valid = false;
|
||||
}
|
||||
|
||||
@ -111,8 +111,8 @@ class Assets {
|
||||
const std::unordered_map<std::string, std::string>& language);
|
||||
auto GetResourceString(const std::string& key) -> std::string;
|
||||
auto CharStr(SpecialChar id) -> std::string;
|
||||
auto CompileResourceString(const std::string& s, const std::string& loc,
|
||||
bool* valid = nullptr) -> std::string;
|
||||
auto CompileResourceString(const std::string& s, bool* valid = nullptr)
|
||||
-> std::string;
|
||||
|
||||
auto sys_assets_loaded() const { return sys_assets_loaded_; }
|
||||
|
||||
|
||||
@ -324,7 +324,7 @@ void SoundAsset::DoUnload() {
|
||||
}
|
||||
|
||||
void SoundAsset::UpdatePlayTime() {
|
||||
last_play_time_ = g_core->GetAppTimeMillisecs();
|
||||
last_play_time_ = g_core->AppTimeMillisecs();
|
||||
}
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -156,7 +156,7 @@ auto Audio::SourceBeginExisting(uint32_t play_id, int debug_id)
|
||||
}
|
||||
|
||||
auto Audio::ShouldPlay(SoundAsset* sound) -> bool {
|
||||
millisecs_t time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t time = g_core->AppTimeMillisecs();
|
||||
assert(sound);
|
||||
return (time - sound->last_play_time() > 50);
|
||||
}
|
||||
|
||||
@ -212,9 +212,8 @@ void AudioServer::OpenALSoftLogCallback(const std::string& msg) {
|
||||
std::scoped_lock lock(openalsoft_android_log_mutex_);
|
||||
|
||||
if (openalsoft_android_log_.size() < log_cap) {
|
||||
openalsoft_android_log_ += "openal-log("
|
||||
+ std::to_string(g_core->GetAppTimeSeconds())
|
||||
+ "s): " + msg;
|
||||
openalsoft_android_log_ +=
|
||||
"openal-log(" + std::to_string(g_core->AppTimeSeconds()) + "s): " + msg;
|
||||
if (openalsoft_android_log_.size() >= log_cap) {
|
||||
openalsoft_android_log_ +=
|
||||
"\n<max openalsoft log storage size reached>\n";
|
||||
@ -477,7 +476,7 @@ void AudioServer::OnAppStartInThread_() {
|
||||
// Now make available any stopped sources (should be all of them).
|
||||
UpdateAvailableSources_();
|
||||
|
||||
last_started_playing_time_ = g_core->GetAppTimeSeconds();
|
||||
last_started_playing_time_ = g_core->AppTimeSeconds();
|
||||
#endif // BA_ENABLE_AUDIO
|
||||
}
|
||||
|
||||
@ -487,7 +486,7 @@ void AudioServer::Shutdown() {
|
||||
return;
|
||||
}
|
||||
shutting_down_ = true;
|
||||
shutdown_start_time_ = g_core->GetAppTimeSeconds();
|
||||
shutdown_start_time_ = g_core->AppTimeSeconds();
|
||||
|
||||
// Stop all playing sounds and note the time. We'll then give everything a
|
||||
// moment to come to a halt before we tear down the audio context to
|
||||
@ -538,8 +537,8 @@ struct AudioServer::SoundFadeNode_ {
|
||||
bool out;
|
||||
SoundFadeNode_(uint32_t play_id_in, millisecs_t duration_in, bool out_in)
|
||||
: play_id(play_id_in),
|
||||
starttime(g_core->GetAppTimeMillisecs()),
|
||||
endtime(g_core->GetAppTimeMillisecs() + duration_in),
|
||||
starttime(g_core->AppTimeMillisecs()),
|
||||
endtime(g_core->AppTimeMillisecs() + duration_in),
|
||||
out(out_in) {}
|
||||
};
|
||||
|
||||
@ -566,15 +565,15 @@ void AudioServer::SetSuspended_(bool suspend) {
|
||||
try {
|
||||
g_core->platform->LowLevelDebugLog(
|
||||
"Calling alcDevicePauseSOFT at "
|
||||
+ std::to_string(g_core->GetAppTimeSeconds()));
|
||||
+ std::to_string(g_core->AppTimeSeconds()));
|
||||
alcDevicePauseSOFT(device);
|
||||
} catch (const std::exception& e) {
|
||||
g_core->Log(LogName::kBaAudio, LogLevel::kError,
|
||||
g_core->Log(
|
||||
LogName::kBaAudio, LogLevel::kError,
|
||||
"Error in alcDevicePauseSOFT at time "
|
||||
+ std::to_string(g_core->GetAppTimeSeconds())
|
||||
+ "( playing since "
|
||||
+ std::to_string(last_started_playing_time_) + "): "
|
||||
+ g_core->platform->DemangleCXXSymbol(typeid(e).name())
|
||||
+ std::to_string(g_core->AppTimeSeconds()) + "( playing since "
|
||||
+ std::to_string(last_started_playing_time_)
|
||||
+ "): " + g_core->platform->DemangleCXXSymbol(typeid(e).name())
|
||||
+ " " + e.what());
|
||||
} catch (...) {
|
||||
g_core->Log(LogName::kBaAudio, LogLevel::kError,
|
||||
@ -609,12 +608,12 @@ void AudioServer::SetSuspended_(bool suspend) {
|
||||
try {
|
||||
g_core->platform->LowLevelDebugLog(
|
||||
"Calling alcDeviceResumeSOFT at "
|
||||
+ std::to_string(g_core->GetAppTimeSeconds()));
|
||||
+ std::to_string(g_core->AppTimeSeconds()));
|
||||
alcDeviceResumeSOFT(device);
|
||||
} catch (const std::exception& e) {
|
||||
g_core->Log(LogName::kBaAudio, LogLevel::kError,
|
||||
"Error in alcDeviceResumeSOFT at time "
|
||||
+ std::to_string(g_core->GetAppTimeSeconds()) + ": "
|
||||
+ std::to_string(g_core->AppTimeSeconds()) + ": "
|
||||
+ g_core->platform->DemangleCXXSymbol(typeid(e).name())
|
||||
+ " " + e.what());
|
||||
} catch (...) {
|
||||
@ -622,7 +621,7 @@ void AudioServer::SetSuspended_(bool suspend) {
|
||||
"Unknown error in alcDeviceResumeSOFT");
|
||||
}
|
||||
#endif
|
||||
last_started_playing_time_ = g_core->GetAppTimeSeconds();
|
||||
last_started_playing_time_ = g_core->AppTimeSeconds();
|
||||
suspended_ = false;
|
||||
#if BA_ENABLE_AUDIO
|
||||
CHECK_AL_ERROR;
|
||||
@ -774,7 +773,7 @@ void AudioServer::UpdateAvailableSources_() {
|
||||
// and see how many are in use, how many are currently locked by the client,
|
||||
// etc.
|
||||
#if (BA_DEBUG_BUILD || BA_TEST_BUILD)
|
||||
millisecs_t t = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t t = g_core->AppTimeMillisecs();
|
||||
if (t - last_sanity_check_time_ > 5000) {
|
||||
last_sanity_check_time_ = t;
|
||||
|
||||
@ -1033,7 +1032,7 @@ void AudioServer::OnDeviceDisconnected() {
|
||||
|
||||
void AudioServer::Process_() {
|
||||
assert(g_base->InAudioThread());
|
||||
seconds_t real_time_seconds = g_core->GetAppTimeSeconds();
|
||||
seconds_t real_time_seconds = g_core->AppTimeSeconds();
|
||||
millisecs_t real_time_millisecs = real_time_seconds * 1000;
|
||||
|
||||
// Only do real work if we're in normal running mode.
|
||||
@ -1085,7 +1084,7 @@ void AudioServer::Process_() {
|
||||
// for the mixer to spit out some silence so we don't hear sudden cut-offs
|
||||
// in one or both ears.
|
||||
if (shutting_down_ && !shutdown_completed_) {
|
||||
if (g_core->GetAppTimeSeconds() - shutdown_start_time_ > 0.2) {
|
||||
if (g_core->AppTimeSeconds() - shutdown_start_time_ > 0.2) {
|
||||
CompleteShutdown_();
|
||||
}
|
||||
}
|
||||
@ -1125,13 +1124,13 @@ void AudioServer::ProcessSoundFades_() {
|
||||
|
||||
AudioServer::ThreadSource_* s = GetPlayingSound_(i->second.play_id);
|
||||
if (s) {
|
||||
if (g_core->GetAppTimeMillisecs() > i->second.endtime) {
|
||||
if (g_core->AppTimeMillisecs() > i->second.endtime) {
|
||||
StopSound(i->second.play_id);
|
||||
sound_fade_nodes_.erase(i);
|
||||
} else {
|
||||
float fade_val =
|
||||
1
|
||||
- (static_cast<float>(g_core->GetAppTimeMillisecs()
|
||||
- (static_cast<float>(g_core->AppTimeMillisecs()
|
||||
- i->second.starttime)
|
||||
/ static_cast<float>(i->second.endtime - i->second.starttime));
|
||||
s->SetFade(fade_val);
|
||||
@ -1639,12 +1638,12 @@ void AudioServer::ClearSoundRefDeleteList() {
|
||||
// g_base->audio_server->PushSetSuspendedCall(true);
|
||||
|
||||
// // Wait a reasonable amount of time for the thread to act on it.
|
||||
// millisecs_t t = g_core->GetAppTimeMillisecs();
|
||||
// millisecs_t t = g_core->AppTimeMillisecs();
|
||||
// while (true) {
|
||||
// if (g_base->audio_server->suspended()) {
|
||||
// break;
|
||||
// }
|
||||
// if (g_core->GetAppTimeMillisecs() - t > 1000) {
|
||||
// if (g_core->AppTimeMillisecs() - t > 1000) {
|
||||
// Log(LogLevel::kError, "Timed out waiting for audio suspend.");
|
||||
// break;
|
||||
// }
|
||||
@ -1657,12 +1656,12 @@ void AudioServer::ClearSoundRefDeleteList() {
|
||||
// g_base->audio_server->PushSetSuspendedCall(false);
|
||||
|
||||
// // Wait a reasonable amount of time for the thread to act on it.
|
||||
// millisecs_t t = g_core->GetAppTimeMillisecs();
|
||||
// millisecs_t t = g_core->AppTimeMillisecs();
|
||||
// while (true) {
|
||||
// if (!g_base->audio_server->suspended()) {
|
||||
// break;
|
||||
// }
|
||||
// if (g_core->GetAppTimeMillisecs() - t > 1000) {
|
||||
// if (g_core->AppTimeMillisecs() - t > 1000) {
|
||||
// Log(LogLevel::kError, "Timed out waiting for audio unsuspend.");
|
||||
// break;
|
||||
// }
|
||||
|
||||
@ -103,7 +103,7 @@ void AudioSource::Lock(int debug_id) {
|
||||
BA_DEBUG_FUNCTION_TIMER_BEGIN();
|
||||
mutex_.lock();
|
||||
#if BA_DEBUG_BUILD
|
||||
last_lock_time_ = g_core->GetAppTimeMillisecs();
|
||||
last_lock_time_ = g_core->AppTimeMillisecs();
|
||||
lock_debug_id_ = debug_id;
|
||||
locked_ = true;
|
||||
#endif
|
||||
@ -115,7 +115,7 @@ auto AudioSource::TryLock(int debug_id) -> bool {
|
||||
#if (BA_DEBUG_BUILD || BA_TEST_BUILD)
|
||||
if (locked) {
|
||||
locked_ = true;
|
||||
last_lock_time_ = g_core->GetAppTimeMillisecs();
|
||||
last_lock_time_ = g_core->AppTimeMillisecs();
|
||||
lock_debug_id_ = debug_id;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -174,6 +174,11 @@ void BaseFeatureSet::ErrorScreenMessage() {
|
||||
}
|
||||
|
||||
auto BaseFeatureSet::GetV2AccountID() -> std::optional<std::string> {
|
||||
// Guard against this getting called early.
|
||||
if (!IsAppStarted()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto gil = Python::ScopedInterpreterLock();
|
||||
auto result =
|
||||
python->objs().Get(BasePython::ObjID::kGetV2AccountIdCall).Call();
|
||||
@ -199,7 +204,7 @@ void BaseFeatureSet::StartApp() {
|
||||
BA_PRECONDITION(g_core->InMainThread());
|
||||
BA_PRECONDITION(g_base);
|
||||
|
||||
auto start_time = g_core->GetAppTimeSeconds();
|
||||
auto start_time = g_core->AppTimeSeconds();
|
||||
|
||||
// Currently limiting this to once per process.
|
||||
BA_PRECONDITION(!called_start_app_);
|
||||
@ -253,7 +258,7 @@ void BaseFeatureSet::StartApp() {
|
||||
// Make some noise if this takes more than a few seconds. If we pass 5
|
||||
// seconds or so we start to trigger App-Not-Responding reports which
|
||||
// isn't good.
|
||||
auto duration = g_core->GetAppTimeSeconds() - start_time;
|
||||
auto duration = g_core->AppTimeSeconds() - start_time;
|
||||
if (duration > 3.0) {
|
||||
char buffer[128];
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
@ -272,7 +277,7 @@ void BaseFeatureSet::SuspendApp() {
|
||||
return;
|
||||
}
|
||||
|
||||
millisecs_t start_time{core::CorePlatform::GetCurrentMillisecs()};
|
||||
millisecs_t start_time{core::CorePlatform::TimeMonotonicMillisecs()};
|
||||
|
||||
// Apple mentioned 5 seconds to run stuff once backgrounded or they bring
|
||||
// down the hammer. Let's aim to stay under 2.
|
||||
@ -280,7 +285,7 @@ void BaseFeatureSet::SuspendApp() {
|
||||
|
||||
g_core->platform->LowLevelDebugLog(
|
||||
"SuspendApp@"
|
||||
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()));
|
||||
+ std::to_string(core::CorePlatform::TimeMonotonicMillisecs()));
|
||||
app_suspended_ = true;
|
||||
|
||||
// IMPORTANT: Any pause related stuff that event-loop-threads need to do
|
||||
@ -311,13 +316,13 @@ void BaseFeatureSet::SuspendApp() {
|
||||
g_core->Log(
|
||||
LogName::kBa, LogLevel::kDebug,
|
||||
"SuspendApp() completed in "
|
||||
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()
|
||||
+ std::to_string(core::CorePlatform::TimeMonotonicMillisecs()
|
||||
- start_time)
|
||||
+ "ms.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
} while (std::abs(core::CorePlatform::GetCurrentMillisecs() - start_time)
|
||||
} while (std::abs(core::CorePlatform::TimeMonotonicMillisecs() - start_time)
|
||||
< max_duration);
|
||||
|
||||
// If we made it here, we timed out. Complain.
|
||||
@ -325,7 +330,8 @@ void BaseFeatureSet::SuspendApp() {
|
||||
std::string("SuspendApp() took too long; ")
|
||||
+ std::to_string(running_loops.size())
|
||||
+ " event-loops not yet suspended after "
|
||||
+ std::to_string(core::CorePlatform::GetCurrentMillisecs() - start_time)
|
||||
+ std::to_string(core::CorePlatform::TimeMonotonicMillisecs()
|
||||
- start_time)
|
||||
+ " ms: (";
|
||||
bool first = true;
|
||||
for (auto* loop : running_loops) {
|
||||
@ -383,10 +389,10 @@ void BaseFeatureSet::UnsuspendApp() {
|
||||
"AppAdapter::UnsuspendApp() called with app not in suspendedstate.");
|
||||
return;
|
||||
}
|
||||
millisecs_t start_time{core::CorePlatform::GetCurrentMillisecs()};
|
||||
millisecs_t start_time{core::CorePlatform::TimeMonotonicMillisecs()};
|
||||
g_core->platform->LowLevelDebugLog(
|
||||
"UnsuspendApp@"
|
||||
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()));
|
||||
+ std::to_string(core::CorePlatform::TimeMonotonicMillisecs()));
|
||||
app_suspended_ = false;
|
||||
|
||||
// Spin all event-loops back up.
|
||||
@ -397,9 +403,10 @@ void BaseFeatureSet::UnsuspendApp() {
|
||||
g_base->networking->OnAppUnsuspend();
|
||||
|
||||
if (g_buildconfig.debug_build()) {
|
||||
g_core->Log(LogName::kBa, LogLevel::kDebug,
|
||||
g_core->Log(
|
||||
LogName::kBa, LogLevel::kDebug,
|
||||
"UnsuspendApp() completed in "
|
||||
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()
|
||||
+ std::to_string(core::CorePlatform::TimeMonotonicMillisecs()
|
||||
- start_time)
|
||||
+ "ms.");
|
||||
}
|
||||
@ -571,7 +578,7 @@ auto BaseFeatureSet::GetAppInstanceUUID() -> const std::string& {
|
||||
g_core->Log(LogName::kBa, LogLevel::kWarning,
|
||||
"GetSessionUUID() using rand fallback.");
|
||||
srand(static_cast<unsigned int>(
|
||||
core::CorePlatform::GetCurrentMillisecs())); // NOLINT
|
||||
core::CorePlatform::TimeMonotonicMillisecs())); // NOLINT
|
||||
app_instance_uuid =
|
||||
std::to_string(static_cast<uint32_t>(rand())); // NOLINT
|
||||
have_app_instance_uuid = true;
|
||||
@ -966,7 +973,7 @@ void BaseFeatureSet::SetAppActive(bool active) {
|
||||
|
||||
g_core->platform->LowLevelDebugLog(
|
||||
"SetAppActive(" + std::to_string(active) + ")@"
|
||||
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()));
|
||||
+ std::to_string(core::CorePlatform::TimeMonotonicMillisecs()));
|
||||
|
||||
// Issue a gentle warning if they are feeding us the same state twice in a
|
||||
// row; might imply faulty logic on an app-adapter or whatnot.
|
||||
@ -990,6 +997,12 @@ void BaseFeatureSet::Reset() {
|
||||
audio->Reset();
|
||||
}
|
||||
|
||||
auto BaseFeatureSet::TimeSinceEpochCloudSeconds() -> seconds_t {
|
||||
// TODO(ericf): wire this up. Just using local time for now. And make sure
|
||||
// that this and utc_now_cloud() in the Python layer are synced up.
|
||||
return core::CorePlatform::TimeSinceEpochSeconds();
|
||||
}
|
||||
|
||||
void BaseFeatureSet::SetUIScale(UIScale scale) {
|
||||
assert(InLogicThread());
|
||||
|
||||
|
||||
@ -476,7 +476,8 @@ enum class SysTextureID : uint8_t {
|
||||
kFontExtras4,
|
||||
kCharacterIconMask,
|
||||
kBlack,
|
||||
kWings
|
||||
kWings,
|
||||
kSpinner
|
||||
};
|
||||
|
||||
enum class SysCubeMapTextureID : uint8_t {
|
||||
@ -761,8 +762,8 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
||||
|
||||
void PushMainThreadRunnable(Runnable* runnable) override;
|
||||
|
||||
/// Return the currently signed in V2 account id as
|
||||
/// reported by the Python layer.
|
||||
/// Return the currently signed in V2 account id as reported by the Python
|
||||
/// layer.
|
||||
auto GetV2AccountID() -> std::optional<std::string>;
|
||||
|
||||
/// Return whether clipboard operations are supported at all. This gets
|
||||
@ -784,6 +785,10 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
||||
/// Set overall ui scale for the app.
|
||||
void SetUIScale(UIScale scale);
|
||||
|
||||
/// Time since epoch on the master-server. Tries to
|
||||
/// be correct even if local time is set wrong.
|
||||
auto TimeSinceEpochCloudSeconds() -> seconds_t;
|
||||
|
||||
// Const subsystems.
|
||||
AppAdapter* const app_adapter;
|
||||
AppConfig* const app_config;
|
||||
|
||||
@ -96,7 +96,7 @@ class BGDynamicsServer::Terrain {
|
||||
if (collision_mesh_) {
|
||||
Object::Ref<CollisionMeshAsset>* ref = collision_mesh_;
|
||||
g_base->logic->event_loop()->PushCall([ref] {
|
||||
(**ref).set_last_used_time(g_core->GetAppTimeMillisecs());
|
||||
(**ref).set_last_used_time(g_core->AppTimeMillisecs());
|
||||
delete ref;
|
||||
});
|
||||
collision_mesh_ = nullptr;
|
||||
|
||||
@ -90,12 +90,12 @@ void RendererGL::CheckGLError(const char* file, int line) {
|
||||
BA_PRECONDITION_FATAL(vendor);
|
||||
const char* renderer = (const char*)glGetString(GL_RENDERER);
|
||||
BA_PRECONDITION_FATAL(renderer);
|
||||
g_core->Log(
|
||||
LogName::kBaGraphics, LogLevel::kError,
|
||||
"OpenGL Error at " + std::string(file) + " line " + std::to_string(line)
|
||||
+ ": " + GLErrorToString(err) + "\nrenderer: " + renderer
|
||||
+ "\nvendor: " + vendor + "\nversion: " + version
|
||||
+ "\ntime: " + std::to_string(g_core->GetAppTimeMillisecs()));
|
||||
g_core->Log(LogName::kBaGraphics, LogLevel::kError,
|
||||
"OpenGL Error at " + std::string(file) + " line "
|
||||
+ std::to_string(line) + ": " + GLErrorToString(err)
|
||||
+ "\nrenderer: " + renderer + "\nvendor: " + vendor
|
||||
+ "\nversion: " + version
|
||||
+ "\ntime: " + std::to_string(g_core->AppTimeMillisecs()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -253,13 +253,13 @@ auto Graphics::GraphicsQualityFromAppConfig() -> GraphicsQualityRequest {
|
||||
void Graphics::SetGyroEnabled(bool enable) {
|
||||
// If we're turning back on, suppress gyro updates for a bit.
|
||||
if (enable && !gyro_enabled_) {
|
||||
last_suppress_gyro_time_ = g_core->GetAppTimeMicrosecs();
|
||||
last_suppress_gyro_time_ = g_core->AppTimeMicrosecs();
|
||||
}
|
||||
gyro_enabled_ = enable;
|
||||
}
|
||||
|
||||
void Graphics::UpdateProgressBarProgress(float target) {
|
||||
millisecs_t real_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t real_time = g_core->AppTimeMillisecs();
|
||||
float p = target;
|
||||
if (p < 0) {
|
||||
p = 0;
|
||||
@ -274,7 +274,7 @@ void Graphics::UpdateProgressBarProgress(float target) {
|
||||
}
|
||||
|
||||
void Graphics::DrawProgressBar(RenderPass* pass, float opacity) {
|
||||
millisecs_t real_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t real_time = g_core->AppTimeMillisecs();
|
||||
float amount = progress_bar_progress_;
|
||||
if (amount < 0) {
|
||||
amount = 0;
|
||||
@ -361,9 +361,9 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) {
|
||||
assert(g_base && g_base->InLogicThread());
|
||||
|
||||
// Every now and then, update our stats.
|
||||
while (g_core->GetAppTimeMillisecs() >= next_stat_update_time_) {
|
||||
if (g_core->GetAppTimeMillisecs() - next_stat_update_time_ > 1000) {
|
||||
next_stat_update_time_ = g_core->GetAppTimeMillisecs() + 1000;
|
||||
while (g_core->AppTimeMillisecs() >= next_stat_update_time_) {
|
||||
if (g_core->AppTimeMillisecs() - next_stat_update_time_ > 1000) {
|
||||
next_stat_update_time_ = g_core->AppTimeMillisecs() + 1000;
|
||||
} else {
|
||||
next_stat_update_time_ += 1000;
|
||||
}
|
||||
@ -482,7 +482,7 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) {
|
||||
// Draw any debug graphs.
|
||||
{
|
||||
float debug_graph_y = 50.0;
|
||||
auto now = g_core->GetAppTimeMillisecs();
|
||||
auto now = g_core->AppTimeMillisecs();
|
||||
for (auto it = debug_graphs_.begin(); it != debug_graphs_.end();) {
|
||||
assert(it->second.exists());
|
||||
if (now - it->second->LastUsedTime() > 1000) {
|
||||
@ -508,7 +508,7 @@ auto Graphics::GetDebugGraph(const std::string& name, bool smoothed)
|
||||
debug_graphs_[name]->SetLabel(name);
|
||||
debug_graphs_[name]->SetSmoothed(smoothed);
|
||||
}
|
||||
debug_graphs_[name]->SetLastUsedTime(g_core->GetAppTimeMillisecs());
|
||||
debug_graphs_[name]->SetLastUsedTime(g_core->AppTimeMillisecs());
|
||||
return debug_graphs_[name].get();
|
||||
}
|
||||
|
||||
@ -770,7 +770,7 @@ void Graphics::BuildAndPushFrameDef() {
|
||||
assert(!building_frame_def_);
|
||||
building_frame_def_ = true;
|
||||
|
||||
microsecs_t app_time_microsecs = g_core->GetAppTimeMicrosecs();
|
||||
microsecs_t app_time_microsecs = g_core->AppTimeMicrosecs();
|
||||
|
||||
// Store how much time this frame_def represents.
|
||||
auto display_time_microsecs = g_base->logic->display_time_microsecs();
|
||||
@ -1222,7 +1222,7 @@ void Graphics::EnableProgressBar(bool fade_in) {
|
||||
if (progress_bar_loads_ > 0) {
|
||||
progress_bar_ = true;
|
||||
progress_bar_fade_in_ = fade_in;
|
||||
last_progress_bar_draw_time_ = g_core->GetAppTimeMillisecs();
|
||||
last_progress_bar_draw_time_ = g_core->AppTimeMillisecs();
|
||||
last_progress_bar_start_time_ = last_progress_bar_draw_time_;
|
||||
progress_bar_progress_ = 0.0f;
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ auto GraphicsServer::TryRender() -> bool {
|
||||
|
||||
auto GraphicsServer::WaitForRenderFrameDef_() -> FrameDef* {
|
||||
assert(g_base->app_adapter->InGraphicsContext());
|
||||
millisecs_t start_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t start_time = g_core->AppTimeMillisecs();
|
||||
|
||||
// Spin and wait for a short bit for a frame_def to appear.
|
||||
while (true) {
|
||||
@ -176,7 +176,7 @@ auto GraphicsServer::WaitForRenderFrameDef_() -> FrameDef* {
|
||||
}
|
||||
|
||||
// If there's no frame_def for us, sleep for a bit and wait for it.
|
||||
millisecs_t t = g_core->GetAppTimeMillisecs() - start_time;
|
||||
millisecs_t t = g_core->AppTimeMillisecs() - start_time;
|
||||
if (t >= 1000) {
|
||||
if (g_buildconfig.debug_build()) {
|
||||
g_core->Log(LogName::kBaGraphics, LogLevel::kWarning,
|
||||
|
||||
@ -650,7 +650,7 @@ void Renderer::UpdatePixelScaleAndBackingBuffer(FrameDef* frame_def) {
|
||||
}
|
||||
|
||||
void Renderer::LoadMedia(FrameDef* frame_def) {
|
||||
millisecs_t t = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t t = g_core->AppTimeMillisecs();
|
||||
for (auto&& i : frame_def->media_components()) {
|
||||
Asset* mc = i.get();
|
||||
assert(mc);
|
||||
@ -667,7 +667,7 @@ void Renderer::LoadMedia(FrameDef* frame_def) {
|
||||
// // default about 1 second after a res change, etc...
|
||||
// // so if we're using a non-1.0 gamma, lets keep setting it periodically
|
||||
// // to force the issue
|
||||
// millisecs_t t = g_core->GetAppTimeMillisecs();
|
||||
// millisecs_t t = g_core->AppTimeMillisecs();
|
||||
// if (screen_gamma_requested_ != screen_gamma_
|
||||
// || (t - last_screen_gamma_update_time_ > 300 && screen_gamma_ != 1.0f))
|
||||
// {
|
||||
|
||||
@ -207,10 +207,9 @@ void Camera::UpdatePosition() {
|
||||
lr_jitter = 0.0f;
|
||||
} else {
|
||||
lr_jitter =
|
||||
sinf(static_cast<float>(g_core->GetAppTimeMillisecs()) / 108.0f)
|
||||
sinf(static_cast<float>(g_core->AppTimeMillisecs()) / 108.0f)
|
||||
* 0.4f
|
||||
+ sinf(static_cast<float>(g_core->GetAppTimeMillisecs())
|
||||
/ 268.0f)
|
||||
+ sinf(static_cast<float>(g_core->AppTimeMillisecs()) / 268.0f)
|
||||
* 1.0f;
|
||||
lr_jitter *= 0.05f;
|
||||
}
|
||||
@ -891,7 +890,7 @@ void Camera::SetMode(CameraMode m) {
|
||||
if (mode_ != m) {
|
||||
mode_ = m;
|
||||
smooth_next_frame_ = false;
|
||||
// last_mode_set_time_ = g_core->GetAppTimeMillisecs();
|
||||
// last_mode_set_time_ = g_core->AppTimeMillisecs();
|
||||
// last_mode_set_time_ = time_;
|
||||
heading_ = kInitialHeading;
|
||||
}
|
||||
|
||||
@ -65,8 +65,8 @@ void ScreenMessages::DrawMiscOverlays(FrameDef* frame_def) {
|
||||
// Delete old ones.
|
||||
if (!screen_messages_.empty()) {
|
||||
millisecs_t cutoff;
|
||||
if (g_core->GetAppTimeMillisecs() > 5000) {
|
||||
cutoff = g_core->GetAppTimeMillisecs() - 5000;
|
||||
if (g_core->AppTimeMillisecs() > 5000) {
|
||||
cutoff = g_core->AppTimeMillisecs() - 5000;
|
||||
for (auto i = screen_messages_.begin(); i != screen_messages_.end();) {
|
||||
if (i->creation_time < cutoff) {
|
||||
auto next = i;
|
||||
@ -128,7 +128,7 @@ void ScreenMessages::DrawMiscOverlays(FrameDef* frame_def) {
|
||||
// which is calculated as part of it.
|
||||
i->GetText();
|
||||
|
||||
millisecs_t age = g_core->GetAppTimeMillisecs() - i->creation_time;
|
||||
millisecs_t age = g_core->AppTimeMillisecs() - i->creation_time;
|
||||
youngest_age = std::min(youngest_age, age);
|
||||
float s_extra = 1.0f;
|
||||
if (age < 100) {
|
||||
@ -244,7 +244,7 @@ void ScreenMessages::DrawMiscOverlays(FrameDef* frame_def) {
|
||||
|
||||
for (auto i = screen_messages_.rbegin(); i != screen_messages_.rend();
|
||||
i++) {
|
||||
millisecs_t age = g_core->GetAppTimeMillisecs() - i->creation_time;
|
||||
millisecs_t age = g_core->AppTimeMillisecs() - i->creation_time;
|
||||
youngest_age = std::min(youngest_age, age);
|
||||
float s_extra = 1.0f;
|
||||
if (age < 100) {
|
||||
@ -315,8 +315,8 @@ void ScreenMessages::DrawMiscOverlays(FrameDef* frame_def) {
|
||||
// Delete old ones.
|
||||
if (!screen_messages_top_.empty()) {
|
||||
millisecs_t cutoff;
|
||||
if (g_core->GetAppTimeMillisecs() > 5000) {
|
||||
cutoff = g_core->GetAppTimeMillisecs() - 5000;
|
||||
if (g_core->AppTimeMillisecs() > 5000) {
|
||||
cutoff = g_core->AppTimeMillisecs() - 5000;
|
||||
for (auto i = screen_messages_top_.begin();
|
||||
i != screen_messages_top_.end();) {
|
||||
if (i->creation_time < cutoff) {
|
||||
@ -354,7 +354,7 @@ void ScreenMessages::DrawMiscOverlays(FrameDef* frame_def) {
|
||||
// Update the translation if need be.
|
||||
i->UpdateTranslation();
|
||||
|
||||
millisecs_t age = g_core->GetAppTimeMillisecs() - i->creation_time;
|
||||
millisecs_t age = g_core->AppTimeMillisecs() - i->creation_time;
|
||||
float s_extra = 1.0f;
|
||||
if (age < 100) {
|
||||
s_extra = std::min(1.1f, 1.1f * (static_cast<float>(age) / 100.0f));
|
||||
@ -466,13 +466,13 @@ void ScreenMessages::AddScreenMessage(const std::string& msg,
|
||||
start_v,
|
||||
std::max(-100.0f, screen_messages_top_.back().v_smoothed - 25.0f));
|
||||
}
|
||||
screen_messages_top_.emplace_back(m, true, g_core->GetAppTimeMillisecs(),
|
||||
screen_messages_top_.emplace_back(m, true, g_core->AppTimeMillisecs(),
|
||||
color, texture, tint_texture, tint,
|
||||
tint2);
|
||||
screen_messages_top_.back().v_smoothed = start_v;
|
||||
} else {
|
||||
screen_messages_.emplace_back(m, false, g_core->GetAppTimeMillisecs(),
|
||||
color, texture, tint_texture, tint, tint2);
|
||||
screen_messages_.emplace_back(m, false, g_core->AppTimeMillisecs(), color,
|
||||
texture, tint_texture, tint, tint2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -534,8 +534,7 @@ auto ScreenMessages::ScreenMessageEntry::GetText() -> TextGroup& {
|
||||
|
||||
void ScreenMessages::ScreenMessageEntry::UpdateTranslation() {
|
||||
if (translation_dirty) {
|
||||
s_translated = g_base->assets->CompileResourceString(
|
||||
s_raw, "Graphics::ScreenMessageEntry::UpdateTranslation");
|
||||
s_translated = g_base->assets->CompileResourceString(s_raw);
|
||||
translation_dirty = false;
|
||||
mesh_dirty = true;
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ JoystickInput::JoystickInput(int sdl_joystick_id,
|
||||
calibration_break_threshold_(kJoystickCalibrationBreakThreshold),
|
||||
custom_device_name_(custom_device_name),
|
||||
can_configure_(can_configure),
|
||||
creation_time_(g_core->GetAppTimeMillisecs()),
|
||||
creation_time_(g_core->AppTimeMillisecs()),
|
||||
calibrate_(calibrate) {
|
||||
// This is the default calibration for 'non-full' analog calibration.
|
||||
for (float& analog_calibration_val : analog_calibration_vals_) {
|
||||
@ -374,7 +374,7 @@ void JoystickInput::Update() {
|
||||
// Let's take this opportunity to update our calibration
|
||||
// (should probably have a specific place to do that but this works)
|
||||
if (calibrate_) {
|
||||
millisecs_t time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t time = g_core->AppTimeMillisecs();
|
||||
|
||||
// If we're doing 'aggressive' auto-recalibration we expand extents outward
|
||||
// but suck them inward a tiny bit too to account for jitter or random fluke
|
||||
@ -545,7 +545,7 @@ void JoystickInput::HandleSDLEvent(const SDL_Event* e) {
|
||||
return;
|
||||
}
|
||||
|
||||
millisecs_t time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t time = g_core->AppTimeMillisecs();
|
||||
SDL_Event e2;
|
||||
|
||||
// Ignore analog-stick input while we're holding a hat switch or d-pad
|
||||
@ -959,7 +959,7 @@ void JoystickInput::HandleSDLEvent(const SDL_Event* e) {
|
||||
&& (e->jbutton.button != hold_position_button_)
|
||||
&& (e->jbutton.button != back_button_)) {
|
||||
if (ui_only_ || e->jbutton.button == remote_enter_button_) {
|
||||
millisecs_t current_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t current_time = g_core->AppTimeMillisecs();
|
||||
if (current_time - last_ui_only_print_time_ > 5000) {
|
||||
g_base->python->objs()
|
||||
.Get(BasePython::ObjID::kUIRemotePressCall)
|
||||
|
||||
@ -93,7 +93,7 @@ TouchInput::TouchInput() {
|
||||
TouchInput::~TouchInput() = default;
|
||||
|
||||
void TouchInput::UpdateButtons(bool new_touch) {
|
||||
millisecs_t real_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t real_time = g_core->AppTimeMillisecs();
|
||||
float spread_scaled_actions =
|
||||
kButtonSpread * base_controls_scale_ * controls_scale_actions_;
|
||||
float width = g_base->graphics->screen_virtual_width();
|
||||
@ -134,7 +134,7 @@ void TouchInput::UpdateButtons(bool new_touch) {
|
||||
closest_to_bomb = true;
|
||||
}
|
||||
if (buttons_touch_) {
|
||||
last_buttons_touch_time_ = g_core->GetAppTimeMillisecs();
|
||||
last_buttons_touch_time_ = g_core->AppTimeMillisecs();
|
||||
}
|
||||
|
||||
// Handle swipe mode.
|
||||
|
||||
@ -158,7 +158,7 @@ void Input::AnnounceConnects_() {
|
||||
|
||||
// For the first announcement just say "X controllers detected" and don't
|
||||
// have a sound.
|
||||
if (first_print && g_core->GetAppTimeSeconds() < 3.0) {
|
||||
if (first_print && g_core->AppTimeSeconds() < 3.0) {
|
||||
first_print = false;
|
||||
|
||||
// If there's been several connected, just give a number.
|
||||
@ -225,7 +225,7 @@ void Input::ShowStandardInputDeviceConnectedMessage_(InputDevice* j) {
|
||||
// On Android we never show messages for initial input-devices; we often
|
||||
// get large numbers of strange virtual devices that aren't actually
|
||||
// controllers so this is more confusing than helpful.
|
||||
if (g_buildconfig.ostype_android() && g_core->GetAppTimeSeconds() < 3.0) {
|
||||
if (g_buildconfig.ostype_android() && g_core->AppTimeSeconds() < 3.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -554,7 +554,7 @@ void Input::OnScreenSizeChange() { assert(g_base->InLogicThread()); }
|
||||
void Input::StepDisplayTime() {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
millisecs_t real_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t real_time = g_core->AppTimeMillisecs();
|
||||
|
||||
// If input has been locked an excessively long amount of time, unlock it.
|
||||
if (input_lock_count_temp_) {
|
||||
@ -622,13 +622,13 @@ void Input::LockAllInput(bool permanent, const std::string& label) {
|
||||
} else {
|
||||
input_lock_count_temp_++;
|
||||
if (input_lock_count_temp_ == 1) {
|
||||
last_input_temp_lock_time_ = g_core->GetAppTimeMillisecs();
|
||||
last_input_temp_lock_time_ = g_core->AppTimeMillisecs();
|
||||
}
|
||||
input_lock_temp_labels_.push_back(label);
|
||||
|
||||
recent_input_locks_unlocks_.push_back(
|
||||
"temp lock: " + label + " time "
|
||||
+ std::to_string(g_core->GetAppTimeMillisecs()));
|
||||
+ std::to_string(g_core->AppTimeMillisecs()));
|
||||
while (recent_input_locks_unlocks_.size() > 10) {
|
||||
recent_input_locks_unlocks_.pop_front();
|
||||
}
|
||||
@ -641,7 +641,7 @@ void Input::UnlockAllInput(bool permanent, const std::string& label) {
|
||||
recent_input_locks_unlocks_.push_back(
|
||||
permanent ? "permanent unlock: "
|
||||
: "temp unlock: " + label + " time "
|
||||
+ std::to_string(g_core->GetAppTimeMillisecs()));
|
||||
+ std::to_string(g_core->AppTimeMillisecs()));
|
||||
while (recent_input_locks_unlocks_.size() > 10) {
|
||||
recent_input_locks_unlocks_.pop_front();
|
||||
}
|
||||
@ -667,7 +667,7 @@ void Input::UnlockAllInput(bool permanent, const std::string& label) {
|
||||
if (input_lock_count_temp_ < 0) {
|
||||
g_core->Log(LogName::kBaInput, LogLevel::kWarning,
|
||||
"temp input unlock at time "
|
||||
+ std::to_string(g_core->GetAppTimeMillisecs())
|
||||
+ std::to_string(g_core->AppTimeMillisecs())
|
||||
+ " with no active lock: '" + label + "'");
|
||||
// This is to be expected since we can reset this to 0.
|
||||
input_lock_count_temp_ = 0;
|
||||
@ -684,7 +684,7 @@ void Input::UnlockAllInput(bool permanent, const std::string& label) {
|
||||
|
||||
void Input::PrintLockLabels_() {
|
||||
std::string s = "INPUT LOCK REPORT (time="
|
||||
+ std::to_string(g_core->GetAppTimeMillisecs()) + "):";
|
||||
+ std::to_string(g_core->AppTimeMillisecs()) + "):";
|
||||
int num;
|
||||
|
||||
s += "\n " + std::to_string(input_lock_temp_labels_.size()) + " TEMP LOCKS:";
|
||||
@ -926,7 +926,7 @@ void Input::HandleKeyPress_(const SDL_Keysym& keysym) {
|
||||
// fluke repeat key press event due to funky OS circumstances.
|
||||
static int count{};
|
||||
static seconds_t last_count_reset_time{};
|
||||
auto now = g_core->GetAppTimeSeconds();
|
||||
auto now = g_core->AppTimeSeconds();
|
||||
if (now - last_count_reset_time > 2.0) {
|
||||
count = 0;
|
||||
last_count_reset_time = now;
|
||||
@ -1238,7 +1238,7 @@ void Input::HandleSmoothMouseScroll_(const Vector2f& velocity, bool momentum) {
|
||||
WidgetMessage(WidgetMessage::Type::kMouseWheelVelocityH, nullptr,
|
||||
cursor_pos_x_, cursor_pos_y_, velocity.x, momentum));
|
||||
|
||||
last_mouse_move_time_ = g_core->GetAppTimeSeconds();
|
||||
last_mouse_move_time_ = g_core->AppTimeSeconds();
|
||||
mouse_move_count_++;
|
||||
|
||||
Camera* camera = g_base->graphics->camera();
|
||||
@ -1282,7 +1282,7 @@ void Input::HandleMouseMotion_(const Vector2f& position) {
|
||||
cursor_pos_y_ = g_base->graphics->PixelToVirtualY(
|
||||
position.y * g_base->graphics->screen_pixel_height());
|
||||
|
||||
last_mouse_move_time_ = g_core->GetAppTimeSeconds();
|
||||
last_mouse_move_time_ = g_core->AppTimeSeconds();
|
||||
mouse_move_count_++;
|
||||
|
||||
// If we have a touch-input in editing mode, pass along events to it. (it
|
||||
@ -1324,7 +1324,7 @@ void Input::HandleMouseDown_(int button, const Vector2f& position) {
|
||||
return;
|
||||
}
|
||||
|
||||
last_mouse_move_time_ = g_core->GetAppTimeSeconds();
|
||||
last_mouse_move_time_ = g_core->AppTimeSeconds();
|
||||
mouse_move_count_++;
|
||||
|
||||
// Convert normalized view coords to our virtual ones.
|
||||
@ -1333,7 +1333,7 @@ void Input::HandleMouseDown_(int button, const Vector2f& position) {
|
||||
cursor_pos_y_ = g_base->graphics->PixelToVirtualY(
|
||||
position.y * g_base->graphics->screen_pixel_height());
|
||||
|
||||
millisecs_t click_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t click_time = g_core->AppTimeMillisecs();
|
||||
bool double_click = (click_time - last_click_time_ <= double_click_time_);
|
||||
last_click_time_ = click_time;
|
||||
|
||||
@ -1528,7 +1528,7 @@ auto Input::IsCursorVisible() const -> bool {
|
||||
bool val;
|
||||
|
||||
// Show our cursor only if its been moved recently.
|
||||
val = (g_core->GetAppTimeSeconds() - last_mouse_move_time_ < 2.071);
|
||||
val = (g_core->AppTimeSeconds() - last_mouse_move_time_ < 2.071);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
@ -221,7 +221,7 @@ void RemoteAppServer::HandleData(int socket, uint8_t* buffer, size_t amt,
|
||||
RemoteAppClient* client = clients_ + joystick_id;
|
||||
|
||||
// Take note that we heard from them.
|
||||
client->last_contact_time = g_core->GetAppTimeMillisecs();
|
||||
client->last_contact_time = g_core->AppTimeMillisecs();
|
||||
|
||||
// Ok now iterate.
|
||||
uint8_t* val = buffer + 4;
|
||||
@ -389,7 +389,7 @@ auto RemoteAppServer::GetClient(int request_id, struct sockaddr* addr,
|
||||
}
|
||||
|
||||
// Don't reuse a slot for 5 seconds (if its been heard from since this time).
|
||||
millisecs_t cooldown_time = g_core->GetAppTimeMillisecs() - 5000;
|
||||
millisecs_t cooldown_time = g_core->AppTimeMillisecs() - 5000;
|
||||
|
||||
// Ok, not there already.. now look for a non-taken one and return that.
|
||||
for (int i = 0; i < kMaxRemoteAppClients; i++) {
|
||||
@ -412,7 +412,7 @@ auto RemoteAppServer::GetClient(int request_id, struct sockaddr* addr,
|
||||
strcpy(clients_[i].display_name, clients_[i].name); // NOLINT
|
||||
char* c = strchr(clients_[i].display_name, '#');
|
||||
if (c) *c = 0;
|
||||
clients_[i].last_contact_time = g_core->GetAppTimeMillisecs();
|
||||
clients_[i].last_contact_time = g_core->AppTimeMillisecs();
|
||||
clients_[i].request_id = request_id;
|
||||
char m[256];
|
||||
|
||||
|
||||
@ -236,7 +236,7 @@ void Logic::OnAppShutdown() {
|
||||
assert(shutting_down_);
|
||||
|
||||
// Nuke the app from orbit if we get stuck while shutting down.
|
||||
g_core->StartSuicideTimer("shutdown", 10000);
|
||||
g_core->StartSuicideTimer("shutdown", 15000);
|
||||
|
||||
// Tell base to disallow shutdown-suppressors from here on out.
|
||||
g_base->ShutdownSuppressDisallow();
|
||||
@ -402,7 +402,7 @@ void Logic::UpdateDisplayTimeForHeadlessMode_() {
|
||||
// scheduled (or at least close enough so we can fudge it and tell them
|
||||
// its that exact time).
|
||||
|
||||
auto app_time_microsecs = g_core->GetAppTimeMicrosecs();
|
||||
auto app_time_microsecs = g_core->AppTimeMicrosecs();
|
||||
|
||||
// Set our int based time vals so we can exactly hit timers.
|
||||
auto old_display_time_microsecs = display_time_microsecs_;
|
||||
@ -438,7 +438,7 @@ void Logic::PostUpdateDisplayTimeForHeadlessMode_() {
|
||||
[headless_display_step_microsecs] {
|
||||
auto sleepsecs =
|
||||
static_cast<double>(headless_display_step_microsecs) / 1000000.0;
|
||||
auto apptimesecs = g_core->GetAppTimeSeconds();
|
||||
auto apptimesecs = g_core->AppTimeSeconds();
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"will try to sleep for %.4f at app-time %.4f (until %.4f)",
|
||||
@ -467,7 +467,7 @@ void Logic::UpdateDisplayTimeForFrameDraw_() {
|
||||
// - 'current' should mostly show '(avg)'; rarely '(sample)'.
|
||||
// - these can vary briefly during load spikes/etc. but should quickly
|
||||
// reconverge to stability. If not, this may need further calibration.
|
||||
auto current_app_time = g_core->GetAppTimeSeconds();
|
||||
auto current_app_time = g_core->AppTimeSeconds();
|
||||
|
||||
// We handle the first measurement specially.
|
||||
if (last_display_time_update_app_time_ < 0) {
|
||||
|
||||
@ -330,8 +330,8 @@ static auto PyAppTime(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
const_cast<char**>(kwlist))) {
|
||||
return nullptr;
|
||||
}
|
||||
return PyFloat_FromDouble(
|
||||
0.001 * static_cast<double>(g_core->GetAppTimeMillisecs()));
|
||||
return PyFloat_FromDouble(0.001
|
||||
* static_cast<double>(g_core->AppTimeMillisecs()));
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
|
||||
@ -497,7 +497,7 @@ static auto PyEvaluateLstr(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
return nullptr;
|
||||
}
|
||||
return PyUnicode_FromString(
|
||||
g_base->assets->CompileResourceString(value, "evaluate_lstr").c_str());
|
||||
g_base->assets->CompileResourceString(value).c_str());
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
@ -533,7 +533,7 @@ static auto PyGetStringHeight(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
}
|
||||
s = g_base->python->GetPyLString(s_obj);
|
||||
#if BA_DEBUG_BUILD
|
||||
if (g_base->assets->CompileResourceString(s, "get_string_height test") != s) {
|
||||
if (g_base->assets->CompileResourceString(s) != s) {
|
||||
BA_LOG_PYTHON_TRACE(
|
||||
"resource-string passed to get_string_height; this should be avoided");
|
||||
}
|
||||
@ -579,8 +579,7 @@ static auto PyGetStringWidth(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
}
|
||||
s = g_base->python->GetPyLString(s_obj);
|
||||
#if BA_DEBUG_BUILD
|
||||
if (g_base->assets->CompileResourceString(s, "get_string_width debug test")
|
||||
!= s) {
|
||||
if (g_base->assets->CompileResourceString(s) != s) {
|
||||
BA_LOG_PYTHON_TRACE(
|
||||
"resource-string passed to get_string_width; this should be avoided");
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
#include "ballistica/shared/math/vector3f.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
@ -46,6 +47,11 @@ class ClassicSoftInterface {
|
||||
virtual auto GetV1AccountTypeIconString(int account_type) -> std::string = 0;
|
||||
virtual auto V1AccountTypeToString(int account_type) -> std::string = 0;
|
||||
virtual void PlayMusic(const std::string& music_type, bool continuous) = 0;
|
||||
virtual void GetClassicChestDisplayInfo(const std::string& id,
|
||||
std::string* texclosed,
|
||||
std::string* texclosedtint,
|
||||
Vector3f* color, Vector3f* tint,
|
||||
Vector3f* tint2) = 0;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -15,6 +15,7 @@ namespace ballistica::base {
|
||||
// other mechanisms are set up to preserve and restore context before
|
||||
// running, and objects can also be invalidated or otherwise cleaned up
|
||||
// when the context they were created under dies.
|
||||
//
|
||||
// The end goal of all this is to support api styles for end users where
|
||||
// standalone snippets of code can be useful; ie: something like
|
||||
// bs.newnode() to create something meaningful without having to worry
|
||||
@ -36,26 +37,27 @@ class ContextRef {
|
||||
ContextRef();
|
||||
explicit ContextRef(Context* sgc);
|
||||
|
||||
/// ContextRefs are considered equal if both are pointing to the exact same
|
||||
/// Context object (or both are pointing to no Context).
|
||||
/// ContextRefs are considered equal if both are pointing to the exact
|
||||
/// same Context object (or both are pointing to no Context).
|
||||
auto operator==(const ContextRef& other) const -> bool;
|
||||
|
||||
template <typename T>
|
||||
auto GetContextTyped() const -> T* {
|
||||
// Ew; dynamic cast.
|
||||
// Note: if it ever seems like speed is an issue here, we can
|
||||
// cache the results with std::type_index entries. There should
|
||||
// generally be a very small number of types involved.
|
||||
//
|
||||
// Note: if it ever seems like speed is an issue here, we can cache the
|
||||
// results with std::type_index entries. There should generally be a
|
||||
// very small number of types involved.
|
||||
return dynamic_cast<T*>(target_.get());
|
||||
}
|
||||
|
||||
/// An empty context-ref was explicitly set to an empty state.
|
||||
/// Note that this is different than an expired context-ref, which
|
||||
/// originally pointed to some context that has since died.
|
||||
/// An empty context-ref was explicitly set to an empty state. Note that
|
||||
/// this is different than an expired context-ref, which originally
|
||||
/// pointed to some context that has since died.
|
||||
auto IsEmpty() const { return empty_; }
|
||||
|
||||
/// Has this context died since it was set?
|
||||
/// Note that a context created as empty is not considered expired.
|
||||
/// Has this context died since it was set? Note that a context created as
|
||||
/// empty is not considered expired.
|
||||
auto IsExpired() const -> bool {
|
||||
if (empty_) {
|
||||
return false; // Can't kill what was never alive.
|
||||
@ -64,7 +66,8 @@ class ContextRef {
|
||||
}
|
||||
|
||||
/// Return the context this ref points to. This will be nullptr for empty
|
||||
/// contexts. Throws an exception if a target context was set but has expired.
|
||||
/// contexts. Throws an exception if a target context was set but has
|
||||
/// expired.
|
||||
auto Get() const -> Context* {
|
||||
auto* target = target_.get();
|
||||
if (target == nullptr && !empty_) {
|
||||
@ -84,14 +87,13 @@ class ContextRef {
|
||||
bool empty_;
|
||||
};
|
||||
|
||||
/// Object containing the actual context_ref data/information.
|
||||
/// App-modes can subclass this to provide the actual context_ref they desire,
|
||||
/// and then code can use CurrentTyped() to safely retrieve context_ref as that
|
||||
/// type.
|
||||
/// Object containing the actual context_ref data/information. App-modes can
|
||||
/// subclass this to provide the actual context_ref they desire, and then
|
||||
/// code can use CurrentTyped() to safely retrieve context_ref as that type.
|
||||
class Context : public Object {
|
||||
public:
|
||||
/// Return the current context_ref cast to a desired type.
|
||||
/// Throws an Exception if the context_ref is unset or is another type.
|
||||
/// Return the current context_ref cast to a desired type. Throws an
|
||||
/// Exception if the context_ref is unset or is another type.
|
||||
template <typename T>
|
||||
static auto CurrentTyped() -> T& {
|
||||
T* t = g_base->CurrentContext().GetContextTyped<T>();
|
||||
@ -102,13 +104,13 @@ class Context : public Object {
|
||||
return *t;
|
||||
}
|
||||
|
||||
/// Called when a PythonContextCall is created in this context_ref.
|
||||
/// The context_ref class may want to store a weak-reference to the
|
||||
/// call and inform the call when the context_ref is going down so that
|
||||
/// resources may be freed. Other permanent contexts may not need to
|
||||
/// bother.
|
||||
/// FIXME: This mechanism can probably be generalized so that other
|
||||
/// things such as assets and timers can use it.
|
||||
/// Called when a PythonContextCall is created in this context_ref. The
|
||||
/// context_ref class may want to store a weak-reference to the call and
|
||||
/// inform the call when the context_ref is going down so that resources
|
||||
/// may be freed. Other permanent contexts may not need to bother.
|
||||
///
|
||||
/// FIXME: This mechanism can probably be generalized so that other things
|
||||
/// such as assets and timers can use it.
|
||||
virtual void RegisterContextCall(PythonContextCall* call);
|
||||
|
||||
/// Return a short description of the context_ref; will be used when
|
||||
@ -118,9 +120,9 @@ class Context : public Object {
|
||||
|
||||
/// Return whether this context should allow default timer-types to be
|
||||
/// created within it (AppTimer, DisplayTimer). Scene type contexts
|
||||
/// generally have their own timer types which are better integrated
|
||||
/// with scenes (responding to changes in game speed/etc.) so this can
|
||||
/// be used to encourage/enforce usage of those timers.
|
||||
/// generally have their own timer types which are better integrated with
|
||||
/// scenes (responding to changes in game speed/etc.) so this can be used
|
||||
/// to encourage/enforce usage of those timers.
|
||||
virtual auto ContextAllowsDefaultTimerTypes() -> bool;
|
||||
};
|
||||
|
||||
|
||||
@ -1683,7 +1683,7 @@ auto DevConsole::PasteFromClipboard() -> bool {
|
||||
}
|
||||
|
||||
void DevConsole::UpdateCarat_() {
|
||||
last_carat_x_change_time_ = g_core->GetAppTimeMillisecs();
|
||||
last_carat_x_change_time_ = g_core->AppTimeMillisecs();
|
||||
auto unichars = Utils::UnicodeFromUTF8(input_string_, "fjfwef");
|
||||
auto unichars_clamped = unichars;
|
||||
|
||||
|
||||
@ -370,7 +370,7 @@ void UI::SetUIInputDevice(InputDevice* input_device) {
|
||||
ui_input_device_ = input_device;
|
||||
|
||||
// So they dont get stolen from immediately.
|
||||
last_input_device_use_time_ = g_core->GetAppTimeMillisecs();
|
||||
last_input_device_use_time_ = g_core->AppTimeMillisecs();
|
||||
}
|
||||
|
||||
void UI::Reset() {
|
||||
@ -432,7 +432,7 @@ auto UI::GetWidgetForInput(InputDevice* input_device) -> ui_v1::Widget* {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
millisecs_t time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t time = g_core->AppTimeMillisecs();
|
||||
|
||||
bool print_menu_owner{};
|
||||
ui_v1::Widget* ret_val;
|
||||
|
||||
@ -250,4 +250,11 @@ void ClassicFeatureSet::PlayMusic(const std::string& music_type,
|
||||
python->PlayMusic(music_type, continuous);
|
||||
}
|
||||
|
||||
void ClassicFeatureSet::GetClassicChestDisplayInfo(
|
||||
const std::string& id, std::string* texclosed, std::string* texclosedtint,
|
||||
Vector3f* color, Vector3f* tint, Vector3f* tint2) {
|
||||
python->GetClassicChestDisplayInfo(id, texclosed, texclosedtint, color, tint,
|
||||
tint2);
|
||||
}
|
||||
|
||||
} // namespace ballistica::classic
|
||||
|
||||
@ -108,6 +108,9 @@ class ClassicFeatureSet : public FeatureSetNativeComponent,
|
||||
auto GetV1AccountTypeIconString(int account_type) -> std::string override;
|
||||
auto V1AccountTypeToString(int account_type) -> std::string override;
|
||||
auto GetV1AccountType() -> int override;
|
||||
void GetClassicChestDisplayInfo(const std::string& id, std::string* texclosed,
|
||||
std::string* texclosedtint, Vector3f* color,
|
||||
Vector3f* tint, Vector3f* tint2) override;
|
||||
|
||||
ClassicPython* const python;
|
||||
V1Account* const v1_account;
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ballistica/base/python/base_python.h"
|
||||
#include "ballistica/classic/python/methods/python_methods_classic.h"
|
||||
#include "ballistica/classic/support/classic_app_mode.h"
|
||||
#include "ballistica/shared/python/python_command.h" // IWYU pragma: keep.
|
||||
@ -30,6 +31,60 @@ extern "C" auto PyInit__baclassic() -> PyObject* {
|
||||
|
||||
void ClassicPython::ImportPythonObjs() {
|
||||
#include "ballistica/classic/mgen/pyembed/binding_classic.inc"
|
||||
|
||||
// Cache some basic display values for chests from the Python layer. This
|
||||
// way C++ UI stuff doesn't have to call out to Python when drawing the
|
||||
// root UI/etc.
|
||||
|
||||
// Pull default chest display info.
|
||||
chest_display_default_ = {ChestDisplayFromPython(
|
||||
objs().Get(ObjID::kChestAppearanceDisplayInfoDefault))};
|
||||
|
||||
// And overrides.
|
||||
for (auto&& item :
|
||||
objs().Get(ObjID::kChestAppearanceDisplayInfos).DictItems()) {
|
||||
chest_displays_[item.first.GetAttr("value").ValueAsString()] =
|
||||
ChestDisplayFromPython(item.second);
|
||||
}
|
||||
}
|
||||
|
||||
auto ClassicPython::ChestDisplayFromPython(const PythonRef& ref)
|
||||
-> ChestDisplay_ {
|
||||
ChestDisplay_ out;
|
||||
|
||||
out.texclosed = ref.GetAttr("texclosed").ValueAsString().c_str();
|
||||
out.texclosedtint = ref.GetAttr("texclosedtint").ValueAsString().c_str();
|
||||
out.color = base::BasePython::GetPyVector3f(ref.GetAttr("color").get());
|
||||
out.tint = base::BasePython::GetPyVector3f(ref.GetAttr("tint").get());
|
||||
out.tint2 = base::BasePython::GetPyVector3f(ref.GetAttr("tint2").get());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void ClassicPython::GetClassicChestDisplayInfo(const std::string& id,
|
||||
std::string* texclosed,
|
||||
std::string* texclosedtint,
|
||||
Vector3f* color, Vector3f* tint,
|
||||
Vector3f* tint2) {
|
||||
assert(texclosed);
|
||||
assert(texclosedtint);
|
||||
assert(color);
|
||||
assert(tint);
|
||||
assert(tint2);
|
||||
auto&& display{chest_displays_.find(id)};
|
||||
if (display != chest_displays_.end()) {
|
||||
*texclosed = display->second.texclosed;
|
||||
*texclosedtint = display->second.texclosedtint;
|
||||
*color = display->second.color;
|
||||
*tint = display->second.tint;
|
||||
*tint2 = display->second.tint2;
|
||||
} else {
|
||||
*texclosed = chest_display_default_.texclosed;
|
||||
*texclosedtint = chest_display_default_.texclosedtint;
|
||||
*color = chest_display_default_.color;
|
||||
*tint = chest_display_default_.tint;
|
||||
*tint2 = chest_display_default_.tint2;
|
||||
}
|
||||
}
|
||||
|
||||
void ClassicPython::PlayMusic(const std::string& music_type, bool continuous) {
|
||||
|
||||
@ -4,9 +4,11 @@
|
||||
#define BALLISTICA_CLASSIC_PYTHON_CLASSIC_PYTHON_H_
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
#include "ballistica/classic/classic.h"
|
||||
#include "ballistica/shared/math/vector3f.h"
|
||||
#include "ballistica/shared/python/python_object_set.h"
|
||||
|
||||
namespace ballistica::classic {
|
||||
@ -20,6 +22,8 @@ class ClassicPython {
|
||||
enum class ObjID {
|
||||
kDoPlayMusicCall,
|
||||
kGetInputDeviceMappedValueCall,
|
||||
kChestAppearanceDisplayInfoDefault,
|
||||
kChestAppearanceDisplayInfos,
|
||||
kLast // Sentinel; must be at end.
|
||||
};
|
||||
|
||||
@ -34,7 +38,22 @@ class ClassicPython {
|
||||
|
||||
const auto& objs() { return objs_; }
|
||||
|
||||
void GetClassicChestDisplayInfo(const std::string& id, std::string* texclosed,
|
||||
std::string* texclosedtint, Vector3f* color,
|
||||
Vector3f* tint, Vector3f* tint2);
|
||||
|
||||
private:
|
||||
struct ChestDisplay_ {
|
||||
Vector3f color;
|
||||
std::string texclosed;
|
||||
std::string texclosedtint;
|
||||
Vector3f tint;
|
||||
Vector3f tint2;
|
||||
};
|
||||
|
||||
auto ChestDisplayFromPython(const PythonRef& ref) -> ChestDisplay_;
|
||||
ChestDisplay_ chest_display_default_;
|
||||
std::unordered_map<std::string, ChestDisplay_> chest_displays_;
|
||||
PythonObjectSet<ObjID> objs_;
|
||||
};
|
||||
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
#include "ballistica/classic/python/methods/python_methods_classic.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -296,9 +295,9 @@ static auto PySetRootUIAccountValues(PyObject* self, PyObject* args,
|
||||
PyObject* keywds) -> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
|
||||
const char* tickets_text;
|
||||
const char* tokens_text;
|
||||
const char* league_rank_text;
|
||||
int tickets;
|
||||
int tokens;
|
||||
int league_rank;
|
||||
const char* league_type;
|
||||
const char* achievements_percent_text;
|
||||
const char* level_text;
|
||||
@ -308,19 +307,19 @@ static auto PySetRootUIAccountValues(PyObject* self, PyObject* args,
|
||||
const char* chest_1_appearance;
|
||||
const char* chest_2_appearance;
|
||||
const char* chest_3_appearance;
|
||||
float chest_0_unlock_time;
|
||||
float chest_1_unlock_time;
|
||||
float chest_2_unlock_time;
|
||||
float chest_3_unlock_time;
|
||||
float chest_0_ad_allow_time;
|
||||
float chest_1_ad_allow_time;
|
||||
float chest_2_ad_allow_time;
|
||||
float chest_3_ad_allow_time;
|
||||
double chest_0_unlock_time;
|
||||
double chest_1_unlock_time;
|
||||
double chest_2_unlock_time;
|
||||
double chest_3_unlock_time;
|
||||
double chest_0_ad_allow_time;
|
||||
double chest_1_ad_allow_time;
|
||||
double chest_2_ad_allow_time;
|
||||
double chest_3_ad_allow_time;
|
||||
int gold_pass{};
|
||||
|
||||
static const char* kwlist[] = {"tickets_text",
|
||||
"tokens_text",
|
||||
"league_rank_text",
|
||||
static const char* kwlist[] = {"tickets",
|
||||
"tokens",
|
||||
"league_rank",
|
||||
"league_type",
|
||||
"achievements_percent_text",
|
||||
"level_text",
|
||||
@ -341,8 +340,8 @@ static auto PySetRootUIAccountValues(PyObject* self, PyObject* args,
|
||||
"chest_3_ad_allow_time",
|
||||
nullptr};
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, keywds, "sssssssspssssffffffff", const_cast<char**>(kwlist),
|
||||
&tickets_text, &tokens_text, &league_rank_text, &league_type,
|
||||
args, keywds, "iiissssspssssdddddddd", const_cast<char**>(kwlist),
|
||||
&tickets, &tokens, &league_rank, &league_type,
|
||||
&achievements_percent_text, &level_text, &xp_text, &inbox_count_text,
|
||||
&gold_pass, &chest_0_appearance, &chest_1_appearance,
|
||||
&chest_2_appearance, &chest_3_appearance, &chest_0_unlock_time,
|
||||
@ -357,20 +356,21 @@ static auto PySetRootUIAccountValues(PyObject* self, PyObject* args,
|
||||
|
||||
// Pass these all along to the app-mode which will store them and forward
|
||||
// them to any existing UI.
|
||||
appmode->SetRootUITicketsMeterText(tickets_text);
|
||||
appmode->SetRootUITokensMeterText(tokens_text);
|
||||
appmode->SetRootUILeagueRankText(league_rank_text);
|
||||
appmode->SetRootUITicketsMeterValue(tickets);
|
||||
appmode->SetRootUITokensMeterValue(tokens);
|
||||
appmode->SetRootUILeagueRankValue(league_rank);
|
||||
appmode->SetRootUILeagueType(league_type);
|
||||
appmode->SetRootUIAchievementsPercentText(achievements_percent_text);
|
||||
appmode->SetRootUILevelText(level_text);
|
||||
appmode->SetRootUIXPText(xp_text);
|
||||
appmode->SetRootUIInboxCountText(inbox_count_text);
|
||||
appmode->SetRootUIGoldPass(gold_pass);
|
||||
appmode->SetRootUIChests(chest_0_appearance, chest_1_appearance,
|
||||
chest_2_appearance, chest_3_appearance);
|
||||
appmode->SetRootUIChests(
|
||||
chest_0_appearance, chest_1_appearance, chest_2_appearance,
|
||||
chest_3_appearance, chest_0_unlock_time, chest_1_unlock_time,
|
||||
chest_2_unlock_time, chest_3_unlock_time, chest_0_ad_allow_time,
|
||||
chest_1_ad_allow_time, chest_2_ad_allow_time, chest_3_ad_allow_time);
|
||||
|
||||
printf("WOULD SET TIMES TO %.2f %.2f\n", chest_0_unlock_time,
|
||||
chest_0_ad_allow_time);
|
||||
Py_RETURN_NONE;
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
@ -381,9 +381,9 @@ static PyMethodDef PySetRootUIAccountValuesDef = {
|
||||
METH_VARARGS | METH_KEYWORDS, // flags
|
||||
|
||||
"set_root_ui_account_values(*,\n"
|
||||
" tickets_text: str,\n"
|
||||
" tokens_text: str,\n"
|
||||
" league_rank_text: str,\n"
|
||||
" tickets: int,\n"
|
||||
" tokens: int,\n"
|
||||
" league_rank: int,\n"
|
||||
" league_type: str,\n"
|
||||
" achievements_percent_text: str,\n"
|
||||
" level_text: str,\n"
|
||||
|
||||
@ -149,10 +149,10 @@ void ClassicAppMode::Reset_() {
|
||||
// At this point uiv1 is in a reset-to-default state. Now plug in our
|
||||
// current values for everything.
|
||||
if (auto* root_widget = uiv1_->root_widget()) {
|
||||
root_widget->SetTicketsMeterText(root_ui_tickets_meter_text_);
|
||||
root_widget->SetTokensMeterText(root_ui_tokens_meter_text_,
|
||||
root_widget->SetTicketsMeterValue(root_ui_tickets_meter_value_);
|
||||
root_widget->SetTokensMeterValue(root_ui_tokens_meter_value_,
|
||||
root_ui_gold_pass_);
|
||||
root_widget->SetLeagueRankText(root_ui_league_rank_text_);
|
||||
root_widget->SetLeagueRankValue(root_ui_league_rank_value_);
|
||||
root_widget->SetLeagueType(root_ui_league_type_);
|
||||
root_widget->SetAchievementPercentText(root_ui_achievement_percent_text_);
|
||||
root_widget->SetLevelText(root_ui_level_text_);
|
||||
@ -160,7 +160,11 @@ void ClassicAppMode::Reset_() {
|
||||
root_widget->SetInboxCountText(root_ui_inbox_count_text_);
|
||||
root_widget->SetChests(
|
||||
root_ui_chest_0_appearance_, root_ui_chest_1_appearance_,
|
||||
root_ui_chest_2_appearance_, root_ui_chest_3_appearance_);
|
||||
root_ui_chest_2_appearance_, root_ui_chest_3_appearance_,
|
||||
root_ui_chest_0_unlock_time_, root_ui_chest_1_unlock_time_,
|
||||
root_ui_chest_2_unlock_time_, root_ui_chest_3_unlock_time_,
|
||||
root_ui_chest_0_ad_allow_time_, root_ui_chest_1_ad_allow_time_,
|
||||
root_ui_chest_2_ad_allow_time_, root_ui_chest_3_ad_allow_time_);
|
||||
root_widget->SetHaveLiveValues(root_ui_have_live_values_);
|
||||
}
|
||||
}
|
||||
@ -332,7 +336,7 @@ void ClassicAppMode::HostScanCycle() {
|
||||
&((reinterpret_cast<sockaddr_in*>(&from))->sin_addr),
|
||||
buffer2, sizeof(buffer2));
|
||||
entry.last_query_id = query_id;
|
||||
entry.last_contact_time = g_core->GetAppTimeMillisecs();
|
||||
entry.last_contact_time = g_core->AppTimeMillisecs();
|
||||
}
|
||||
}
|
||||
PruneScanResults_();
|
||||
@ -357,7 +361,7 @@ void ClassicAppMode::EndHostScanning() {
|
||||
}
|
||||
|
||||
void ClassicAppMode::PruneScanResults_() {
|
||||
millisecs_t t = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t t = g_core->AppTimeMillisecs();
|
||||
auto i = scan_results_.begin();
|
||||
while (i != scan_results_.end()) {
|
||||
auto i_next = i;
|
||||
@ -516,8 +520,8 @@ auto ClassicAppMode::GetHeadlessNextDisplayTimeStep() -> microsecs_t {
|
||||
void ClassicAppMode::StepDisplayTime() {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
auto startms{core::CorePlatform::GetCurrentMillisecs()};
|
||||
millisecs_t app_time = g_core->GetAppTimeMillisecs();
|
||||
auto startms{core::CorePlatform::TimeMonotonicMillisecs()};
|
||||
millisecs_t app_time = g_core->AppTimeMillisecs();
|
||||
g_core->platform->SetDebugKey("LastUpdateTime", std::to_string(startms));
|
||||
in_update_ = true;
|
||||
|
||||
@ -592,7 +596,7 @@ void ClassicAppMode::StepDisplayTime() {
|
||||
// Report excessively long updates.
|
||||
if (g_core->core_config().debug_timing
|
||||
&& app_time >= next_long_update_report_time_) {
|
||||
auto duration{core::CorePlatform::GetCurrentMillisecs() - startms};
|
||||
auto duration{core::CorePlatform::TimeMonotonicMillisecs() - startms};
|
||||
|
||||
// Complain when our full update takes longer than 1/60th second.
|
||||
if (duration > (1000 / 60)) {
|
||||
@ -762,7 +766,7 @@ void ClassicAppMode::UpdateKickVote_() {
|
||||
kick_vote_in_progress_ = false;
|
||||
return;
|
||||
}
|
||||
millisecs_t current_time{g_core->GetAppTimeMillisecs()};
|
||||
millisecs_t current_time{g_core->AppTimeMillisecs()};
|
||||
int total_client_count = 0;
|
||||
int yes_votes = 0;
|
||||
int no_votes = 0;
|
||||
@ -859,7 +863,7 @@ void ClassicAppMode::UpdateKickVote_() {
|
||||
void ClassicAppMode::StartKickVote(scene_v1::ConnectionToClient* starter,
|
||||
scene_v1::ConnectionToClient* target) {
|
||||
// Restrict votes per client.
|
||||
millisecs_t current_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t current_time = g_core->AppTimeMillisecs();
|
||||
|
||||
if (starter == target) {
|
||||
// Don't let anyone kick themselves.
|
||||
@ -1413,7 +1417,7 @@ auto ClassicAppMode::ShouldAnnouncePartyJoinsAndLeaves() -> bool {
|
||||
}
|
||||
|
||||
auto ClassicAppMode::IsPlayerBanned(const scene_v1::PlayerSpec& spec) -> bool {
|
||||
millisecs_t current_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t current_time = g_core->AppTimeMillisecs();
|
||||
|
||||
// Now is a good time to prune no-longer-banned specs.
|
||||
while (!banned_players_.empty()
|
||||
@ -1431,7 +1435,7 @@ auto ClassicAppMode::IsPlayerBanned(const scene_v1::PlayerSpec& spec) -> bool {
|
||||
|
||||
void ClassicAppMode::BanPlayer(const scene_v1::PlayerSpec& spec,
|
||||
millisecs_t duration) {
|
||||
banned_players_.emplace_back(g_core->GetAppTimeMillisecs() + duration, spec);
|
||||
banned_players_.emplace_back(g_core->AppTimeMillisecs() + duration, spec);
|
||||
}
|
||||
|
||||
void ClassicAppMode::HandleQuitOnIdle_() {
|
||||
@ -1550,51 +1554,51 @@ void ClassicAppMode::RunMainMenu() {
|
||||
}
|
||||
}
|
||||
|
||||
void ClassicAppMode::SetRootUITicketsMeterText(const std::string text) {
|
||||
void ClassicAppMode::SetRootUITicketsMeterValue(int value) {
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
if (text == root_ui_tickets_meter_text_) {
|
||||
if (value == root_ui_tickets_meter_value_) {
|
||||
return;
|
||||
}
|
||||
// Store the value.
|
||||
root_ui_tickets_meter_text_ = text;
|
||||
root_ui_tickets_meter_value_ = value;
|
||||
|
||||
// Apply it to any existing UI.
|
||||
if (uiv1_) {
|
||||
if (auto* root_widget = uiv1_->root_widget()) {
|
||||
root_widget->SetTicketsMeterText(root_ui_tickets_meter_text_);
|
||||
root_widget->SetTicketsMeterValue(root_ui_tickets_meter_value_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClassicAppMode::SetRootUITokensMeterText(const std::string text) {
|
||||
void ClassicAppMode::SetRootUITokensMeterValue(int value) {
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
if (text == root_ui_tokens_meter_text_) {
|
||||
if (value == root_ui_tokens_meter_value_) {
|
||||
return;
|
||||
}
|
||||
// Store the value.
|
||||
root_ui_tokens_meter_text_ = text;
|
||||
root_ui_tokens_meter_value_ = value;
|
||||
|
||||
// Apply it to any existing UI.
|
||||
if (uiv1_) {
|
||||
if (auto* root_widget = uiv1_->root_widget()) {
|
||||
root_widget->SetTokensMeterText(root_ui_tokens_meter_text_,
|
||||
root_widget->SetTokensMeterValue(root_ui_tokens_meter_value_,
|
||||
root_ui_gold_pass_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClassicAppMode::SetRootUILeagueRankText(const std::string text) {
|
||||
void ClassicAppMode::SetRootUILeagueRankValue(int value) {
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
if (text == root_ui_league_rank_text_) {
|
||||
if (value == root_ui_league_rank_value_) {
|
||||
return;
|
||||
}
|
||||
// Store the value.
|
||||
root_ui_league_rank_text_ = text;
|
||||
root_ui_league_rank_value_ = value;
|
||||
|
||||
// Apply it to any existing UI.
|
||||
if (uiv1_) {
|
||||
if (auto* root_widget = uiv1_->root_widget()) {
|
||||
root_widget->SetLeagueRankText(root_ui_league_rank_text_);
|
||||
root_widget->SetLeagueRankValue(root_ui_league_rank_value_);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1694,7 +1698,7 @@ void ClassicAppMode::SetRootUIGoldPass(bool enabled) {
|
||||
// Apply it to any existing UI.
|
||||
if (uiv1_) {
|
||||
if (auto* root_widget = uiv1_->root_widget()) {
|
||||
root_widget->SetTokensMeterText(root_ui_tokens_meter_text_,
|
||||
root_widget->SetTokensMeterValue(root_ui_tokens_meter_value_,
|
||||
root_ui_gold_pass_);
|
||||
}
|
||||
}
|
||||
@ -1716,15 +1720,28 @@ void ClassicAppMode::SetRootUIHaveLiveValues(bool have_live_values) {
|
||||
}
|
||||
}
|
||||
|
||||
void ClassicAppMode::SetRootUIChests(const std::string& chest_0_appearance,
|
||||
void ClassicAppMode::SetRootUIChests(
|
||||
const std::string& chest_0_appearance,
|
||||
const std::string& chest_1_appearance,
|
||||
const std::string& chest_2_appearance,
|
||||
const std::string& chest_3_appearance) {
|
||||
const std::string& chest_3_appearance, seconds_t chest_0_unlock_time,
|
||||
seconds_t chest_1_unlock_time, seconds_t chest_2_unlock_time,
|
||||
seconds_t chest_3_unlock_time, seconds_t chest_0_ad_allow_time,
|
||||
seconds_t chest_1_ad_allow_time, seconds_t chest_2_ad_allow_time,
|
||||
seconds_t chest_3_ad_allow_time) {
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
if (chest_0_appearance == root_ui_chest_0_appearance_
|
||||
&& chest_1_appearance == root_ui_chest_1_appearance_
|
||||
&& chest_2_appearance == root_ui_chest_2_appearance_
|
||||
&& chest_3_appearance == root_ui_chest_3_appearance_) {
|
||||
&& chest_3_appearance == root_ui_chest_3_appearance_
|
||||
&& chest_0_unlock_time == root_ui_chest_0_unlock_time_
|
||||
&& chest_1_unlock_time == root_ui_chest_1_unlock_time_
|
||||
&& chest_2_unlock_time == root_ui_chest_2_unlock_time_
|
||||
&& chest_3_unlock_time == root_ui_chest_3_unlock_time_
|
||||
&& chest_0_ad_allow_time == root_ui_chest_0_ad_allow_time_
|
||||
&& chest_1_ad_allow_time == root_ui_chest_1_ad_allow_time_
|
||||
&& chest_2_ad_allow_time == root_ui_chest_2_ad_allow_time_
|
||||
&& chest_3_ad_allow_time == root_ui_chest_3_ad_allow_time_) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1733,13 +1750,25 @@ void ClassicAppMode::SetRootUIChests(const std::string& chest_0_appearance,
|
||||
root_ui_chest_1_appearance_ = chest_1_appearance;
|
||||
root_ui_chest_2_appearance_ = chest_2_appearance;
|
||||
root_ui_chest_3_appearance_ = chest_3_appearance;
|
||||
root_ui_chest_0_unlock_time_ = chest_0_unlock_time;
|
||||
root_ui_chest_1_unlock_time_ = chest_1_unlock_time;
|
||||
root_ui_chest_2_unlock_time_ = chest_2_unlock_time;
|
||||
root_ui_chest_3_unlock_time_ = chest_3_unlock_time;
|
||||
root_ui_chest_0_ad_allow_time_ = chest_0_ad_allow_time;
|
||||
root_ui_chest_1_ad_allow_time_ = chest_1_ad_allow_time;
|
||||
root_ui_chest_2_ad_allow_time_ = chest_2_ad_allow_time;
|
||||
root_ui_chest_3_ad_allow_time_ = chest_3_ad_allow_time;
|
||||
|
||||
// Apply it to any existing UI.
|
||||
if (uiv1_) {
|
||||
if (auto* root_widget = uiv1_->root_widget()) {
|
||||
root_widget->SetChests(
|
||||
root_ui_chest_0_appearance_, root_ui_chest_1_appearance_,
|
||||
root_ui_chest_2_appearance_, root_ui_chest_3_appearance_);
|
||||
root_ui_chest_2_appearance_, root_ui_chest_3_appearance_,
|
||||
root_ui_chest_0_unlock_time_, root_ui_chest_1_unlock_time_,
|
||||
root_ui_chest_2_unlock_time_, root_ui_chest_3_unlock_time_,
|
||||
root_ui_chest_0_ad_allow_time_, root_ui_chest_1_ad_allow_time_,
|
||||
root_ui_chest_2_ad_allow_time_, root_ui_chest_3_ad_allow_time_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,19 +215,24 @@ class ClassicAppMode : public base::AppMode {
|
||||
public_party_public_address_ipv6_ = val;
|
||||
}
|
||||
|
||||
void SetRootUITicketsMeterText(const std::string text);
|
||||
void SetRootUITokensMeterText(const std::string text);
|
||||
void SetRootUILeagueRankText(const std::string text);
|
||||
void SetRootUITicketsMeterValue(int value);
|
||||
void SetRootUITokensMeterValue(int value);
|
||||
void SetRootUILeagueRankValue(int value);
|
||||
void SetRootUILeagueType(const std::string text);
|
||||
void SetRootUIAchievementsPercentText(const std::string text);
|
||||
void SetRootUILevelText(const std::string text);
|
||||
void SetRootUIXPText(const std::string text);
|
||||
void SetRootUIInboxCountText(const std::string text);
|
||||
void SetRootUIGoldPass(bool enabled);
|
||||
void SetRootUIChests(const std::string& chest_0_appearance,
|
||||
void SetRootUIChests(
|
||||
const std::string& chest_0_appearance,
|
||||
const std::string& chest_1_appearance,
|
||||
const std::string& chest_2_appearance,
|
||||
const std::string& chest_3_appearance);
|
||||
const std::string& chest_3_appearance, seconds_t chest_0_unlock_time,
|
||||
seconds_t chest_1_unlock_time, seconds_t chest_2_unlock_time,
|
||||
seconds_t chest_3_unlock_time, seconds_t chest_0_ad_allow_time,
|
||||
seconds_t chest_1_ad_allow_time, seconds_t chest_2_ad_allow_time,
|
||||
seconds_t chest_3_ad_allow_time);
|
||||
void SetRootUIHaveLiveValues(bool val);
|
||||
|
||||
private:
|
||||
@ -250,6 +255,15 @@ class ClassicAppMode : public base::AppMode {
|
||||
std::string root_ui_chest_1_appearance_;
|
||||
std::string root_ui_chest_2_appearance_;
|
||||
std::string root_ui_chest_3_appearance_;
|
||||
seconds_t root_ui_chest_0_unlock_time_;
|
||||
seconds_t root_ui_chest_1_unlock_time_;
|
||||
seconds_t root_ui_chest_2_unlock_time_;
|
||||
seconds_t root_ui_chest_3_unlock_time_;
|
||||
seconds_t root_ui_chest_0_ad_allow_time_;
|
||||
seconds_t root_ui_chest_1_ad_allow_time_;
|
||||
seconds_t root_ui_chest_2_ad_allow_time_;
|
||||
seconds_t root_ui_chest_3_ad_allow_time_;
|
||||
|
||||
uint32_t next_scan_query_id_{};
|
||||
int scan_socket_{-1};
|
||||
int host_protocol_version_{-1};
|
||||
@ -301,6 +315,9 @@ class ClassicAppMode : public base::AppMode {
|
||||
int public_party_max_size_{8};
|
||||
int public_party_player_count_{0};
|
||||
int public_party_max_player_count_{8};
|
||||
int root_ui_tickets_meter_value_;
|
||||
int root_ui_tokens_meter_value_;
|
||||
int root_ui_league_rank_value_;
|
||||
float debug_speed_mult_{1.0f};
|
||||
float replay_speed_mult_{1.0f};
|
||||
std::set<std::string> admin_public_ids_;
|
||||
@ -308,9 +325,6 @@ class ClassicAppMode : public base::AppMode {
|
||||
std::string public_party_name_;
|
||||
std::string public_party_min_league_;
|
||||
std::string public_party_stats_url_;
|
||||
std::string root_ui_tickets_meter_text_;
|
||||
std::string root_ui_tokens_meter_text_;
|
||||
std::string root_ui_league_rank_text_;
|
||||
std::string root_ui_league_type_;
|
||||
std::string root_ui_achievement_percent_text_;
|
||||
std::string root_ui_level_text_;
|
||||
|
||||
@ -53,7 +53,7 @@ void StressTest::ProcessInputs(int player_count) {
|
||||
assert(g_base->InLogicThread());
|
||||
assert(player_count >= 0);
|
||||
|
||||
millisecs_t time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t time = g_core->AppTimeMillisecs();
|
||||
|
||||
// FIXME: If we don't check for stress_test_last_leave_time_ we totally
|
||||
// confuse the game.. need to be able to survive that.
|
||||
|
||||
@ -72,7 +72,7 @@ auto CoreFeatureSet::Import(const CoreConfig* config) -> CoreFeatureSet* {
|
||||
}
|
||||
|
||||
void CoreFeatureSet::DoImport_(const CoreConfig& config) {
|
||||
millisecs_t start_millisecs = CorePlatform::GetCurrentMillisecs();
|
||||
millisecs_t start_millisecs = CorePlatform::TimeMonotonicMillisecs();
|
||||
|
||||
assert(g_core == nullptr);
|
||||
g_core = new CoreFeatureSet(config);
|
||||
@ -87,7 +87,7 @@ CoreFeatureSet::CoreFeatureSet(CoreConfig config)
|
||||
python{new CorePython()},
|
||||
platform{CorePlatform::Create()},
|
||||
core_config_{std::move(config)},
|
||||
last_app_time_measure_microsecs_{CorePlatform::GetCurrentMicrosecs()},
|
||||
last_app_time_measure_microsecs_{CorePlatform::TimeMonotonicMicrosecs()},
|
||||
vr_mode_{config.vr_mode} {
|
||||
// We're a singleton. If there's already one of us, something's wrong.
|
||||
assert(g_core == nullptr);
|
||||
@ -313,7 +313,7 @@ auto CoreFeatureSet::SoftImportBase() -> BaseSoftInterface* {
|
||||
// // We include time-since-start as part of the message here.
|
||||
// char buffer[128];
|
||||
// snprintf(buffer, sizeof(buffer), "%s @ %.3fs.", msg,
|
||||
// g_core->GetAppTimeSeconds() + offset_seconds);
|
||||
// g_core->AppTimeSeconds() + offset_seconds);
|
||||
// Log(LogName::kBaLifecycle, LogLevel::kDebug, buffer);
|
||||
// } else {
|
||||
// Log(LogName::kBaLifecycle, LogLevel::kDebug, msg);
|
||||
@ -355,23 +355,23 @@ static void WaitThenDie(millisecs_t wait, const std::string& action) {
|
||||
FatalError("Timed out waiting for " + action + ".");
|
||||
}
|
||||
|
||||
auto CoreFeatureSet::GetAppTimeMillisecs() -> millisecs_t {
|
||||
auto CoreFeatureSet::AppTimeMillisecs() -> millisecs_t {
|
||||
UpdateAppTime_();
|
||||
return app_time_microsecs_ / 1000;
|
||||
}
|
||||
|
||||
auto CoreFeatureSet::GetAppTimeMicrosecs() -> microsecs_t {
|
||||
auto CoreFeatureSet::AppTimeMicrosecs() -> microsecs_t {
|
||||
UpdateAppTime_();
|
||||
return app_time_microsecs_;
|
||||
}
|
||||
|
||||
auto CoreFeatureSet::GetAppTimeSeconds() -> seconds_t {
|
||||
auto CoreFeatureSet::AppTimeSeconds() -> seconds_t {
|
||||
UpdateAppTime_();
|
||||
return static_cast<seconds_t>(app_time_microsecs_) / 1000000;
|
||||
}
|
||||
|
||||
void CoreFeatureSet::UpdateAppTime_() {
|
||||
microsecs_t t = CorePlatform::GetCurrentMicrosecs();
|
||||
microsecs_t t = CorePlatform::TimeMonotonicMicrosecs();
|
||||
|
||||
// If we're at a different time than our last query, do our funky math.
|
||||
if (t != last_app_time_measure_microsecs_) {
|
||||
|
||||
@ -73,21 +73,21 @@ class CoreFeatureSet {
|
||||
/// App-time is basically the total time that the engine has been actively
|
||||
/// running. (The 'App' here is a slight misnomer). It will stop
|
||||
/// progressing while the app is suspended and will never go backwards.
|
||||
auto GetAppTimeMillisecs() -> millisecs_t;
|
||||
auto AppTimeMillisecs() -> millisecs_t;
|
||||
|
||||
/// Return current app-time in microseconds.
|
||||
///
|
||||
/// App-time is basically the total time that the engine has been actively
|
||||
/// running. (The 'App' here is a slight misnomer). It will stop
|
||||
/// progressing while the app is suspended and will never go backwards.
|
||||
auto GetAppTimeMicrosecs() -> microsecs_t;
|
||||
auto AppTimeMicrosecs() -> microsecs_t;
|
||||
|
||||
/// Return current app-time in seconds.
|
||||
///
|
||||
/// App-time is basically the total time that the engine has been actively
|
||||
/// running. (The 'App' here is a slight misnomer). It will stop
|
||||
/// progressing while the app is suspended and will never go backwards.
|
||||
auto GetAppTimeSeconds() -> seconds_t;
|
||||
auto AppTimeSeconds() -> seconds_t;
|
||||
|
||||
/// Are we in the 'main' thread? The thread that first inited Core is
|
||||
/// considered the 'main' thread; on most platforms it is the one where
|
||||
|
||||
@ -116,7 +116,8 @@ void CorePlatform::LowLevelDebugLog(const std::string& msg) {
|
||||
HandleLowLevelDebugLog(msg);
|
||||
}
|
||||
|
||||
CorePlatform::CorePlatform() : start_time_millisecs_(GetCurrentMillisecs()) {}
|
||||
CorePlatform::CorePlatform()
|
||||
: start_time_millisecs_(TimeMonotonicMillisecs()) {}
|
||||
|
||||
void CorePlatform::PostInit() {
|
||||
// Hmm; we seem to get some funky invalid utf8 out of
|
||||
@ -960,8 +961,8 @@ auto CorePlatform::SetSocketNonBlocking(int sd) -> bool {
|
||||
#endif
|
||||
}
|
||||
|
||||
auto CorePlatform::GetTicks() const -> millisecs_t {
|
||||
return GetCurrentMillisecs() - start_time_millisecs_;
|
||||
auto CorePlatform::TimeSinceLaunchMillisecs() const -> millisecs_t {
|
||||
return TimeMonotonicMillisecs() - start_time_millisecs_;
|
||||
}
|
||||
|
||||
auto CorePlatform::GetPlatformName() -> std::string {
|
||||
@ -1072,27 +1073,27 @@ void CorePlatform::SetDebugKey(const std::string& key,
|
||||
|
||||
void CorePlatform::HandleLowLevelDebugLog(const std::string& msg) {}
|
||||
|
||||
auto CorePlatform::GetCurrentMillisecs() -> millisecs_t {
|
||||
auto CorePlatform::TimeMonotonicMillisecs() -> millisecs_t {
|
||||
return std::chrono::time_point_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now())
|
||||
.time_since_epoch()
|
||||
.count();
|
||||
}
|
||||
|
||||
auto CorePlatform::GetCurrentMicrosecs() -> millisecs_t {
|
||||
auto CorePlatform::TimeMonotonicMicrosecs() -> millisecs_t {
|
||||
return std::chrono::time_point_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now())
|
||||
.time_since_epoch()
|
||||
.count();
|
||||
}
|
||||
|
||||
auto CorePlatform::GetSecondsSinceEpoch() -> double {
|
||||
auto CorePlatform::TimeSinceEpochSeconds() -> double {
|
||||
return std::chrono::duration<double>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
}
|
||||
|
||||
auto CorePlatform::GetCurrentWholeSeconds() -> int64_t {
|
||||
auto CorePlatform::TimeMonotonicWholeSeconds() -> int64_t {
|
||||
return std::chrono::time_point_cast<std::chrono::seconds>(
|
||||
std::chrono::steady_clock::now())
|
||||
.time_since_epoch()
|
||||
|
||||
@ -346,31 +346,31 @@ class CorePlatform {
|
||||
/// monotonic. For most purposes, AppTime values are preferable since
|
||||
/// their progression pauses during app suspension and they are 100%
|
||||
/// guaranteed to not go backwards.
|
||||
auto GetTicks() const -> millisecs_t;
|
||||
auto TimeSinceLaunchMillisecs() const -> millisecs_t;
|
||||
|
||||
/// Return a raw current milliseconds value. It *should* be monotonic. It
|
||||
/// is relative to an undefined start point; only use it for time
|
||||
/// differences. Generally the AppTime values are preferable since their
|
||||
/// progression pauses during app suspension and they are 100% guaranteed
|
||||
/// to not go backwards.
|
||||
static auto GetCurrentMillisecs() -> millisecs_t;
|
||||
static auto TimeMonotonicMillisecs() -> millisecs_t;
|
||||
|
||||
/// Return a raw current microseconds value. It *should* be monotonic. It
|
||||
/// is relative to an undefined start point; only use it for time
|
||||
/// differences. Generally the AppTime values are preferable since their
|
||||
/// progression pauses during app suspension and they are 100% guaranteed
|
||||
/// to not go backwards.
|
||||
static auto GetCurrentMicrosecs() -> microsecs_t;
|
||||
static auto TimeMonotonicMicrosecs() -> microsecs_t;
|
||||
|
||||
/// Return a raw current seconds integer value. It *should* be monotonic.
|
||||
/// It is relative to an undefined start point; only use it for time
|
||||
/// differences. Generally the AppTime values are preferable since their
|
||||
/// progression pauses during app suspension and they are 100% guaranteed
|
||||
/// to not go backwards.
|
||||
static auto GetCurrentWholeSeconds() -> int64_t;
|
||||
static auto TimeMonotonicWholeSeconds() -> int64_t;
|
||||
|
||||
/// Return seconds since the epoch; same as Python's time.time().
|
||||
static auto GetSecondsSinceEpoch() -> double;
|
||||
static auto TimeSinceEpochSeconds() -> double;
|
||||
|
||||
static void SleepSeconds(seconds_t duration);
|
||||
static void SleepMillisecs(millisecs_t duration);
|
||||
|
||||
@ -10,8 +10,8 @@
|
||||
|
||||
namespace ballistica::core {
|
||||
|
||||
/// Collection of low level options for a run of the engine; passed
|
||||
/// when initing the core feature-set.
|
||||
/// A collection of low level options for a run of the engine; passed when
|
||||
/// initing the core feature-set.
|
||||
class CoreConfig {
|
||||
public:
|
||||
static auto ForArgsAndEnvVars(int argc, char** argv) -> CoreConfig;
|
||||
|
||||
@ -34,7 +34,7 @@ const int kPingMeasureInterval = 2000;
|
||||
|
||||
Connection::Connection() {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
||||
creation_time_ = last_average_update_time_ = g_core->GetAppTimeMillisecs();
|
||||
creation_time_ = last_average_update_time_ = g_core->AppTimeMillisecs();
|
||||
}
|
||||
|
||||
void Connection::ProcessWaitingMessages() {
|
||||
@ -181,13 +181,13 @@ void Connection::HandleGamePacket(const std::vector<uint8_t>& data) {
|
||||
"Error: got invalid BA_SCENEPACKET_KEEPALIVE packet.");
|
||||
return;
|
||||
}
|
||||
millisecs_t real_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t real_time = g_core->AppTimeMillisecs();
|
||||
HandleResends(real_time, data, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case BA_SCENEPACKET_MESSAGE: {
|
||||
millisecs_t real_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t real_time = g_core->AppTimeMillisecs();
|
||||
|
||||
// Expect 1 byte type, 2 byte num, 3 byte acks, at least 1 byte payload.
|
||||
if (data.size() < 7) {
|
||||
@ -211,7 +211,7 @@ void Connection::HandleGamePacket(const std::vector<uint8_t>& data) {
|
||||
ReliableMessageIn& msg(in_messages_[num]);
|
||||
msg.data.resize(data.size() - 6);
|
||||
memcpy(&(msg.data[0]), &(data[6]), msg.data.size());
|
||||
msg.arrival_time = g_core->GetAppTimeMillisecs();
|
||||
msg.arrival_time = g_core->AppTimeMillisecs();
|
||||
|
||||
// Now run all in-order packets we've got.
|
||||
ProcessWaitingMessages();
|
||||
@ -308,7 +308,7 @@ void Connection::SendReliableMessage(const std::vector<uint8_t>& data) {
|
||||
assert(out_messages_.find(num) == out_messages_.end());
|
||||
ReliableMessageOut& msg(out_messages_[num]);
|
||||
|
||||
millisecs_t real_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t real_time = g_core->AppTimeMillisecs();
|
||||
|
||||
msg.data = data;
|
||||
msg.first_send_time = msg.last_send_time = real_time;
|
||||
@ -341,7 +341,7 @@ void Connection::SendUnreliableMessage(const std::vector<uint8_t>& data) {
|
||||
}
|
||||
|
||||
uint16_t num = next_out_unreliable_message_num_++;
|
||||
millisecs_t real_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t real_time = g_core->AppTimeMillisecs();
|
||||
|
||||
// Add our header/acks and go ahead and send this one out.
|
||||
// 1 byte for type, 2 for packet-num, 2 for unreliable packet-num, 3 for acks.
|
||||
@ -367,7 +367,7 @@ void Connection::SendJMessage(cJSON* val) {
|
||||
}
|
||||
|
||||
void Connection::Update() {
|
||||
millisecs_t real_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t real_time = g_core->AppTimeMillisecs();
|
||||
|
||||
// Update our averages once per second.
|
||||
while (real_time - last_average_update_time_ > 1000) {
|
||||
|
||||
@ -95,7 +95,7 @@ ConnectionToClient::~ConnectionToClient() {
|
||||
void ConnectionToClient::Update() {
|
||||
Connection::Update(); // Handles common stuff.
|
||||
|
||||
millisecs_t real_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t real_time = g_core->AppTimeMillisecs();
|
||||
|
||||
// If we're waiting for handshake response still, keep sending out handshake
|
||||
// attempts.
|
||||
@ -246,7 +246,7 @@ void ConnectionToClient::HandleGamePacket(const std::vector<uint8_t>& data) {
|
||||
|
||||
// Don't allow fresh clients to start kick votes for a while.
|
||||
next_kick_vote_allow_time_ =
|
||||
g_core->GetAppTimeMillisecs() + kNewClientKickVoteDelay;
|
||||
g_core->AppTimeMillisecs() + kNewClientKickVoteDelay;
|
||||
|
||||
// At this point we have their name, so lets announce their arrival.
|
||||
if (appmode->ShouldAnnouncePartyJoinsAndLeaves()) {
|
||||
@ -263,7 +263,7 @@ void ConnectionToClient::HandleGamePacket(const std::vector<uint8_t>& data) {
|
||||
// Also mark the time for flashing the 'someone just joined your
|
||||
// party' message in the corner.
|
||||
appmode->set_last_connection_to_client_join_time(
|
||||
g_core->GetAppTimeMillisecs());
|
||||
g_core->AppTimeMillisecs());
|
||||
|
||||
// Added midway through protocol 29:
|
||||
// We now send a json dict of info about ourself first thing. This
|
||||
@ -338,8 +338,7 @@ void ConnectionToClient::SendScreenMessage(const std::string& s, float r,
|
||||
// Older clients don't support the screen-message message, so in that case
|
||||
// we just send it as a chat-message from <HOST>.
|
||||
if (build_number() < 14248) {
|
||||
std::string value =
|
||||
g_base->assets->CompileResourceString(s, "sendScreenMessage");
|
||||
std::string value = g_base->assets->CompileResourceString(s);
|
||||
std::string our_spec_string =
|
||||
PlayerSpec::GetDummyPlayerSpec("<HOST>").GetSpecString();
|
||||
std::vector<uint8_t> msg_out(1 + 1 + our_spec_string.size() + value.size());
|
||||
@ -500,7 +499,7 @@ void ConnectionToClient::HandleMessagePacket(
|
||||
|
||||
case BA_MESSAGE_CHAT: {
|
||||
// We got a chat message from a client.
|
||||
millisecs_t now = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t now = g_core->AppTimeMillisecs();
|
||||
|
||||
// Ignore this if they're chat blocked.
|
||||
if (now >= chat_block_time_) {
|
||||
@ -636,7 +635,7 @@ void ConnectionToClient::HandleMessagePacket(
|
||||
}
|
||||
|
||||
case BA_MESSAGE_REMOVE_REMOTE_PLAYER: {
|
||||
last_remove_player_time_ = g_core->GetAppTimeMillisecs();
|
||||
last_remove_player_time_ = g_core->AppTimeMillisecs();
|
||||
if (buffer.size() != 2) {
|
||||
g_core->Log(LogName::kBaNetworking, LogLevel::kError,
|
||||
"Error: invalid remove-remote-player packet");
|
||||
@ -693,7 +692,7 @@ void ConnectionToClient::HandleMessagePacket(
|
||||
// master-server info for this client, delay their join (we'll
|
||||
// eventually give up and just give them a blank slate).
|
||||
if (still_waiting_for_auth
|
||||
&& (g_core->GetAppTimeMillisecs() - creation_time() < 10000)) {
|
||||
&& (g_core->AppTimeMillisecs() - creation_time() < 10000)) {
|
||||
SendScreenMessage(
|
||||
"{\"v\":\"${A}...\",\"s\":[[\"${A}\",{\"r\":"
|
||||
"\"loadingTryAgainText\",\"f\":\"loadingText\"}]]}",
|
||||
|
||||
@ -58,7 +58,7 @@ ConnectionToHost::~ConnectionToHost() {
|
||||
}
|
||||
|
||||
void ConnectionToHost::Update() {
|
||||
millisecs_t real_time = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t real_time = g_core->AppTimeMillisecs();
|
||||
|
||||
// Send out null messages occasionally for ping measurement purposes.
|
||||
// Note that we currently only do this from the client since we might not
|
||||
|
||||
@ -514,7 +514,7 @@ void Dynamics::ProcessCollision_() {
|
||||
void Dynamics::Process() {
|
||||
in_process_ = true;
|
||||
// Update this once so we can recycle results.
|
||||
real_time_ = g_core->GetAppTimeMillisecs();
|
||||
real_time_ = g_core->AppTimeMillisecs();
|
||||
ProcessCollision_();
|
||||
dWorldQuickStep(ode_world_, kGameStepSeconds);
|
||||
dJointGroupEmpty(ode_contact_group_);
|
||||
|
||||
@ -27,7 +27,7 @@ class GlobalsNodeType : public NodeType {
|
||||
public:
|
||||
#define BA_NODE_TYPE_CLASS GlobalsNode
|
||||
BA_NODE_CREATE_CALL(CreateGlobals);
|
||||
BA_INT64_ATTR_READONLY(real_time, GetAppTimeMillisecs);
|
||||
BA_INT64_ATTR_READONLY(real_time, AppTimeMillisecs);
|
||||
BA_INT64_ATTR_READONLY(time, GetTime);
|
||||
BA_INT64_ATTR_READONLY(step, GetStep);
|
||||
BA_FLOAT_ATTR(debris_friction, debris_friction, SetDebrisFriction);
|
||||
@ -206,7 +206,7 @@ auto GlobalsNode::IsCurrentGlobals() const -> bool {
|
||||
&& scene->globals_node() == this);
|
||||
}
|
||||
|
||||
auto GlobalsNode::GetAppTimeMillisecs() -> millisecs_t {
|
||||
auto GlobalsNode::AppTimeMillisecs() -> millisecs_t {
|
||||
// Pull this from our scene so we return consistent values throughout a step.
|
||||
return scene()->last_step_real_time();
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ class GlobalsNode : public Node {
|
||||
~GlobalsNode() override;
|
||||
void SetAsForeground();
|
||||
auto IsCurrentGlobals() const -> bool;
|
||||
auto GetAppTimeMillisecs() -> millisecs_t;
|
||||
auto AppTimeMillisecs() -> millisecs_t;
|
||||
auto GetTime() -> millisecs_t;
|
||||
auto GetStep() -> int64_t;
|
||||
auto debris_friction() const -> float { return debris_friction_; }
|
||||
|
||||
@ -12,7 +12,7 @@ class SessionGlobalsNodeType : public NodeType {
|
||||
public:
|
||||
#define BA_NODE_TYPE_CLASS SessionGlobalsNode
|
||||
BA_NODE_CREATE_CALL(CreateSessionGlobals);
|
||||
BA_INT64_ATTR_READONLY(real_time, GetAppTimeMillisecs);
|
||||
BA_INT64_ATTR_READONLY(real_time, AppTimeMillisecs);
|
||||
BA_INT64_ATTR_READONLY(time, GetTime);
|
||||
BA_INT64_ATTR_READONLY(step, GetStep);
|
||||
#undef BA_NODE_TYPE_CLASS
|
||||
@ -38,7 +38,7 @@ SessionGlobalsNode::SessionGlobalsNode(Scene* scene) : Node(scene, node_type) {
|
||||
|
||||
SessionGlobalsNode::~SessionGlobalsNode() = default;
|
||||
|
||||
auto SessionGlobalsNode::GetAppTimeMillisecs() -> millisecs_t {
|
||||
auto SessionGlobalsNode::AppTimeMillisecs() -> millisecs_t {
|
||||
// Pull this from our scene so we return consistent values throughout a step.
|
||||
return scene()->last_step_real_time();
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ class SessionGlobalsNode : public Node {
|
||||
static auto InitType() -> NodeType*;
|
||||
explicit SessionGlobalsNode(Scene* scene);
|
||||
~SessionGlobalsNode() override;
|
||||
auto GetAppTimeMillisecs() -> millisecs_t;
|
||||
auto AppTimeMillisecs() -> millisecs_t;
|
||||
auto GetTime() -> millisecs_t;
|
||||
auto GetStep() -> int64_t;
|
||||
};
|
||||
|
||||
@ -142,7 +142,7 @@ void SoundNode::Step() {
|
||||
}
|
||||
}
|
||||
if (positional_ && position_dirty_ && playing_) {
|
||||
millisecs_t t = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t t = g_core->AppTimeMillisecs();
|
||||
if (t - last_position_update_time_ > 100) {
|
||||
base::AudioSource* s = g_base->audio->SourceBeginExisting(play_id_, 107);
|
||||
if (s) {
|
||||
|
||||
@ -1797,7 +1797,7 @@ void SpazNode::DoFlyPress() {
|
||||
|
||||
// Keep from doing too many sparkles.
|
||||
static millisecs_t last_sparkle_time = 0;
|
||||
millisecs_t t = g_core->GetAppTimeMillisecs();
|
||||
millisecs_t t = g_core->AppTimeMillisecs();
|
||||
if (t - last_sparkle_time > 200) {
|
||||
last_sparkle_time = t;
|
||||
auto* s = g_base->audio->SourceBeginNew();
|
||||
|
||||
@ -104,7 +104,7 @@ TerrainNode::~TerrainNode() {
|
||||
// without our reference.
|
||||
if (collision_mesh_.exists()) {
|
||||
collision_mesh_->collision_mesh_data()->set_last_used_time(
|
||||
g_core->GetAppTimeMillisecs());
|
||||
g_core->AppTimeMillisecs());
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +123,7 @@ void TerrainNode::set_collision_mesh(SceneCollisionMesh* val) {
|
||||
// if we had an old one, mark its last-used time so caching works properly..
|
||||
if (collision_mesh_.exists()) {
|
||||
collision_mesh_->collision_mesh_data()->set_last_used_time(
|
||||
g_core->GetAppTimeMillisecs());
|
||||
g_core->AppTimeMillisecs());
|
||||
}
|
||||
collision_mesh_ = val;
|
||||
|
||||
|
||||
@ -117,8 +117,7 @@ void TextNode::SetText(const std::string& val) {
|
||||
|
||||
if (do_format_check) {
|
||||
bool valid;
|
||||
g_base->assets->CompileResourceString(val, "setText format check",
|
||||
&valid);
|
||||
g_base->assets->CompileResourceString(val, &valid);
|
||||
if (!valid) {
|
||||
BA_LOG_ONCE(
|
||||
LogName::kBa, LogLevel::kError,
|
||||
@ -354,8 +353,7 @@ void TextNode::Draw(base::FrameDef* frame_def) {
|
||||
|
||||
// Apply subs/resources to get our actual text if need be.
|
||||
if (text_translation_dirty_) {
|
||||
text_translated_ =
|
||||
g_base->assets->CompileResourceString(text_raw_, "TextNode::OnDraw");
|
||||
text_translated_ = g_base->assets->CompileResourceString(text_raw_);
|
||||
text_translation_dirty_ = false;
|
||||
text_group_dirty_ = true;
|
||||
text_width_dirty_ = true;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user