diff --git a/.efrocachemap b/.efrocachemap index 766871e3..5d32affb 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,7 +420,7 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/dc/d2/160fc27fcaff10793327ac2c70fd", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/11/7a/87d6bca0acfb877fd4fd8fe3a598", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/44/f5/c943c9075abb3e1835d2408a1ef8", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/d8/0d/d6dad794d0f2396af2a9fb530a94", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/c0/d4/7c3ce60ba5575ccc675250ce2072", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/ec/97/713007418488dd543cf6edcdd9d2", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/61/03/89070ca765e06da3a419a579f503", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/17/21/7b6371bde52392eb4a38e7c6d55a", @@ -432,9 +432,9 @@ "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/70/7d/6cbdaf130eaa5c58cffb1f321e3d", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/4c/c7/0184b8178869d1a3827a1bfcd5bb", "assets/build/ba_data/data/languages/filipino.json": "https://files.ballistica.net/cache/ba1/c1/3c/2d45627563fbfbbbda2b7e6799e1", - "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/3f/f9/6097340f73ab465b0565c0e96e41", + "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/25/65/1cb03566e73811fc6e1b841d9072", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/ef/e6/d4909f571d7473fd04055728490e", - "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/23/b6/8f7175147d8a6d5de45c2147e294", + "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/a5/28/6bf6b15f8359a145cd2e599849f1", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/82/eb/37ff44af76812097f9c98f05c730", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/08/3b/68cea4d16f7020d932829af85323", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/d8/f2/aa16bc336bd7660cc86c3264bfc4", @@ -452,9 +452,9 @@ "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/91/0a/35c4baf539d5951fc03a794c0e0b", "assets/build/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/b5/7e/8dc92a39fb826c1d360ad639d9cb", "assets/build/ba_data/data/languages/thai.json": "https://files.ballistica.net/cache/ba1/f7/df/7ba5f99c5c2c4c86fc0503fcf0b7", - "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/37/30/ba543ac18fa6c7f9721942d6984f", + "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/14/a0/783cc6da2d122e9a7482c6a5ef8c", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/ab/35/644e4239cfa62a597a905412b90c", - "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/af/98/82ceb2748a068ad03245dcb9eeff", + "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/1c/a1/9f5cf59e3215489298d2c9628dab", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/25/13/b64b849fc9fedcc18d81f6e08c4d", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", "assets/build/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/03/4b/57ee9b42854b26f23f81bd8c58ef", @@ -3995,26 +3995,26 @@ "assets/src/ba_data/python/ba/_generated/__init__.py": "https://files.ballistica.net/cache/ba1/ee/e8/cad05aa531c7faf7ff7b96db7f6e", "assets/src/ba_data/python/ba/_generated/enums.py": "https://files.ballistica.net/cache/ba1/b2/e5/0ee0561e16257a32830645239f34", "ballisticacore-windows/Generic/BallisticaCore.ico": "https://files.ballistica.net/cache/ba1/89/c0/e32c7d2a35dc9aef57cc73b0911a", - "build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c7/0e/47a1cc6413aaad0c0afe0884b716", - "build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/53/6f/5daf49965bace69f17f7b4ed2e55", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9a/35/4e8366fc775df35f7633d7a224ae", - "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/93/f2/0d4333951f150ea0aadfeaaae852", - "build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e7/01/2bec5299c6ff6bc9722f51b7839e", - "build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b3/70/90c234a390e49a1eff61a0de9eca", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2d/33/2ef1276ec090ed01884623346dd7", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/49/21/89e770f7339c8fa9782c7280c0af", - "build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/62/15/699580dbe1d45625e063e056a547", - "build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4b/45/d857357c0c226d768434ade291d3", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f5/53/e0a72c39bbc8980f6cf3309e8074", - "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8b/6d/7c315ab5f44211be0f025d7b2c68", - "build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/32/ad/5f826af4b9773a900b2709298943", - "build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/82/31/94fef121e7a83af30760e550d800", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9a/12/e77b1a75fd08a625755d862700c4", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3d/4a/a0a222d942d7b36d4a58325c3f95", - "build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/50/e8/001aa174b93d5ee0f076390add7a", - "build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/15/2d/f1bc569de45c97fd5c1a769a4cb2", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/14/4f/6729d832b56076aeeb5b62db0b18", - "build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/fc/ac/fdeac05ecc7a4ff5d4a0e33b4cd4", + "build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/90/73/dff1b4d85ea98db0c8b4ff78c020", + "build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/98/bf/81733f92722fd5e83f6214c132f0", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2b/32/3e99bc4cfaed354e57fcb4a3dd40", + "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/40/20/5f960eb9ba935361c59820e8ef04", + "build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3a/10/f54b1434f7a47848b10678bd4d09", + "build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1f/fa/5c91c8e326b84f612a5fb883225b", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0d/9d/ed68633a0c217a6d1b99fcef5549", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/49/ae/301143ae1da54f68939cc9a80f2d", + "build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5e/72/2c065e7cc4abdb01752097ba0e26", + "build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/94/8e2ad739dff57e219ad501f5ccbd", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/98/1a86545870f974601141e2f0b4ed", + "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/48/80/76ed52b9a122ced54a4b211ca6a2", + "build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fd/a7/e4a7a1c96a8a1319236172863fbf", + "build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/66/53/92a38158e765e3edb42f6b725da0", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/73/32/e772b962f0ec33f73f4a60173fb6", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/94/a5/257b9a3be63c7e532726f7a0280a", + "build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/71/c7/7011fe1fb42a056e2038ae2fb013", + "build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5a/a3/3758255ad3e589757f831ec00e07", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/ba/95/b3baaf2f97a891041efaa3b275b2", + "build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/f8/8d/0111d89d59b3a280c61b515b248a", "build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/13/6a/baff53fa7c286e51469b0b32f05b", "build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/57/24/9f56b62f3d49ffcab8813e155311", "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/db/15/191884a40ea1128a47058b19da6b", diff --git a/CHANGELOG.md b/CHANGELOG.md index 30576c0d..69cbda15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.7 (build 20690, api 7, 2022-08-11) +### 1.7.7 (build 20692, api 7, 2022-08-17) - added `ba.app.meta.load_exported_classes()` for loading classes discovered by the meta subsystem cleanly in a background thread - improved logging of missing playlist game types - some ba.Lstr functionality can now be used in background threads diff --git a/README.md b/README.md index 810527ff..c734879d 100644 --- a/README.md +++ b/README.md @@ -6,28 +6,33 @@ ![](https://github.com/efroemling/ballistica/workflows/CI/badge.svg) -The Ballistica project is the foundation for the next generation of [BombSquad](https://www.froemling.net/apps/bombsquad). It debuted with version 1.5 of the game and lays the foundation for some of the big changes coming in 2.0. +The Ballistica project is the foundation for [BombSquad](https://www.froemling.net/apps/bombsquad) and potentially other future projects. [Head to the project wiki to get started](https://github.com/efroemling/ballistica/wiki), or learn more about the project below. ### Project Goals -* Cleanup - * BombSquad's codebase, and especially its scripting layer, have grown a lot over its lifetime, but not always in a 'designed' way. It was overdue for a major refactoring, which should keep it more maintainable for years to come. Examples of this include breaking up the monstrous twenty-six-thousand-line bsUI.py file into a much cleaner individual subpackages, updating all code from Python 2.7 to the latest 3.X versions, and adding type annotations to the entire codebase. -* Provide modders and tinkerers with the best possible development environment - * I've spent a lot of time incorporating auto-formatters, type-checkers, linters, and smart IDEs into my development workflow and have found them to be an enormous help. By sharing my setup here I hope to make them easily accessible to everyone. -* Improve transparency - * I get a lot of "what's in the next update?" or "how is 2.0 coming?" questions. By working here in the open I hope to make many of these questions unnecessary. -* Increase community involvement - * Provide a single place for tracking issues related to the engine/game - * Allow people to submit their own bug fixes or improvements, making myself less of a bottleneck - * Migrate modding documentation to this repo's wiki, allowing other modders to add their own bits of wisdom +* **Do one thing and do it well** + + Ballistica is not aiming to be a general purpose game engine. Rather it aims to support creating one particular type of experience; namely 'physics based multiplayer action on small table-top-ish environments built from real-world objects'. If you've got something you'd like to create that fits that description (like BombSquad itself does), give Ballistica a look. Of course, there is nothing preventing you from going and building an FPS out of this stuff, but I wouldn't recommend it. + +* **Python tomfoolery** + + Ballistica is built on a C++ core for performance-sensitive code with a Python layer for high level game/app logic. This Python layer is designed to be mucked with. Users can override core game functionality, write their own mini games, or anything else they can dream up, either by directly accessing files on disk or by working through an integrated web-based editor. It can be a fun way to learn Python without any danger of getting real work done. + +* **Physics-y goodness** + + I love playing with physics simulations, and Ballistica was built partly to scratch this itch. Though the game physics in BombSquad have stayed largely unchanged for a while, my future plans for the engine lean heavily on making this more flexible and open-ended, opening up lots of fun multiplayer physics-y potential. Stay tuned... + +* **Community** + BombSquad started as a 'just for fun' project to play with my friends, and I want to keep that spirit alive as the Ballistica project moves forward. Whether this means making it easier to share mods, organize tournaments, join up with friends, teach each other some Python, or whatever else. Life is short; let's play some games. Or make them. Maybe both. + ### Frequently Asked Questions -* **Q: What's with this new name? Is BombSquad getting renamed?** -* A: No, BombSquad is still BombSquad. 'Ballistica' is simply the new name for the engine/app-framework. This way it can also be used for other game/app projects without causing confusion (though that is mostly theoretical at this point). As a modder, the biggest changes you will notice is 'ba' prefixes in the API instead of 'bs' and naming that follows Python PEP8 standards (underscores and lowercase instead of camel-case). So `bs.playSound(mySound)` in the old system might look like `ba.playsound(my_sound)` in the new. You may also see the word 'BallisticaCore' show up various places, which in actual releases gets replaced by 'BombSquad'. +* **Q: What's with this name? Is it BombSquad or Ballistica?** + * A: BombSquad is the game. Ballistica is the engine. + +* **Q: When are you adding more maps/characters/minigames/etc. to BombSquad!?!?** + * A: Check out the [Ballistica Roadmap](https://github.com/efroemling/ballistica/wiki/Roadmap) to get a sense of what's planned for when. And for the record, the answer to that particular question is basically '1.8'. * **Q: Does this mean BombSquad is open source?** -* A: Yes and no. All code contained in this repo is MIT licensed and free for use anywhere. This includes game scripts, pipeline tools, and most of the binary engine sources. Anything not directly contained in this repository, however, even if automatically downloaded by build scripts, is still proprietary and cannot be redistributed without explicit consent. This includes assets and game libraries/binaries. So in a nutshell: create and share mods or use any of this code in your own projects, but please don't distribute your own complete copies of BombSquad without permission. Please email support@froemling.net if you have any questions about this. - -* **Q: Will my existing BombSquad 1.4.x mods still work?** -* A: Not 'out of the box'. All mods will need to be explicitly updated to work with the new ballistica apis in 1.5+. This may or may not be a significant amount of work depending on the mod. I would highly suggest tinkering around with some of the new features in 1.5 such as type-safe Python and dynamic assets before attempting to port any old mods, as some things are done significantly differently now. You may also want to consider simply sticking with 1.4 builds for a while longer, especially for server duties, since they will remain fully compatible with clients running 1.5. The new ballistica APIs may be changing significantly for at least a while as the dust settles, but they will be worth switching to in the end, I promise! + * A: Yes and no. All code contained in this repo is MIT licensed and free for use anywhere. This includes game scripts, pipeline tools, and most of the binary engine sources. Anything not directly contained in this repository, however, even if automatically downloaded by build scripts, is still proprietary and cannot be redistributed without explicit consent. This includes assets and game libraries/binaries. So in a nutshell: create and share mods or use any of this code in your own projects, but please don't distribute your own complete copies of BombSquad without permission. Please email support@froemling.net if you have any questions about this. diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index 1917f74f..552d02e9 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 modify them here. -const int kAppBuildNumber = 20690; +const int kAppBuildNumber = 20692; const char* kAppVersion = "1.7.7"; // Our standalone globals. diff --git a/tools/efro/message/_message.py b/tools/efro/message/_message.py index 60e108f9..adc2d190 100644 --- a/tools/efro/message/_message.py +++ b/tools/efro/message/_message.py @@ -45,21 +45,21 @@ class Response: @ioprepped @dataclass class ErrorResponse(Response): - """Message saying some error has occurred on the other end. + """Response saying some error has occurred for the send. This type is unique in that it is not returned to the user; it instead results in a local exception being raised. """ class ErrorType(Enum): - """Type of error that occurred in remote message handling.""" - OTHER = 0 - CLEAN = 1 + """Type of error that occurred while sending a message.""" + REMOTE = 0 + REMOTE_CLEAN = 1 LOCAL = 2 COMMUNICATION = 3 error_message: Annotated[str, IOAttrs('m')] - error_type: Annotated[ErrorType, IOAttrs('e')] = ErrorType.OTHER + error_type: Annotated[ErrorType, IOAttrs('e')] = ErrorType.REMOTE @ioprepped diff --git a/tools/efro/message/_protocol.py b/tools/efro/message/_protocol.py index e1e5cfc0..ae6c2df0 100644 --- a/tools/efro/message/_protocol.py +++ b/tools/efro/message/_protocol.py @@ -152,14 +152,16 @@ class MessageProtocol: logging.exception('Error handling message.') # If anything goes wrong, return a ErrorResponse instead. + # (either CLEAN or generic REMOTE) if isinstance(exc, CleanError) and self.preserve_clean_errors: - return ErrorResponse(error_message=str(exc), - error_type=ErrorResponse.ErrorType.CLEAN) + return ErrorResponse( + error_message=str(exc), + error_type=ErrorResponse.ErrorType.REMOTE_CLEAN) return ErrorResponse( error_message=(traceback.format_exc() if self.receiver_returns_stack_traces else 'An internal error has occurred.'), - error_type=ErrorResponse.ErrorType.OTHER) + error_type=ErrorResponse.ErrorType.REMOTE) def _to_dict(self, message: Any, ids_by_type: dict[type, int], opname: str) -> dict: diff --git a/tools/efro/message/_sender.py b/tools/efro/message/_sender.py index 31cbd0cc..18359675 100644 --- a/tools/efro/message/_sender.py +++ b/tools/efro/message/_sender.py @@ -57,8 +57,9 @@ class MessageSender: """Function decorator for setting raw send method. Send methods take strings and should return strings. - Any Exception raised during the send_method manifests as - a CommunicationError for the message sender. + CommunicationErrors raised here will be returned to the sender + as such; all other exceptions will result in a RuntimeError for + the sender. """ assert self._send_raw_message_call is None self._send_raw_message_call = call @@ -70,8 +71,9 @@ class MessageSender: """Function decorator for setting raw send-async method. Send methods take strings and should return strings. - Any Exception raised during the send_method manifests as - a CommunicationError for the message sender. + CommunicationErrors raised here will be returned to the sender + as such; all other exceptions will result in a RuntimeError for + the sender. """ assert self._send_async_raw_message_call is None self._send_async_raw_message_call = call @@ -140,8 +142,7 @@ class MessageSender: # Any error in the raw send call gets recorded as either # a local or communication error. return ErrorResponse( - error_message=( - f'Error in send async method ({type(exc)}): {exc}'), + error_message=f'Error in send method ({type(exc)}): {exc}', error_type=(ErrorResponse.ErrorType.COMMUNICATION if isinstance(exc, CommunicationError) else ErrorResponse.ErrorType.LOCAL)) @@ -167,7 +168,8 @@ class MessageSender: # Any error in the raw send call gets recorded as either # a local or communication error. return ErrorResponse( - error_message=f'Error in send async method: {exc}', + error_message=f'Error in send async method ({type(exc)}):' + f' {exc}', error_type=(ErrorResponse.ErrorType.COMMUNICATION if isinstance(exc, CommunicationError) else ErrorResponse.ErrorType.LOCAL)) @@ -241,17 +243,17 @@ class MessageSender: ErrorResponse.ErrorType.COMMUNICATION): raise CommunicationError(raw_response.error_message) - # If something went wrong on our end of the connection, + # If something went wrong on *our* end of the connection, # don't say it was a remote error. if raw_response.error_type is ErrorResponse.ErrorType.LOCAL: raise RuntimeError(raw_response.error_message) # If they want to support clean errors, do those. - if (self.protocol.preserve_clean_errors and - raw_response.error_type is ErrorResponse.ErrorType.CLEAN): + if (self.protocol.preserve_clean_errors and raw_response.error_type + is ErrorResponse.ErrorType.REMOTE_CLEAN): raise CleanError(raw_response.error_message) - # In all other cases, just say something went wrong 'out there'. + # Everything else gets lumped in as a remote error. raise RemoteError(raw_response.error_message) return raw_response