mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-26 00:47:10 +08:00
Initial 1.6 builds with private party front-end in place
This commit is contained in:
parent
ebaf83c502
commit
2a66b5b93f
@ -420,7 +420,7 @@
|
||||
"assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/a9/71/9286d55c45c37877f3267850f90b",
|
||||
"assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/2f/09/36e691de67eb8f155449a7170861",
|
||||
"assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/fd/a8/ad50785ce206e8dc3dcc7358b173",
|
||||
"assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/34/93/4989950b5dd035da056a0291dbb2",
|
||||
"assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/c2/36/59ab3af6b45307c79ba8c296df5b",
|
||||
"assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/0d/25/26de912f111de8189f40aeeddee6",
|
||||
"assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/44/ed/5b972fa848cffb73723533c2ccb7",
|
||||
"assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/6a/20/57d91c24e0aeb1fe6b7d6dbbcac9",
|
||||
@ -429,27 +429,27 @@
|
||||
"assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/ce/de/b0f462205cdf687a875abc6f39bd",
|
||||
"assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28",
|
||||
"assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/d1/07/37b7adc3dbec7328d26c5325f212",
|
||||
"assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/3f/ee/72767c1e922d3f2cf668147ef143",
|
||||
"assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/66/d1/8adfe1479fe6b4c30cd0d0e694d6",
|
||||
"assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731",
|
||||
"assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/18/b2/9c1f6e3ca6e18d6a6fdbdb14e224",
|
||||
"assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/19/ba/b12493cfaa28d27f9bfee0459e20",
|
||||
"assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/82/9f/bdcff3ac022c125a7232a412568e",
|
||||
"assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/43/f3/9e88a199337b7913cb5e7961b1c6",
|
||||
"assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/51/31/64479524c0ee990b3e97ffdca068",
|
||||
"assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/ed/98/37d9457755f7e86e2f2875e3b055",
|
||||
"assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/87/2d/027aa239eb66ea8f496562f4fd83",
|
||||
"assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/a4/01/1fcc28b303858b3d028d26516907",
|
||||
"assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/20/ca/d675783cd094030a625e7ce023cf",
|
||||
"assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/6b/5a/6e8e3692347d9ba01aff607af5a8",
|
||||
"assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52",
|
||||
"assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/f8/e6/773d3da1cbdb2215956f9d99c348",
|
||||
"assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/29/72/bcf75316f71373a47739a72ad6da",
|
||||
"assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/3d/ba/7f4c8846babc5ef59187e87efa3d",
|
||||
"assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/29/7d/be03fa23b8d80404b1b56c305edc",
|
||||
"assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf",
|
||||
"assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/07/42/382831beefb1f134eed95d18b20b",
|
||||
"assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/05/5b/910b8963f48cd494dc01d5a18a5c",
|
||||
"assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2",
|
||||
"assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/58/3b/2bdbad7748ab0c76b9cf3d65c70e",
|
||||
"assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/e0/83/32c5bc6544b647dbc599c11123df",
|
||||
"assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0",
|
||||
"assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/19/fe/c97df315575d999ad2bb63478b5f",
|
||||
"assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/2d/a3/114ca23a3fb0f2885bfbbabb9727",
|
||||
"assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/66/b0/e1d71e57673a6fc78e0ea181b76b",
|
||||
"assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/e4/3e/243eaa0237361b984fc6c56042be",
|
||||
"assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/04/52/683a27aaf9aa7c63e7e595f80d08",
|
||||
@ -3932,40 +3932,40 @@
|
||||
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
|
||||
"assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e",
|
||||
"assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f",
|
||||
"build/prefab/full/linux_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1c/5f/2e5338ab577aa7dac9942dda3d43",
|
||||
"build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/50/bb/7a9daf22e3a09c6ab40f6b6909f2",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e5/6f/10a4fc55ee08a4f6e1d8f3b87422",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f3/fa/ba9a4fd942854e6d330079a5d5b2",
|
||||
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/68/5d/09e80048115eaaa434ffe85a7f8f",
|
||||
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/60/0e/804d130b536483882ee3f4299375",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/73/15/f45a3b15110a0cc0493ef17fae4c",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/55/e7/618d3ecd8072a67d07b1c1098369",
|
||||
"build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/54/31/bce32b4e1aef2b4bd27dc9336619",
|
||||
"build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/bf/5a/45640c9cdda02fdffd1c9b3beebe",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ed/ab/1d70d046b60626e74ab6a6d8d733",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cb/fb/135c187787329c51b6770a5f5135",
|
||||
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1a/1d/fb869851bf6e54e215d1447d1b68",
|
||||
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/99/58dfc239e6fdac005d583287507f",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/00/a6/2727ba6b98c46e4ab1414be214a7",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a9/47/954ea39895cad0354cd1b39e4436",
|
||||
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ac/62/9c8551a51d8f458e59e856cd4a3a",
|
||||
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/75/e9/9674fac783d2827e5daf33b91afc",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f2/46/c17af441ceb12cd41895c8482475",
|
||||
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c8/16/000156a1d2728de92b7bcdaa1f22",
|
||||
"build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/65/e2/82162e0ab11caf2634692d2d7a4e",
|
||||
"build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6f/4d/baa3f14360c0d379ccb5ae330295",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c9/4a/167038e8603b915bc6bdebc886a5",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fa/a3/3f9a8d8856f9db3340adc5488d9b",
|
||||
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ef/d0/49b99ce32e5e2b01b056fbac5c67",
|
||||
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/83/25/980050d75bbea49a84652209050c",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/47/aa/e82233695a50974e7e22db4e7146",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/2b/45/7f9fbae208890455fce2fbc172d3",
|
||||
"build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fc/75/8ea8b8eeb9a1c47c534bfb9e5d3f",
|
||||
"build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/69/a9/01af1b4a126cf517e9bbbfade412",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d5/f5/7c740da86b84653a3d7b23cb11d7",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/47/64/f4a9fb9a0c338dd0daa0dc0e52a6",
|
||||
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/74/66/c94da5b860d0581b20c9679d183f",
|
||||
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0f/c1/90db918c2dce94bd94725b25b2b4",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0f/49/4269f4e88a55e6712841b7b56f5a",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f7/6c/fe17cf1a3f98cacbe946549631c5"
|
||||
"build/prefab/full/linux_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3c/61/69d59f46d61b3aeee054aa5daab1",
|
||||
"build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d2/41/e8362cfe9f6fd6dc882858021874",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/83/ff/29cf07587f212d5278bb5ed92e75",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/90/e7/c4834a3b41d8f9d837071dc0800a",
|
||||
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ce/3d/0febcd4db42fe5dedb701c60bddf",
|
||||
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c5/d8/3d7ca6668af72200a6eea00c6d84",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/79/f2/3381ea14e11854a9e8804953bb06",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/80/00/a02fdfe67796bc04a78dbd6ed353",
|
||||
"build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/19/36/ebf5f0f1c7a2923f7e3c4ee292ad",
|
||||
"build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fb/4f/fbddddae2d5963a1ec6f97234db3",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0d/32/8755d570c2e74316497bdd290f0d",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/24/30/863f0c9948669219f66b117502bc",
|
||||
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3c/dc/317d57caa8b27d5b685193cf3de9",
|
||||
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cd/8a/3fc0cca1383b6af2a4f8a5ae2cfe",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/20/16/c0cf342b1971dcbc757abd29bdc5",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1b/06/f81485b10ac37b58a012bc158952",
|
||||
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/85/44/92172591b72302dc4909b0e91108",
|
||||
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d4/e6/8d5a9ffcf32588f8b770a88a80d5",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c7/9c/e55d58caf88ad6bb88f1a5ebfdbf",
|
||||
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f2/6e/981553869590e8367854b5df2802",
|
||||
"build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/34/21/016123d9ec8293ce92ba910dd00a",
|
||||
"build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6f/f8/cf46e7c33a0a237e2c6f19ef4f92",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/10/67/5a3d6131d1b1fdf9f629301b68db",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6b/bc/72d32c36d51acb255b2667c4d386",
|
||||
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7c/9b/af5e799cb4d296074598f11a063f",
|
||||
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/35/7c/b5f26ca01907df6ea80ff3ae5861",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8c/76/9ea770a68773fd4a08fb78855fbb",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1d/b3/329956f15f5cb76a63bd4fd3e0cc",
|
||||
"build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/30/04/7b7c4f847fd992b23719f755981a",
|
||||
"build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/bc/20/e13686c62052e3e388431d4859aa",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a3/a1/1bb8a1926628e34054aeca5a0178",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5a/33/c232d2c633bf70915e1a8eecdf95",
|
||||
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/84/8c/2930553d642210c81b6342bffb9f",
|
||||
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/68/22/cc580cef75b9e452de66095ba62b",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/93/2d/b6482a7ce6957156fe050f4cc9dc",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d1/a2/1d592f5d21dd39d7b16da8f1c8c4"
|
||||
}
|
||||
23
.idea/dictionaries/ericf.xml
generated
23
.idea/dictionaries/ericf.xml
generated
@ -45,6 +45,7 @@
|
||||
<w>adbcfaca</w>
|
||||
<w>adbpath</w>
|
||||
<w>addcall</w>
|
||||
<w>addchars</w>
|
||||
<w>addgame</w>
|
||||
<w>addlevel</w>
|
||||
<w>addr</w>
|
||||
@ -98,6 +99,7 @@
|
||||
<w>archs</w>
|
||||
<w>argh</w>
|
||||
<w>argparse</w>
|
||||
<w>argsjoined</w>
|
||||
<w>argtypes</w>
|
||||
<w>argval</w>
|
||||
<w>armeabi</w>
|
||||
@ -146,6 +148,7 @@
|
||||
<w>autoretain</w>
|
||||
<w>autoselect</w>
|
||||
<w>autotools</w>
|
||||
<w>availmins</w>
|
||||
<w>availplug</w>
|
||||
<w>aval</w>
|
||||
<w>axismotion</w>
|
||||
@ -244,6 +247,7 @@
|
||||
<w>bsuffix</w>
|
||||
<w>bsui</w>
|
||||
<w>btnh</w>
|
||||
<w>btnlabel</w>
|
||||
<w>btnv</w>
|
||||
<w>btnx</w>
|
||||
<w>btype</w>
|
||||
@ -279,6 +283,7 @@
|
||||
<w>cameraflash</w>
|
||||
<w>camerashake</w>
|
||||
<w>campaignname</w>
|
||||
<w>cancelbtn</w>
|
||||
<w>capb</w>
|
||||
<w>capturetheflag</w>
|
||||
<w>carentity</w>
|
||||
@ -286,6 +291,7 @@
|
||||
<w>cbits</w>
|
||||
<w>cbot</w>
|
||||
<w>cbtn</w>
|
||||
<w>cbtnoffs</w>
|
||||
<w>ccfgs</w>
|
||||
<w>ccode</w>
|
||||
<w>ccompiler</w>
|
||||
@ -433,6 +439,7 @@
|
||||
<w>crashlytics</w>
|
||||
<w>creationflags</w>
|
||||
<w>creditslist</w>
|
||||
<w>cresult</w>
|
||||
<w>cryptmodule</w>
|
||||
<w>cspbd</w>
|
||||
<w>cspnf</w>
|
||||
@ -782,6 +789,7 @@
|
||||
<w>freeforallendscreen</w>
|
||||
<w>freeforallsession</w>
|
||||
<w>freeforallvictory</w>
|
||||
<w>freemins</w>
|
||||
<w>freepik</w>
|
||||
<w>freesound</w>
|
||||
<w>froemling</w>
|
||||
@ -966,6 +974,7 @@
|
||||
<w>homebrew</w>
|
||||
<w>hometest</w>
|
||||
<w>hostconfig</w>
|
||||
<w>hostingstate</w>
|
||||
<w>hostuser</w>
|
||||
<w>hout</w>
|
||||
<w>howtoplay</w>
|
||||
@ -1201,6 +1210,7 @@
|
||||
<w>locationlist</w>
|
||||
<w>locationsingles</w>
|
||||
<w>locationval</w>
|
||||
<w>lockpath</w>
|
||||
<w>lockstr</w>
|
||||
<w>locktype</w>
|
||||
<w>locs</w>
|
||||
@ -1417,6 +1427,7 @@
|
||||
<w>nosynctool</w>
|
||||
<w>nosynctools</w>
|
||||
<w>notdir</w>
|
||||
<w>nowtickets</w>
|
||||
<w>npos</w>
|
||||
<w>nprocessors</w>
|
||||
<w>ntpath</w>
|
||||
@ -1439,6 +1450,8 @@
|
||||
<w>oculus</w>
|
||||
<w>oenval</w>
|
||||
<w>offsanchor</w>
|
||||
<w>offsx</w>
|
||||
<w>offsy</w>
|
||||
<w>ofval</w>
|
||||
<w>oggenc</w>
|
||||
<w>oghash</w>
|
||||
@ -1591,6 +1604,7 @@
|
||||
<w>powervr</w>
|
||||
<w>ppos</w>
|
||||
<w>pproxy</w>
|
||||
<w>pptabcom</w>
|
||||
<w>pragmas</w>
|
||||
<w>prch</w>
|
||||
<w>prec</w>
|
||||
@ -1619,6 +1633,7 @@
|
||||
<w>printobjects</w>
|
||||
<w>printpaths</w>
|
||||
<w>priv</w>
|
||||
<w>privatetab</w>
|
||||
<w>proactor</w>
|
||||
<w>proc</w>
|
||||
<w>procs</w>
|
||||
@ -1628,6 +1643,7 @@
|
||||
<w>profilenames</w>
|
||||
<w>proj</w>
|
||||
<w>projconfig</w>
|
||||
<w>projdir</w>
|
||||
<w>projectpath</w>
|
||||
<w>projectroot</w>
|
||||
<w>projroot</w>
|
||||
@ -1751,6 +1767,7 @@
|
||||
<w>reqtype</w>
|
||||
<w>reqtypes</w>
|
||||
<w>resample</w>
|
||||
<w>resetbtn</w>
|
||||
<w>resetinput</w>
|
||||
<w>resourcetypeinfo</w>
|
||||
<w>respawn</w>
|
||||
@ -1802,6 +1819,7 @@
|
||||
<w>samsung</w>
|
||||
<w>sandboxing</w>
|
||||
<w>sandyrb</w>
|
||||
<w>savebtn</w>
|
||||
<w>savebutton</w>
|
||||
<w>saxutils</w>
|
||||
<w>sbblk</w>
|
||||
@ -1844,7 +1862,11 @@
|
||||
<w>sdkcheck</w>
|
||||
<w>sdkutils</w>
|
||||
<w>sdtk</w>
|
||||
<w>selchild</w>
|
||||
<w>selectmodule</w>
|
||||
<w>selindex</w>
|
||||
<w>selwidget</w>
|
||||
<w>selwidgets</w>
|
||||
<w>senze</w>
|
||||
<w>seqtype</w>
|
||||
<w>seqtypestr</w>
|
||||
@ -2145,6 +2167,7 @@
|
||||
<w>this'll</w>
|
||||
<w>threadtype</w>
|
||||
<w>throwiness</w>
|
||||
<w>ticon</w>
|
||||
<w>timedisplay</w>
|
||||
<w>timeformat</w>
|
||||
<w>timemax</w>
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
### 1.5.30 (20263)
|
||||
### 1.6.0 (20268)
|
||||
- Added private parties functionality (cloud hosted parties with associated codes making it easier to play with friends)
|
||||
- The meta subsystem now enables new plugins by default in headless builds.
|
||||
- Added option to save party in Manual tab
|
||||
- Slight tidying on the tourney entry popup
|
||||
- Env var to override UI scale is now BA_UI_SCALE instead of BA_FORCE_UI_SCALE.
|
||||
- Fixed an issue where ba.storagename() could prevent objects on the stack from getting released cleanly
|
||||
- Improvements to documentation generation such as link to some external base types.
|
||||
- Added ba.clipboard_* functions for copying and pasting text on supported platforms.
|
||||
- Implemented clipboard functionality on SDL based builds (such as prefab)
|
||||
- Fixed an issue where click locations on scaled text fields could be incorrectly calculated.
|
||||
|
||||
### 1.5.29 (20246)
|
||||
- Exposed ba method/class initing in public C++ layer.
|
||||
|
||||
@ -364,16 +364,14 @@
|
||||
"ba_data/python/bastd/ui/gather/__init__.py",
|
||||
"ba_data/python/bastd/ui/gather/__pycache__/__init__.cpython-38.opt-1.pyc",
|
||||
"ba_data/python/bastd/ui/gather/__pycache__/abouttab.cpython-38.opt-1.pyc",
|
||||
"ba_data/python/bastd/ui/gather/__pycache__/bases.cpython-38.opt-1.pyc",
|
||||
"ba_data/python/bastd/ui/gather/__pycache__/googleplaytab.cpython-38.opt-1.pyc",
|
||||
"ba_data/python/bastd/ui/gather/__pycache__/manualtab.cpython-38.opt-1.pyc",
|
||||
"ba_data/python/bastd/ui/gather/__pycache__/nearbytab.cpython-38.opt-1.pyc",
|
||||
"ba_data/python/bastd/ui/gather/__pycache__/privatetab.cpython-38.opt-1.pyc",
|
||||
"ba_data/python/bastd/ui/gather/__pycache__/publictab.cpython-38.opt-1.pyc",
|
||||
"ba_data/python/bastd/ui/gather/abouttab.py",
|
||||
"ba_data/python/bastd/ui/gather/bases.py",
|
||||
"ba_data/python/bastd/ui/gather/googleplaytab.py",
|
||||
"ba_data/python/bastd/ui/gather/manualtab.py",
|
||||
"ba_data/python/bastd/ui/gather/nearbytab.py",
|
||||
"ba_data/python/bastd/ui/gather/privatetab.py",
|
||||
"ba_data/python/bastd/ui/gather/publictab.py",
|
||||
"ba_data/python/bastd/ui/getcurrency.py",
|
||||
"ba_data/python/bastd/ui/getremote.py",
|
||||
|
||||
@ -296,10 +296,9 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
build/ba_data/python/bastd/ui/fileselector.py \
|
||||
build/ba_data/python/bastd/ui/gather/__init__.py \
|
||||
build/ba_data/python/bastd/ui/gather/abouttab.py \
|
||||
build/ba_data/python/bastd/ui/gather/bases.py \
|
||||
build/ba_data/python/bastd/ui/gather/googleplaytab.py \
|
||||
build/ba_data/python/bastd/ui/gather/manualtab.py \
|
||||
build/ba_data/python/bastd/ui/gather/nearbytab.py \
|
||||
build/ba_data/python/bastd/ui/gather/privatetab.py \
|
||||
build/ba_data/python/bastd/ui/gather/publictab.py \
|
||||
build/ba_data/python/bastd/ui/getcurrency.py \
|
||||
build/ba_data/python/bastd/ui/getremote.py \
|
||||
@ -541,10 +540,9 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
||||
build/ba_data/python/bastd/ui/__pycache__/fileselector.cpython-38.opt-1.pyc \
|
||||
build/ba_data/python/bastd/ui/gather/__pycache__/__init__.cpython-38.opt-1.pyc \
|
||||
build/ba_data/python/bastd/ui/gather/__pycache__/abouttab.cpython-38.opt-1.pyc \
|
||||
build/ba_data/python/bastd/ui/gather/__pycache__/bases.cpython-38.opt-1.pyc \
|
||||
build/ba_data/python/bastd/ui/gather/__pycache__/googleplaytab.cpython-38.opt-1.pyc \
|
||||
build/ba_data/python/bastd/ui/gather/__pycache__/manualtab.cpython-38.opt-1.pyc \
|
||||
build/ba_data/python/bastd/ui/gather/__pycache__/nearbytab.cpython-38.opt-1.pyc \
|
||||
build/ba_data/python/bastd/ui/gather/__pycache__/privatetab.cpython-38.opt-1.pyc \
|
||||
build/ba_data/python/bastd/ui/gather/__pycache__/publictab.cpython-38.opt-1.pyc \
|
||||
build/ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-38.opt-1.pyc \
|
||||
build/ba_data/python/bastd/ui/__pycache__/getremote.cpython-38.opt-1.pyc \
|
||||
|
||||
@ -996,7 +996,7 @@ class Timer:
|
||||
|
||||
time: length of time (in seconds by default) that the timer will wait
|
||||
before firing. Note that the actual delay experienced may vary
|
||||
depending on the timetype. (see below)
|
||||
depending on the timetype. (see below)
|
||||
|
||||
call: A callable Python object. Note that the timer will retain a
|
||||
strong reference to the callable for as long as it exists, so you
|
||||
@ -1006,28 +1006,11 @@ class Timer:
|
||||
repeat: if True, the timer will fire repeatedly, with each successive
|
||||
firing having the same delay as the first.
|
||||
|
||||
timetype can be either 'sim', 'base', or 'real'. It defaults to
|
||||
'sim'. Types are explained below:
|
||||
timetype: A ba.TimeType value determining which timeline the timer is
|
||||
placed onto.
|
||||
|
||||
'sim' time maps to local simulation time in ba.Activity or ba.Session
|
||||
Contexts. This means that it may progress slower in slow-motion play
|
||||
modes, stop when the game is paused, etc. This time type is not
|
||||
available in UI contexts.
|
||||
|
||||
'base' time is also linked to gameplay in ba.Activity or ba.Session
|
||||
Contexts, but it progresses at a constant rate regardless of
|
||||
slow-motion states or pausing. It can, however, slow down or stop
|
||||
in certain cases such as network outages or game slowdowns due to
|
||||
cpu load. Like 'sim' time, this is unavailable in UI contexts.
|
||||
|
||||
'real' time always maps to actual clock time with a bit of filtering
|
||||
added, regardless of Context. (the filtering prevents it from going
|
||||
backwards or jumping forward by large amounts due to the app being
|
||||
backgrounded, system time changing, etc.)
|
||||
Real time timers are currently only available in the UI context.
|
||||
|
||||
the 'timeformat' arg defaults to SECONDS but can also be MILLISECONDS
|
||||
if you want to pass time as milliseconds.
|
||||
timeformat: A ba.TimeFormat value determining how the passed time is
|
||||
interpreted.
|
||||
|
||||
# Example: use a Timer object to print repeatedly for a few seconds:
|
||||
def say_it():
|
||||
@ -1035,9 +1018,9 @@ class Timer:
|
||||
def stop_saying_it():
|
||||
self.t = None
|
||||
ba.screenmessage('MUSHROOM MUSHROOM!')
|
||||
# create our timer; it will run as long as we hold self.t
|
||||
# Create our timer; it will run as long as we have the self.t ref.
|
||||
self.t = ba.Timer(0.3, say_it, repeat=True)
|
||||
# now fire off a one-shot timer to kill it
|
||||
# Now fire off a one-shot timer to kill it.
|
||||
ba.timer(3.89, stop_saying_it)
|
||||
"""
|
||||
|
||||
@ -1579,6 +1562,58 @@ def client_info_query_response(token: str, response: Any) -> None:
|
||||
return None
|
||||
|
||||
|
||||
def clipboard_get_text() -> str:
|
||||
"""clipboard_get_text() -> str
|
||||
|
||||
Return text currently on the system clipboard.
|
||||
|
||||
Category: General Utility Functions
|
||||
|
||||
Ensure that ba.clipboard_has_text() returns True before calling
|
||||
this function.
|
||||
"""
|
||||
return str()
|
||||
|
||||
|
||||
def clipboard_has_text() -> bool:
|
||||
"""clipboard_has_text() -> bool
|
||||
|
||||
Return whether there is currently text on the clipboard.
|
||||
|
||||
Category: General Utility Functions
|
||||
|
||||
This will return False if no system clipboard is available; no need
|
||||
to call ba.clipboard_available() separately.
|
||||
"""
|
||||
return bool()
|
||||
|
||||
|
||||
def clipboard_is_supported() -> bool:
|
||||
"""clipboard_is_supported() -> bool
|
||||
|
||||
Return whether this platform supports clipboard operations at all.
|
||||
|
||||
Category: General Utility Functions
|
||||
|
||||
If this returns False, UIs should not show 'copy to clipboard'
|
||||
buttons, etc.
|
||||
"""
|
||||
return bool()
|
||||
|
||||
|
||||
def clipboard_set_text(value: str) -> None:
|
||||
"""clipboard_set_text(value: str) -> None
|
||||
|
||||
Copy a string to the system clipboard.
|
||||
|
||||
Category: General Utility Functions
|
||||
|
||||
Ensure that ba.clipboard_available() returns True before adding
|
||||
buttons/etc. that make use of this functionality.
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
def columnwidget(edit: ba.Widget = None,
|
||||
parent: ba.Widget = None,
|
||||
size: Sequence[float] = None,
|
||||
@ -3293,24 +3328,24 @@ def restore_purchases() -> None:
|
||||
return None
|
||||
|
||||
|
||||
def rowwidget(edit: Widget = None,
|
||||
parent: Widget = None,
|
||||
def rowwidget(edit: ba.Widget = None,
|
||||
parent: ba.Widget = None,
|
||||
size: Sequence[float] = None,
|
||||
position: Sequence[float] = None,
|
||||
background: bool = None,
|
||||
selected_child: Widget = None,
|
||||
visible_child: Widget = None,
|
||||
selected_child: ba.Widget = None,
|
||||
visible_child: ba.Widget = None,
|
||||
claims_left_right: bool = None,
|
||||
claims_tab: bool = None,
|
||||
selection_loops_to_parent: bool = None) -> Widget:
|
||||
"""rowwidget(edit: Widget = None, parent: Widget = None,
|
||||
selection_loops_to_parent: bool = None) -> ba.Widget:
|
||||
"""rowwidget(edit: ba.Widget = None, parent: ba.Widget = None,
|
||||
size: Sequence[float] = None,
|
||||
position: Sequence[float] = None,
|
||||
background: bool = None, selected_child: Widget = None,
|
||||
visible_child: Widget = None,
|
||||
background: bool = None, selected_child: ba.Widget = None,
|
||||
visible_child: ba.Widget = None,
|
||||
claims_left_right: bool = None,
|
||||
claims_tab: bool = None,
|
||||
selection_loops_to_parent: bool = None) -> Widget
|
||||
selection_loops_to_parent: bool = None) -> ba.Widget
|
||||
|
||||
Create or edit a row widget.
|
||||
|
||||
@ -3320,7 +3355,8 @@ def rowwidget(edit: Widget = None,
|
||||
a new one is created and returned. Arguments that are not set to None
|
||||
are applied to the Widget.
|
||||
"""
|
||||
return Widget()
|
||||
import ba # pylint: disable=cyclic-import
|
||||
return ba.Widget()
|
||||
|
||||
|
||||
def run_transactions() -> None:
|
||||
@ -3775,8 +3811,8 @@ def submit_score(game: str,
|
||||
return None
|
||||
|
||||
|
||||
def textwidget(edit: Widget = None,
|
||||
parent: Widget = None,
|
||||
def textwidget(edit: ba.Widget = None,
|
||||
parent: ba.Widget = None,
|
||||
size: Sequence[float] = None,
|
||||
position: Sequence[float] = None,
|
||||
text: Union[str, ba.Lstr] = None,
|
||||
@ -3787,13 +3823,13 @@ def textwidget(edit: Widget = None,
|
||||
on_return_press_call: Callable[[], None] = None,
|
||||
on_activate_call: Callable[[], None] = None,
|
||||
selectable: bool = None,
|
||||
query: Widget = None,
|
||||
query: ba.Widget = None,
|
||||
max_chars: int = None,
|
||||
color: Sequence[float] = None,
|
||||
click_activate: bool = None,
|
||||
on_select_call: Callable[[], None] = None,
|
||||
always_highlight: bool = None,
|
||||
draw_controller: Widget = None,
|
||||
draw_controller: ba.Widget = None,
|
||||
scale: float = None,
|
||||
corner_scale: float = None,
|
||||
description: Union[str, ba.Lstr] = None,
|
||||
@ -3810,16 +3846,16 @@ def textwidget(edit: Widget = None,
|
||||
big: bool = None,
|
||||
extra_touch_border_scale: float = None,
|
||||
res_scale: float = None) -> Widget:
|
||||
"""textwidget(edit: Widget = None, parent: Widget = None,
|
||||
"""textwidget(edit: ba.Widget = None, parent: ba.Widget = None,
|
||||
size: Sequence[float] = None, position: Sequence[float] = None,
|
||||
text: Union[str, ba.Lstr] = None, v_align: str = None,
|
||||
h_align: str = None, editable: bool = None, padding: float = None,
|
||||
on_return_press_call: Callable[[], None] = None,
|
||||
on_activate_call: Callable[[], None] = None,
|
||||
selectable: bool = None, query: Widget = None, max_chars: int = None,
|
||||
selectable: bool = None, query: ba.Widget = None, max_chars: int = None,
|
||||
color: Sequence[float] = None, click_activate: bool = None,
|
||||
on_select_call: Callable[[], None] = None,
|
||||
always_highlight: bool = None, draw_controller: Widget = None,
|
||||
always_highlight: bool = None, draw_controller: ba.Widget = None,
|
||||
scale: float = None, corner_scale: float = None,
|
||||
description: Union[str, ba.Lstr] = None,
|
||||
transition_delay: float = None, maxwidth: float = None,
|
||||
|
||||
@ -9,16 +9,16 @@ In some specific cases you may need to pull in individual submodules instead.
|
||||
# pylint: disable=unused-import
|
||||
# pylint: disable=redefined-builtin
|
||||
|
||||
from _ba import (CollideModel, Context, ContextCall, Data, InputDevice,
|
||||
Material, Model, Node, SessionPlayer, Sound, Texture, Timer,
|
||||
Vec3, Widget, buttonwidget, camerashake, checkboxwidget,
|
||||
columnwidget, containerwidget, do_once, emitfx, getactivity,
|
||||
getcollidemodel, getmodel, getnodes, getsession, getsound,
|
||||
gettexture, hscrollwidget, imagewidget, log, newactivity,
|
||||
newnode, playsound, printnodes, printobjects, pushcall, quit,
|
||||
rowwidget, safecolor, screenmessage, scrollwidget,
|
||||
set_analytics_screen, charstr, textwidget, time, timer,
|
||||
open_url, widget)
|
||||
from _ba import (
|
||||
CollideModel, Context, ContextCall, Data, InputDevice, Material, Model,
|
||||
Node, SessionPlayer, Sound, Texture, Timer, Vec3, Widget, buttonwidget,
|
||||
camerashake, checkboxwidget, columnwidget, containerwidget, do_once,
|
||||
emitfx, getactivity, getcollidemodel, getmodel, getnodes, getsession,
|
||||
getsound, gettexture, hscrollwidget, imagewidget, log, newactivity,
|
||||
newnode, playsound, printnodes, printobjects, pushcall, quit, rowwidget,
|
||||
safecolor, screenmessage, scrollwidget, set_analytics_screen, charstr,
|
||||
textwidget, time, timer, open_url, widget, clipboard_is_supported,
|
||||
clipboard_has_text, clipboard_get_text, clipboard_set_text)
|
||||
from ba._activity import Activity
|
||||
from ba._plugin import PotentialPlugin, Plugin, PluginSubsystem
|
||||
from ba._actor import Actor
|
||||
|
||||
@ -192,7 +192,7 @@ class Actor:
|
||||
"""Return the ba.Activity this Actor is associated with.
|
||||
|
||||
If the Activity no longer exists, raises a ba.ActivityNotFoundError
|
||||
or returns None depending on whether 'doraise' is set.
|
||||
or returns None depending on whether 'doraise' is True.
|
||||
"""
|
||||
activity = self._activity()
|
||||
if activity is None and doraise:
|
||||
|
||||
@ -24,7 +24,7 @@ class AppConfig(dict):
|
||||
|
||||
AppConfig data is stored as json on disk on so make sure to only place
|
||||
json-friendly values in it (dict, list, str, float, int, bool).
|
||||
Be aware that tuples will be quietly converted to lists.
|
||||
Be aware that tuples will be quietly converted to lists when stored.
|
||||
"""
|
||||
|
||||
def resolve(self, key: str) -> Any:
|
||||
|
||||
@ -38,16 +38,18 @@ T = TypeVar('T')
|
||||
|
||||
|
||||
def existing(obj: Optional[ExistableType]) -> Optional[ExistableType]:
|
||||
"""Convert invalid references to None for any ba.Existable type.
|
||||
"""Convert invalid references to None for any ba.Existable object.
|
||||
|
||||
Category: Gameplay Functions
|
||||
|
||||
To best support type checking, it is important that invalid references
|
||||
not be passed around and instead get converted to values of None.
|
||||
That way the type checker can properly flag attempts to pass dead
|
||||
objects into functions expecting only live ones, etc.
|
||||
This call can be used on any 'existable' object (one with an exists()
|
||||
method) and will convert it to a None value if it does not exist.
|
||||
objects (Optional[FooType]) into functions expecting only live ones
|
||||
(FooType), etc. This call can be used on any 'existable' object
|
||||
(one with an exists() method) and will convert it to a None value
|
||||
if it does not exist.
|
||||
|
||||
For more info, see notes on 'existables' here:
|
||||
https://ballistica.net/wiki/Coding-Style-Guide
|
||||
"""
|
||||
@ -358,15 +360,17 @@ def _verify_object_death(wref: ReferenceType) -> None:
|
||||
|
||||
|
||||
def storagename(suffix: str = None) -> str:
|
||||
"""Generate a (hopefully) unique name for storing things in public places.
|
||||
"""Generate a unique name for storing class data in shared places.
|
||||
|
||||
Category: General Utility Functions
|
||||
|
||||
This consists of a leading underscore, the module path at the
|
||||
call site with dots replaced by underscores, the class name, and
|
||||
the provided suffix. When storing data in public places such as
|
||||
'customdata' dicts, this minimizes the chance of collisions if a
|
||||
module or class is duplicated or renamed.
|
||||
call site with dots replaced by underscores, the containing class's
|
||||
qualified name, and the provided suffix. When storing data in public
|
||||
places such as 'customdata' dicts, this minimizes the chance of
|
||||
collisions with other similarly named classes.
|
||||
|
||||
Note that this will function even if called in the class definition.
|
||||
|
||||
# Example: generate a unique name for storage purposes:
|
||||
class MyThingie:
|
||||
@ -374,14 +378,21 @@ def storagename(suffix: str = None) -> str:
|
||||
# This will give something like '_mymodule_submodule_mythingie_data'.
|
||||
_STORENAME = ba.storagename('data')
|
||||
|
||||
# Use that name to store some data in the Activity we were passed.
|
||||
def __init__(self, activity):
|
||||
# Store some data in the Activity we were passed
|
||||
activity.customdata[self._STORENAME] = {}
|
||||
"""
|
||||
frame = inspect.currentframe()
|
||||
if frame is None:
|
||||
raise RuntimeError('Cannot get current stack frame.')
|
||||
fback = frame.f_back
|
||||
|
||||
# Note: We need to explicitly clear frame here to avoid a ref-loop
|
||||
# that keeps all function-dicts in the stack alive until the next
|
||||
# full GC cycle (the stack frame refers to this function's dict,
|
||||
# which refers to the stack frame).
|
||||
del frame
|
||||
|
||||
if fback is None:
|
||||
raise RuntimeError('Cannot get parent stack frame.')
|
||||
modulepath = fback.f_globals.get('__name__')
|
||||
|
||||
@ -12,6 +12,7 @@ import _ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any, Optional, Dict, Union, Type
|
||||
import ba
|
||||
|
||||
|
||||
class MusicType(Enum):
|
||||
@ -469,8 +470,9 @@ class MusicPlayer:
|
||||
self._actually_playing = False
|
||||
|
||||
|
||||
def setmusic(musictype: Optional[MusicType], continuous: bool = False) -> None:
|
||||
"""Tell the game to play (or stop playing) a certain type of music.
|
||||
def setmusic(musictype: Optional[ba.MusicType],
|
||||
continuous: bool = False) -> None:
|
||||
"""Set the app to play (or stop playing) a certain type of music.
|
||||
|
||||
category: Gameplay Functions
|
||||
|
||||
|
||||
@ -284,8 +284,8 @@ class EmptyPlayer(Player['ba.EmptyTeam']):
|
||||
|
||||
Category: Gameplay Classes
|
||||
|
||||
ba.Player and ba.Team are 'Generic' types, and so passing them as
|
||||
type arguments when defining a ba.Activity reduces type safety.
|
||||
ba.Player and ba.Team are 'Generic' types, and so passing those top level
|
||||
classes as type arguments when defining a ba.Activity reduces type safety.
|
||||
For example, activity.teams[0].player will have type 'Any' in that case.
|
||||
For that reason, it is better to pass EmptyPlayer and EmptyTeam when
|
||||
defining a ba.Activity that does not need custom types of its own.
|
||||
|
||||
@ -17,7 +17,7 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class Session:
|
||||
"""Defines a high level series of activities with a common purpose.
|
||||
"""Defines a high level series of ba.Activities with a common purpose.
|
||||
|
||||
category: Gameplay Classes
|
||||
|
||||
|
||||
@ -200,8 +200,8 @@ class EmptyTeam(Team['ba.EmptyPlayer']):
|
||||
|
||||
Category: Gameplay Classes
|
||||
|
||||
ba.Player and ba.Team are 'Generic' types, and so passing them as
|
||||
type arguments when defining a ba.Activity reduces type safety.
|
||||
ba.Player and ba.Team are 'Generic' types, and so passing those top level
|
||||
classes as type arguments when defining a ba.Activity reduces type safety.
|
||||
For example, activity.teams[0].player will have type 'Any' in that case.
|
||||
For that reason, it is better to pass EmptyPlayer and EmptyTeam when
|
||||
defining a ba.Activity that does not need custom types of its own.
|
||||
|
||||
@ -10,7 +10,7 @@ import _ba
|
||||
from ba._enums import UIScale
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Optional, Dict, Any, Callable, List
|
||||
from typing import Optional, Dict, Any, Callable, List, Type
|
||||
from ba.ui import UICleanupCheck
|
||||
import ba
|
||||
|
||||
@ -43,7 +43,7 @@ class UISubsystem:
|
||||
else:
|
||||
raise RuntimeError(f'Invalid UIScale value: {interfacetype}')
|
||||
|
||||
self.window_states: Dict = {} # FIXME: Kill this.
|
||||
self.window_states: Dict[Type, Any] = {} # FIXME: Kill this.
|
||||
self.main_menu_selection: Optional[str] = None # FIXME: Kill this.
|
||||
self.have_party_queue_window = False
|
||||
self.quit_window: Any = None
|
||||
@ -76,7 +76,7 @@ class UISubsystem:
|
||||
# this holds true at all aspect ratios.
|
||||
|
||||
# UPDATE: A better way to test this is now by setting the environment
|
||||
# variable BA_FORCE_UI_SCALE to "small", "medium", or "large".
|
||||
# variable BA_UI_SCALE to "small", "medium", or "large".
|
||||
# This will affect system UIs not covered by the values below such
|
||||
# as screen-messages. The below values remain functional, however,
|
||||
# for cases such as Android where environment variables can't be set
|
||||
|
||||
@ -118,7 +118,7 @@ class UIEntry:
|
||||
|
||||
|
||||
class UIController:
|
||||
"""Wrangles UILocations.
|
||||
"""Wrangles ba.UILocations.
|
||||
|
||||
Category: User Interface Classes
|
||||
"""
|
||||
|
||||
@ -1088,13 +1088,13 @@ class AccountSettingsWindow(ba.Window):
|
||||
sel_name = 'Scroll'
|
||||
else:
|
||||
raise ValueError('unrecognized selection')
|
||||
ba.app.ui.window_states[self.__class__.__name__] = sel_name
|
||||
ba.app.ui.window_states[type(self)] = sel_name
|
||||
except Exception:
|
||||
ba.print_exception(f'Error saving state for {self}.')
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
try:
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__)
|
||||
sel_name = ba.app.ui.window_states.get(type(self))
|
||||
if sel_name == 'Back':
|
||||
sel = self._back_button
|
||||
elif sel_name == 'Scroll':
|
||||
|
||||
@ -1542,7 +1542,7 @@ class CoopBrowserWindow(ba.Window):
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
try:
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__,
|
||||
sel_name = ba.app.ui.window_states.get(type(self),
|
||||
{}).get('sel_name')
|
||||
if sel_name == 'Back':
|
||||
sel = self._back_button
|
||||
@ -1572,9 +1572,7 @@ class CoopBrowserWindow(ba.Window):
|
||||
sel_name = 'Scroll'
|
||||
else:
|
||||
raise ValueError('unrecognized selection')
|
||||
ba.app.ui.window_states[self.__class__.__name__] = {
|
||||
'sel_name': sel_name
|
||||
}
|
||||
ba.app.ui.window_states[type(self)] = {'sel_name': sel_name}
|
||||
except Exception:
|
||||
ba.print_exception(f'Error saving state for {self}.')
|
||||
|
||||
|
||||
@ -4,22 +4,56 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import weakref
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
from bastd.ui.gather.abouttab import AboutGatherTab
|
||||
from bastd.ui.gather.manualtab import ManualGatherTab
|
||||
from bastd.ui.gather.googleplaytab import GooglePlayGatherTab
|
||||
from bastd.ui.gather.publictab import PublicGatherTab
|
||||
from bastd.ui.gather.nearbytab import NearbyGatherTab
|
||||
from bastd.ui.tabs import TabRow
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import (Any, Optional, Tuple, Dict, List, Union, Callable,
|
||||
Type)
|
||||
from bastd.ui.gather.bases import GatherTab
|
||||
|
||||
|
||||
class GatherTab:
|
||||
"""Defines a tab for use in the gather UI."""
|
||||
|
||||
def __init__(self, window: GatherWindow) -> None:
|
||||
self._window = weakref.ref(window)
|
||||
|
||||
@property
|
||||
def window(self) -> GatherWindow:
|
||||
"""The GatherWindow that this tab belongs to."""
|
||||
window = self._window()
|
||||
if window is None:
|
||||
raise ba.NotFoundError("GatherTab's window no longer exists.")
|
||||
return window
|
||||
|
||||
def on_activate(
|
||||
self,
|
||||
parent_widget: ba.Widget,
|
||||
tab_button: ba.Widget,
|
||||
region_width: float,
|
||||
region_height: float,
|
||||
region_left: float,
|
||||
region_bottom: float,
|
||||
) -> ba.Widget:
|
||||
"""Called when the tab becomes the active one.
|
||||
|
||||
The tab should create and return a container widget covering the
|
||||
specified region.
|
||||
"""
|
||||
|
||||
def on_deactivate(self) -> None:
|
||||
"""Called when the tab will no longer be the active one."""
|
||||
|
||||
def save_state(self) -> None:
|
||||
"""Called when the parent window is saving state."""
|
||||
|
||||
def restore_state(self) -> None:
|
||||
"""Called when the parent window is restoring state."""
|
||||
|
||||
|
||||
class GatherWindow(ba.Window):
|
||||
@ -29,8 +63,8 @@ class GatherWindow(ba.Window):
|
||||
"""Our available tab types."""
|
||||
ABOUT = 'about'
|
||||
INTERNET = 'internet'
|
||||
GOOGLE_PLAY = 'google_play'
|
||||
LOCAL_NETWORK = 'local_network'
|
||||
PRIVATE = 'private'
|
||||
NEARBY = 'nearby'
|
||||
MANUAL = 'manual'
|
||||
|
||||
def __init__(self,
|
||||
@ -38,6 +72,13 @@ class GatherWindow(ba.Window):
|
||||
origin_widget: ba.Widget = None):
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.gather.abouttab import AboutGatherTab
|
||||
from bastd.ui.gather.manualtab import ManualGatherTab
|
||||
from bastd.ui.gather.privatetab import PrivateGatherTab
|
||||
from bastd.ui.gather.publictab import PublicGatherTab
|
||||
from bastd.ui.gather.nearbytab import NearbyGatherTab
|
||||
|
||||
ba.set_analytics_screen('Gather Window')
|
||||
scale_origin: Optional[Tuple[float, float]]
|
||||
if origin_widget is not None:
|
||||
@ -104,9 +145,6 @@ class GatherWindow(ba.Window):
|
||||
text=ba.Lstr(resource=self._r + '.titleText'),
|
||||
maxwidth=550)
|
||||
|
||||
platform = ba.app.platform
|
||||
subplatform = ba.app.subplatform
|
||||
|
||||
scroll_buffer_h = 130 + 2 * x_offs
|
||||
tab_buffer_h = ((320 if condensed else 250) + 2 * x_offs)
|
||||
|
||||
@ -117,11 +155,10 @@ class GatherWindow(ba.Window):
|
||||
if _ba.get_account_misc_read_val('enablePublicParties', True):
|
||||
tabdefs.append((self.TabID.INTERNET,
|
||||
ba.Lstr(resource=self._r + '.publicText')))
|
||||
if platform == 'android' and subplatform == 'google':
|
||||
tabdefs.append((self.TabID.GOOGLE_PLAY,
|
||||
ba.Lstr(resource=self._r + '.googlePlayText')))
|
||||
tabdefs.append((self.TabID.LOCAL_NETWORK,
|
||||
ba.Lstr(resource=self._r + '.nearbyText')))
|
||||
tabdefs.append(
|
||||
(self.TabID.PRIVATE, ba.Lstr(resource=self._r + '.privateText')))
|
||||
tabdefs.append(
|
||||
(self.TabID.NEARBY, ba.Lstr(resource=self._r + '.nearbyText')))
|
||||
tabdefs.append(
|
||||
(self.TabID.MANUAL, ba.Lstr(resource=self._r + '.manualText')))
|
||||
|
||||
@ -139,9 +176,9 @@ class GatherWindow(ba.Window):
|
||||
tabtypes: Dict[GatherWindow.TabID, Type[GatherTab]] = {
|
||||
self.TabID.ABOUT: AboutGatherTab,
|
||||
self.TabID.MANUAL: ManualGatherTab,
|
||||
self.TabID.GOOGLE_PLAY: GooglePlayGatherTab,
|
||||
self.TabID.PRIVATE: PrivateGatherTab,
|
||||
self.TabID.INTERNET: PublicGatherTab,
|
||||
self.TabID.LOCAL_NETWORK: NearbyGatherTab
|
||||
self.TabID.NEARBY: NearbyGatherTab
|
||||
}
|
||||
self._tabs: Dict[GatherWindow.TabID, GatherTab] = {}
|
||||
for tab_id in self._tab_row.tabs:
|
||||
@ -234,7 +271,7 @@ class GatherWindow(ba.Window):
|
||||
sel_name = 'TabContainer'
|
||||
else:
|
||||
raise ValueError(f'unrecognized selection: \'{sel}\'')
|
||||
ba.app.ui.window_states[self.__class__.__name__] = {
|
||||
ba.app.ui.window_states[type(self)] = {
|
||||
'sel_name': sel_name,
|
||||
}
|
||||
except Exception:
|
||||
@ -247,7 +284,7 @@ class GatherWindow(ba.Window):
|
||||
tab.restore_state()
|
||||
|
||||
sel: Optional[ba.Widget]
|
||||
winstate = ba.app.ui.window_states.get(self.__class__.__name__, {})
|
||||
winstate = ba.app.ui.window_states.get(type(self), {})
|
||||
sel_name = winstate.get('sel_name', None)
|
||||
assert isinstance(sel_name, (str, type(None)))
|
||||
current_tab = self.TabID.ABOUT
|
||||
|
||||
@ -8,7 +8,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
import _ba
|
||||
from bastd.ui.gather.bases import GatherTab
|
||||
from bastd.ui.gather import GatherTab
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Optional
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Provides UI for inviting/joining friends."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import weakref
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bastd.ui.gather import GatherWindow
|
||||
|
||||
|
||||
class GatherTab:
|
||||
"""Defines a tab for use in the gather UI."""
|
||||
|
||||
def __init__(self, window: GatherWindow) -> None:
|
||||
self._window = weakref.ref(window)
|
||||
|
||||
@property
|
||||
def window(self) -> GatherWindow:
|
||||
"""The GatherWindow that this tab belongs to."""
|
||||
window = self._window()
|
||||
if window is None:
|
||||
raise ba.NotFoundError("GatherTab's window no longer exists.")
|
||||
return window
|
||||
|
||||
def on_activate(
|
||||
self,
|
||||
parent_widget: ba.Widget,
|
||||
tab_button: ba.Widget,
|
||||
region_width: float,
|
||||
region_height: float,
|
||||
region_left: float,
|
||||
region_bottom: float,
|
||||
) -> ba.Widget:
|
||||
"""Called when the tab becomes the active one.
|
||||
|
||||
The tab should create and return a container widget covering the
|
||||
specified region.
|
||||
"""
|
||||
|
||||
def on_deactivate(self) -> None:
|
||||
"""Called when the tab will no longer be the active one."""
|
||||
|
||||
def save_state(self) -> None:
|
||||
"""Called when the parent window is saving state."""
|
||||
|
||||
def restore_state(self) -> None:
|
||||
"""Called when the parent window is restoring state."""
|
||||
@ -1,86 +0,0 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Defines the Google Play tab in the gather UI."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
from bastd.ui.gather.bases import GatherTab
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Optional
|
||||
from bastd.ui.gather import GatherWindow
|
||||
|
||||
|
||||
class GooglePlayGatherTab(GatherTab):
|
||||
"""The public tab in the gather UI"""
|
||||
|
||||
def __init__(self, window: GatherWindow) -> None:
|
||||
super().__init__(window)
|
||||
self._container: Optional[ba.Widget] = None
|
||||
|
||||
def on_activate(
|
||||
self,
|
||||
parent_widget: ba.Widget,
|
||||
tab_button: ba.Widget,
|
||||
region_width: float,
|
||||
region_height: float,
|
||||
region_left: float,
|
||||
region_bottom: float,
|
||||
) -> ba.Widget:
|
||||
c_width = region_width
|
||||
c_height = 380.0
|
||||
self._container = ba.containerwidget(
|
||||
parent=parent_widget,
|
||||
position=(region_left,
|
||||
region_bottom + (region_height - c_height) * 0.5),
|
||||
size=(c_width, c_height),
|
||||
background=False,
|
||||
selection_loops_to_parent=True)
|
||||
v = c_height - 30.0
|
||||
ba.textwidget(
|
||||
parent=self._container,
|
||||
position=(c_width * 0.5, v - 140.0),
|
||||
color=(0.6, 1.0, 0.6),
|
||||
scale=1.3,
|
||||
size=(0.0, 0.0),
|
||||
maxwidth=c_width * 0.9,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
text=ba.Lstr(resource='googleMultiplayerDiscontinuedText'))
|
||||
return self._container
|
||||
|
||||
def _on_google_play_show_invites_press(self) -> None:
|
||||
from bastd.ui import account
|
||||
if (_ba.get_account_state() != 'signed_in'
|
||||
or _ba.get_account_type() != 'Google Play'):
|
||||
account.show_sign_in_prompt('Google Play')
|
||||
else:
|
||||
_ba.show_invites_ui()
|
||||
|
||||
def _on_google_play_invite_press(self) -> None:
|
||||
from bastd.ui.confirm import ConfirmWindow
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
if (_ba.get_account_state() != 'signed_in'
|
||||
or _ba.get_account_type() != 'Google Play'):
|
||||
show_sign_in_prompt('Google Play')
|
||||
else:
|
||||
# If there's google play people connected to us, inform the user
|
||||
# that they will get disconnected. Otherwise just go ahead.
|
||||
google_player_count = (_ba.get_google_play_party_client_count())
|
||||
if google_player_count > 0:
|
||||
ConfirmWindow(
|
||||
ba.Lstr(resource='gatherWindow.'
|
||||
'googlePlayReInviteText',
|
||||
subs=[('${COUNT}', str(google_player_count))]),
|
||||
lambda: ba.timer(
|
||||
0.2, _ba.invite_players, timetype=ba.TimeType.REAL),
|
||||
width=500,
|
||||
height=150,
|
||||
ok_text=ba.Lstr(resource='gatherWindow.'
|
||||
'googlePlayInviteText'))
|
||||
else:
|
||||
ba.timer(0.1, _ba.invite_players, timetype=ba.TimeType.REAL)
|
||||
@ -9,7 +9,7 @@ from typing import TYPE_CHECKING, cast
|
||||
|
||||
from enum import Enum
|
||||
from dataclasses import dataclass
|
||||
from bastd.ui.gather.bases import GatherTab
|
||||
from bastd.ui.gather import GatherTab
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
@ -161,11 +161,10 @@ class ManualGatherTab(GatherTab):
|
||||
return self._container
|
||||
|
||||
def save_state(self) -> None:
|
||||
ba.app.ui.window_states[self.__class__.__name__] = State(
|
||||
sub_tab=self._sub_tab)
|
||||
ba.app.ui.window_states[type(self)] = State(sub_tab=self._sub_tab)
|
||||
|
||||
def restore_state(self) -> None:
|
||||
state = ba.app.ui.window_states.get(self.__class__.__name__)
|
||||
state = ba.app.ui.window_states.get(type(self))
|
||||
if state is None:
|
||||
state = State()
|
||||
assert isinstance(state, State)
|
||||
|
||||
@ -9,7 +9,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
import _ba
|
||||
from bastd.ui.gather.bases import GatherTab
|
||||
from bastd.ui.gather import GatherTab
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
755
assets/src/ba_data/python/bastd/ui/gather/privatetab.py
Normal file
755
assets/src/ba_data/python/bastd/ui/gather/privatetab.py
Normal file
@ -0,0 +1,755 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Defines the Private tab in the gather UI."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import copy
|
||||
import time
|
||||
from enum import Enum
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
import ba
|
||||
import _ba
|
||||
from efro.dataclasses import dataclass_from_dict
|
||||
from bastd.ui.gather import GatherTab
|
||||
from bastd.ui import getcurrency
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Optional, Dict, Any, List
|
||||
from bastd.ui.gather import GatherWindow
|
||||
|
||||
# Print a bit of info about queries, etc.
|
||||
DEBUG_SERVER_COMMUNICATION = os.environ.get('BA_DEBUG_PPTABCOM') == '1'
|
||||
|
||||
|
||||
class SubTabType(Enum):
|
||||
"""Available sub-tabs."""
|
||||
JOIN = 'join'
|
||||
HOST = 'host'
|
||||
|
||||
|
||||
@dataclass
|
||||
class State:
|
||||
"""Our core state that persists while the app is running."""
|
||||
sub_tab: SubTabType = SubTabType.JOIN
|
||||
|
||||
|
||||
@dataclass
|
||||
class ConnectResult:
|
||||
"""Info about a server we get back when connecting."""
|
||||
error: Optional[str] = None
|
||||
addr: Optional[str] = None
|
||||
port: Optional[int] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class HostingState:
|
||||
"""Our combined state of whether we're hosting, whether we can, etc."""
|
||||
unavailable_error: Optional[str] = None
|
||||
party_code: Optional[str] = None
|
||||
able_to_host: bool = False
|
||||
tickets_to_host_now: int = 0
|
||||
minutes_until_free_host: Optional[float] = None
|
||||
free_host_minutes_remaining: Optional[float] = None
|
||||
|
||||
|
||||
class PrivateGatherTab(GatherTab):
|
||||
"""The private tab in the gather UI"""
|
||||
|
||||
def __init__(self, window: GatherWindow) -> None:
|
||||
super().__init__(window)
|
||||
self._container: Optional[ba.Widget] = None
|
||||
self._state: State = State()
|
||||
self._hostingstate = HostingState()
|
||||
self._join_sub_tab_text: Optional[ba.Widget] = None
|
||||
self._host_sub_tab_text: Optional[ba.Widget] = None
|
||||
self._update_timer: Optional[ba.Timer] = None
|
||||
self._join_party_code_text: Optional[ba.Widget] = None
|
||||
self._c_width: float = 0.0
|
||||
self._c_height: float = 0.0
|
||||
self._last_hosting_state_query_time: Optional[float] = None
|
||||
self._initial_waiting_for_hosting_state = True
|
||||
self._waiting_for_hosting_state = True
|
||||
self._host_playlist_button: Optional[ba.Widget] = None
|
||||
self._host_copy_button: Optional[ba.Widget] = None
|
||||
self._host_connect_button: Optional[ba.Widget] = None
|
||||
self._host_start_stop_button: Optional[ba.Widget] = None
|
||||
self._get_tickets_button: Optional[ba.Widget] = None
|
||||
self._ticket_count_text: Optional[ba.Widget] = None
|
||||
self._showing_not_signed_in_screen = False
|
||||
self._create_time = time.time()
|
||||
self._last_action_send_time: Optional[float] = None
|
||||
|
||||
def on_activate(
|
||||
self,
|
||||
parent_widget: ba.Widget,
|
||||
tab_button: ba.Widget,
|
||||
region_width: float,
|
||||
region_height: float,
|
||||
region_left: float,
|
||||
region_bottom: float,
|
||||
) -> ba.Widget:
|
||||
self._c_width = region_width
|
||||
self._c_height = region_height - 20
|
||||
self._container = ba.containerwidget(
|
||||
parent=parent_widget,
|
||||
position=(region_left,
|
||||
region_bottom + (region_height - self._c_height) * 0.5),
|
||||
size=(self._c_width, self._c_height),
|
||||
background=False,
|
||||
selection_loops_to_parent=True)
|
||||
v = self._c_height - 30.0
|
||||
self._join_sub_tab_text = ba.textwidget(
|
||||
parent=self._container,
|
||||
position=(self._c_width * 0.5 - 245, v - 13),
|
||||
color=(0.6, 1.0, 0.6),
|
||||
scale=1.3,
|
||||
size=(200, 30),
|
||||
maxwidth=250,
|
||||
h_align='left',
|
||||
v_align='center',
|
||||
click_activate=True,
|
||||
selectable=True,
|
||||
autoselect=True,
|
||||
on_activate_call=lambda: self._set_sub_tab(
|
||||
SubTabType.JOIN,
|
||||
playsound=True,
|
||||
),
|
||||
text=ba.Lstr(resource='gatherWindow.privatePartyJoinText'))
|
||||
self._host_sub_tab_text = ba.textwidget(
|
||||
parent=self._container,
|
||||
position=(self._c_width * 0.5 + 45, v - 13),
|
||||
color=(0.6, 1.0, 0.6),
|
||||
scale=1.3,
|
||||
size=(200, 30),
|
||||
maxwidth=250,
|
||||
h_align='left',
|
||||
v_align='center',
|
||||
click_activate=True,
|
||||
selectable=True,
|
||||
autoselect=True,
|
||||
on_activate_call=lambda: self._set_sub_tab(
|
||||
SubTabType.HOST,
|
||||
playsound=True,
|
||||
),
|
||||
text=ba.Lstr(resource='gatherWindow.privatePartyHostText'))
|
||||
ba.widget(edit=self._join_sub_tab_text, up_widget=tab_button)
|
||||
ba.widget(edit=self._host_sub_tab_text,
|
||||
left_widget=self._join_sub_tab_text,
|
||||
up_widget=tab_button)
|
||||
ba.widget(edit=self._join_sub_tab_text,
|
||||
right_widget=self._host_sub_tab_text)
|
||||
|
||||
self._update_timer = ba.Timer(1.0,
|
||||
ba.WeakCall(self._update),
|
||||
repeat=True,
|
||||
timetype=ba.TimeType.REAL)
|
||||
|
||||
# Get a new state query kicked off immediately and show nothing
|
||||
# until it is back.
|
||||
self._initial_waiting_for_hosting_state = True
|
||||
self._last_hosting_state_query_time = None
|
||||
self._last_action_send_time = None # So we don't ignore response.
|
||||
self._update()
|
||||
|
||||
self._set_sub_tab(self._state.sub_tab)
|
||||
|
||||
return self._container
|
||||
|
||||
def on_deactivate(self) -> None:
|
||||
self._update_timer = None
|
||||
|
||||
def _update_currency_ui(self) -> None:
|
||||
# Keep currency count up to date if applicable.
|
||||
try:
|
||||
t_str = str(_ba.get_account_ticket_count())
|
||||
except Exception:
|
||||
t_str = '?'
|
||||
if self._get_tickets_button:
|
||||
ba.buttonwidget(edit=self._get_tickets_button,
|
||||
label=ba.charstr(ba.SpecialChar.TICKET) + t_str)
|
||||
if self._ticket_count_text:
|
||||
ba.textwidget(edit=self._ticket_count_text,
|
||||
text=ba.charstr(ba.SpecialChar.TICKET) + t_str)
|
||||
|
||||
def _update(self) -> None:
|
||||
"""Periodic updating."""
|
||||
|
||||
now = ba.time(ba.TimeType.REAL)
|
||||
|
||||
self._update_currency_ui()
|
||||
|
||||
if self._state.sub_tab is SubTabType.HOST:
|
||||
|
||||
# If we're not signed in, just refresh to show that.
|
||||
if (_ba.get_account_state() != 'signed_in'
|
||||
and self._showing_not_signed_in_screen):
|
||||
self._refresh_sub_tab()
|
||||
else:
|
||||
|
||||
# Query an updated state periodically.
|
||||
if (self._last_hosting_state_query_time is None
|
||||
or now - self._last_hosting_state_query_time > 15.0):
|
||||
self._debug_server_comm('querying private party state')
|
||||
if _ba.get_account_state() == 'signed_in':
|
||||
_ba.add_transaction(
|
||||
{'type': 'PRIVATE_PARTY_QUERY'},
|
||||
callback=ba.WeakCall(
|
||||
self._hosting_state_idle_response),
|
||||
)
|
||||
_ba.run_transactions()
|
||||
else:
|
||||
self._hosting_state_idle_response(None)
|
||||
self._last_hosting_state_query_time = now
|
||||
|
||||
def _hosting_state_idle_response(self,
|
||||
result: Optional[Dict[str, Any]]) -> None:
|
||||
|
||||
# This simply passes through to our standard response handler.
|
||||
# The one exception is if we've recently sent an action to the
|
||||
# server (start/stop hosting/etc.) In that case we want to ignore
|
||||
# idle background updates and wait for the response to our action.
|
||||
# (this keeps the button showing 'one moment...' until the change
|
||||
# takes effect, etc.)
|
||||
if (self._last_action_send_time is not None
|
||||
and time.time() - self._last_action_send_time < 5.0):
|
||||
self._debug_server_comm('ignoring private party state response'
|
||||
' due to recent action')
|
||||
return
|
||||
self._hosting_state_response(result)
|
||||
|
||||
def _hosting_state_response(self, result: Optional[Dict[str,
|
||||
Any]]) -> None:
|
||||
state: Optional[HostingState] = None
|
||||
if result is not None:
|
||||
self._debug_server_comm('got private party state response')
|
||||
try:
|
||||
state = dataclass_from_dict(HostingState, result)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
self._debug_server_comm('private party state response errored')
|
||||
|
||||
# Hmm I guess let's just ignore failed responses?...
|
||||
# Or should we show some sort of error state to the user?...
|
||||
if result is None or state is None:
|
||||
return
|
||||
|
||||
self._initial_waiting_for_hosting_state = False
|
||||
self._waiting_for_hosting_state = False
|
||||
self._hostingstate = state
|
||||
self._refresh_sub_tab()
|
||||
|
||||
def _set_sub_tab(self, value: SubTabType, playsound: bool = False) -> None:
|
||||
assert self._container
|
||||
if playsound:
|
||||
ba.playsound(ba.getsound('click01'))
|
||||
|
||||
# If switching from join to host, do a fresh state query.
|
||||
if self._state.sub_tab is SubTabType.JOIN and value is SubTabType.HOST:
|
||||
self._last_hosting_state_query_time = None
|
||||
self._initial_waiting_for_hosting_state = True
|
||||
self._last_action_send_time = None # So we don't ignore response.
|
||||
self._update()
|
||||
|
||||
self._state.sub_tab = value
|
||||
active_color = (0.6, 1.0, 0.6)
|
||||
inactive_color = (0.5, 0.4, 0.5)
|
||||
ba.textwidget(
|
||||
edit=self._join_sub_tab_text,
|
||||
color=active_color if value is SubTabType.JOIN else inactive_color)
|
||||
ba.textwidget(
|
||||
edit=self._host_sub_tab_text,
|
||||
color=active_color if value is SubTabType.HOST else inactive_color)
|
||||
|
||||
self._refresh_sub_tab()
|
||||
|
||||
# Kick off an update to get any needed messages sent/etc.
|
||||
ba.pushcall(self._update)
|
||||
|
||||
def _selwidgets(self) -> List[Optional[ba.Widget]]:
|
||||
"""An indexed list of widgets we can use for saving/restoring sel."""
|
||||
return [
|
||||
self._host_playlist_button, self._host_copy_button,
|
||||
self._host_connect_button, self._host_start_stop_button,
|
||||
self._get_tickets_button
|
||||
]
|
||||
|
||||
def _refresh_sub_tab(self) -> None:
|
||||
assert self._container
|
||||
|
||||
# Store an index for our current selection so we can
|
||||
# reselect the equivalent recreated widget if possible.
|
||||
selindex: Optional[int] = None
|
||||
selchild = self._container.get_selected_child()
|
||||
if selchild is not None:
|
||||
try:
|
||||
selindex = self._selwidgets().index(selchild)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Clear anything existing in the old sub-tab.
|
||||
for widget in self._container.get_children():
|
||||
if widget and widget not in {
|
||||
self._host_sub_tab_text,
|
||||
self._join_sub_tab_text,
|
||||
}:
|
||||
widget.delete()
|
||||
|
||||
if self._state.sub_tab is SubTabType.JOIN:
|
||||
self._build_join_tab()
|
||||
elif self._state.sub_tab is SubTabType.HOST:
|
||||
self._build_host_tab()
|
||||
else:
|
||||
raise RuntimeError('Invalid state.')
|
||||
|
||||
# Select the new equivalent widget if there is one.
|
||||
if selindex is not None:
|
||||
selwidget = self._selwidgets()[selindex]
|
||||
if selwidget:
|
||||
ba.containerwidget(edit=self._container,
|
||||
selected_child=selwidget)
|
||||
|
||||
def _build_join_tab(self) -> None:
|
||||
|
||||
ba.textwidget(parent=self._container,
|
||||
position=(self._c_width * 0.5, self._c_height - 140),
|
||||
color=(0.5, 0.46, 0.5),
|
||||
scale=1.5,
|
||||
size=(0, 0),
|
||||
maxwidth=250,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
text=ba.Lstr(resource='gatherWindow.partyCodeText'))
|
||||
|
||||
self._join_party_code_text = ba.textwidget(
|
||||
parent=self._container,
|
||||
position=(self._c_width * 0.5 - 150, self._c_height - 250),
|
||||
flatness=1.0,
|
||||
scale=1.5,
|
||||
size=(300, 50),
|
||||
editable=True,
|
||||
description=ba.Lstr(resource='gatherWindow.partyCodeText'),
|
||||
autoselect=True,
|
||||
maxwidth=250,
|
||||
h_align='left',
|
||||
v_align='center',
|
||||
text='')
|
||||
btn = ba.buttonwidget(parent=self._container,
|
||||
size=(300, 70),
|
||||
label=ba.Lstr(resource='gatherWindow.'
|
||||
'manualConnectText'),
|
||||
position=(self._c_width * 0.5 - 150,
|
||||
self._c_height - 350),
|
||||
on_activate_call=self._connect_press,
|
||||
autoselect=True)
|
||||
ba.textwidget(edit=self._join_party_code_text,
|
||||
on_return_press_call=btn.activate)
|
||||
|
||||
def _on_get_tickets_press(self) -> None:
|
||||
|
||||
if self._waiting_for_hosting_state:
|
||||
return
|
||||
|
||||
# Bring up get-tickets window and then kill ourself (we're on the
|
||||
# overlay layer so we'd show up above it).
|
||||
getcurrency.GetCurrencyWindow(modal=True,
|
||||
origin_widget=self._get_tickets_button)
|
||||
# self._transition_out()
|
||||
|
||||
def _build_host_tab(self) -> None:
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
|
||||
if _ba.get_account_state() != 'signed_in':
|
||||
ba.textwidget(parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=200,
|
||||
scale=0.8,
|
||||
color=(0.6, 0.56, 0.6),
|
||||
position=(self._c_width * 0.5, self._c_height * 0.5),
|
||||
text=ba.Lstr(resource='notSignedInErrorText'))
|
||||
self._showing_not_signed_in_screen = True
|
||||
return
|
||||
self._showing_not_signed_in_screen = False
|
||||
|
||||
# At first we don't want to show anything until we've gotten a state.
|
||||
if self._initial_waiting_for_hosting_state:
|
||||
ba.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=200,
|
||||
scale=0.8,
|
||||
color=(0.6, 0.56, 0.6),
|
||||
position=(self._c_width * 0.5, self._c_height * 0.5),
|
||||
text=ba.Lstr(
|
||||
value='${A}...',
|
||||
subs=[('${A}', ba.Lstr(resource='store.loadingText'))],
|
||||
),
|
||||
)
|
||||
return
|
||||
|
||||
# If we're not currently hosting and hosting requires tickets,
|
||||
# Show our count (possibly with a link to purchase more).
|
||||
if (self._hostingstate.party_code is None
|
||||
and self._hostingstate.tickets_to_host_now != 0):
|
||||
if not ba.app.ui.use_toolbars:
|
||||
if ba.app.allow_ticket_purchases:
|
||||
self._get_tickets_button = ba.buttonwidget(
|
||||
parent=self._container,
|
||||
position=(self._c_width - 210 + 125,
|
||||
self._c_height - 44),
|
||||
autoselect=True,
|
||||
scale=0.6,
|
||||
size=(120, 60),
|
||||
textcolor=(0.2, 1, 0.2),
|
||||
label=ba.charstr(ba.SpecialChar.TICKET),
|
||||
color=(0.65, 0.5, 0.8),
|
||||
on_activate_call=self._on_get_tickets_press)
|
||||
else:
|
||||
self._ticket_count_text = ba.textwidget(
|
||||
parent=self._container,
|
||||
scale=0.6,
|
||||
position=(self._c_width - 210 + 125,
|
||||
self._c_height - 44),
|
||||
color=(0.2, 1, 0.2),
|
||||
h_align='center',
|
||||
v_align='center')
|
||||
# Set initial ticket count.
|
||||
self._update_currency_ui()
|
||||
|
||||
v = self._c_height - 90
|
||||
if self._hostingstate.party_code is None:
|
||||
ba.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=self._c_width * 0.9,
|
||||
scale=0.7,
|
||||
flatness=1.0,
|
||||
color=(0.5, 0.46, 0.5),
|
||||
position=(self._c_width * 0.5, v),
|
||||
text=ba.Lstr(
|
||||
resource='gatherWindow.privatePartyCloudDescriptionText'))
|
||||
|
||||
v -= 100
|
||||
if self._hostingstate.party_code is None:
|
||||
# We've got no current party running; show options to set one up.
|
||||
ba.textwidget(parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
maxwidth=200,
|
||||
scale=0.8,
|
||||
color=(0.6, 0.56, 0.6),
|
||||
position=(self._c_width * 0.5 - 210, v),
|
||||
text=ba.Lstr(resource='playlistText'))
|
||||
self._host_playlist_button = ba.buttonwidget(
|
||||
parent=self._container,
|
||||
size=(400, 70),
|
||||
color=(0.6, 0.5, 0.6),
|
||||
textcolor=(0.8, 0.75, 0.8),
|
||||
label='Default Free-For-All Playlist',
|
||||
on_activate_call=lambda: ba.screenmessage(
|
||||
'TODO: WIRE UP PLAYLIST SELECTION'),
|
||||
position=(self._c_width * 0.5 - 200, v - 35),
|
||||
up_widget=self._host_sub_tab_text,
|
||||
autoselect=True)
|
||||
else:
|
||||
# We've got a current party; show its info.
|
||||
ba.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=600,
|
||||
scale=0.9,
|
||||
color=(0.7, 0.64, 0.7),
|
||||
position=(self._c_width * 0.5, v + 90),
|
||||
text=ba.Lstr(resource='gatherWindow.partyServerRunningText'))
|
||||
ba.textwidget(parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=600,
|
||||
scale=0.7,
|
||||
color=(0.7, 0.64, 0.7),
|
||||
position=(self._c_width * 0.5, v + 50),
|
||||
text=ba.Lstr(resource='gatherWindow.partyCodeText'))
|
||||
ba.textwidget(parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
scale=2.0,
|
||||
color=(0.0, 1.0, 0.0),
|
||||
position=(self._c_width * 0.5, v + 10),
|
||||
text=self._hostingstate.party_code)
|
||||
|
||||
# Also action buttons to copy it and connect to it.
|
||||
if ba.clipboard_is_supported():
|
||||
cbtnoffs = 10
|
||||
self._host_copy_button = ba.buttonwidget(
|
||||
parent=self._container,
|
||||
size=(140, 40),
|
||||
color=(0.6, 0.5, 0.6),
|
||||
textcolor=(0.8, 0.75, 0.8),
|
||||
label=ba.Lstr(resource='gatherWindow.copyCodeText'),
|
||||
on_activate_call=self._host_copy_press,
|
||||
position=(self._c_width * 0.5 - 150, v - 70),
|
||||
autoselect=True)
|
||||
else:
|
||||
cbtnoffs = -70
|
||||
self._host_connect_button = ba.buttonwidget(
|
||||
parent=self._container,
|
||||
size=(140, 40),
|
||||
color=(0.6, 0.5, 0.6),
|
||||
textcolor=(0.8, 0.75, 0.8),
|
||||
label=ba.Lstr(resource='gatherWindow.manualConnectText'),
|
||||
on_activate_call=self._host_connect_press,
|
||||
position=(self._c_width * 0.5 + cbtnoffs, v - 70),
|
||||
autoselect=True)
|
||||
|
||||
v -= 120
|
||||
|
||||
# Line above the main action button:
|
||||
|
||||
# If hosting is unavailable, show the associated reason.
|
||||
if self._hostingstate.unavailable_error is not None:
|
||||
ba.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=self._c_width * 0.9,
|
||||
scale=0.7,
|
||||
flatness=1.0,
|
||||
color=(1.0, 0.0, 0.0),
|
||||
position=(self._c_width * 0.5, v),
|
||||
text=ba.Lstr(translate=('serverResponses',
|
||||
self._hostingstate.unavailable_error)))
|
||||
elif self._hostingstate.free_host_minutes_remaining is not None:
|
||||
# If we've been pre-approved to start/stop for free, show that.
|
||||
ba.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=self._c_width * 0.9,
|
||||
scale=0.7,
|
||||
flatness=1.0,
|
||||
color=((0.7, 0.64, 0.7) if self._hostingstate.party_code else
|
||||
(0.0, 1.0, 0.0)),
|
||||
position=(self._c_width * 0.5, v),
|
||||
text=ba.Lstr(
|
||||
resource='gatherWindow.startStopHostingMinutesText',
|
||||
subs=[(
|
||||
'${MINUTES}',
|
||||
f'{self._hostingstate.free_host_minutes_remaining:.0f}'
|
||||
)]))
|
||||
else:
|
||||
# Otherwise tell whether the free cloud server is available
|
||||
# or will be at some point.
|
||||
if self._hostingstate.party_code is None:
|
||||
if self._hostingstate.tickets_to_host_now == 0:
|
||||
ba.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=self._c_width * 0.9,
|
||||
scale=0.7,
|
||||
flatness=1.0,
|
||||
color=(0.0, 1.0, 0.0),
|
||||
position=(self._c_width * 0.5, v),
|
||||
text=ba.Lstr(
|
||||
resource=
|
||||
'gatherWindow.freeCloudServerAvailableNowText'))
|
||||
else:
|
||||
if self._hostingstate.minutes_until_free_host is None:
|
||||
ba.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=self._c_width * 0.9,
|
||||
scale=0.7,
|
||||
flatness=1.0,
|
||||
color=(1.0, 0.6, 0.0),
|
||||
position=(self._c_width * 0.5, v),
|
||||
text=ba.Lstr(
|
||||
resource=
|
||||
'gatherWindow.freeCloudServerNotAvailableText')
|
||||
)
|
||||
else:
|
||||
availmins = self._hostingstate.minutes_until_free_host
|
||||
ba.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=self._c_width * 0.9,
|
||||
scale=0.7,
|
||||
flatness=1.0,
|
||||
color=(1.0, 0.6, 0.0),
|
||||
position=(self._c_width * 0.5, v),
|
||||
text=ba.Lstr(resource='gatherWindow.'
|
||||
'freeCloudServerAvailableMinutesText',
|
||||
subs=[('${MINUTES}',
|
||||
f'{availmins:.0f}')]))
|
||||
|
||||
v -= 100
|
||||
|
||||
if self._waiting_for_hosting_state:
|
||||
btnlabel = ba.Lstr(resource='oneMomentText')
|
||||
else:
|
||||
if self._hostingstate.unavailable_error is not None:
|
||||
btnlabel = ba.Lstr(
|
||||
resource='gatherWindow.hostingUnavailableText')
|
||||
elif self._hostingstate.party_code is None:
|
||||
ticon = _ba.charstr(ba.SpecialChar.TICKET)
|
||||
nowtickets = self._hostingstate.tickets_to_host_now
|
||||
if nowtickets > 0:
|
||||
btnlabel = ba.Lstr(
|
||||
resource='gatherWindow.startHostingPaidText',
|
||||
subs=[('${COST}', f'{ticon}{nowtickets}')])
|
||||
else:
|
||||
btnlabel = ba.Lstr(
|
||||
resource='gatherWindow.startHostingText')
|
||||
else:
|
||||
btnlabel = ba.Lstr(resource='gatherWindow.stopHostingText')
|
||||
|
||||
self._host_start_stop_button = ba.buttonwidget(
|
||||
parent=self._container,
|
||||
size=(400, 80),
|
||||
color=((0.6, 0.6, 0.6)
|
||||
if self._hostingstate.unavailable_error is not None else
|
||||
(0.5, 1.0,
|
||||
0.5) if self._waiting_for_hosting_state else None),
|
||||
enable_sound=False,
|
||||
label=btnlabel,
|
||||
textcolor=((0.7, 0.7, 0.7)
|
||||
if self._hostingstate.unavailable_error else None),
|
||||
position=(self._c_width * 0.5 - 200, v),
|
||||
on_activate_call=self._host_button_press,
|
||||
autoselect=True)
|
||||
|
||||
def _host_copy_press(self) -> None:
|
||||
assert self._hostingstate.party_code is not None
|
||||
ba.clipboard_set_text(self._hostingstate.party_code)
|
||||
ba.screenmessage(ba.Lstr(resource='gatherWindow.copyCodeConfirmText'))
|
||||
|
||||
def _host_connect_press(self) -> None:
|
||||
assert self._hostingstate.party_code is not None
|
||||
self._connect_to_party_code(self._hostingstate.party_code)
|
||||
|
||||
def _debug_server_comm(self, msg: str) -> None:
|
||||
if DEBUG_SERVER_COMMUNICATION:
|
||||
print(f'PPTABCOM: {msg} at time '
|
||||
f'{time.time()-self._create_time:.2f}')
|
||||
|
||||
def _connect_to_party_code(self, code: str) -> None:
|
||||
self._debug_server_comm('sending private party connect')
|
||||
_ba.add_transaction(
|
||||
{
|
||||
'type': 'PRIVATE_PARTY_CONNECT',
|
||||
'code': code
|
||||
},
|
||||
callback=ba.WeakCall(self._connect_response),
|
||||
)
|
||||
_ba.run_transactions()
|
||||
|
||||
def _host_button_press(self) -> None:
|
||||
if self._waiting_for_hosting_state:
|
||||
return
|
||||
|
||||
if _ba.get_account_state() != 'signed_in':
|
||||
ba.screenmessage(ba.Lstr(resource='notSignedInErrorText'))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
self._refresh_sub_tab()
|
||||
return
|
||||
|
||||
if self._hostingstate.unavailable_error is not None:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
# If we're not hosting, start.
|
||||
if self._hostingstate.party_code is None:
|
||||
|
||||
# If there's a ticket cost, make sure we have enough tickets.
|
||||
if self._hostingstate.tickets_to_host_now > 0:
|
||||
ticket_count: Optional[int]
|
||||
try:
|
||||
ticket_count = _ba.get_account_ticket_count()
|
||||
except Exception:
|
||||
# FIXME: should add a ba.NotSignedInError we can use here.
|
||||
ticket_count = None
|
||||
ticket_cost = self._hostingstate.tickets_to_host_now
|
||||
if ticket_count is not None and ticket_count < ticket_cost:
|
||||
getcurrency.show_get_tickets_prompt()
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
self._last_action_send_time = time.time()
|
||||
_ba.add_transaction({'type': 'PRIVATE_PARTY_START'},
|
||||
callback=ba.WeakCall(
|
||||
self._hosting_state_response))
|
||||
_ba.run_transactions()
|
||||
|
||||
else:
|
||||
self._last_action_send_time = time.time()
|
||||
_ba.add_transaction({'type': 'PRIVATE_PARTY_STOP'},
|
||||
callback=ba.WeakCall(
|
||||
self._hosting_state_response))
|
||||
_ba.run_transactions()
|
||||
ba.playsound(ba.getsound('click01'))
|
||||
|
||||
self._waiting_for_hosting_state = True
|
||||
self._refresh_sub_tab()
|
||||
|
||||
def _connect_press(self) -> None:
|
||||
code: Optional[str] = None
|
||||
if self._join_party_code_text:
|
||||
code = cast(str, ba.textwidget(query=self._join_party_code_text))
|
||||
if not code:
|
||||
ba.screenmessage(
|
||||
ba.Lstr(resource='internal.invalidAddressErrorText'),
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
self._connect_to_party_code(code)
|
||||
|
||||
def _connect_response(self, result: Optional[Dict[str, Any]]) -> None:
|
||||
try:
|
||||
if result is None:
|
||||
raise RuntimeError()
|
||||
cresult = dataclass_from_dict(ConnectResult, result)
|
||||
if cresult.error is not None:
|
||||
self._debug_server_comm('got error connect response')
|
||||
ba.screenmessage(
|
||||
ba.Lstr(translate=('serverResponses', cresult.error)),
|
||||
(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
self._debug_server_comm('got valid connect response')
|
||||
assert cresult.addr is not None and cresult.port is not None
|
||||
_ba.connect_to_party(cresult.addr, port=cresult.port)
|
||||
except Exception:
|
||||
self._debug_server_comm('got connect response error')
|
||||
ba.playsound(ba.getsound('error'))
|
||||
|
||||
def save_state(self) -> None:
|
||||
ba.app.ui.window_states[type(self)] = copy.deepcopy(self._state)
|
||||
|
||||
def restore_state(self) -> None:
|
||||
state = ba.app.ui.window_states.get(type(self))
|
||||
if state is None:
|
||||
state = State()
|
||||
assert isinstance(state, State)
|
||||
self._state = state
|
||||
@ -14,7 +14,7 @@ from typing import TYPE_CHECKING, cast
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
from bastd.ui.gather.bases import GatherTab
|
||||
from bastd.ui.gather import GatherTab
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any, Optional, Dict, Union, Tuple, List
|
||||
@ -448,7 +448,7 @@ class PublicGatherTab(GatherTab):
|
||||
# display these immediately when our UI comes back up which should
|
||||
# be enough to make things feel nice and crisp while we do a full
|
||||
# server re-query or whatnot.
|
||||
ba.app.ui.window_states[self.__class__.__name__] = State(
|
||||
ba.app.ui.window_states[type(self)] = State(
|
||||
sub_tab=self._sub_tab,
|
||||
parties=[(i, copy.copy(p)) for i, p in self._parties_sorted[:40]],
|
||||
next_entry_index=self._next_entry_index,
|
||||
@ -457,7 +457,7 @@ class PublicGatherTab(GatherTab):
|
||||
have_valid_server_list=self._have_valid_server_list)
|
||||
|
||||
def restore_state(self) -> None:
|
||||
state = ba.app.ui.window_states.get(self.__class__.__name__)
|
||||
state = ba.app.ui.window_states.get(type(self))
|
||||
if state is None:
|
||||
state = State()
|
||||
assert isinstance(state, State)
|
||||
@ -544,9 +544,8 @@ class PublicGatherTab(GatherTab):
|
||||
position=(270, v + 13),
|
||||
maxwidth=150,
|
||||
scale=0.8,
|
||||
color=(0.5, 0.5, 0.5),
|
||||
color=(0.5, 0.46, 0.5),
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
h_align='right',
|
||||
v_align='center')
|
||||
|
||||
@ -556,9 +555,8 @@ class PublicGatherTab(GatherTab):
|
||||
position=(90, v - 8),
|
||||
maxwidth=60,
|
||||
scale=0.6,
|
||||
color=(0.5, 0.5, 0.5),
|
||||
color=(0.5, 0.46, 0.5),
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
h_align='center',
|
||||
v_align='center')
|
||||
ba.textwidget(text=ba.Lstr(resource='gatherWindow.partySizeText'),
|
||||
@ -567,9 +565,8 @@ class PublicGatherTab(GatherTab):
|
||||
position=(755, v - 8),
|
||||
maxwidth=60,
|
||||
scale=0.6,
|
||||
color=(0.5, 0.5, 0.5),
|
||||
color=(0.5, 0.46, 0.5),
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
h_align='center',
|
||||
v_align='center')
|
||||
ba.textwidget(text=ba.Lstr(resource='gatherWindow.pingText'),
|
||||
@ -578,9 +575,8 @@ class PublicGatherTab(GatherTab):
|
||||
position=(825, v - 8),
|
||||
maxwidth=60,
|
||||
scale=0.6,
|
||||
color=(0.5, 0.5, 0.5),
|
||||
color=(0.5, 0.46, 0.5),
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
h_align='center',
|
||||
v_align='center')
|
||||
v -= sub_scroll_height + 23
|
||||
@ -617,6 +613,20 @@ class PublicGatherTab(GatherTab):
|
||||
v -= 25
|
||||
is_public_enabled = _ba.get_public_party_enabled()
|
||||
v -= 30
|
||||
|
||||
ba.textwidget(
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=c_width * 0.9,
|
||||
scale=0.7,
|
||||
flatness=1.0,
|
||||
color=(0.5, 0.46, 0.5),
|
||||
position=(region_width * 0.5, v + 10),
|
||||
text=ba.Lstr(resource='gatherWindow.publicHostRouterConfigText'))
|
||||
v -= 30
|
||||
|
||||
party_name_text = ba.Lstr(
|
||||
resource='gatherWindow.partyNameText',
|
||||
fallback_resource='editGameListWindow.nameText')
|
||||
@ -710,11 +720,10 @@ class PublicGatherTab(GatherTab):
|
||||
size=(0, 0),
|
||||
scale=0.7,
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
h_align='center',
|
||||
v_align='top',
|
||||
maxwidth=c_width,
|
||||
color=(0.6, 0.6, 0.6),
|
||||
maxwidth=c_width * 0.9,
|
||||
color=(0.6, 0.56, 0.6),
|
||||
position=(c_width * 0.5, v))
|
||||
v -= 90
|
||||
ba.textwidget(
|
||||
@ -723,11 +732,10 @@ class PublicGatherTab(GatherTab):
|
||||
size=(0, 0),
|
||||
scale=0.7,
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=c_width * 0.9,
|
||||
color=ba.app.ui.infotextcolor,
|
||||
color=(0.5, 0.46, 0.5),
|
||||
position=(c_width * 0.5, v))
|
||||
|
||||
# If public sharing is already on,
|
||||
@ -750,8 +758,6 @@ class PublicGatherTab(GatherTab):
|
||||
self._have_valid_server_list = True
|
||||
parties_in = result['l']
|
||||
|
||||
# parties_in.reverse()
|
||||
|
||||
assert isinstance(parties_in, list)
|
||||
self._pending_party_infos += parties_in
|
||||
|
||||
@ -1060,7 +1066,6 @@ class PublicGatherTab(GatherTab):
|
||||
callback=ba.WeakCall(self._on_public_party_query_result))
|
||||
_ba.run_transactions()
|
||||
else:
|
||||
# This will kick us over to a 'not signed in' message.
|
||||
self._on_public_party_query_result(None)
|
||||
|
||||
def _ping_parties_periodically(self) -> None:
|
||||
|
||||
@ -316,7 +316,7 @@ class KioskWindow(ba.Window):
|
||||
repeat=True)
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__)
|
||||
sel_name = ba.app.ui.window_states.get(type(self))
|
||||
sel: Optional[ba.Widget]
|
||||
if sel_name == 'b1':
|
||||
sel = self._b1
|
||||
@ -355,7 +355,7 @@ class KioskWindow(ba.Window):
|
||||
sel_name = 'b7'
|
||||
else:
|
||||
sel_name = 'b1'
|
||||
ba.app.ui.window_states[self.__class__.__name__] = sel_name
|
||||
ba.app.ui.window_states[type(self)] = sel_name
|
||||
|
||||
def _update(self) -> None:
|
||||
# Kiosk-mode is designed to be used signed-out... try for force
|
||||
|
||||
@ -540,13 +540,13 @@ class PlayWindow(ba.Window):
|
||||
sel_name = 'Back'
|
||||
else:
|
||||
raise ValueError(f'unrecognized selection {sel}')
|
||||
ba.app.ui.window_states[self.__class__.__name__] = sel_name
|
||||
ba.app.ui.window_states[type(self)] = sel_name
|
||||
except Exception:
|
||||
ba.print_exception(f'Error saving state for {self}.')
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
try:
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__)
|
||||
sel_name = ba.app.ui.window_states.get(type(self))
|
||||
if sel_name == 'Team Games':
|
||||
sel = self._teams_button
|
||||
elif sel_name == 'Co-op Games':
|
||||
|
||||
@ -628,13 +628,13 @@ class PlaylistBrowserWindow(ba.Window):
|
||||
sel_name = 'Scroll'
|
||||
else:
|
||||
raise Exception('unrecognized selected widget')
|
||||
ba.app.ui.window_states[self.__class__.__name__] = sel_name
|
||||
ba.app.ui.window_states[type(self)] = sel_name
|
||||
except Exception:
|
||||
ba.print_exception(f'Error saving state for {self}.')
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
try:
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__)
|
||||
sel_name = ba.app.ui.window_states.get(type(self))
|
||||
if sel_name == 'Back':
|
||||
sel = self._back_button
|
||||
elif sel_name == 'Scroll':
|
||||
|
||||
@ -347,13 +347,13 @@ class ProfileBrowserWindow(ba.Window):
|
||||
sel_name = 'Scroll'
|
||||
else:
|
||||
sel_name = 'Back'
|
||||
ba.app.ui.window_states[self.__class__.__name__] = sel_name
|
||||
ba.app.ui.window_states[type(self)] = sel_name
|
||||
except Exception:
|
||||
ba.print_exception(f'Error saving state for {self}.')
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
try:
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__)
|
||||
sel_name = ba.app.ui.window_states.get(type(self))
|
||||
if sel_name == 'Scroll':
|
||||
sel = self._scrollwidget
|
||||
elif sel_name == 'New':
|
||||
|
||||
@ -626,16 +626,14 @@ class AdvancedSettingsWindow(ba.Window):
|
||||
sel_name = 'Back'
|
||||
else:
|
||||
raise ValueError(f'unrecognized selection \'{sel}\'')
|
||||
ba.app.ui.window_states[self.__class__.__name__] = {
|
||||
'sel_name': sel_name
|
||||
}
|
||||
ba.app.ui.window_states[type(self)] = {'sel_name': sel_name}
|
||||
except Exception:
|
||||
ba.print_exception(f'Error saving state for {self.__class__}')
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
# pylint: disable=too-many-branches
|
||||
try:
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__,
|
||||
sel_name = ba.app.ui.window_states.get(type(self),
|
||||
{}).get('sel_name')
|
||||
if sel_name == 'Back':
|
||||
sel = self._back_button
|
||||
|
||||
@ -256,15 +256,13 @@ class AllSettingsWindow(ba.Window):
|
||||
sel_name = 'Back'
|
||||
else:
|
||||
raise ValueError(f'unrecognized selection \'{sel}\'')
|
||||
ba.app.ui.window_states[self.__class__.__name__] = {
|
||||
'sel_name': sel_name
|
||||
}
|
||||
ba.app.ui.window_states[type(self)] = {'sel_name': sel_name}
|
||||
except Exception:
|
||||
ba.print_exception(f'Error saving state for {self}.')
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
try:
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__,
|
||||
sel_name = ba.app.ui.window_states.get(type(self),
|
||||
{}).get('sel_name')
|
||||
sel: Optional[ba.Widget]
|
||||
if sel_name == 'Controllers':
|
||||
|
||||
@ -252,13 +252,13 @@ class AudioSettingsWindow(ba.Window):
|
||||
sel_name = 'VRHeadRelative'
|
||||
else:
|
||||
raise ValueError(f'unrecognized selection \'{sel}\'')
|
||||
ba.app.ui.window_states[self.__class__.__name__] = sel_name
|
||||
ba.app.ui.window_states[type(self)] = sel_name
|
||||
except Exception:
|
||||
ba.print_exception(f'Error saving state for {self.__class__}.')
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
try:
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__)
|
||||
sel_name = ba.app.ui.window_states.get(type(self))
|
||||
sel: Optional[ba.Widget]
|
||||
if sel_name == 'SoundMinus':
|
||||
sel = self._sound_volume_numedit.minusbutton
|
||||
|
||||
@ -457,10 +457,10 @@ class ControlsSettingsWindow(ba.Window):
|
||||
sel_name = 'Wiimotes'
|
||||
else:
|
||||
sel_name = 'Back'
|
||||
ba.app.ui.window_states[self.__class__.__name__] = sel_name
|
||||
ba.app.ui.window_states[type(self)] = sel_name
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__)
|
||||
sel_name = ba.app.ui.window_states.get(type(self))
|
||||
if sel_name == 'GamePads':
|
||||
sel = self._gamepads_button
|
||||
elif sel_name == 'Touch':
|
||||
|
||||
@ -463,13 +463,13 @@ class SoundtrackBrowserWindow(ba.Window):
|
||||
sel_name = 'Back'
|
||||
else:
|
||||
raise ValueError(f'unrecognized selection \'{sel}\'')
|
||||
ba.app.ui.window_states[self.__class__.__name__] = sel_name
|
||||
ba.app.ui.window_states[type(self)] = sel_name
|
||||
except Exception:
|
||||
ba.print_exception(f'Error saving state for {self}.')
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
try:
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__)
|
||||
sel_name = ba.app.ui.window_states.get(type(self))
|
||||
if sel_name == 'Scroll':
|
||||
sel = self._scrollwidget
|
||||
elif sel_name == 'New':
|
||||
|
||||
@ -1011,7 +1011,7 @@ class StoreBrowserWindow(ba.Window):
|
||||
sel_name = f'Tab:{selected_tab_ids[0].value}'
|
||||
else:
|
||||
raise ValueError(f'unrecognized selection \'{sel}\'')
|
||||
ba.app.ui.window_states[self.__class__.__name__] = {
|
||||
ba.app.ui.window_states[type(self)] = {
|
||||
'sel_name': sel_name,
|
||||
}
|
||||
except Exception:
|
||||
@ -1021,7 +1021,7 @@ class StoreBrowserWindow(ba.Window):
|
||||
from efro.util import enum_by_value
|
||||
try:
|
||||
sel: Optional[ba.Widget]
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__,
|
||||
sel_name = ba.app.ui.window_states.get(type(self),
|
||||
{}).get('sel_name')
|
||||
assert isinstance(sel_name, (str, type(None)))
|
||||
|
||||
|
||||
@ -35,6 +35,7 @@ class TeamNamesColorsWindow(popup.PopupWindow):
|
||||
appconfig = ba.app.config
|
||||
self._names = list(
|
||||
appconfig.get('Custom Team Names', DEFAULT_TEAM_NAMES))
|
||||
|
||||
# We need to flatten the translation since it will be an
|
||||
# editable string.
|
||||
self._names = [
|
||||
@ -46,7 +47,7 @@ class TeamNamesColorsWindow(popup.PopupWindow):
|
||||
self._color_buttons: List[ba.Widget] = []
|
||||
self._color_text_fields: List[ba.Widget] = []
|
||||
|
||||
ba.buttonwidget(
|
||||
resetbtn = ba.buttonwidget(
|
||||
parent=self.root_widget,
|
||||
label=ba.Lstr(resource='settingsWindowAdvanced.resetText'),
|
||||
autoselect=True,
|
||||
@ -77,20 +78,27 @@ class TeamNamesColorsWindow(popup.PopupWindow):
|
||||
description=ba.Lstr(resource='nameText'),
|
||||
editable=True,
|
||||
padding=4))
|
||||
ba.buttonwidget(parent=self.root_widget,
|
||||
label=ba.Lstr(resource='cancelText'),
|
||||
autoselect=True,
|
||||
on_activate_call=self._on_cancel_press,
|
||||
size=(150, 50),
|
||||
position=(self._width * 0.5 - 200, 20))
|
||||
ba.buttonwidget(parent=self.root_widget,
|
||||
label=ba.Lstr(resource='saveText'),
|
||||
autoselect=True,
|
||||
on_activate_call=self._save,
|
||||
size=(150, 50),
|
||||
position=(self._width * 0.5 + 50, 20))
|
||||
ba.widget(edit=self._color_text_fields[0],
|
||||
down_widget=self._color_text_fields[1])
|
||||
ba.widget(edit=self._color_text_fields[1],
|
||||
up_widget=self._color_text_fields[0])
|
||||
ba.widget(edit=self._color_text_fields[0], up_widget=resetbtn)
|
||||
|
||||
cancelbtn = ba.buttonwidget(parent=self.root_widget,
|
||||
label=ba.Lstr(resource='cancelText'),
|
||||
autoselect=True,
|
||||
on_activate_call=self._on_cancel_press,
|
||||
size=(150, 50),
|
||||
position=(self._width * 0.5 - 200, 20))
|
||||
savebtn = ba.buttonwidget(parent=self.root_widget,
|
||||
label=ba.Lstr(resource='saveText'),
|
||||
autoselect=True,
|
||||
on_activate_call=self._save,
|
||||
size=(150, 50),
|
||||
position=(self._width * 0.5 + 50, 20))
|
||||
ba.containerwidget(edit=self.root_widget,
|
||||
selected_child=self._color_buttons[0])
|
||||
ba.widget(edit=savebtn, left_widget=cancelbtn)
|
||||
self._update()
|
||||
|
||||
def _color_click(self, i: int) -> None:
|
||||
|
||||
@ -496,9 +496,7 @@ class WatchWindow(ba.Window):
|
||||
sel_name = 'TabContainer'
|
||||
else:
|
||||
raise ValueError(f'unrecognized selection {sel}')
|
||||
ba.app.ui.window_states[self.__class__.__name__] = {
|
||||
'sel_name': sel_name
|
||||
}
|
||||
ba.app.ui.window_states[type(self)] = {'sel_name': sel_name}
|
||||
except Exception:
|
||||
ba.print_exception(f'Error saving state for {self}.')
|
||||
|
||||
@ -506,7 +504,7 @@ class WatchWindow(ba.Window):
|
||||
from efro.util import enum_by_value
|
||||
try:
|
||||
sel: Optional[ba.Widget]
|
||||
sel_name = ba.app.ui.window_states.get(self.__class__.__name__,
|
||||
sel_name = ba.app.ui.window_states.get(type(self),
|
||||
{}).get('sel_name')
|
||||
assert isinstance(sel_name, (str, type(None)))
|
||||
try:
|
||||
|
||||
23
ballisticacore-cmake/.idea/dictionaries/ericf.xml
generated
23
ballisticacore-cmake/.idea/dictionaries/ericf.xml
generated
@ -17,6 +17,7 @@
|
||||
<w>aclass's</w>
|
||||
<w>activityplayer</w>
|
||||
<w>addcall</w>
|
||||
<w>addchars</w>
|
||||
<w>addrs</w>
|
||||
<w>adjoint</w>
|
||||
<w>adminset</w>
|
||||
@ -47,6 +48,7 @@
|
||||
<w>appname</w>
|
||||
<w>appnameupper</w>
|
||||
<w>appstate</w>
|
||||
<w>argsjoined</w>
|
||||
<w>asci</w>
|
||||
<w>assigninput</w>
|
||||
<w>athome</w>
|
||||
@ -54,6 +56,7 @@
|
||||
<w>audiocache</w>
|
||||
<w>automagically</w>
|
||||
<w>autoselect</w>
|
||||
<w>availmins</w>
|
||||
<w>avel</w>
|
||||
<w>avels</w>
|
||||
<w>axismotion</w>
|
||||
@ -114,6 +117,7 @@
|
||||
<w>bsstd</w>
|
||||
<w>bstat</w>
|
||||
<w>bsuuid</w>
|
||||
<w>btnlabel</w>
|
||||
<w>bufs</w>
|
||||
<w>buildconfig</w>
|
||||
<w>buildnumber</w>
|
||||
@ -131,8 +135,10 @@
|
||||
<w>camalign</w>
|
||||
<w>camelback</w>
|
||||
<w>camerashake</w>
|
||||
<w>cancelbtn</w>
|
||||
<w>capitan</w>
|
||||
<w>cargs</w>
|
||||
<w>cbtnoffs</w>
|
||||
<w>ccdd</w>
|
||||
<w>ccontext</w>
|
||||
<w>ccylinder</w>
|
||||
@ -177,6 +183,7 @@
|
||||
<w>cpuid</w>
|
||||
<w>crashenv</w>
|
||||
<w>crashlytics</w>
|
||||
<w>cresult</w>
|
||||
<w>crom</w>
|
||||
<w>crosswire</w>
|
||||
<w>crvel</w>
|
||||
@ -329,6 +336,7 @@
|
||||
<w>fread</w>
|
||||
<w>freeform</w>
|
||||
<w>freeifaddrs</w>
|
||||
<w>freemins</w>
|
||||
<w>freqs</w>
|
||||
<w>froemling</w>
|
||||
<w>fromini</w>
|
||||
@ -411,6 +419,7 @@
|
||||
<w>hostactivity</w>
|
||||
<w>hostcmd</w>
|
||||
<w>hostinfo</w>
|
||||
<w>hostingstate</w>
|
||||
<w>hotkeys</w>
|
||||
<w>hotplug</w>
|
||||
<w>hscrollwidget</w>
|
||||
@ -491,6 +500,7 @@
|
||||
<w>linearsize</w>
|
||||
<w>listobj</w>
|
||||
<w>llock</w>
|
||||
<w>lockpath</w>
|
||||
<w>lockstr</w>
|
||||
<w>locktype</w>
|
||||
<w>logmsg</w>
|
||||
@ -596,6 +606,7 @@
|
||||
<w>nonlint</w>
|
||||
<w>noone</w>
|
||||
<w>nothin</w>
|
||||
<w>nowtickets</w>
|
||||
<w>nptr</w>
|
||||
<w>nsize</w>
|
||||
<w>ntoa</w>
|
||||
@ -613,6 +624,8 @@
|
||||
<w>obvs</w>
|
||||
<w>oculus</w>
|
||||
<w>oenval</w>
|
||||
<w>offsx</w>
|
||||
<w>offsy</w>
|
||||
<w>oiffsss</w>
|
||||
<w>oldname</w>
|
||||
<w>oooo</w>
|
||||
@ -668,6 +681,7 @@
|
||||
<w>positivez</w>
|
||||
<w>postinit</w>
|
||||
<w>powerup</w>
|
||||
<w>pptabcom</w>
|
||||
<w>precalc</w>
|
||||
<w>predeclare</w>
|
||||
<w>prefs</w>
|
||||
@ -679,9 +693,11 @@
|
||||
<w>printnodes</w>
|
||||
<w>printobjects</w>
|
||||
<w>priv</w>
|
||||
<w>privatetab</w>
|
||||
<w>profilers</w>
|
||||
<w>prog</w>
|
||||
<w>proj</w>
|
||||
<w>projdir</w>
|
||||
<w>prolly</w>
|
||||
<w>psmx</w>
|
||||
<w>pspec</w>
|
||||
@ -739,6 +755,7 @@
|
||||
<w>reprfunc</w>
|
||||
<w>rerase</w>
|
||||
<w>resends</w>
|
||||
<w>resetbtn</w>
|
||||
<w>resetinput</w>
|
||||
<w>resync</w>
|
||||
<w>retrysecs</w>
|
||||
@ -759,6 +776,7 @@
|
||||
<w>safecolor</w>
|
||||
<w>samsung</w>
|
||||
<w>sapspace</w>
|
||||
<w>savebtn</w>
|
||||
<w>savebutton</w>
|
||||
<w>scancode</w>
|
||||
<w>scenetime</w>
|
||||
@ -767,6 +785,10 @@
|
||||
<w>sdkcheck</w>
|
||||
<w>sdl's</w>
|
||||
<w>sdlk</w>
|
||||
<w>selchild</w>
|
||||
<w>selindex</w>
|
||||
<w>selwidget</w>
|
||||
<w>selwidgets</w>
|
||||
<w>seqlen</w>
|
||||
<w>seqtype</w>
|
||||
<w>seqtypestr</w>
|
||||
@ -884,6 +906,7 @@
|
||||
<w>theres</w>
|
||||
<w>threadname</w>
|
||||
<w>threadtype</w>
|
||||
<w>ticon</w>
|
||||
<w>tiltage</w>
|
||||
<w>timedisplay</w>
|
||||
<w>timeformat</w>
|
||||
|
||||
@ -30,7 +30,8 @@
|
||||
"requests",
|
||||
"typing_extensions",
|
||||
"cpplint",
|
||||
"ansiwrap"
|
||||
"ansiwrap",
|
||||
"filelock"
|
||||
],
|
||||
"python_paths": [
|
||||
"assets/src/ba_data/python",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
||||
<h4><em>last updated on 2021-01-15 for Ballistica version 1.5.30 build 20267</em></h4>
|
||||
<h4><em>last updated on 2021-01-26 for Ballistica version 1.6.0 build 20278</em></h4>
|
||||
<p>This page documents the Python classes and functions in the 'ba' module,
|
||||
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
|
||||
<hr>
|
||||
@ -85,6 +85,10 @@
|
||||
<h4><a name="function_category_General_Utility_Functions">General Utility Functions</a></h4>
|
||||
<ul>
|
||||
<li><a href="#function_ba_charstr">ba.charstr()</a></li>
|
||||
<li><a href="#function_ba_clipboard_get_text">ba.clipboard_get_text()</a></li>
|
||||
<li><a href="#function_ba_clipboard_has_text">ba.clipboard_has_text()</a></li>
|
||||
<li><a href="#function_ba_clipboard_is_supported">ba.clipboard_is_supported()</a></li>
|
||||
<li><a href="#function_ba_clipboard_set_text">ba.clipboard_set_text()</a></li>
|
||||
<li><a href="#function_ba_do_once">ba.do_once()</a></li>
|
||||
<li><a href="#function_ba_garbage_collect">ba.garbage_collect()</a></li>
|
||||
<li><a href="#function_ba_getclass">ba.getclass()</a></li>
|
||||
@ -395,7 +399,7 @@ actually award achievements.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_Activity">ba.Activity</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a>, <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>Inherits from: <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a>, <a href="https://docs.python.org/3/library/typing.html#typing.Generic">typing.Generic</a></p>
|
||||
<p>Units of execution wrangled by a <a href="#class_ba_Session">ba.Session</a>.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
|
||||
@ -659,7 +663,7 @@ is a convenient way to access this same functionality.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_ActivityNotFoundError">ba.ActivityNotFoundError</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when an expected <a href="#class_ba_Activity">ba.Activity</a> does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
@ -784,7 +788,7 @@ even if myactor is set to None.</p>
|
||||
<p>Return the <a href="#class_ba_Activity">ba.Activity</a> this Actor is associated with.</p>
|
||||
|
||||
<p>If the Activity no longer exists, raises a <a href="#class_ba_ActivityNotFoundError">ba.ActivityNotFoundError</a>
|
||||
or returns None depending on whether 'doraise' is set.</p>
|
||||
or returns None depending on whether 'doraise' is True.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Actor__handlemessage">handlemessage()</a></dt></h4><dd>
|
||||
@ -823,7 +827,7 @@ likely result in errors.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_ActorNotFoundError">ba.ActorNotFoundError</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when an expected <a href="#class_ba_Actor">ba.Actor</a> does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
@ -1010,7 +1014,7 @@ to resume.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_AppConfig">ba.AppConfig</a></strong></h3>
|
||||
<p>Inherits from: dict</p>
|
||||
<p>Inherits from: builtins.dict</p>
|
||||
<p>A special dict that holds the game's persistent configuration values.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_App_Classes">App Classes</a></p>
|
||||
@ -1023,7 +1027,7 @@ to resume.</p>
|
||||
|
||||
<p> AppConfig data is stored as json on disk on so make sure to only place
|
||||
json-friendly values in it (dict, list, str, float, int, bool).
|
||||
Be aware that tuples will be quietly converted to lists.
|
||||
Be aware that tuples will be quietly converted to lists when stored.
|
||||
</p>
|
||||
|
||||
<h3>Methods Defined or Overridden:</h3>
|
||||
@ -1596,7 +1600,7 @@ start_long_action(callback_when_done=<a href="#class_ba_ContextCall">ba.ContextC
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_ContextError">ba.ContextError</a></strong></h3>
|
||||
<p>Inherits from: Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when a call is made in an invalid context.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a></p>
|
||||
@ -1606,10 +1610,10 @@ start_long_action(callback_when_done=<a href="#class_ba_ContextCall">ba.ContextC
|
||||
</p>
|
||||
|
||||
<h3>Methods:</h3>
|
||||
<p><all methods inherited from <a href="#class_builtins_Exception">builtins.Exception</a>></p>
|
||||
<p><all methods inherited from <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>></p>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_CoopGameActivity">ba.CoopGameActivity</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_GameActivity">ba.GameActivity</a>, <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a>, <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>Inherits from: <a href="#class_ba_GameActivity">ba.GameActivity</a>, <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a>, <a href="https://docs.python.org/3/library/typing.html#typing.Generic">typing.Generic</a></p>
|
||||
<p>Base class for cooperative-mode games.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a>
|
||||
@ -1841,7 +1845,7 @@ the data object is requested and when it's value is accessed.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_DeathType">ba.DeathType</a></strong></h3>
|
||||
<p>Inherits from: enum.Enum</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/enum.html#enum.Enum">enum.Enum</a></p>
|
||||
<p>A reason for a death.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Enums">Enums</a>
|
||||
@ -1858,7 +1862,7 @@ the data object is requested and when it's value is accessed.</p>
|
||||
</ul>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_DelegateNotFoundError">ba.DelegateNotFoundError</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when an expected delegate object does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
@ -1868,7 +1872,7 @@ the data object is requested and when it's value is accessed.</p>
|
||||
<p><all methods inherited from <a href="#class_ba_NotFoundError">ba.NotFoundError</a>></p>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_Dependency">ba.Dependency</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/typing.html#typing.Generic">typing.Generic</a></p>
|
||||
<p>A dependency on a DependencyComponent (with an optional config).</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Dependency_Classes">Dependency Classes</a></p>
|
||||
@ -1941,7 +1945,7 @@ on the dep config value. (for instance a map required by a game type)</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_DependencyError">ba.DependencyError</a></strong></h3>
|
||||
<p>Inherits from: Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when one or more <a href="#class_ba_Dependency">ba.Dependency</a> items are missing.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a></p>
|
||||
@ -1968,7 +1972,7 @@ on the dep config value. (for instance a map required by a game type)</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_DependencySet">ba.DependencySet</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/typing.html#typing.Generic">typing.Generic</a></p>
|
||||
<p>Set of resolved dependencies and their associated data.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Dependency_Classes">Dependency Classes</a></p>
|
||||
@ -2129,13 +2133,13 @@ its time with lingering corpses, sound effects, etc.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_EmptyPlayer">ba.EmptyPlayer</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_Player">ba.Player</a>, <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>Inherits from: <a href="#class_ba_Player">ba.Player</a>, <a href="https://docs.python.org/3/library/typing.html#typing.Generic">typing.Generic</a></p>
|
||||
<p>An empty player for use by Activities that don't need to define one.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
|
||||
|
||||
<p> <a href="#class_ba_Player">ba.Player</a> and <a href="#class_ba_Team">ba.Team</a> are 'Generic' types, and so passing them as
|
||||
type arguments when defining a <a href="#class_ba_Activity">ba.Activity</a> reduces type safety.
|
||||
<p> <a href="#class_ba_Player">ba.Player</a> and <a href="#class_ba_Team">ba.Team</a> are 'Generic' types, and so passing those top level
|
||||
classes as type arguments when defining a <a href="#class_ba_Activity">ba.Activity</a> reduces type safety.
|
||||
For example, activity.teams[0].player will have type 'Any' in that case.
|
||||
For that reason, it is better to pass EmptyPlayer and EmptyTeam when
|
||||
defining a <a href="#class_ba_Activity">ba.Activity</a> that does not need custom types of its own.</p>
|
||||
@ -2192,13 +2196,13 @@ its time with lingering corpses, sound effects, etc.</p>
|
||||
<p><all methods inherited from <a href="#class_ba_Player">ba.Player</a>></p>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_EmptyTeam">ba.EmptyTeam</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_Team">ba.Team</a>, <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>Inherits from: <a href="#class_ba_Team">ba.Team</a>, <a href="https://docs.python.org/3/library/typing.html#typing.Generic">typing.Generic</a></p>
|
||||
<p>An empty player for use by Activities that don't need to define one.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
|
||||
|
||||
<p> <a href="#class_ba_Player">ba.Player</a> and <a href="#class_ba_Team">ba.Team</a> are 'Generic' types, and so passing them as
|
||||
type arguments when defining a <a href="#class_ba_Activity">ba.Activity</a> reduces type safety.
|
||||
<p> <a href="#class_ba_Player">ba.Player</a> and <a href="#class_ba_Team">ba.Team</a> are 'Generic' types, and so passing those top level
|
||||
classes as type arguments when defining a <a href="#class_ba_Activity">ba.Activity</a> reduces type safety.
|
||||
For example, activity.teams[0].player will have type 'Any' in that case.
|
||||
For that reason, it is better to pass EmptyPlayer and EmptyTeam when
|
||||
defining a <a href="#class_ba_Activity">ba.Activity</a> that does not need custom types of its own.</p>
|
||||
@ -2234,7 +2238,7 @@ its time with lingering corpses, sound effects, etc.</p>
|
||||
<p><all methods inherited from <a href="#class_ba_Team">ba.Team</a>></p>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_Existable">ba.Existable</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_typing_Protocol">typing.Protocol</a>, <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/typing.html#typing.Protocol">typing.Protocol</a>, <a href="https://docs.python.org/3/library/typing.html#typing.Generic">typing.Generic</a></p>
|
||||
<p>A Protocol for objects supporting an exists() method.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Protocols">Protocols</a>
|
||||
@ -2337,8 +2341,8 @@ its time with lingering corpses, sound effects, etc.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_GameActivity">ba.GameActivity</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a>, <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>Common base class for all game ba.Activities.</p>
|
||||
<p>Inherits from: <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a>, <a href="https://docs.python.org/3/library/typing.html#typing.Generic">typing.Generic</a></p>
|
||||
<p>Common base class for all game <a href="#class_ba_Activity">ba.Activities</a>.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a>
|
||||
</p>
|
||||
@ -2990,7 +2994,7 @@ prefs, etc.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_InputDeviceNotFoundError">ba.InputDeviceNotFoundError</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when an expected <a href="#class_ba_InputDevice">ba.InputDevice</a> does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
@ -3000,7 +3004,7 @@ prefs, etc.</p>
|
||||
<p><all methods inherited from <a href="#class_ba_NotFoundError">ba.NotFoundError</a>></p>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_InputType">ba.InputType</a></strong></h3>
|
||||
<p>Inherits from: enum.Enum</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/enum.html#enum.Enum">enum.Enum</a></p>
|
||||
<p>Types of input a controller can send to the game.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Enums">Enums</a></p>
|
||||
@ -4053,7 +4057,7 @@ signify that the default soundtrack should be used..</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_MusicPlayMode">ba.MusicPlayMode</a></strong></h3>
|
||||
<p>Inherits from: enum.Enum</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/enum.html#enum.Enum">enum.Enum</a></p>
|
||||
<p>Influences behavior when playing music.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Enums">Enums</a>
|
||||
@ -4156,7 +4160,7 @@ account what is supported locally.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_MusicType">ba.MusicType</a></strong></h3>
|
||||
<p>Inherits from: enum.Enum</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/enum.html#enum.Enum">enum.Enum</a></p>
|
||||
<p>Types of music available to play in-game.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Enums">Enums</a></p>
|
||||
@ -4368,7 +4372,7 @@ even if myactor is set to None.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_NodeNotFoundError">ba.NodeNotFoundError</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when an expected <a href="#class_ba_Node">ba.Node</a> does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
@ -4378,14 +4382,14 @@ even if myactor is set to None.</p>
|
||||
<p><all methods inherited from <a href="#class_ba_NotFoundError">ba.NotFoundError</a>></p>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_NotFoundError">ba.NotFoundError</a></strong></h3>
|
||||
<p>Inherits from: Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when a referenced object does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
</p>
|
||||
|
||||
<h3>Methods:</h3>
|
||||
<p><all methods inherited from <a href="#class_builtins_Exception">builtins.Exception</a>></p>
|
||||
<p><all methods inherited from <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>></p>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_OutOfBoundsMessage">ba.OutOfBoundsMessage</a></strong></h3>
|
||||
<p><em><top level class></em>
|
||||
@ -4404,7 +4408,7 @@ even if myactor is set to None.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_Permission">ba.Permission</a></strong></h3>
|
||||
<p>Inherits from: enum.Enum</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/enum.html#enum.Enum">enum.Enum</a></p>
|
||||
<p>Permissions that can be requested from the OS.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Enums">Enums</a>
|
||||
@ -4462,7 +4466,7 @@ even if myactor is set to None.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_Player">ba.Player</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/typing.html#typing.Generic">typing.Generic</a></p>
|
||||
<p>A player in a specific <a href="#class_ba_Activity">ba.Activity</a>.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
|
||||
@ -4657,7 +4661,7 @@ the type-checker properly identifies the returned value as one.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_PlayerNotFoundError">ba.PlayerNotFoundError</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when an expected <a href="#class_ba_Player">ba.Player</a> does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
@ -4944,7 +4948,7 @@ change this. Defaults to an empty string.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_ScoreType">ba.ScoreType</a></strong></h3>
|
||||
<p>Inherits from: enum.Enum</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/enum.html#enum.Enum">enum.Enum</a></p>
|
||||
<p>Type of scores.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Enums">Enums</a>
|
||||
@ -5010,7 +5014,7 @@ Pass 0 or a negative number for no ban time.</p>
|
||||
<h2><strong><a name="class_ba_Session">ba.Session</a></strong></h3>
|
||||
<p><em><top level class></em>
|
||||
</p>
|
||||
<p>Defines a high level series of activities with a common purpose.</p>
|
||||
<p>Defines a high level series of <a href="#class_ba_Activity">ba.Activities</a> with a common purpose.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
|
||||
|
||||
@ -5201,7 +5205,7 @@ session.setactivity(foo) and then <a href="#function_ba_newnode">ba.newnode</a>(
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_SessionNotFoundError">ba.SessionNotFoundError</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when an expected <a href="#class_ba_Session">ba.Session</a> does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
@ -5345,7 +5349,7 @@ other players.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_SessionPlayerNotFoundError">ba.SessionPlayerNotFoundError</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when an expected <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a> does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
@ -5411,7 +5415,7 @@ of the session.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_SessionTeamNotFoundError">ba.SessionTeamNotFoundError</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when an expected <a href="#class_ba_SessionTeam">ba.SessionTeam</a> does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
@ -5463,7 +5467,7 @@ of the session.</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_SpecialChar">ba.SpecialChar</a></strong></h3>
|
||||
<p>Inherits from: enum.Enum</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/enum.html#enum.Enum">enum.Enum</a></p>
|
||||
<p>Special characters the game can print.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Enums">Enums</a>
|
||||
@ -5680,7 +5684,7 @@ of the session.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_Team">ba.Team</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/typing.html#typing.Generic">typing.Generic</a></p>
|
||||
<p>A team in a specific <a href="#class_ba_Activity">ba.Activity</a>.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
|
||||
@ -5729,7 +5733,7 @@ of the session.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_TeamGameActivity">ba.TeamGameActivity</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_GameActivity">ba.GameActivity</a>, <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a>, <a href="#class_typing_Generic">typing.Generic</a></p>
|
||||
<p>Inherits from: <a href="#class_ba_GameActivity">ba.GameActivity</a>, <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a>, <a href="https://docs.python.org/3/library/typing.html#typing.Generic">typing.Generic</a></p>
|
||||
<p>Base class for teams and free-for-all mode games.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
|
||||
@ -5859,7 +5863,7 @@ False otherwise.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_TeamNotFoundError">ba.TeamNotFoundError</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when an expected <a href="#class_ba_Team">ba.Team</a> does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
@ -5895,7 +5899,7 @@ False otherwise.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_TimeFormat">ba.TimeFormat</a></strong></h3>
|
||||
<p>Inherits from: enum.Enum</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/enum.html#enum.Enum">enum.Enum</a></p>
|
||||
<p>Specifies the format time values are provided in.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Enums">Enums</a>
|
||||
@ -5927,7 +5931,7 @@ you should use the <a href="#function_ba_timer">ba.timer</a>() function instead.
|
||||
|
||||
<p>time: length of time (in seconds by default) that the timer will wait
|
||||
before firing. Note that the actual delay experienced may vary
|
||||
depending on the timetype. (see below)</p>
|
||||
depending on the timetype. (see below)</p>
|
||||
|
||||
<p>call: A callable Python object. Note that the timer will retain a
|
||||
strong reference to the callable for as long as it exists, so you
|
||||
@ -5937,28 +5941,11 @@ desired.</p>
|
||||
<p>repeat: if True, the timer will fire repeatedly, with each successive
|
||||
firing having the same delay as the first.</p>
|
||||
|
||||
<p>timetype can be either 'sim', 'base', or 'real'. It defaults to
|
||||
'sim'. Types are explained below:</p>
|
||||
<p>timetype: A <a href="#class_ba_TimeType">ba.TimeType</a> value determining which timeline the timer is
|
||||
placed onto.</p>
|
||||
|
||||
<p>'sim' time maps to local simulation time in <a href="#class_ba_Activity">ba.Activity</a> or <a href="#class_ba_Session">ba.Session</a>
|
||||
Contexts. This means that it may progress slower in slow-motion play
|
||||
modes, stop when the game is paused, etc. This time type is not
|
||||
available in UI contexts.</p>
|
||||
|
||||
<p>'base' time is also linked to gameplay in <a href="#class_ba_Activity">ba.Activity</a> or <a href="#class_ba_Session">ba.Session</a>
|
||||
Contexts, but it progresses at a constant rate regardless of
|
||||
slow-motion states or pausing. It can, however, slow down or stop
|
||||
in certain cases such as network outages or game slowdowns due to
|
||||
cpu load. Like 'sim' time, this is unavailable in UI contexts.</p>
|
||||
|
||||
<p>'real' time always maps to actual clock time with a bit of filtering
|
||||
added, regardless of Context. (the filtering prevents it from going
|
||||
backwards or jumping forward by large amounts due to the app being
|
||||
backgrounded, system time changing, etc.)
|
||||
Real time timers are currently only available in the UI context.</p>
|
||||
|
||||
<p>the 'timeformat' arg defaults to SECONDS but can also be MILLISECONDS
|
||||
if you want to pass time as milliseconds.</p>
|
||||
<p>timeformat: A <a href="#class_ba_TimeFormat">ba.TimeFormat</a> value determining how the passed time is
|
||||
interpreted.</p>
|
||||
|
||||
<pre><span><em><small># Example: use a Timer object to print repeatedly for a few seconds:</small></em></span>
|
||||
def say_it():
|
||||
@ -5966,14 +5953,14 @@ def say_it():
|
||||
def stop_saying_it():
|
||||
self.t = None
|
||||
<a href="#function_ba_screenmessage">ba.screenmessage</a>('MUSHROOM MUSHROOM!')
|
||||
<span><em><small># create our timer; it will run as long as we hold self.t</small></em></span>
|
||||
<span><em><small># Create our timer; it will run as long as we have the self.t ref.</small></em></span>
|
||||
self.t = <a href="#class_ba_Timer">ba.Timer</a>(0.3, say_it, repeat=True)
|
||||
<span><em><small># now fire off a one-shot timer to kill it</small></em></span>
|
||||
<span><em><small># Now fire off a one-shot timer to kill it.</small></em></span>
|
||||
<a href="#function_ba_timer">ba.timer</a>(3.89, stop_saying_it)</pre>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_TimeType">ba.TimeType</a></strong></h3>
|
||||
<p>Inherits from: enum.Enum</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/enum.html#enum.Enum">enum.Enum</a></p>
|
||||
<p>Specifies the type of time for various operations to target/use.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Enums">Enums</a></p>
|
||||
@ -6001,7 +5988,7 @@ self.t = <a href="#class_ba_Timer">ba.Timer</a>(0.3, say_it, repeat=True)
|
||||
<h2><strong><a name="class_ba_UIController">ba.UIController</a></strong></h3>
|
||||
<p><em><top level class></em>
|
||||
</p>
|
||||
<p>Wrangles UILocations.</p>
|
||||
<p>Wrangles ba.UILocations.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_User_Interface_Classes">User Interface Classes</a>
|
||||
</p>
|
||||
@ -6022,7 +6009,7 @@ self.t = <a href="#class_ba_Timer">ba.Timer</a>(0.3, say_it, repeat=True)
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_UIScale">ba.UIScale</a></strong></h3>
|
||||
<p>Inherits from: enum.Enum</p>
|
||||
<p>Inherits from: <a href="https://docs.python.org/3/library/enum.html#enum.Enum">enum.Enum</a></p>
|
||||
<p>The overall scale the UI is being rendered for. Note that this is
|
||||
independent of pixel resolution. For example, a phone and a desktop PC
|
||||
might render the game at similar pixel resolutions but the size they
|
||||
@ -6306,7 +6293,7 @@ widgets.</p>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_WidgetNotFoundError">ba.WidgetNotFoundError</a></strong></h3>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, Exception, BaseException</p>
|
||||
<p>Inherits from: <a href="#class_ba_NotFoundError">ba.NotFoundError</a>, <a href="https://docs.python.org/3/library/exceptions.html#Exception">Exception</a>, <a href="https://docs.python.org/3/library/exceptions.html#BaseException">BaseException</a></p>
|
||||
<p>Exception raised when an expected <a href="#class_ba_Widget">ba.Widget</a> does not exist.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Exception_Classes">Exception Classes</a>
|
||||
@ -6473,6 +6460,50 @@ them elsewhere will be meaningless.</p>
|
||||
a new one is created and returned. Arguments that are not set to None
|
||||
are applied to the Widget.</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_clipboard_get_text">ba.clipboard_get_text()</a></strong></h3>
|
||||
<p><span>clipboard_get_text() -> str</span></p>
|
||||
|
||||
<p>Return text currently on the system clipboard.</p>
|
||||
|
||||
<p>Category: <a href="#function_category_General_Utility_Functions">General Utility Functions</a></p>
|
||||
|
||||
<p>Ensure that <a href="#function_ba_clipboard_has_text">ba.clipboard_has_text</a>() returns True before calling
|
||||
this function.</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_clipboard_has_text">ba.clipboard_has_text()</a></strong></h3>
|
||||
<p><span>clipboard_has_text() -> bool</span></p>
|
||||
|
||||
<p>Return whether there is currently text on the clipboard.</p>
|
||||
|
||||
<p>Category: <a href="#function_category_General_Utility_Functions">General Utility Functions</a></p>
|
||||
|
||||
<p>This will return False if no system clipboard is available; no need
|
||||
to call ba.clipboard_available() separately.</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_clipboard_is_supported">ba.clipboard_is_supported()</a></strong></h3>
|
||||
<p><span>clipboard_is_supported() -> bool</span></p>
|
||||
|
||||
<p>Return whether this platform supports clipboard operations at all.</p>
|
||||
|
||||
<p>Category: <a href="#function_category_General_Utility_Functions">General Utility Functions</a></p>
|
||||
|
||||
<p>If this returns False, UIs should not show 'copy to clipboard'
|
||||
buttons, etc.</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_clipboard_set_text">ba.clipboard_set_text()</a></strong></h3>
|
||||
<p><span>clipboard_set_text(value: str) -> None</span></p>
|
||||
|
||||
<p>Copy a string to the system clipboard.</p>
|
||||
|
||||
<p>Category: <a href="#function_category_General_Utility_Functions">General Utility Functions</a></p>
|
||||
|
||||
<p>Ensure that ba.clipboard_available() returns True before adding
|
||||
buttons/etc. that make use of this functionality.</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_columnwidget">ba.columnwidget()</a></strong></h3>
|
||||
<p><span>columnwidget(edit: <a href="#class_ba_Widget">ba.Widget</a> = None,
|
||||
@ -6582,17 +6613,19 @@ settings, exiting element counts, or other factors.</p>
|
||||
<h2><strong><a name="function_ba_existing">ba.existing()</a></strong></h3>
|
||||
<p><span>existing(obj: Optional[ExistableType]) -> Optional[ExistableType]</span></p>
|
||||
|
||||
<p>Convert invalid references to None for any <a href="#class_ba_Existable">ba.Existable</a> type.</p>
|
||||
<p>Convert invalid references to None for any <a href="#class_ba_Existable">ba.Existable</a> object.</p>
|
||||
|
||||
<p>Category: <a href="#function_category_Gameplay_Functions">Gameplay Functions</a></p>
|
||||
|
||||
<p>To best support type checking, it is important that invalid references
|
||||
not be passed around and instead get converted to values of None.
|
||||
That way the type checker can properly flag attempts to pass dead
|
||||
objects into functions expecting only live ones, etc.
|
||||
This call can be used on any 'existable' object (one with an exists()
|
||||
method) and will convert it to a None value if it does not exist.
|
||||
For more info, see notes on 'existables' here:
|
||||
objects (Optional[FooType]) into functions expecting only live ones
|
||||
(FooType), etc. This call can be used on any 'existable' object
|
||||
(one with an exists() method) and will convert it to a None value
|
||||
if it does not exist.</p>
|
||||
|
||||
<p>For more info, see notes on 'existables' here:
|
||||
https://ballistica.net/wiki/Coding-Style-Guide</p>
|
||||
|
||||
<hr>
|
||||
@ -6989,14 +7022,14 @@ app running.</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_rowwidget">ba.rowwidget()</a></strong></h3>
|
||||
<p><span>rowwidget(edit: Widget = None, parent: Widget = None,
|
||||
<p><span>rowwidget(edit: <a href="#class_ba_Widget">ba.Widget</a> = None, parent: <a href="#class_ba_Widget">ba.Widget</a> = None,
|
||||
size: Sequence[float] = None,
|
||||
position: Sequence[float] = None,
|
||||
background: bool = None, selected_child: Widget = None,
|
||||
visible_child: Widget = None,
|
||||
background: bool = None, selected_child: <a href="#class_ba_Widget">ba.Widget</a> = None,
|
||||
visible_child: <a href="#class_ba_Widget">ba.Widget</a> = None,
|
||||
claims_left_right: bool = None,
|
||||
claims_tab: bool = None,
|
||||
selection_loops_to_parent: bool = None) -> Widget</span></p>
|
||||
selection_loops_to_parent: bool = None) -> <a href="#class_ba_Widget">ba.Widget</a></span></p>
|
||||
|
||||
<p>Create or edit a row widget.</p>
|
||||
|
||||
@ -7076,9 +7109,9 @@ are applied to the Widget.</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_setmusic">ba.setmusic()</a></strong></h3>
|
||||
<p><span>setmusic(musictype: Optional[MusicType], continuous: bool = False) -> None</span></p>
|
||||
<p><span>setmusic(musictype: Optional[<a href="#class_ba_MusicType">ba.MusicType</a>], continuous: bool = False) -> None</span></p>
|
||||
|
||||
<p>Tell the game to play (or stop playing) a certain type of music.</p>
|
||||
<p>Set the app to play (or stop playing) a certain type of music.</p>
|
||||
|
||||
<p>Category: <a href="#function_category_Gameplay_Functions">Gameplay Functions</a></p>
|
||||
|
||||
@ -7103,15 +7136,17 @@ playing, the playing track will not be restarted.</p>
|
||||
<h2><strong><a name="function_ba_storagename">ba.storagename()</a></strong></h3>
|
||||
<p><span>storagename(suffix: str = None) -> str</span></p>
|
||||
|
||||
<p>Generate a (hopefully) unique name for storing things in public places.</p>
|
||||
<p>Generate a unique name for storing class data in shared places.</p>
|
||||
|
||||
<p>Category: <a href="#function_category_General_Utility_Functions">General Utility Functions</a></p>
|
||||
|
||||
<p>This consists of a leading underscore, the module path at the
|
||||
call site with dots replaced by underscores, the class name, and
|
||||
the provided suffix. When storing data in public places such as
|
||||
'customdata' dicts, this minimizes the chance of collisions if a
|
||||
module or class is duplicated or renamed.</p>
|
||||
call site with dots replaced by underscores, the containing class's
|
||||
qualified name, and the provided suffix. When storing data in public
|
||||
places such as 'customdata' dicts, this minimizes the chance of
|
||||
collisions with other similarly named classes.</p>
|
||||
|
||||
<p>Note that this will function even if called in the class definition.</p>
|
||||
|
||||
<pre><span><em><small># Example: generate a unique name for storage purposes:</small></em></span>
|
||||
class MyThingie:</pre>
|
||||
@ -7119,22 +7154,22 @@ class MyThingie:</pre>
|
||||
<pre><span><em><small> # This will give something like '_mymodule_submodule_mythingie_data'.</small></em></span>
|
||||
_STORENAME = <a href="#function_ba_storagename">ba.storagename</a>('data')</pre>
|
||||
|
||||
<p> def __init__(self, activity):
|
||||
# Store some data in the Activity we were passed
|
||||
activity.customdata[self._STORENAME] = {}</p>
|
||||
<pre><span><em><small> # Use that name to store some data in the Activity we were passed.</small></em></span>
|
||||
def __init__(self, activity):
|
||||
activity.customdata[self._STORENAME] = {}</pre>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_textwidget">ba.textwidget()</a></strong></h3>
|
||||
<p><span>textwidget(edit: Widget = None, parent: Widget = None,
|
||||
<p><span>textwidget(edit: <a href="#class_ba_Widget">ba.Widget</a> = None, parent: <a href="#class_ba_Widget">ba.Widget</a> = None,
|
||||
size: Sequence[float] = None, position: Sequence[float] = None,
|
||||
text: Union[str, <a href="#class_ba_Lstr">ba.Lstr</a>] = None, v_align: str = None,
|
||||
h_align: str = None, editable: bool = None, padding: float = None,
|
||||
on_return_press_call: Callable[[], None] = None,
|
||||
on_activate_call: Callable[[], None] = None,
|
||||
selectable: bool = None, query: Widget = None, max_chars: int = None,
|
||||
selectable: bool = None, query: <a href="#class_ba_Widget">ba.Widget</a> = None, max_chars: int = None,
|
||||
color: Sequence[float] = None, click_activate: bool = None,
|
||||
on_select_call: Callable[[], None] = None,
|
||||
always_highlight: bool = None, draw_controller: Widget = None,
|
||||
always_highlight: bool = None, draw_controller: <a href="#class_ba_Widget">ba.Widget</a> = None,
|
||||
scale: float = None, corner_scale: float = None,
|
||||
description: Union[str, <a href="#class_ba_Lstr">ba.Lstr</a>] = None,
|
||||
transition_delay: float = None, maxwidth: float = None,
|
||||
|
||||
@ -21,8 +21,8 @@
|
||||
namespace ballistica {
|
||||
|
||||
// These are set automatically via script; don't change here.
|
||||
const int kAppBuildNumber = 20268;
|
||||
const char* kAppVersion = "1.5.30";
|
||||
const int kAppBuildNumber = 20279;
|
||||
const char* kAppVersion = "1.6.0";
|
||||
|
||||
// Our standalone globals.
|
||||
// These are separated out for easy access.
|
||||
|
||||
@ -263,9 +263,6 @@ class Graphics {
|
||||
internal_components_inited_ = val;
|
||||
}
|
||||
auto set_gyro_vals(const Vector3f& vals) -> void { gyro_vals_ = vals; }
|
||||
// auto draw_overlay_bounds() const -> bool { return draw_overlay_bounds_; }
|
||||
// auto set_draw_overlay_bounds(bool val) -> void { draw_overlay_bounds_ =
|
||||
// val; }
|
||||
auto show_net_info() const -> bool { return show_net_info_; }
|
||||
auto set_show_net_info(bool val) -> void { show_net_info_ = val; }
|
||||
auto debug_graph_1() const -> NetGraph* { return debug_graph_1_.get(); }
|
||||
|
||||
@ -286,8 +286,8 @@ void GraphicsServer::SetScreen(bool fullscreen, int width, int height,
|
||||
// we request fullscreen-windows for full-screen situations and that's it.
|
||||
// (otherwise we may wind up with huge windows due to passing in desktop
|
||||
// resolutions and retina wonkiness)
|
||||
width = 800;
|
||||
height = 600;
|
||||
width = static_cast<int>(kBaseVirtualResX * 0.8f);
|
||||
height = static_cast<int>(kBaseVirtualResY * 0.8f);
|
||||
|
||||
// We should never have to recreate the context after the initial time on
|
||||
// our modern builds.
|
||||
|
||||
@ -1209,13 +1209,24 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
||||
if (!repeat_press && keysym->sym == SDLK_q
|
||||
&& ((keysym->mod & KMOD_CTRL) || (keysym->mod & KMOD_GUI))) { // NOLINT
|
||||
g_game->PushConfirmQuitCall();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Let the console intercept stuff if it wants at this point.
|
||||
if (g_app_globals->console != nullptr
|
||||
&& g_app_globals->console->HandleKeyPress(keysym)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl-V or Cmd-V sends paste commands to any interested text fields.
|
||||
// Command-Q or Control-Q quits.
|
||||
if (!repeat_press && keysym->sym == SDLK_v
|
||||
&& ((keysym->mod & KMOD_CTRL) || (keysym->mod & KMOD_GUI))) { // NOLINT
|
||||
g_ui->SendWidgetMessage(WidgetMessage(WidgetMessage::Type::kPaste));
|
||||
return;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
|
||||
// None of the following stuff accepts key repeats.
|
||||
|
||||
@ -1361,4 +1361,88 @@ auto Platform::GetCurrentSeconds() -> int64_t {
|
||||
.count();
|
||||
}
|
||||
|
||||
auto Platform::ClipboardIsSupported() -> bool {
|
||||
// We only call our actual virtual function once.
|
||||
if (!have_clipboard_is_supported_) {
|
||||
clipboard_is_supported_ = DoClipboardIsSupported();
|
||||
have_clipboard_is_supported_ = true;
|
||||
}
|
||||
return clipboard_is_supported_;
|
||||
}
|
||||
|
||||
auto Platform::ClipboardHasText() -> bool {
|
||||
// If subplatform says they don't support clipboards, don't even ask.
|
||||
if (!ClipboardIsSupported()) {
|
||||
return false;
|
||||
}
|
||||
return DoClipboardHasText();
|
||||
}
|
||||
|
||||
auto Platform::ClipboardSetText(const std::string& text) -> void {
|
||||
// If subplatform says they don't support clipboards, this is an error.
|
||||
if (!ClipboardIsSupported()) {
|
||||
throw Exception("ClipboardSetText called with no clipboard support.",
|
||||
PyExcType::kRuntime);
|
||||
}
|
||||
DoClipboardSetText(text);
|
||||
}
|
||||
|
||||
auto Platform::ClipboardGetText() -> std::string {
|
||||
// If subplatform says they don't support clipboards, this is an error.
|
||||
if (!ClipboardIsSupported()) {
|
||||
throw Exception("ClipboardGetText called with no clipboard support.",
|
||||
PyExcType::kRuntime);
|
||||
}
|
||||
return DoClipboardGetText();
|
||||
}
|
||||
|
||||
auto Platform::DoClipboardIsSupported() -> bool {
|
||||
// Go through SDL functionality on SDL based platforms;
|
||||
// otherwise default to no clipboard.
|
||||
#if BA_SDL2_BUILD && !BA_OSTYPE_IOS_TVOS
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
auto Platform::DoClipboardHasText() -> bool {
|
||||
// Go through SDL functionality on SDL based platforms;
|
||||
// otherwise default to no clipboard.
|
||||
#if BA_SDL2_BUILD && !BA_OSTYPE_IOS_TVOS
|
||||
return SDL_HasClipboardText();
|
||||
#else
|
||||
// Shouldn't get here since we default to no clipboard support.
|
||||
FatalError("Shouldn't get here.");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
auto Platform::DoClipboardSetText(const std::string& text) -> void {
|
||||
// Go through SDL functionality on SDL based platforms;
|
||||
// otherwise default to no clipboard.
|
||||
#if BA_SDL2_BUILD && !BA_OSTYPE_IOS_TVOS
|
||||
SDL_SetClipboardText(text.c_str());
|
||||
#else
|
||||
// Shouldn't get here since we default to no clipboard support.
|
||||
FatalError("Shouldn't get here.");
|
||||
#endif
|
||||
}
|
||||
|
||||
auto Platform::DoClipboardGetText() -> std::string {
|
||||
// Go through SDL functionality on SDL based platforms;
|
||||
// otherwise default to no clipboard.
|
||||
#if BA_SDL2_BUILD && !BA_OSTYPE_IOS_TVOS
|
||||
char* out = SDL_GetClipboardText();
|
||||
if (out == nullptr) {
|
||||
throw Exception("Error fetching clipboard contents.", PyExcType::kRuntime);
|
||||
}
|
||||
return out;
|
||||
#else
|
||||
// Shouldn't get here since we default to no clipboard support.
|
||||
FatalError("Shouldn't get here.");
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace ballistica
|
||||
|
||||
@ -103,7 +103,25 @@ class Platform {
|
||||
virtual auto GetCWD() -> std::string;
|
||||
|
||||
// Unlink a file.
|
||||
virtual void Unlink(const char* path);
|
||||
virtual auto Unlink(const char* path) -> void;
|
||||
|
||||
#pragma mark CLIPBOARD ---------------------------------------------------------
|
||||
|
||||
/// Return whether clipboard operations are supported at all.
|
||||
/// This gets called when determining whether to display clipboard related
|
||||
/// UI elements/etc.
|
||||
auto ClipboardIsSupported() -> bool;
|
||||
|
||||
/// Return whether there is currently text on the clipboard.
|
||||
auto ClipboardHasText() -> bool;
|
||||
|
||||
/// Set current clipboard text. Raises an Exception if clipboard is
|
||||
/// unsupported.
|
||||
auto ClipboardSetText(const std::string& text) -> void;
|
||||
|
||||
/// Return current text from the clipboard. Raises an Exception if
|
||||
/// clipboard is unsupported or if there's no text on the clipboard.
|
||||
auto ClipboardGetText() -> std::string;
|
||||
|
||||
#pragma mark PRINTING/LOGGING --------------------------------------------------
|
||||
|
||||
@ -493,6 +511,11 @@ class Platform {
|
||||
// Generate a random UUID string.
|
||||
virtual auto GenerateUUID() -> std::string;
|
||||
|
||||
virtual auto DoClipboardIsSupported() -> bool;
|
||||
virtual auto DoClipboardHasText() -> bool;
|
||||
virtual auto DoClipboardSetText(const std::string& text) -> void;
|
||||
virtual auto DoClipboardGetText() -> std::string;
|
||||
|
||||
private:
|
||||
int py_call_num_{};
|
||||
bool using_custom_app_python_dir_{};
|
||||
@ -500,6 +523,8 @@ class Platform {
|
||||
bool have_has_touchscreen_value_{};
|
||||
bool have_touchscreen_{};
|
||||
bool is_tegra_k1_{};
|
||||
bool have_clipboard_is_supported_{};
|
||||
bool clipboard_is_supported_{};
|
||||
millisecs_t starttime_{};
|
||||
std::string device_uuid_;
|
||||
bool have_device_uuid_{};
|
||||
|
||||
@ -32,7 +32,7 @@ void PythonClassTimer::SetupType(PyTypeObject* obj) {
|
||||
"you should use the ba.timer() function instead.\n"
|
||||
"\n"
|
||||
"time: length of time (in seconds by default) that the timer will wait\n"
|
||||
"before firing. Note that the actual delay experienced may vary\n "
|
||||
"before firing. Note that the actual delay experienced may vary\n"
|
||||
"depending on the timetype. (see below)\n"
|
||||
"\n"
|
||||
"call: A callable Python object. Note that the timer will retain a\n"
|
||||
@ -43,28 +43,11 @@ void PythonClassTimer::SetupType(PyTypeObject* obj) {
|
||||
"repeat: if True, the timer will fire repeatedly, with each successive\n"
|
||||
"firing having the same delay as the first.\n"
|
||||
"\n"
|
||||
"timetype can be either 'sim', 'base', or 'real'. It defaults to\n"
|
||||
"'sim'. Types are explained below:\n"
|
||||
"timetype: A ba.TimeType value determining which timeline the timer is\n"
|
||||
"placed onto.\n"
|
||||
"\n"
|
||||
"'sim' time maps to local simulation time in ba.Activity or ba.Session\n"
|
||||
"Contexts. This means that it may progress slower in slow-motion play\n"
|
||||
"modes, stop when the game is paused, etc. This time type is not\n"
|
||||
"available in UI contexts.\n"
|
||||
"\n"
|
||||
"'base' time is also linked to gameplay in ba.Activity or ba.Session\n"
|
||||
"Contexts, but it progresses at a constant rate regardless of\n "
|
||||
"slow-motion states or pausing. It can, however, slow down or stop\n"
|
||||
"in certain cases such as network outages or game slowdowns due to\n"
|
||||
"cpu load. Like 'sim' time, this is unavailable in UI contexts.\n"
|
||||
"\n"
|
||||
"'real' time always maps to actual clock time with a bit of filtering\n"
|
||||
"added, regardless of Context. (the filtering prevents it from going\n"
|
||||
"backwards or jumping forward by large amounts due to the app being\n"
|
||||
"backgrounded, system time changing, etc.)\n"
|
||||
"Real time timers are currently only available in the UI context.\n"
|
||||
"\n"
|
||||
"the 'timeformat' arg defaults to SECONDS but can also be MILLISECONDS\n"
|
||||
"if you want to pass time as milliseconds.\n"
|
||||
"timeformat: A ba.TimeFormat value determining how the passed time is\n"
|
||||
"interpreted.\n"
|
||||
"\n"
|
||||
"# Example: use a Timer object to print repeatedly for a few seconds:\n"
|
||||
"def say_it():\n"
|
||||
@ -72,9 +55,9 @@ void PythonClassTimer::SetupType(PyTypeObject* obj) {
|
||||
"def stop_saying_it():\n"
|
||||
" self.t = None\n"
|
||||
" ba.screenmessage('MUSHROOM MUSHROOM!')\n"
|
||||
"# create our timer; it will run as long as we hold self.t\n"
|
||||
"# Create our timer; it will run as long as we have the self.t ref.\n"
|
||||
"self.t = ba.Timer(0.3, say_it, repeat=True)\n"
|
||||
"# now fire off a one-shot timer to kill it\n"
|
||||
"# Now fire off a one-shot timer to kill it.\n"
|
||||
"ba.timer(3.89, stop_saying_it)";
|
||||
obj->tp_new = tp_new;
|
||||
obj->tp_dealloc = (destructor)tp_dealloc;
|
||||
|
||||
@ -16,4 +16,5 @@ class PythonMethodsApp {
|
||||
};
|
||||
|
||||
} // namespace ballistica
|
||||
|
||||
#endif // BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_APP_H_
|
||||
|
||||
@ -16,4 +16,5 @@ class PythonMethodsGameplay {
|
||||
};
|
||||
|
||||
} // namespace ballistica
|
||||
|
||||
#endif // BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_GAMEPLAY_H_
|
||||
|
||||
@ -16,4 +16,5 @@ class PythonMethodsGraphics {
|
||||
};
|
||||
|
||||
} // namespace ballistica
|
||||
|
||||
#endif // BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_GRAPHICS_H_
|
||||
|
||||
@ -32,6 +32,46 @@ namespace ballistica {
|
||||
#pragma ide diagnostic ignored "hicpp-signed-bitwise"
|
||||
#pragma ide diagnostic ignored "RedundantCast"
|
||||
|
||||
auto PyClipboardIsSupported(PyObject* self) -> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
if (g_platform->ClipboardIsSupported()) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
Py_RETURN_FALSE;
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
auto PyClipboardHasText(PyObject* self) -> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
if (g_platform->ClipboardHasText()) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
Py_RETURN_FALSE;
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
auto PyClipboardSetText(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
-> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
Platform::SetLastPyCall("clipboard_set_text");
|
||||
const char* value;
|
||||
static const char* kwlist[] = {"value", nullptr};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "s",
|
||||
const_cast<char**>(kwlist), &value)) {
|
||||
return nullptr;
|
||||
}
|
||||
g_platform->ClipboardSetText(value);
|
||||
Py_RETURN_NONE;
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
auto PyClipboardGetText(PyObject* self) -> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
return PyUnicode_FromString(g_platform->ClipboardGetText().c_str());
|
||||
Py_RETURN_FALSE;
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
auto PyIsRunningOnOuya(PyObject* self, PyObject* args) -> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
Platform::SetLastPyCall("is_running_on_ouya");
|
||||
@ -743,6 +783,44 @@ auto PyApp(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* {
|
||||
|
||||
auto PythonMethodsSystem::GetMethods() -> std::vector<PyMethodDef> {
|
||||
return {
|
||||
{"clipboard_is_supported", (PyCFunction)PyClipboardIsSupported,
|
||||
METH_NOARGS,
|
||||
"clipboard_is_supported() -> bool\n"
|
||||
"\n"
|
||||
"Return whether this platform supports clipboard operations at all.\n"
|
||||
"\n"
|
||||
"Category: General Utility Functions\n"
|
||||
"\n"
|
||||
"If this returns False, UIs should not show 'copy to clipboard'\n"
|
||||
"buttons, etc."},
|
||||
{"clipboard_has_text", (PyCFunction)PyClipboardHasText, METH_NOARGS,
|
||||
"clipboard_has_text() -> bool\n"
|
||||
"\n"
|
||||
"Return whether there is currently text on the clipboard.\n"
|
||||
"\n"
|
||||
"Category: General Utility Functions\n"
|
||||
"\n"
|
||||
"This will return False if no system clipboard is available; no need\n"
|
||||
" to call ba.clipboard_available() separately."},
|
||||
{"clipboard_set_text", (PyCFunction)PyClipboardSetText,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
"clipboard_set_text(value: str) -> None\n"
|
||||
"\n"
|
||||
"Copy a string to the system clipboard.\n"
|
||||
"\n"
|
||||
"Category: General Utility Functions\n"
|
||||
"\n"
|
||||
"Ensure that ba.clipboard_available() returns True before adding\n"
|
||||
" buttons/etc. that make use of this functionality."},
|
||||
{"clipboard_get_text", (PyCFunction)PyClipboardGetText, METH_NOARGS,
|
||||
"clipboard_get_text() -> str\n"
|
||||
"\n"
|
||||
"Return text currently on the system clipboard.\n"
|
||||
"\n"
|
||||
"Category: General Utility Functions\n"
|
||||
"\n"
|
||||
"Ensure that ba.clipboard_has_text() returns True before calling\n"
|
||||
" this function."},
|
||||
{"printobjects", (PyCFunction)PyPrintObjects,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
"printobjects() -> None\n"
|
||||
|
||||
@ -2636,14 +2636,14 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
|
||||
"are applied to the Widget."},
|
||||
|
||||
{"rowwidget", (PyCFunction)PyRowWidget, METH_VARARGS | METH_KEYWORDS,
|
||||
"rowwidget(edit: Widget = None, parent: Widget = None,\n"
|
||||
"rowwidget(edit: ba.Widget = None, parent: ba.Widget = None,\n"
|
||||
" size: Sequence[float] = None,\n"
|
||||
" position: Sequence[float] = None,\n"
|
||||
" background: bool = None, selected_child: Widget = None,\n"
|
||||
" visible_child: Widget = None,\n"
|
||||
" background: bool = None, selected_child: ba.Widget = None,\n"
|
||||
" visible_child: ba.Widget = None,\n"
|
||||
" claims_left_right: bool = None,\n"
|
||||
" claims_tab: bool = None,\n"
|
||||
" selection_loops_to_parent: bool = None) -> Widget\n"
|
||||
" selection_loops_to_parent: bool = None) -> ba.Widget\n"
|
||||
"\n"
|
||||
"Create or edit a row widget.\n"
|
||||
"\n"
|
||||
@ -2699,17 +2699,17 @@ auto PythonMethodsUI::GetMethods() -> std::vector<PyMethodDef> {
|
||||
"are applied to the Widget."},
|
||||
|
||||
{"textwidget", (PyCFunction)PyTextWidget, METH_VARARGS | METH_KEYWORDS,
|
||||
"textwidget(edit: Widget = None, parent: Widget = None,\n"
|
||||
"textwidget(edit: ba.Widget = None, parent: ba.Widget = None,\n"
|
||||
" size: Sequence[float] = None, position: Sequence[float] = None,\n"
|
||||
" text: Union[str, ba.Lstr] = None, v_align: str = None,\n"
|
||||
" h_align: str = None, editable: bool = None, padding: float = None,\n"
|
||||
" on_return_press_call: Callable[[], None] = None,\n"
|
||||
" on_activate_call: Callable[[], None] = None,\n"
|
||||
" selectable: bool = None, query: Widget = None, max_chars: int = "
|
||||
" selectable: bool = None, query: ba.Widget = None, max_chars: int = "
|
||||
"None,\n"
|
||||
" color: Sequence[float] = None, click_activate: bool = None,\n"
|
||||
" on_select_call: Callable[[], None] = None,\n"
|
||||
" always_highlight: bool = None, draw_controller: Widget = None,\n"
|
||||
" always_highlight: bool = None, draw_controller: ba.Widget = None,\n"
|
||||
" scale: float = None, corner_scale: float = None,\n"
|
||||
" description: Union[str, ba.Lstr] = None,\n"
|
||||
" transition_delay: float = None, maxwidth: float = None,\n"
|
||||
|
||||
@ -29,7 +29,7 @@ UI::UI() {
|
||||
assert(g_platform);
|
||||
|
||||
// Allow overriding via an environment variable.
|
||||
auto* ui_override = getenv("BA_FORCE_UI_SCALE");
|
||||
auto* ui_override = getenv("BA_UI_SCALE");
|
||||
bool force_test_small{};
|
||||
bool force_test_medium{};
|
||||
bool force_test_large{};
|
||||
|
||||
@ -296,6 +296,7 @@ auto ContainerWidget::HandleMessage(const WidgetMessage& m) -> bool {
|
||||
switch (m.type) {
|
||||
case WidgetMessage::Type::kTextInput:
|
||||
case WidgetMessage::Type::kKey:
|
||||
case WidgetMessage::Type::kPaste:
|
||||
if (selected_widget_) {
|
||||
bool val = selected_widget_->HandleMessage(m);
|
||||
if (val != 0) {
|
||||
@ -1218,8 +1219,7 @@ void ContainerWidget::SetTransition(TransitionType t) {
|
||||
// stack, update the toolbar for the new topmost input-accepting window
|
||||
// *immediately* (otherwise we'd have to wait for our transition to complete
|
||||
// before the toolbar switches).
|
||||
if (transitioning_ && transitioning_out_ && parent != nullptr
|
||||
&& parent->is_main_window_stack_) {
|
||||
if (transitioning_ && transitioning_out_ && parent->is_main_window_stack_) {
|
||||
g_ui->root_widget()->UpdateForFocusedWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,8 +116,8 @@ void TextWidget::Draw(RenderPass* pass, bool draw_transparent) {
|
||||
|
||||
// Center-scale.
|
||||
{
|
||||
// We should really be scaling our bounds and things, but for now lets just
|
||||
// do a hacky overall scale.
|
||||
// We should really be scaling our bounds and things,
|
||||
// but for now lets just do a hacky overall scale.
|
||||
EmptyComponent c(pass);
|
||||
c.SetTransparent(true);
|
||||
c.PushTransform();
|
||||
@ -178,6 +178,7 @@ void TextWidget::Draw(RenderPass* pass, bool draw_transparent) {
|
||||
highlight_center_y_ = b2 - b_border + highlight_height_ * 0.5f;
|
||||
highlight_dirty_ = false;
|
||||
}
|
||||
|
||||
SimpleComponent c(pass);
|
||||
c.SetTransparent(true);
|
||||
c.SetPremultiplied(true);
|
||||
@ -596,6 +597,16 @@ auto TextWidget::HandleMessage(const WidgetMessage& m) -> bool {
|
||||
bottom_overlap = 3.0f * extra_touch_border_scale_;
|
||||
}
|
||||
|
||||
// If we're doing inline editing, handle clipboard paste.
|
||||
if (editable() && !ShouldUseStringEditDialog()
|
||||
&& m.type == WidgetMessage::Type::kPaste) {
|
||||
if (g_platform->ClipboardIsSupported()) {
|
||||
if (g_platform->ClipboardHasText()) {
|
||||
// Just enter it char by char as if we had typed it...
|
||||
AddCharsToText(g_platform->ClipboardGetText());
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we're doing inline editing, handle some key events.
|
||||
if (m.has_keysym && !ShouldUseStringEditDialog()) {
|
||||
last_carat_change_time_ = g_game->master_time();
|
||||
@ -769,22 +780,7 @@ auto TextWidget::HandleMessage(const WidgetMessage& m) -> bool {
|
||||
} else {
|
||||
// Otherwise apply the text directly.
|
||||
if (editable() && m.sval != nullptr) {
|
||||
std::vector<uint32_t> unichars =
|
||||
Utils::UnicodeFromUTF8(text_raw_, "jcjwf8f");
|
||||
int len = static_cast<int>(unichars.size());
|
||||
std::vector<uint32_t> sval =
|
||||
Utils::UnicodeFromUTF8(*m.sval, "j4958fbv");
|
||||
for (unsigned int i : sval) {
|
||||
if (len < max_chars_) {
|
||||
text_group_dirty_ = true;
|
||||
if (carat_position_ > len) carat_position_ = len;
|
||||
unichars.insert(unichars.begin() + carat_position_, i);
|
||||
len++;
|
||||
carat_position_++;
|
||||
}
|
||||
}
|
||||
text_raw_ = Utils::UTF8FromUnicode(unichars);
|
||||
text_translation_dirty_ = true;
|
||||
AddCharsToText(*m.sval);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -794,8 +790,8 @@ auto TextWidget::HandleMessage(const WidgetMessage& m) -> bool {
|
||||
if (!IsSelectable()) {
|
||||
return false;
|
||||
}
|
||||
float x = m.fval1;
|
||||
float y = m.fval2;
|
||||
float x{ScaleAdjustedX(m.fval1)};
|
||||
float y{ScaleAdjustedY(m.fval2)};
|
||||
bool claimed = (m.fval3 > 0.0f);
|
||||
if (claimed) {
|
||||
mouse_over_ = clear_mouse_over_ = false;
|
||||
@ -813,8 +809,9 @@ auto TextWidget::HandleMessage(const WidgetMessage& m) -> bool {
|
||||
if (!IsSelectable()) {
|
||||
return false;
|
||||
}
|
||||
float x = m.fval1;
|
||||
float y = m.fval2;
|
||||
float x{ScaleAdjustedX(m.fval1)};
|
||||
float y{ScaleAdjustedY(m.fval2)};
|
||||
|
||||
auto click_count = static_cast<int>(m.fval3);
|
||||
|
||||
// See if a click is in our clear button.
|
||||
@ -856,8 +853,8 @@ auto TextWidget::HandleMessage(const WidgetMessage& m) -> bool {
|
||||
}
|
||||
}
|
||||
case WidgetMessage::Type::kMouseUp: {
|
||||
float x = m.fval1;
|
||||
float y = m.fval2;
|
||||
float x{ScaleAdjustedX(m.fval1)};
|
||||
float y{ScaleAdjustedY(m.fval2)};
|
||||
bool claimed = (m.fval3 > 0.0f);
|
||||
|
||||
if (clear_pressed_ && !claimed && editable()
|
||||
@ -903,6 +900,38 @@ auto TextWidget::HandleMessage(const WidgetMessage& m) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto TextWidget::ScaleAdjustedX(float x) -> float {
|
||||
// Account for our center_scale_ value.
|
||||
float offsx = x - width_ * 0.5f;
|
||||
return width_ * 0.5f + offsx / center_scale_;
|
||||
}
|
||||
|
||||
auto TextWidget::ScaleAdjustedY(float y) -> float {
|
||||
// Account for our center_scale_ value.
|
||||
float offsy = y - height_ * 0.5f;
|
||||
return height_ * 0.5f + offsy / center_scale_;
|
||||
}
|
||||
|
||||
auto TextWidget::AddCharsToText(const std::string& addchars) -> void {
|
||||
assert(editable());
|
||||
std::vector<uint32_t> unichars = Utils::UnicodeFromUTF8(text_raw_, "jcjwf8f");
|
||||
int len = static_cast<int>(unichars.size());
|
||||
std::vector<uint32_t> sval = Utils::UnicodeFromUTF8(addchars, "j4958fbv");
|
||||
for (unsigned int i : sval) {
|
||||
if (len < max_chars_) {
|
||||
text_group_dirty_ = true;
|
||||
if (carat_position_ > len) {
|
||||
carat_position_ = len;
|
||||
}
|
||||
unichars.insert(unichars.begin() + carat_position_, i);
|
||||
len++;
|
||||
carat_position_++;
|
||||
}
|
||||
}
|
||||
text_raw_ = Utils::UTF8FromUnicode(unichars);
|
||||
text_translation_dirty_ = true;
|
||||
}
|
||||
|
||||
void TextWidget::UpdateTranslation() {
|
||||
// Apply subs/resources to get our actual text if need be.
|
||||
if (text_translation_dirty_) {
|
||||
|
||||
@ -89,6 +89,9 @@ class TextWidget : public Widget {
|
||||
}
|
||||
|
||||
private:
|
||||
auto ScaleAdjustedX(float x) -> float;
|
||||
auto ScaleAdjustedY(float y) -> float;
|
||||
auto AddCharsToText(const std::string& addchars) -> void;
|
||||
auto ShouldUseStringEditDialog() const -> bool;
|
||||
void BringUpEditDialog();
|
||||
void UpdateTranslation();
|
||||
|
||||
@ -37,7 +37,8 @@ struct WidgetMessage {
|
||||
kMouseWheelVelocityH,
|
||||
kMouseMove,
|
||||
kScrollMouseDown,
|
||||
kTextInput
|
||||
kTextInput,
|
||||
kPaste
|
||||
};
|
||||
|
||||
Type type{};
|
||||
|
||||
@ -30,10 +30,10 @@ class PipRequirement:
|
||||
|
||||
PIP_REQUIREMENTS = [
|
||||
PipRequirement(modulename='pylint', minversion=[2, 6, 0]),
|
||||
PipRequirement(modulename='mypy', minversion=[0, 790]),
|
||||
PipRequirement(modulename='mypy', minversion=[0, 800]),
|
||||
PipRequirement(modulename='yapf', minversion=[0, 30, 0]),
|
||||
PipRequirement(modulename='cpplint', minversion=[1, 5, 4]),
|
||||
PipRequirement(modulename='pytest', minversion=[6, 1, 2]),
|
||||
PipRequirement(modulename='pytest', minversion=[6, 2, 1]),
|
||||
PipRequirement(modulename='typing_extensions'),
|
||||
PipRequirement(modulename='pytz'),
|
||||
PipRequirement(modulename='ansiwrap'),
|
||||
|
||||
@ -112,7 +112,7 @@ def _windows_enable_color() -> bool:
|
||||
# open CONOUT$ instead
|
||||
fdout = os.open('CONOUT$', os.O_RDWR)
|
||||
try:
|
||||
hout = msvcrt.get_osfhandle(fdout)
|
||||
hout = msvcrt.get_osfhandle(fdout) # type: ignore
|
||||
old_mode = wintypes.DWORD()
|
||||
kernel32.GetConsoleMode(hout, ctypes.byref(old_mode))
|
||||
mode = (new_mode & mask) | (old_mode.value & ~mask)
|
||||
|
||||
@ -703,12 +703,10 @@ def _run_idea_inspections(projroot: Path,
|
||||
if result.returncode != 0:
|
||||
# In verbose mode this stuff got printed already.
|
||||
if not verbose:
|
||||
stdout = (
|
||||
result.stdout.decode() if isinstance( # type: ignore
|
||||
result.stdout, bytes) else str(result.stdout))
|
||||
stderr = (
|
||||
result.stderr.decode() if isinstance( # type: ignore
|
||||
result.stdout, bytes) else str(result.stdout))
|
||||
stdout = (result.stdout.decode() if isinstance(
|
||||
result.stdout, bytes) else str(result.stdout))
|
||||
stderr = (result.stderr.decode() if isinstance(
|
||||
result.stdout, bytes) else str(result.stdout))
|
||||
print(f'{displayname} inspection failure stdout:\n{stdout}' +
|
||||
f'{displayname} inspection failure stderr:\n{stderr}')
|
||||
raise RuntimeError(f'{displayname} inspection failed.')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user