Skip to content

ISSUE-035: accept perpetuum.ini files carrying obsolete connection string keywords - #26

Merged
Sellafield merged 2 commits into
OpenPerpetuum:developfrom
meketreve:issue-035-connection-string-compat
Aug 17, 2026
Merged

ISSUE-035: accept perpetuum.ini files carrying obsolete connection string keywords#26
Sellafield merged 2 commits into
OpenPerpetuum:developfrom
meketreve:issue-035-connection-string-compat

Conversation

@meketreve

@meketreve meketreve commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Fixes ISSUE-035: the perpetuum.ini written by the Perpetuum Dedicated Server installer does not start this server, and neither error message names the file.

This PR changed direction on 2026-08-15 after the maintainers said on Discord that they would rather see the bad setting reported than silently removed. The original approach removed it. The two comments below record that decision and the rework; this body describes what the branch does now.

The problem

The installer's file was written for the original server, which used System.Data.SqlClient. This one uses Microsoft.Data.SqlClient, which refuses settings the old driver accepted. SqlConnection throws while it is being constructed, naming the setting but not the file it came from — and the file is the part an operator needs.

What this does

ConnectionStringSupport.FindUnsupportedKeywords reports every setting the driver will refuse. Nothing is ever rewritten: the connection string reaches the driver exactly as it was written.

PerpetuumBootstrapper.Init calls it right after resolving GlobalConfiguration, and when anything comes back it logs an error naming perpetuum.ini, the directory it sits in, and every offending setting, then throws so the server does not start on a connection that cannot open.

[03:07:28] INF >>>> Perpetuum Server State : [Init]
[03:07:28] ERR perpetuum.ini in <game root> has a connectionString carrying 2 setting(s)
Microsoft.Data.SqlClient does not accept: connection reset, network library. Remove them and
start the server again. The original server used System.Data.SqlClient, which accepted them.

No keyword list. The check parses with DbConnectionStringBuilder, then offers each setting to SqlConnectionStringBuilder and reports whatever it refuses. The old list was short only because removing a setting had to be provably safe; reporting always is. So Network Library and Context Connection are named too, and a setting nobody anticipated is handled the same way.

All offenders in one message, because the installer's file carries more than one and a first-failure-only report costs a restart per setting.

The Encrypt / TrustServerCertificate half of ISSUE-035 stays documentation only: defaulting TrustServerCertificate would weaken authentication for every operator to fix a local development case. README.md gains a setup section — the repository had none — stating the requirement, a working connection string, and that TrustServerCertificate=True belongs on a local instance only.

The one decision I would most like overruled if it is wrong

InvalidOperationException. CLAUDE.md points at PerpetuumException / ErrorCodes, but those model game protocol errors and this is a startup configuration problem, so adding an ErrorCode for it seemed heavier than the problem. There is no precedent to copy either: PerpetuumBootstrapper.cs contains no other throw, so refusing to start is new behaviour for that file however it is spelled.

Verification

Check Result
Unit tests 15 new in ConnectionStringSupportTests; 8 observed failing against a stub before the detection was written
Full unit tier 73/73
Build 0 errors; no warning comes from a project this touches
Bad file One ERR line naming both settings, process exits 1, before anything else in Init needs the game root
Good file tools/smoke-test.ps1 green against a real database — [Online] after 80 s, 6435 members spawned, graceful shutdown, exit 0
Driver premise The_driver_really_does_reject_the_installer_string fails the day the driver stops rejecting the keyword, which is the day this check becomes dead weight

Branch rebased onto the current develop, so the first commit's hash changed. Reading the second commit on its own shows the change of direction.

@meketreve

Copy link
Copy Markdown
Contributor Author

Flagging the one thing in here that deserves a deliberate yes or no rather than a skim:

This changes behaviour. A perpetuum.ini carrying Connection Reset fails to start the server
today. After this it starts, with a warning. That is the intent of the change, but it is a decision
about your product, not a bug fix, so it should be yours rather than mine.

If you would rather the server kept refusing that file, the alternative is a couple of lines away and
I am happy to switch: the same detection can abort with a message that names perpetuum.ini and the
offending keyword instead of removing it. That still fixes the actual complaint in ISSUE-035 — the
current error names neither the file nor what to do about it — while leaving the operator to edit
their own config.

What does not change either way: a connection string carrying none of these keywords is handed
back as the same instance and never rebuilt, so a valid configuration behaves exactly as it does
today. Verified on a real server run — the log is identical to the run before the change.

@meketreve

Copy link
Copy Markdown
Contributor Author

Direction confirmed with the maintainers on Discord on 2026-08-15. Recording it here so the decision is on the record rather than only in chat.

The obsolete keyword should be reported, not removed. The reasoning given: the installer already deploys a corrected perpetuum.ini, so this only bites when a fresh PP2 install is pointed at an old PP1 data folder. In that case a clear diagnostic is more useful than silently accepting the bad file.

So this PR changes shape. Instead of stripping the keyword, PerpetuumBootstrapper.Init will detect it and fail with a message naming the file and the offending keyword, so the operator is told exactly what to remove.

One assumption in that, stated plainly so it can be overruled in one line: the wording was "check and log the error". Logging alone would leave the server to fail a moment later inside SqlConnection.Open() with a much less useful message, so I am reading it as report and refuse to start rather than report and carry on. If carrying on was intended, say so and it is a small change.

Please hold this PR — the rework is not pushed yet. The unit tests for this code exist on a local branch and their expectations need to be inverted to match the new behaviour. I will push both together and update this thread.

meketreve and others added 2 commits August 16, 2026 02:57
…eywords (ISSUE-035)

The perpetuum.ini written by the Perpetuum Dedicated Server installer does not
start this server. It was written for the original server, which used
System.Data.SqlClient; this one uses Microsoft.Data.SqlClient, which differs in
two ways that both abort startup before any zone loads.

Measured against Microsoft.Data.SqlClient 6.0.1 with neutral resources, so the
messages below are the ones a maintainer sees rather than a translation:

  Connection Reset=True
    System.NotSupportedException: The keyword 'Connection Reset' is not
    supported on this platform.
  thrown while SqlConnection is being constructed, not on Open().

  no Encrypt / TrustServerCertificate
    SqlException on Open(): A connection was successfully established with the
    server, but then an error occurred during the login process. (provider: SSL
    Provider, error: 0 - ...)

Neither message names perpetuum.ini, which is what makes a fresh setup hard to
diagnose.

The first is now handled. LegacyConnectionString.RemoveObsoleteKeywords drops
keywords that Microsoft.Data.SqlClient refuses AND that the framework had
already stopped honouring, so removing them cannot change how the server
connects. PerpetuumBootstrapper.Init calls it directly after resolving
GlobalConfiguration — before anything constructs a SqlConnection — and logs a
warning naming perpetuum.ini and the keyword.

Keywords that still carry meaning are deliberately left alone. Network Library
selects a protocol and Context Connection selects a SQLCLR connection; both
need an operator decision, and the driver's own error already names the
replacement.

Two implementation notes, both measured rather than assumed:

  - Parsing goes through DbConnectionStringBuilder, the provider-agnostic
    parser. SqlConnectionStringBuilder throws on the same keyword, so it cannot
    be used to find it. Splitting on ';' by hand was rejected because it
    corrupts quoted values containing a separator, verified against
    Password="a;b=c".

  - The input is returned untouched when nothing is removed. Rebuilding through
    DbConnectionStringBuilder lower-cases every key and drops the trailing
    separator, and a connection string that reaches a log should be the one the
    operator wrote.

The second failure is documentation only. Defaulting TrustServerCertificate in
code would weaken authentication for every operator in order to fix a local
development case. README.md gains a setup section instead: the requirement, a
working connection string, and the caveat that TrustServerCertificate=True
belongs on a local instance only.

Verified against a real server run in three states:

  Connection Reset present, fix applied   warning naming perpetuum.ini and the
                                          keyword, then Database: perpetuumsa
  Connection Reset present, fix reverted  the NotSupportedException above, the
                                          process exits, no mention of the file
  keyword absent, fix applied             no warning, log identical to before

The third state is the one that shows valid configurations are unaffected.
Maintainer direction, given on Discord on 2026-08-15: the installer already
deploys a corrected perpetuum.ini, so this only bites when a fresh PP2 is
pointed at an old PP1 data folder, and a clear diagnostic serves that case
better than silently accepting the file. This is also what ISSUE-035's own
Proposed Fix asked for: "an error that names perpetuum.ini and the
offending key".

LegacyConnectionString is replaced by ConnectionStringSupport, which
reports and never rewrites. The connection string reaches the driver
exactly as the operator wrote it.

PerpetuumBootstrapper.Init now logs an error naming perpetuum.ini, the
directory it sits in, and every offending setting, then throws so the
server does not start on a connection that cannot open. There is no
precedent for refusing to start in this file -- it holds no other throw --
so the choice of InvalidOperationException is stated in the pull request
for the maintainers to overrule.

The check keeps no keyword list. It parses with DbConnectionStringBuilder,
then offers each setting to SqlConnectionStringBuilder and reports whatever
that refuses. Two consequences: Network Library and Context Connection are
now named, where removal had to leave them alone because dropping them
would change how the server connects; and a setting nobody anticipated is
reported the same way.

Every offending setting is reported in one message. The installer's file
carries more than one, so a first-failure-only report would cost the
operator a restart per setting.

The catch around the per-setting probe is deliberately broad. Measured
against Microsoft.Data.SqlClient 6.0.1, the driver uses three different
exception types for this -- NotSupportedException for Connection Reset and
Network Library, ArgumentException for Asynchronous Processing,
InvalidOperationException for Context Connection -- and a narrow filter
that missed one would report the setting as supported and hand the operator
the obscure failure this check exists to replace.

Verified:

- 15 unit tests in ConnectionStringSupportTests, 8 of them observed failing
  against a stub before the detection was written
- full unit tier green, 73/73
- solution builds with 0 errors, and no warning comes from a project this
  touches
- a game root carrying Connection Reset and Network Library produces one
  ERR line naming both and exits 1, before anything else in Init needs the
  game root
- tools/smoke-test.ps1 green against the real database with a good file:
  [Online] after 80s, 6435 members spawned, graceful shutdown, exit 0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@meketreve
meketreve force-pushed the issue-035-connection-string-compat branch from fc93d13 to b14cf40 Compare August 16, 2026 06:13
@meketreve

Copy link
Copy Markdown
Contributor Author

The rework is pushed — this PR now reports the rejected settings and refuses to start, instead of removing them. The branch was also rebased onto the current develop, which is why the first commit's hash changed.

Read the second commit on its own to see the change of direction; the first is the original work, unchanged apart from the rebase.

What it does now

ConnectionStringSupport.FindUnsupportedKeywords reports; nothing is ever rewritten, so the connection string reaches the driver exactly as it was written in perpetuum.ini. PerpetuumBootstrapper.Init logs an error naming the file, the directory it sits in, and every offending setting, then throws.

Against a game root carrying two bad settings:

[03:07:28] INF >>>> Perpetuum Server State : [Init]
[03:07:28] ERR perpetuum.ini in <game root> has a connectionString carrying 2 setting(s)
Microsoft.Data.SqlClient does not accept: connection reset, network library. Remove them and
start the server again. The original server used System.Data.SqlClient, which accepted them.

Process exits 1. The check runs before anything else in Init needs the game root.

Two decisions worth a look

No keyword list. The check parses with DbConnectionStringBuilder, then offers each setting to SqlConnectionStringBuilder and reports whatever it refuses. This fell out of the change of direction: the old list was short only because removing a setting had to be provably safe, and reporting always is. So Network Library and Context Connection are now named too, and a setting nobody anticipated is handled the same way. Nothing to maintain when the driver changes.

InvalidOperationException, and this is the part I would most like overruled if it is wrong. CLAUDE.md points at PerpetuumException / ErrorCodes, but those model game protocol errors and this is a startup configuration problem — adding an ErrorCode for it seemed heavier than the problem. There is also no precedent to copy: PerpetuumBootstrapper.cs contains no other throw, so refusing to start is new behaviour for that file however it is spelled.

Verification

Check Result
Unit tests 15 new in ConnectionStringSupportTests; 8 observed failing against a stub before the detection was written
Full unit tier 73/73
Build Solution builds with 0 errors; no warning comes from a project this touches
Bad file One ERR line naming both settings, exit 1
Good file tools/smoke-test.ps1 green against a real database — [Online] after 80 s, 6435 members spawned, graceful shutdown, exit 0
Driver premise The_driver_really_does_reject_the_installer_string fails the day the driver stops rejecting the keyword, which is the day this whole check becomes dead weight

The three settings-reporting details — all offenders in one message rather than one per restart, the deliberately broad catch around the per-setting probe, and the lower-cased spelling that DbConnectionStringBuilder produces — are each explained in the commit message and in the ISSUE-035 backlog entry.

@Sellafield
Sellafield merged commit 56ea9cb into OpenPerpetuum:develop Aug 17, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants