Repository: missionpinball/mpf

Issue:
Crash in BCP when decoding a percent sign
```
ERROR : BCP Client : DECODE BCP ERROR. Message: monitored_event?json={"event_name": "logicblock_baby_bonus_hit", "event_type": null, "event_callback": null, "event_kwargs": {"count": 3}, "registered_handlers": [["<bound method ConfigPlayer.config_play_callback of ConfigPlayer.event_player/events>", 175, {"calling_context": "logicblock_baby_bonus_hit{count%10==5}", "mode": "<Mode.baby_bonus>", "settings": {"random_baby_mode": {"priority": 0}}}, "93fd9d4a-4fad-4e70-9853-6efa695eec8e", "<mpf.core.placeholder_manager.BoolTemplate object at 0x106a0f240>", null], ["<bound method ConfigPlayer.config_play_callback of ConfigPlayer.event_player/events>", 100, {"calling_context": "logicblock_baby_bonus_hit", "mode": "<Mode.base>", "settings": {"baby_bonus_start": {"priority": 0}}}, "be0a073d-7c5b-4f12-92e7-8429aa78d47d", null, null]]}
```

Discussion:

Patch:
diff --git a/mpf/core/bcp/bcp_socket_client.py b/mpf/core/bcp/bcp_socket_client.py
index 19fb225f9..a0ba6c7f6 100644
--- a/mpf/core/bcp/bcp_socket_client.py
+++ b/mpf/core/bcp/bcp_socket_client.py
@@ -38,12 +38,12 @@ def decode_command_string(bcp_string):
     """
     bcp_command = urlsplit(bcp_string)
 
+    if bcp_command.query[0:5] == "json=":
+        kwargs = json.loads(bcp_command.query[5:])
+        return bcp_command.path.lower(), kwargs
+
     try:
         kwargs = parse_qs(bcp_command.query, keep_blank_values=True)
-        if 'json' in kwargs:
-            kwargs = json.loads(kwargs['json'][0])
-            return bcp_command.path.lower(), kwargs
-
     except AttributeError:
         kwargs = dict()
 


Test patch:
diff --git a/mpf/tests/test_BcpSocketClient.py b/mpf/tests/test_BcpSocketClient.py
index e1dd82c6e..fc2dc0bcf 100644
--- a/mpf/tests/test_BcpSocketClient.py
+++ b/mpf/tests/test_BcpSocketClient.py
@@ -8,6 +8,12 @@ from mpf.tests.loop import MockQueueSocket
 
 class TestBcpSocketClientEncoding(unittest.TestCase):
 
+    def test_roundtrip(self):
+        test_kwargs = {"registered_handlers": [{"calling_context": "logicblock_baby_bonus_hit{count%10==5}"}]}
+        encoded_cmd = encode_command_string("test", **test_kwargs)
+        decoded_cmd, decoded_cmd_kwargs = decode_command_string(encoded_cmd)
+        self.assertEqual(decoded_cmd_kwargs, test_kwargs)
+
     def test_decode_command_string(self):
         # test strings
         string_in = 'play?some_value=7&another_value=2'