diff --git a/.efrocachemap b/.efrocachemap index a5a1bcb3..0507a2f8 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,24 +420,24 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/14/f1/4f2995d78fc20dd79dfb39c5d554", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/57/ac/6ed0caecd25dc23688debed24c45", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/32/08/38dac4a79ab2acee76a75d32a310", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/dd/f3/f401d6adf6f91b8189d73f17aaf0", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/5a/7d/3a4c37ada60b546b1ff1dfaa6d3e", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/46/d2/ffaeb8d34e72e5d4baee7ffa2df8", - "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/44/ed/5b972fa848cffb73723533c2ccb7", + "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/53/65/623cbd373025127bbce64ffb8979", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/ce/d6/c90afebc5dfca2b43d2defc3a42c", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/0b/8a/eafc8bcf22576fa24fc8a697ecfe", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/66/bf/6e98398016da261296b8c306560e", "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/e3/10/ace3a73616f1f36540e585e5bbce", "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/a0/78/7d4ef87f7f8c04f9684db7098b91", + "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/b6/92/f245bd6c11a4ab2eaff037b38cfe", "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/41/30/040a5038fccbfeaa28e85d3bc863", + "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/c5/9b/e627b5c99b11ac88e85267a02244", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/d1/2d/47f4f84ca569a8b64bd500d4b36d", - "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/3d/88/6ca54f6089c255f9e788c1878965", + "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/17/82/e053185f86ba5c907185881273fb", "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/32/a4/fae7a30ead18c6cb97db60dd9445", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/f7/60/bfe1977d51b66db1084b123cd69e", - "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/69/cf/4a1e297b73613fd1b87fed8d2565", + "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/d6/43/599430105ffecff486da7fc32a4c", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/93/0d/b511ed987ac27769204b624e73b4", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/78/d3/16b37707d4ce4df826d0b0bc1766", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/c1/14/b013ec0a6557533f0ff49f27d000", @@ -450,7 +450,7 @@ "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/32/83/8fa66d906da02dde3a87f18999cb", "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/5b/c4/2173bc10edea17ed3734f08a8c94", - "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/3e/f3/4e9003c88e959d0d75a225c7a87e", + "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/20/b3/b52d8c6db509c2c74a97e202e335", "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/9b/b7/c9fd483742201911caeef3d89822", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/5c/1c/8af479b70c9e6595b338dbb563c5", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", @@ -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/6c/7e/79149d8af4291810bbd832ef7701", - "build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3f/50/160d497455a7476adbf7c753a5e2", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cd/9e/d9edf9e5583bb4f20ee8c73b38f3", - "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/09/5d/29f79e4288346f4d78a5afd906c0", - "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2f/56/16f552d4a957cb1c575b12d1164c", - "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/51/7b/a018f0f6d8127bcad72b79a5c6b3", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b7/c4/8d78dbe2a68936c252a7ed285d50", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/eb/8b/94351be14bb57ddf3b8907acf900", - "build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c8/1a/2e390a528232f76eb0cc9fe58aa9", - "build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/19/4c/da621e6aad46901b735335d5e033", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6c/83/4b689f57bb212538e852083acc41", - "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7e/8d/957899a603943879ae09bee71b18", - "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1f/3e/9bcc32d3032cc1201e5f57e9c261", - "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/66/73/be60f521a16f3b28fdf3769e9c5c", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4c/f0/66034910a954d533bff1c4e2f97a", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/21/a1/617bba8cc95bd35f333591cd02b1", - "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/00/70/a42d41cbcc0b332c93b8a330e3d8", - "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c0/b4/aee6ae279007ef8f517ad7239082", - "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c6/4d/3c89d6c16046f87e2de408f9b346", - "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ae/ea/5ff962d1d91641d7a2d56e077655", - "build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ed/77/ede8e30345b9cd8e91e010572062", - "build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/17/ac/7234096717caeab0184e614b92e2", - "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/25/db/c7cbb696d01b3e06473dd245f238", - "build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a3/91/7ce48b71049da124347507beca0d", - "build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/94/75/3d443e98f12ae5cdd1ffb721e778", - "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/16/95/102d669e9201cbb19d612aa8989a", - "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/95/66/80c8745d3b4cd1e094b497d5a26b", - "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/91/8f/2786d57375fa7fb6895df63ca912", - "build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/df/96/85db2b907e626288067812fb1572", - "build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0e/d5/4e4aa07be3cad0571fd5b7ef53b1", - "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/17/62/13517437b0f3a86ea60f20c98a46", - "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/26/ce/d5a5768d56bbcf3efc5ad447c97f", - "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/11/b4/9815e9f95ea41a6ea5ddceca4c68", - "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/53/3e/a46827f7195fa97c583cffad3798", - "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d5/68/49f82ac1f5161d843f2fdbd4dffe", - "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/88/a4/74dd159772dd8ae4d49f53e358dc" + "build/prefab/full/linux_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2b/e1/628191b4c0b260036e0d7abc6ee3", + "build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/83/51/0511414b7d61f636b55bb6e63b00", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/83/a1/3046fc4c86fb31655da6b2d076cb", + "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/e7/d0c78aaf3c6982eee87471ff5637", + "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a3/43/5e2dd209bedf7f3c5550f416fb6e", + "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7b/e0/5c94fd10dfb247529548a76ddd75", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/13/54/1e3e4532fa176cca029fc448ac6e", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/5b/d8a9b7d2cda3eaff208944273b08", + "build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/37/1055f167fbab28003f7129e5aee6", + "build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/25/aa/6f6c4ef8ab7d39f46b8bf69fa18b", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f3/c4/619b03c16992b06d8162cdb96126", + "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2f/1b/6ec4f564ea77d42a30917c8434c9", + "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b5/73/194f8c35a467b775eebe24de90a2", + "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b0/a7/7848042fbcd5764af31020e53ae1", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/28/a0/d2d53829a074e5c06cf5785af1cd", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4d/53/3027bbbab3c19fa2b8d0fa718d96", + "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f9/c7/b04b34fcdc0e0e0f9976b5639c0c", + "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/87/a9/e295e82a1f3b423fb2f8f2eb462f", + "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1c/bd/4afc4c92dcaf095928f66d5c61d3", + "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ca/56/0923f65bb7c80211f614c4816ab5", + "build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/54/e0/8c89d241ca37ae32c9b46ea71456", + "build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e0/05/94ac67cbf2e665eeecfc77246caf", + "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0f/e1/be897ef0e73b0e52c59f3396e0cd", + "build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f6/12/cbf8807fe66907ea9cc2a2da6a48", + "build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7e/b6/aa2c6f318fc52e6e76b31501a937", + "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1f/b3/80375870a9ab83bbb63b50b03a73", + "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5c/2e/a1b1f2126b3150c6f11e799c3805", + "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b6/6b/37174b3a0d72a05f1bb3d904b78b", + "build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/43/b7/8f87aa950891250923c7cb617d32", + "build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1a/e9/a0c9c846c00b5ed9645ddc70e44a", + "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8a/e5/1f93415fb55842479f5ce0d375af", + "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e7/36/2475ad00f41cf75d63c786f3db39", + "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6c/52/ff241eeae0d43f433f66a8b2dcbb", + "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/40/a3/a2c2c741e551c40d0700888737a7", + "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a1/ef/fa977c1c8a05781f6af8321b31f2", + "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0d/15/336d51f7894aeedba54f5aabb04a" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 76442c67..08230e08 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -67,6 +67,8 @@ androidstudiocode anim animcurve + annarg + annargs anntype anota anroid @@ -1087,6 +1089,7 @@ introspectable intstr iobj + iometa ioprep ioprepped ipaddress @@ -1805,6 +1808,7 @@ rankbutton rankwindow raspbian + rawkey rawpath rawpaths rcfile diff --git a/ballisticacore-cmake/.idea/dictionaries/ericf.xml b/ballisticacore-cmake/.idea/dictionaries/ericf.xml index bf2854f7..613b7565 100644 --- a/ballisticacore-cmake/.idea/dictionaries/ericf.xml +++ b/ballisticacore-cmake/.idea/dictionaries/ericf.xml @@ -41,6 +41,8 @@ anchorx animcurve aniso + annarg + annargs anntype ansiwrap anyofallof @@ -487,6 +489,7 @@ intstr invote iobj + iometa ioprep ioprepped iserverget @@ -797,6 +800,7 @@ rakhov raspbian rasterizer + rawkey reaaaly readset realloc diff --git a/docs/ba_module.md b/docs/ba_module.md index 337c15f2..8f3a4fee 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

last updated on 2021-05-14 for Ballistica version 1.6.3 build 20367

+

last updated on 2021-05-24 for Ballistica version 1.6.3 build 20367

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 let me know. Happy modding!


diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index 8a428eeb..fa8238c9 100644 --- a/src/ballistica/ballistica.cc +++ b/src/ballistica/ballistica.cc @@ -21,7 +21,7 @@ namespace ballistica { // These are set automatically via script; don't change here. -const int kAppBuildNumber = 20367; +const int kAppBuildNumber = 20368; const char* kAppVersion = "1.6.3"; // Our standalone globals. diff --git a/src/ballistica/core/types.h b/src/ballistica/core/types.h index 732bd079..a6a3e7d3 100644 --- a/src/ballistica/core/types.h +++ b/src/ballistica/core/types.h @@ -852,7 +852,7 @@ enum class NodeMessageType { kFooting }; -enum class AccountState { kSignedOut, kSigningIn, kSignedIn }; +enum class LoginState { kSignedOut, kSigningIn, kSignedIn }; enum class CameraMode { kFollow, kOrbit }; diff --git a/src/ballistica/game/account.h b/src/ballistica/game/account.h index a471b61a..eba14d12 100644 --- a/src/ballistica/game/account.h +++ b/src/ballistica/game/account.h @@ -12,7 +12,7 @@ namespace ballistica { -// Global account functionality. +/// Global account functionality. class Account { public: Account(); @@ -20,25 +20,26 @@ class Account { static auto AccountTypeToString(AccountType type) -> std::string; static auto AccountTypeToIconString(AccountType type) -> std::string; - auto GetAccountName() -> std::string; - auto GetAccountID() -> std::string; - auto GetAccountToken() -> std::string; - auto GetAccountExtra() -> std::string; - auto GetAccountExtra2() -> std::string; + auto GetLoginName() -> std::string; + auto GetLoginID() -> std::string; + auto GetToken() -> std::string; + auto GetExtra() -> std::string; + auto GetExtra2() -> std::string; - // Return the current account state. - // If an int pointer is passed, state-num will also be returned. - auto GetAccountState(int* state_num = nullptr) -> AccountState; + /// Return the current account state. + /// If an int pointer is passed, state-num will also be returned. + auto GetLoginState(int* state_num = nullptr) -> LoginState; // An extra value included when passing our account info to the server // ..(can be used for platform-specific install-signature stuff, etc). - auto SetAccountExtra(const std::string& extra) -> void; - auto SetAccountExtra2(const std::string& extra) -> void; - auto SetAccountToken(const std::string& account_id, const std::string& token) + auto SetExtra(const std::string& extra) -> void; + auto SetExtra2(const std::string& extra) -> void; + auto SetToken(const std::string& account_id, const std::string& token) -> void; - auto SetAccount(AccountType account_type, AccountState account_state, - const std::string& name, const std::string& id) -> void; + auto SetLogin(AccountType account_type, LoginState login_state, + const std::string& login_name, const std::string& login_id) + -> void; auto SetProductsPurchased(const std::vector& products) -> void; auto GetProductPurchased(const std::string& product) -> bool; @@ -51,13 +52,13 @@ class Account { std::mutex mutex_; std::unordered_map product_purchases_; int product_purchases_state_{}; - std::string account_name_; - std::string account_id_; - std::string account_token_; - std::string account_extra_; - std::string account_extra_2_; - AccountState account_state_{AccountState::kSignedOut}; - int account_state_num_{}; + std::string login_name_; + std::string login_id_; + std::string token_; + std::string extra_; + std::string extra_2_; + LoginState login_state_{LoginState::kSignedOut}; + int login_state_num_{}; }; } // namespace ballistica diff --git a/src/ballistica/game/game.cc b/src/ballistica/game/game.cc index 38cd76d4..72d57abe 100644 --- a/src/ballistica/game/game.cc +++ b/src/ballistica/game/game.cc @@ -255,17 +255,14 @@ void Game::PushMediaPruneCall(int level) { void Game::PushSetAccountTokenCall(const std::string& account_id, const std::string& token) { - PushCall( - [account_id, token] { g_account->SetAccountToken(account_id, token); }); + PushCall([account_id, token] { g_account->SetToken(account_id, token); }); } -void Game::PushSetAccountCall(AccountType account_type, - AccountState account_state, - const std::string& account_name, - const std::string& account_id) { +void Game::PushSetLoginCall(AccountType account_type, LoginState account_state, + const std::string& account_name, + const std::string& account_id) { PushCall([this, account_type, account_state, account_name, account_id] { - g_account->SetAccount(account_type, account_state, account_name, - account_id); + g_account->SetLogin(account_type, account_state, account_name, account_id); }); } diff --git a/src/ballistica/game/game.h b/src/ballistica/game/game.h index c70df4e8..d6120248 100644 --- a/src/ballistica/game/game.h +++ b/src/ballistica/game/game.h @@ -32,9 +32,9 @@ class Game : public Module { auto LaunchClientSession() -> void; auto LaunchReplaySession(const std::string& file_name) -> void; - auto PushSetAccountCall(AccountType account_type, AccountState account_state, - const std::string& account_name, - const std::string& account_id) -> void; + auto PushSetLoginCall(AccountType account_type, LoginState account_state, + const std::string& account_name, + const std::string& account_id) -> void; auto PushSetAccountTokenCall(const std::string& account_id, const std::string& token) -> void; auto PushPartyInviteCall(const std::string& name, diff --git a/src/ballistica/game/player_spec.cc b/src/ballistica/game/player_spec.cc index 4f849e10..ac685d54 100644 --- a/src/ballistica/game/player_spec.cc +++ b/src/ballistica/game/player_spec.cc @@ -75,10 +75,10 @@ auto PlayerSpec::GetSpecString() const -> std::string { auto PlayerSpec::GetAccountPlayerSpec() -> PlayerSpec { PlayerSpec spec; - if (g_account->GetAccountState() == AccountState::kSignedIn) { + if (g_account->GetLoginState() == LoginState::kSignedIn) { spec.account_type_ = g_app_globals->account_type; spec.name_ = - Utils::GetValidUTF8(g_account->GetAccountName().c_str(), "bsgaps"); + Utils::GetValidUTF8(g_account->GetLoginName().c_str(), "bsgaps"); } else { spec.name_ = Utils::GetValidUTF8(g_platform->GetDeviceName().c_str(), "bsgaps2"); diff --git a/src/ballistica/platform/platform.cc b/src/ballistica/platform/platform.cc index 04d575cb..e1962598 100644 --- a/src/ballistica/platform/platform.cc +++ b/src/ballistica/platform/platform.cc @@ -1072,7 +1072,7 @@ void Platform::SignIn(const std::string& account_type) { Log("SignIn() unimplemented"); } -void Platform::AccountDidChange() { +void Platform::LoginDidChange() { // Default is no-op. } diff --git a/src/ballistica/platform/platform.h b/src/ballistica/platform/platform.h index 3eaaf367..061513da 100644 --- a/src/ballistica/platform/platform.h +++ b/src/ballistica/platform/platform.h @@ -295,7 +295,7 @@ class Platform { virtual auto SignIn(const std::string& account_type) -> void; virtual auto SignOut() -> void; virtual auto GameCenterLogin() -> void; - virtual auto AccountDidChange() -> void; + virtual auto LoginDidChange() -> void; #pragma mark MUSIC PLAYBACK ---------------------------------------------------- diff --git a/tests/test_efro/test_dataclassio.py b/tests/test_efro/test_dataclassio.py index c4c11cc8..030f771f 100644 --- a/tests/test_efro/test_dataclassio.py +++ b/tests/test_efro/test_dataclassio.py @@ -9,12 +9,13 @@ import datetime from dataclasses import field, dataclass from typing import (TYPE_CHECKING, Optional, List, Set, Any, Dict, Sequence, Union, Tuple) +from typing_extensions import Annotated import pytest from efro.util import utc_now from efro.dataclassio import (dataclass_validate, dataclass_from_dict, - dataclass_to_dict, ioprepped) + dataclass_to_dict, ioprepped, IOMeta) if TYPE_CHECKING: pass @@ -460,6 +461,58 @@ def test_extra_data() -> None: assert 'nonexistent' not in out +def test_meta() -> None: + """Testing iometa annotations.""" + + @ioprepped + @dataclass + class _TestClass: + dval: Annotated[Dict, IOMeta('d')] + + obj = _TestClass(dval={'foo': 'bar'}) + + # Make sure key is working. + assert dataclass_to_dict(obj) == {'d': {'foo': 'bar'}} + + # Setting store_default False without providing a default or + # default_factory should fail. + with pytest.raises(TypeError): + + @ioprepped + @dataclass + class _TestClass2: + dval: Annotated[Dict, IOMeta('d', store_default=False)] + + @ioprepped + @dataclass + class _TestClass3: + dval: Annotated[Dict, IOMeta('d', store_default=False)] = field( + default_factory=dict) + ival: Annotated[int, IOMeta('i', store_default=False)] = 123 + + # Both attrs are default; should get stripped out. + obj3 = _TestClass3() + assert dataclass_to_dict(obj3) == {} + + # Both attrs are non-default vals; should remain in output. + obj3 = _TestClass3(dval={'foo': 'bar'}, ival=124) + assert dataclass_to_dict(obj3) == {'d': {'foo': 'bar'}, 'i': 124} + + # Test going the other way. + obj3 = dataclass_from_dict( + _TestClass3, + { + 'd': { + 'foo': 'barf' + }, + 'i': 125 + }, + allow_unknown_attrs=False, + ) + assert obj3.dval == {'foo': 'barf'} + assert obj3.ival == 125 + + def test_dict() -> None: """Test various dict related bits.""" diff --git a/tools/efro/dataclassio.py b/tools/efro/dataclassio.py index 1ccde936..3d6ad3ae 100644 --- a/tools/efro/dataclassio.py +++ b/tools/efro/dataclassio.py @@ -21,7 +21,10 @@ from enum import Enum import dataclasses import typing import datetime -from typing import TYPE_CHECKING, TypeVar, Generic, get_type_hints +from typing import TYPE_CHECKING, TypeVar, Generic +# Note: can pull this from typing once we update to Python 3.9+ +# noinspection PyProtectedMember +from typing_extensions import get_args, get_type_hints, _AnnotatedAlias from efro.util import enum_by_value @@ -54,6 +57,27 @@ PREP_ATTR = '_DCIOPREP' EXTRA_ATTRS_ATTR = '_DCIOEXATTRS' +class IOMeta: + """Metadata for specifying io behavior.""" + + def __init__(self, storagename: str = None, store_default: bool = True): + self.storagename = storagename + self.store_default = store_default + + def validate_for_field(self, cls: Type, field: dataclasses.Field) -> None: + """Ensure the IOMeta instance is ok to use with the provided field.""" + + # Turning off store_default requires the field to have either + # a default_factory or a default + if not self.store_default: + default_factory: Any = field.default_factory # type: ignore + if (default_factory is dataclasses.MISSING + and field.default is dataclasses.MISSING): + raise TypeError(f'Field {field.name} of {cls} has' + f' neither a default nor a default_factory;' + f' store_default=False cannot be set for it.') + + def dataclass_to_dict(obj: Any, coerce_to_float: bool = True) -> dict: """Given a dataclass object, return a json-friendly dict. @@ -192,6 +216,9 @@ class PrepData: # Resolved annotation data with 'live' classes. annotations: Dict[str, Any] + # Map of storage names to attr names. + storage_names_to_attr_names: Dict[str, str] + class PrepSession: """Context for a prep.""" @@ -202,6 +229,7 @@ class PrepSession: def prep_dataclass(self, cls: Type, recursion_level: int) -> PrepData: """Run prep on a dataclass if necessary and return its prep data.""" + # We should only need to do this once per dataclass. existing_data = getattr(cls, PREP_ATTR, None) if existing_data is not None: assert isinstance(existing_data, PrepData) @@ -227,11 +255,11 @@ class PrepSession: ' @efro.dataclassio.prepped decorator).', cls) try: - # Use default globalns which should be the class' module, - # but provide our own locals to cover things like typing.* - # which are generally not actually present at runtime for us. - # resolved_annotations = get_type_hints(cls, localns=localns) - resolved_annotations = get_type_hints(cls) + # NOTE: perhaps we want to expose the globalns/localns args + # to this? + # pylint: disable=unexpected-keyword-arg + resolved_annotations = get_type_hints(cls, include_extras=True) + # pylint: enable=unexpected-keyword-arg except Exception as exc: raise RuntimeError( f'dataclassio prep for {cls} failed with error: {exc}.' @@ -239,17 +267,35 @@ class PrepSession: f' at the module level or add them as part of an explicit' f' prep call.') from exc + # noinspection PyDataclass + fields = dataclasses.fields(cls) + fields_by_name = {f.name: f for f in fields} + + storage_names_to_attr_names: Dict[str, str] = {} + # Ok; we've resolved actual types for this dataclass. # now recurse through them, verifying that we support all contained # types and prepping any contained dataclass types. - for attrname, attrtype in resolved_annotations.items(): + for attrname, anntype in resolved_annotations.items(): + + anntype, iometa = _parse_annotated(anntype) + + # If we found attached IOMeta data, make sure it contains + # valid values for the field it is attached to. + if iometa is not None: + iometa.validate_for_field(cls, fields_by_name[attrname]) + if iometa.storagename is not None: + storage_names_to_attr_names[iometa.storagename] = attrname + self.prep_type(cls, attrname, - attrtype, + anntype, recursion_level=recursion_level + 1) # Success! Store our resolved stuff with the class and we're done. - prepdata = PrepData(annotations=resolved_annotations) + prepdata = PrepData( + annotations=resolved_annotations, + storage_names_to_attr_names=storage_names_to_attr_names) setattr(cls, PREP_ATTR, prepdata) return prepdata @@ -279,10 +325,15 @@ class PrepSession: # Everything below this point assumes the annotation type resolves # to a concrete type. if not isinstance(origin, type): + print('ORIGIN IS', origin, type(origin)) raise TypeError( f'Unsupported type found for \'{attrname}\' on {cls}:' f' {anntype}') + # extras = get_args(anntype) + # if extras: + # print('FOUND EXTRAS FOR', anntype) + if origin in SIMPLE_TYPES: return @@ -467,6 +518,8 @@ class _Outputter: return self._process_dataclass(type(self._obj), self._obj, '') def _process_dataclass(self, cls: Type, obj: Any, fieldpath: str) -> Any: + # pylint: disable=too-many-locals + # pylint: disable=too-many-branches prep = PrepSession(explicit=False).prep_dataclass(type(obj), recursion_level=0) fields = dataclasses.fields(obj) @@ -477,12 +530,35 @@ class _Outputter: subfieldpath = f'{fieldpath}.{fieldname}' else: subfieldpath = fieldname - fieldtype = prep.annotations[fieldname] + anntype = prep.annotations[fieldname] value = getattr(obj, fieldname) - outvalue = self._process_value(cls, subfieldpath, fieldtype, value) + + anntype, iometa = _parse_annotated(anntype) + + # If we're not storing default values for this fella, + # we can skip all output processing if we've got a default value. + if iometa is not None and not iometa.store_default: + default_factory: Any = field.default_factory # type: ignore + if default_factory is not dataclasses.MISSING: + if default_factory() == value: + continue + elif field.default is not dataclasses.MISSING: + if field.default == value: + continue + else: + raise RuntimeError( + f'Field {fieldname} of {cls} has' + f' neither a default nor a default_factory;' + f' store_default=False cannot be set for it.' + f' (AND THIS SHOULD HAVE BEEN CAUGHT IN PREP!)') + + outvalue = self._process_value(cls, subfieldpath, anntype, value) if self._create: assert out is not None - out[fieldname] = outvalue + storagename = (fieldname if + (iometa is None or iometa.storagename is None) + else iometa.storagename) + out[storagename] = outvalue # If there's extra-attrs stored on us, check/include them. extra_attrs = getattr(obj, EXTRA_ATTRS_ATTR, None) @@ -820,8 +896,11 @@ class _Inputter(Generic[T]): fields = dataclasses.fields(cls) fields_by_name = {f.name: f for f in fields} args: Dict[str, Any] = {} - for key, value in values.items(): + for rawkey, value in values.items(): + key = prep.storage_names_to_attr_names.get(rawkey, rawkey) field = fields_by_name.get(key) + + # Store unknown attrs off to the side (or error if desired). if field is None: if self._allow_unknown_attrs: if self._discard_unknown_attrs: @@ -840,11 +919,13 @@ class _Inputter(Generic[T]): f"'{cls.__name__}' has no '{key}' field.") else: fieldname = field.name - fieldtype = prep.annotations[fieldname] + anntype = prep.annotations[fieldname] + anntype, _iometa = _parse_annotated(anntype) + subfieldpath = (f'{fieldpath}.{fieldname}' if fieldpath else fieldname) - args[key] = self._value_from_input(cls, subfieldpath, - fieldtype, value) + args[key] = self._value_from_input(cls, subfieldpath, anntype, + value) try: out = cls(**args) except Exception as exc: @@ -1026,3 +1107,22 @@ class _Inputter(Generic[T]): assert len(out) == len(childanntypes) return tuple(out) + + +def _parse_annotated(anntype: Any) -> Tuple[Any, Optional[IOMeta]]: + """Parse Annotated() constructs, returning annotated type & IOMeta data.""" + # If we get an Annotated[foo, bar, eep] we take + # foo as the actual type and we look for IOMeta instances in + # bar/eep to affect our behavior. + iometa: Optional[IOMeta] = None + if isinstance(anntype, _AnnotatedAlias): + annargs = get_args(anntype) + for annarg in annargs[1:]: + if isinstance(annarg, IOMeta): + if iometa is not None: + raise RuntimeError( + 'Multiple IOMeta instances found for a' + ' single annotation; this is not supported.') + iometa = annarg + anntype = annargs[0] + return anntype, iometa diff --git a/tools/efro/entity/_entity.py b/tools/efro/entity/_entity.py index b866964c..25ba2023 100644 --- a/tools/efro/entity/_entity.py +++ b/tools/efro/entity/_entity.py @@ -48,9 +48,8 @@ class EntityMixin: Note that it is more efficient to pass data to an Entity's constructor than it is to create a default Entity and then call this on it. """ - self.d_data = data assert isinstance(self, CompoundValue) - self.apply_fields_to_data(self.d_data, error=error) + self.d_data = self.filter_input(data, error=error) def copy_data(self, target: Union[CompoundValue, BoundCompoundValue]) -> None: diff --git a/tools/efro/entity/_value.py b/tools/efro/entity/_value.py index 57981796..5fa50a2d 100644 --- a/tools/efro/entity/_value.py +++ b/tools/efro/entity/_value.py @@ -66,7 +66,7 @@ class SimpleValue(TypedValue[T]): self._allow_none = allow_none # We store _default_data in our internal data format so need - # to run user-facing value through our input filter. + # to run user-facing values through our input filter. # Make sure we do this last since filter_input depends on above vals. self._default_data: T = self.filter_input(default, error=True)