Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Looterkings — Direct Connect

Keeps Looterkings (see SteamDB) playable after the shutdown of its Zeus master servers, by adding a direct IP connection using F9 in the Main menu.

Background

After the announcement of the server shutdown, my brother and I wanted to 100% the game. We tried for an hour to get a multiplayer session running, but without success. I asked Claude if it could build a workaround. A few iterations later we were able to connect and play together. Something that would have taken me days, done in a few hours.

What we were able to do with this modification:

  • Play the football / soccer mini game.
  • Play the normal mode and finish it.
  • And in the end get all achievements.

Noteworthy: I play on Linux and my brother on Windows. The mod worked for both of us. We used Wireguard to be in the same local network.

Apart from this section, the rest is written by AI. I corrected a few links. Have fun.

Technical

The game uses Photon Bolt. The master server was only ever responsible for the server list and for punching connections through routers — the gameplay traffic always went directly between the players' machines. That is what makes playing on possible at all.

A direct IP input was even planned in the game, but never finished: the input field is permanently greyed out and SessionBrowserScript.OnIpSet is an empty method body. This project fills that gap, frees host and client from the master server dependency, and puts the input on F9.

Status: working. The game has been played through to 100% by two people across two machines (Windows host / Linux+Proton client); round duration, automatic rematch, XP and gold multiplier and the test dummies all work.


For players

Grab the release archive and follow dist/README.md: back up Assembly-CSharp.dll, copy three files in, press F9 in the server browser.

There is no installer — it is one rename and three copies, and a script that has to be trusted with your game folder is a worse trade than doing it by hand.


How it works

LKDirect.dll is a new assembly holding all the logic. Patcher.exe (Mono.Cecil) rewrites a small number of IL sites in the game's Assembly-CSharp.dll to call into it. Nothing else about the game is modified.

# Site Change
A SessionBrowserScript.OnIpSet was an empty body (ret); now calls LKDirect.ConnectTo()
B ConnectionUtility.StartServer (2×) hardcoded useMasterServer = trueLKDirect.UseMasterServer()
C SessionBrowserScript.Setup calls LKDirect.Boot() — creates the overlay
D Client-/ServerStartJob.OnBoltStarted Zeus.IsConnectedLKDirect.ZeusReady()
E ServerStartJob.OnBoltStarted offline branch now runs InitHostInfo() before Finish()
F Dbg.Log/LogFast/LogWarning empty bodies in the release build → LKDirect.GameLog()
G MasterServerChoice.ResolveURL LKDirect.ResolveMaster(), survives a dead DNS record
H HostProcess.SearchForSession FindSessionLKDirect.FindSessionOrLocal()
I MatchManager_Server (3×) m_playTimeLKDirect.MatchTime()
J MatchManager_Server.EndGame LKDirect.AutoRematch()
K/L/M/N/Q Player, MatchManager_Server, LooterLeagueServerCallback dummy players (see below)
O/P MatchManager_Server.EndGame / .StartMatch count a win once per match, not once per frame
R Player.AddExperience p_amountLKDirect.ScaleXp()
S LootBehaviorScript.Start GetLootValue result → LKDirect.ScaleGold()

The patcher refuses to run on an assembly that does not look like the expected original — it aborts if OnIpSet is not the empty body it expects, or if a site count does not match. It cannot be applied twice to the same file by accident.

Notes on the trickier parts

Direct connect bypasses ConnectProcess, so a handful of things the normal join path does have to be done by hand: setting ConnectionStatus.Connected (otherwise the screen stays black after cutscenes), raising OnConnected (otherwise loot data stays null and throws), switching to the lobby menu, and setting the game mode — which is why the F9 overlay has a mode picker, since without a session the client cannot learn the host's mode.

Dummy players exist to test a round alone. GoblinBall requires at three points that every player has acted (scene loaded, team picked, character picked); a dummy has no BoltConnection and can trigger none of them, so each hurdle is cleared server-side. The whole feature is gated behind dummy_players > 0 and can also be compiled out entirely with --no-dummy.

GoblinBall-only options. dummy_players, goblinball_time and auto_rematch_* are additionally gated on GameManager.mode == LooterLeague, so a config left over from a GoblinBall evening does not leak into a normal round. The check is deliberately not cached — the mode changes between matches without the game being restarted — while the config values themselves still are. All three are host-only, so the host's menu selection is the authority.

XP multiplier hooks Player.AddExperience, the only route by which XP is gained. The Bolt state is server authoritative, so only the host's setting matters — it then applies to everyone in the match.

Gold multiplier hooks the return value of GameInfo.GetLootValue(), which has exactly one caller: LootBehaviorScript.Start(), where it initialises m_lootValue. That one field then feeds everything downstream — Player.AddGold(), the "+X gold" popup via FireOnLootCollectedEvent, and the halving when two players are stacked — so scaling there keeps all three consistent. Player.AddGold() deliberately is not the hook: the shop refund (StreamAction.SetSold) and the debug cheats go through it too.

Note that unlike AddExperience, AddGold has no clamp — it is a plain state.gold + amount in int32, accumulated across a whole round. Both the factor (max 1000) and the per-pickup result (max 1e6) are therefore capped, so the sum cannot overflow into negative gold.


Building

Requirements:

  • Mono C# compiler and runtime (mcs, mono) — pacman -S mono / apt install mono-devel.
  • Mono.Cecil 0.11.x — the patcher is built against it. Usually already there: Mono ships it in its GAC and build.sh finds it by itself. See below if yours does not.
  • Your own copy of Looterkings, for the eight game assemblies the build references (Assembly-CSharp, mscorlib, System, System.Core, UnityEngine, bolt, bolt.user, udpkit.common). They are not in this repository. The Assembly-CSharp.dll among them has to be the unpatched one.
  • bashbuild.sh is a bash script, so on Windows use WSL or Git Bash.

Nothing else is downloaded during the build, and nothing is written outside the repository.

Getting Mono.Cecil

On Arch, pacman -S mono covers it. On Debian it can be a separate package (apt install libmono-cecil-cil). Failing that, drop a copy into tools/, or point CECIL at one you already have (CECIL=/path/to/Mono.Cecil.dll ./build.sh):

curl -sL -o cecil.zip https://www.nuget.org/api/v2/package/Mono.Cecil/0.11.1
unzip -j cecil.zip lib/net40/Mono.Cecil.dll -d tools/

0.9.x is a different API and will not compile. If several versions are installed, the highest one is used.

Getting the game assemblies

Copy them out of your own install into refs/ (gitignored):

cp "$HOME/.steam/steam/steamapps/common/Looterkings/looterkings_Data/Managed/"*.dll refs/
./build.sh

Or point REFS somewhere else: REFS=/path/to/Managed ./build.sh.

Either way that folder needs the unpatched Assembly-CSharp.dll. If the patch is already installed, use the Assembly-CSharp.dll.orig backup you made when installing.

Output lands in dist/. Add --no-dummy for a build without the dummy-player patches.

src/LKDirect.cs    the helper assembly — all logic lives here
src/Patcher.cs     the Cecil patcher
tools/             optional local copy of Mono.Cecil (gitignored)
refs/              your local copy of the game assemblies (gitignored)
dist/              release payload: config template, built DLLs, player README

build.sh prints the MD5 of the unpatched Assembly-CSharp.dll it built against. That is the value quoted in dist/README.md under Does the patch fit my version? — if you build against a different game version, update it there.


Compatibility

Built against the final Steam release of Looterkings, Assembly-CSharp.dll MD5 218ad7184b1dff6ba2f019ecf94aa91d. Check yours before installing — the patched assembly is built by rewriting exactly that file, and a different build will not work.

A Steam file verification reverts the patch (LKDirect.dll stays behind but is then inert). Just copy the patched Assembly-CSharp.dll in again.

About

Mod to allow local multiplayer in Looterkings

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages