Multiplayer - Unreal C++
This project showcases a multiplayer system built in C++, featuring a menu, a lobby, and a game level. In the video, players can select a skin, host a game, or connect to a specific IP. Once connected, they are seamlessly transported to the game map with their chosen skins. When two players are in the lobby, a synchronized 10-second countdown starts, remaining accurate even with 500ms latency. A third player joins, changes their skin in the lobby, and the update is correctly replicated for everyone. Once the countdown ends, all players are teleported into the game, maintaining their selected skins.

When a player connects, the server checks how many players are in the lobby. If at least two players are present, a countdown starts automatically. Once the timer reaches zero, all players are teleported to the game map while keeping their selected skins.
The countdown is fully managed by the server and synchronized across all clients. Even if a player joins late or experiences network lag, they instantly receive the correct remaining time. This ensures a smooth and fair game start for everyone.

📌 Multiplayer Skin Replication in Unreal Engine
In this project, I implemented a multiplayer skin replication system using Unreal Engine’s networking framework. The system ensures that:
✅ Players can select their skin in the menu or lobby.
✅ The selected skin is instantly replicated across all clients.
✅ Even after seamless travel, the correct skin is applied.
✅ The system is optimized for network efficiency, minimizing unnecessary updates.
✅ Players can select their skin in the menu or lobby.
✅ The selected skin is instantly replicated across all clients.
✅ Even after seamless travel, the correct skin is applied.
✅ The system is optimized for network efficiency, minimizing unnecessary updates.
Below is a simplified overview of the key components involved in skin replication:


This project highlights a lag compensation system in a C++ multiplayer shooter. Every 100ms, the server records each player's position. When a player fires, the client quickly checks the hit locally, then sends the shot time and hit data to the server. The server adjusts for the player's latency, rewinds the target’s position to where it was at the moment of the shot, and runs a precise hit trace. If it confirms the target was indeed hit at that past position, damage is applied. This ensures fair and accurate hit registration, even under high network latency.

he process starts with the server continuously recording each player's position. For instance, in the RecordMove() function, every 100ms the server saves the player's current transform (which includes both location and rotation) along with a timestamp. This function also calls CleanUpHistory() to remove outdated entries, ensuring that the history only holds data for a defined period. Here’s an excerpt from the RecordMove() function
When a player fires a shot, the system needs to determine where the target was at the moment of the shot. This is achieved by the RewindPlayerPosition() function, which uses the saved moves to reconstruct the target’s position at a past time. The function checks whether the requested hit time falls within the recorded history. If it does, it finds two saved positions that bracket the hit time and, if necessary, interpolates between them to determine the exact location.


Once the target’s past position is determined, the server needs to validate the shot. In the Server_ValidateShot() function, the server receives the client’s shot information including the shot time, the start and end points of the trace, and the target actor. The server corrects the client’s reported time by subtracting half of the player’s ping, thereby estimating the true time the shot was fired. It then calls ServerSideRewind() to perform the actual hit verification.
On the client side, the Shoot() function handles the initial hit detection. The client performs a local line trace to provide immediate feedback, and if a valid target is hit, it collects the shot’s timestamp along with the trace’s start and end points. This information is then sent to the server by calling Server_ValidateShot() on the LagCompensationComponent, where the shot is later verified through the rewind logic. Here’s the implementation of the Shoot() function:
