From 67bac94aa9f63ba3800b2cccf903feabfed67208 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 15 Feb 2026 12:14:04 +0100 Subject: [PATCH] Fix evennia connection line break issue. Resolve #2775 --- CHANGELOG.md | 2 + evennia/server/game_index_client/client.py | 8 +++- .../server/tests/test_game_index_client.py | 47 +++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 evennia/server/tests/test_game_index_client.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 8044329380..95c6191929 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ - [Fix][issue3560]: Tutorial QuestHandler failed to load after server restart (Griatch) - [Fix][issue3601]: `CmdSet.add(..., allow_duplicates=True)` didn't allow duplicate cmd keys (Griatch) - [Fix][issue3194]: Make filtering on AttributeProperties consistent across typeclasses (Griatch) +- [Fix][issue2774]: Properly support `\n` in `evennia connections` long descriptions (Griatch) - [Doc][pull3801]: Move Evennia doc build system to latest Sphinx/myST (PowershellNinja, also honorary mention to electroglyph) - [Doc][pull3800]: Describe support for Telnet SSH in HAProxy documentation (holl0wstar) @@ -71,6 +72,7 @@ [issue3560]: https://github.com/evennia/evennia/issues/3560 [issue3601]: https://github.com/evennia/evennia/issues/3601 [issue3194]: https://github.com/evennia/evennia/issues/3194 +[issue2774]: https://github.com/evennia/evennia/issues/2774 ## Evennia 5.0.1 diff --git a/evennia/server/game_index_client/client.py b/evennia/server/game_index_client/client.py index c39c336f70..c6660c27eb 100644 --- a/evennia/server/game_index_client/client.py +++ b/evennia/server/game_index_client/client.py @@ -86,13 +86,19 @@ class EvenniaGameIndexClient: # We are using `or` statements below with dict.get() to avoid sending # stringified 'None' values to the server. try: + long_description = egi_config.get("long_description", "") + if long_description: + # The connection wizard documents using "\n" for line breaks; + # normalize that to actual newlines before sending to EGI. + long_description = long_description.replace("\\n", "\n") + values = { # Game listing stuff "game_name": egi_config.get("game_name", settings.SERVERNAME), "game_status": egi_config["game_status"], "game_website": egi_config.get("game_website", ""), "short_description": egi_config["short_description"], - "long_description": egi_config.get("long_description", ""), + "long_description": long_description, "listing_contact": egi_config["listing_contact"], # How to play "telnet_hostname": egi_config.get("telnet_hostname", ""), diff --git a/evennia/server/tests/test_game_index_client.py b/evennia/server/tests/test_game_index_client.py new file mode 100644 index 0000000000..820c1e7446 --- /dev/null +++ b/evennia/server/tests/test_game_index_client.py @@ -0,0 +1,47 @@ +import urllib.parse +from unittest.mock import patch + +from django.test import TestCase, override_settings +from twisted.internet import defer + +from evennia.server.game_index_client.client import EvenniaGameIndexClient + + +class _DummyResponse: + code = 200 + + +class _RecordingAgent: + latest_data = None + + def __init__(self, *args, **kwargs): + pass + + def request(self, method, url, headers=None, bodyProducer=None): + _RecordingAgent.latest_data = bodyProducer.body.decode("utf-8") + return defer.succeed(_DummyResponse()) + + +@override_settings( + GAME_INDEX_LISTING={ + "game_status": "pre-alpha", + "game_name": "TestGame", + "short_description": "Short", + "long_description": "Line 1\\nLine 2", + "listing_contact": "admin@example.com", + } +) +class TestGameIndexClient(TestCase): + @patch("evennia.server.game_index_client.client.AccountDB.objects.num_total_accounts", return_value=0) + @patch("evennia.server.game_index_client.client.evennia.SESSION_HANDLER.account_count", return_value=0) + @patch("evennia.server.game_index_client.client.Agent", _RecordingAgent) + def test_backslash_n_in_long_description_becomes_newline(self, *_): + client = EvenniaGameIndexClient() + d = client._form_and_send_request() + + result = [] + d.addCallback(result.append) + + payload = urllib.parse.parse_qs(_RecordingAgent.latest_data) + self.assertEqual(payload["long_description"][0], "Line 1\nLine 2") + self.assertEqual(result, [(200, "OK")])