Alice in Space
Role
Gameplay / Multiplayer Engineer
Description
A multiplayer third-person shooter where players travel the universe, landing on unstable planets to capture zones and gather resources before time runs out. Race against destruction, outsmart rival players and NPCs, and reach a checkpoint to save your upgrades, or lose everything if you don't make it out in time.
Date
Jan 2025 - Dec 2025
Engine
Unreal Engine 5
​
​​
Team Size
Startup company - team size was variable during my time. Anywhere from 6 to 25.
Contributions
I joined Rogue Rooster as a Gameplay/Multiplayer Engineer Intern, and later was offered to continue on the project in a part-time Gameplay/Multiplayer Engineer role. Over that time, I worked on a wide range of multiplayer gameplay systems in Unreal Engine 5, with a strong focus on server-authoritative combat, AI, and movement. My work included implementing bullet rollback for lag compensation, building a custom animation pose rollback system for precise multiplayer rewinds, and creating a ghost component that rendered an estimate of the player’s true server position to give players better strategic awareness in online play.
​
I also worked on enemy and traversal systems that supported both gameplay variety and multiplayer reliability. I created AI archetypes such as booster-powered droids and tactical grunts, helped build an AI framework around perception, navlink traversal, and weapon-driven behavior, and developed flocks of “billiard bird” enemies that scattered and regrouped with custom smoothing and replication support. In addition, I refactored the bullet system into a component-based architecture, added burst-fire support, and reworked the traversal system to more reliably choose environment-aware animations for smoother movement.
Lag Compensation and Bullet Rollback
Implementing bullet rollback/rewind was something I was interested since I learned about the concept. Thankfully for me, I got the perfect chance to do it, as it had not yet been implemented in the project. There were no plans to do it yet, but as I was developing enemy AI within the project, I noticed that when I would try to do shoot them, I would consistently miss, even when I knew it should be hitting. After noticing that it only happened when the enemy would be moving, I realized it was this exact problem of lag compensation.
​
Now, doing the rollback details was not overly complex itself. We used a nice multiplayer plugin called the General Movement Component (GMC), which already handled the messy details like saving move history for pawns, and all you had to do was give it the timestamp and it would handle setting the server pawn back to the state at that timestamp.
​
However it wasn't this simple, as on top of the basic rollback itself, I also had to build the full server-side hit resolution pipeline around it. When a shot came in, the server first traced along the bullet path to identify which pawns were even possible rollback candidates, rather than rewinding every actor in the world. After rewinding nearby targets, the server would run the actual hit detection using the rewound state, then resolve the hit and spawn the appropriate impact effects.
​
I also implemented a secondary near-miss sweep around the bullet path to make hit registration more forgiving and consistent for fast-moving targets. This helped catch cases where a strict line trace could miss due to latency, small hitboxes, or minor differences between what the shooter saw and what the server was evaluating. The result was a more robust lag compensation pipeline where the server remained fully authoritative, but shots still felt fair and responsive to the player.
Custom Pose Rollback Solution
The big issue with the GMC solution was it only handled rollback based on a capsule root transform, meaning only the overall position of the pawn would be rewound. We wanted the detailed pose of the character’s hitboxes to also be rewound, since a character's root position can remain the same but in an animation the collision physics bodies can change drastically (take crouching for example).​
So, this is where it got fun for me, because now I got to implement the fundamentals of rollback, but with the physics bodies rather than just the root transform. On the right, there is a video representing what my solution is doing. There is an NPC just crouching repeatedly. As it does so, you can see an orange outline of its physics bodies which is the server's version of the enemy. This is ahead of the simulated proxy, as the proxy has a simulation delay. This is being done with Unreal's "Bad" network emulation, which is 100-200ms of latency and 5% packet loss. You can see the problem: if you shot its head just as it was about to crouch, it's already crouching on the server! So if you were to just simply run the hit resolution against that current server pose, it would come back as a miss.
​
So instead, I have to rewind the entire pose, which is
what happens in the video. After I shoot its head, I keep the server pose there in orange and also put a cyan outline that is the rewound version of the pose, which is also the same pose as how the client saw the simulated proxy when it shot. Now the collision check is done against the rewound pose rather than the current server pose, and as a result, it is a hit confirmed (as by hit the particles), yay!
​
So, how did I do this? I implemented a lightweight history system that records the world transforms of each physics body in the character’s PhysicsAsset at a fixed frequency on the server. Compared to storing all skeletal bone transforms, this approach is significantly more memory efficient, since most characters only have around 15–25 collision bodies but can easily have over 100 bones. Each snapshot is stored alongside a timestamp so the server can reconstruct the exact hitbox configuration at any moment in the recent past.
​
When a shot is processed, the server determines the correct rewind timestamp using GMC’s rollback parameters, then queries the pose history for the two snapshots surrounding that time. The transforms of each physics body are interpolated between those snapshots to approximate the pose the shooter saw when the shot occurred. These interpolated transforms are applied directly to the physics bodies, then the hit detection is executed against this rewound pose.
​
An additional benefit of this approach was that I did not need separate restore logic after the rewind. Because the solution applies temporary transforms directly to the physics bodies, Unreal naturally updates them back to their normal state on the next tick. That made the system simpler than GMC’s rewind, which required explicit restore handling after the rollback.
​
Because this operates only on the physics bodies and not the full animation skeleton, the system is fast enough to run per-shot while still producing accurate hit registration for rapidly changing poses like crouching, leaning, or attack animations. The result is a fully server-authoritative solution that maintains fairness while ensuring the player’s aim matches what the game evaluates as a hit.