S4 League was fast, strange, stylish, and unusually expressive. Its movement and combat gave players room to build a real mechanical identity, and almost nothing since has asked the same of them. Project Zin exists to bring that back properly: not by patching the old client, but by taking it apart, learning why it felt the way it did, and rebuilding it from scratch.
This is Project Zin
We are rebuilding the game as a modern Unity 6 client backed by dedicated .NET services. This is not a visual imitation sitting on top of unrelated movement, and it is not simply the original client pointed at a new server. The goal is to understand the systems that made S4 feel like S4, reproduce them deliberately, and give the project an architecture we can maintain.
Why remake it?
Preservation is the first reason. A live game is more than models and maps: timing, collision, camera behavior, weapon scripts, effects, networking rules, and dozens of tiny edge cases combine into its identity. If those rules remain trapped inside one old executable, they slowly become inaccessible.
The second reason is everything a rebuild makes possible. Once the behavior lives in code we wrote, in an engine we control, the work downstream gets dramatically easier. Fixes land in minutes or hours, not whenever someone can find room in a binary. Modern resolutions and frame rates stop being a fight. New maps, weapons, and modes can be built with the same rules the originals followed, and security gets handled at the source instead of patched around.
Reading the original client
The capture below is where the movement work started. CCollisionObject__MoveAndSlide is the original client’s collision routine, caught scaling position and movement vectors before it hands them to the solver. Around it sit ray casts, triangle-mesh collision, collider lookup, and physics-world updates — the whole locomotion path, laid out in the open. IDA is one of the tools we use to recover that intent, and a symbol name is never proof that a path is live, so every finding is traced through its callers and checked against runtime behavior before it earns a place in the rebuild.
Static evidence
Decompiled control flow, constants, call sites, original Lua and XBN tables, plus SCN, SEQ, and OCT resource structures.
Runtime evidence
Sessions recorded on the original client: the inputs a player gave, and everything the game did with them. Feeding those same inputs to Zin puts the two runs side by side.
Rebuilding the movement physics
Movement is where a remake can look correct and still feel completely wrong. The Project Zin client therefore has its own MoveAndSlide solver instead of delegating character motion to Unity’s CharacterController. The implementation follows the original client’s recursive swept-sphere approach in ellipsoid-normalized space: scale the player volume into a unit sphere, find the nearest collision along the movement vector, move to contact, build a sliding plane, project the remaining movement, and repeat.
world space
-> scale by actor ellipsoid
-> sweep a unit sphere against candidate triangles
-> move to the nearest contact
-> project the remaining vector onto the sliding plane
-> recurse, then transform back to world spaceKasper Fauerby’s paper Improved Collision Detection and Response is the clearest public description of this family of algorithms: an ellipsoid moving through arbitrary triangle meshes, solved by transforming into ellipsoid space, sweeping a unit sphere, and recursively resolving what is left of the motion along a sliding plane. If that sounds like the character controller shipped with your engine of choice, that is not a coincidence — the same lineage runs through most of them, Unity’s included. It is worth reading if you want the geometry in full.
The trick the paper turns is that an ellipsoid sliding through a triangle soup is an ugly problem, and a unit sphere sliding through the same soup is a solved one. Divide the world by the actor’s radii and the character becomes that sphere, so every test reduces to the same question: how far can a sphere of radius one travel along this vector before it touches something? Each candidate triangle is answered in two parts — the sweep against its plane, and, when the contact falls outside the triangle, sweeps against its three vertices and three edges. The nearest of those answers wins, the sphere is moved to just short of it, and a sliding plane is built at the contact so the leftover motion can be projected along the surface instead of stopping dead against it. Then the whole thing runs again on what is left, until the remaining distance is too small to matter. That is what a wall feels like when you run along it, and it is the same loop the original client runs.
The original data still matters
Rebuilding the runtime does not mean throwing the game’s authored data away. Our editor tooling reads original map scenes and compiled collision data, reconstructs SCN nodes and transforms, and interprets SEQ effects such as particles, trails, and lightning. Weapon import follows the original XBN tables, Lua calls, models, effects, and sound references. Maps, weapons, and effects come across with the relationships that made them work intact instead of being flattened into a pile of one-off Unity prefabs — and once they are in our pipeline, we can build on them with the same rules the originals followed.
What we are doing differently
A maintainable client
Unity 6 gives us a current rendering and tooling foundation, while custom gameplay systems preserve the behavior that cannot be replaced by engine defaults.
Measured, not eyeballed
Those replays are scored against the original’s trajectory and state at every tick, so “it feels right” stops being an opinion and becomes a number we can fail.
What comes next
The server-authoritative migration is next. Every match will run on its own dedicated server — the arrangement any modern competitive shooter uses — simulating at the same 60 Hz tick the original ran. As the game feel settles we are opening a small closed alpha with a hand-picked group, and the simulation work runs alongside it. Later devlogs will go deeper into the collision solver, map and effect importing, movement comparison against the original, and the match services.
The goal was never to build something that resembles S4 League. It is to understand why it felt the way it did, keep that knowledge in code anyone can maintain, and build forward from there.
— Project Zin development team
Follow the work, ask the awkward technical questions, or put your name forward for a future test session.
