Hello, this is Team Samoyed!
Teamfight Manager 2 will be sharing consistent development updates every 2–3 weeks through development logs. We appreciate your interest and support!
Match Engine
The first development log will cover the most crucial aspect of the game: the design of the match engine. Since we are still in the early stages of development, many changes are expected. For now, we will briefly outline the direction we are taking with the match engine.
Game Rules
In Teamfight Manager, the team that secures the most kills within one minute wins. This simple rule makes the game easy to understand, but it also has the downside of limiting strategic diversity, which can make the game feel repetitive over time.
With Teamfight Manager 2, we aim to create a deeper game simulation that remains engaging for a longer period. To achieve this, we have moved away from the deathmatch rule and introduced a simplified MOBA-style game structure.
- Matches are played in a 4v4 format, just like in the previous game.
- There are four positions: Top, Jungle, Bottom, and Support.
- The map features two lanes, Top and Bottom. The Top position plays in the top lane, while the Bottom and Support positions play in the bottom lane. The Jungle position focuses on farming jungle monsters and ganking.
- A leveling system has been introduced. Champions gain experience by killing minions, jungle monsters, destroying towers, and participating in kills. Leveling up increases their stats, and at level 3, they unlock a second skill.
- The team that destroys the opponent’s relic first wins.
Since this is a fictional game within the game, we are designing the rules to be as simple and intuitive as possible. Our goal is to make it easy for players to understand the game mechanics just by watching a couple of matches.
Player Actions
In Teamfight Manager, player behavior in matches was mostly governed by simple rules, with a few traits influencing AI decisions. However, this often made it feel like the players weren’t actively making decisions.
One of the goals for Teamfight Manager 2’s match engine is to make it feel more like the players are actually controlling the game. For example:
- In Teamfight Manager, players would always attack the closest enemy unless a trait dictated otherwise.
- In Teamfight Manager 2, players can choose to target more distant enemies based on their judgment.
Additionally, we are reworking how player stats function:
- In Teamfight Manager, player stats (attack, defense, champion proficiency, etc.) directly influenced in-game champion stats. This made it feel like “better players just deal more damage,” which was intuitive but somewhat unrealistic.
- In Teamfight Manager 2, player stats no longer directly modify champion stats. Instead, they influence AI decision-making, leading to different playstyles.
- A player with high mechanics will dodge skill shots more effectively.
- A player with high decision-making will make better strategic choices.
This new system allows for a more dynamic simulation, creating distinct team playstyles, tactics, and in-game situations.
Champion Design
With this shift in direction, champion skills are also being designed to highlight player AI differences.
Dual Blader skillfully evades all of Executioner’s attacks, gaining a significant advantage in the battle.
For example, in the match engine currently in development:
- Dual Blader successfully dodges all of Executioner’s skills, securing an advantage in lane.
- Executioner’s pull skill and Dual Blader’s dash skill have been converted to skill shots.
- Dual Blader’s dash can be used both offensively and defensively, depending on the player’s judgment.
Since these skill shots require precise execution, champions like Dual Blader are more effective when controlled by a player with high mechanics. However, if a player’s mechanics aren’t high enough, the outcome may be drastically different.
Executioner’s skill interrupts Dual Blader’s skill, causing a significant disadvantage in the ensuing fight.
This design allows champions to have distinct identities based on player skill. Some champions benefit from high mechanics, while others rely on decision-making. This variance affects lane matchups, strategy, and team compositions, creating more depth in draft strategies.
Tactics
With the introduction of new game rules, we can now incorporate more strategic elements. Players will be able to adjust their overall game plan according to their preferred playstyle.
For example:
- If both the Top and Bottom lanes are picked for late-game scaling, they can be instructed to play defensively early on.
- If a team picks an early-game focused Jungler, tactics can be set so that the Jungler prioritizes ganks over farming, helping the weak lanes survive the early game.
A successful early-game engage setup that utilizes a ninja with a powerful initiation and a knight whose taunts generate an excellent response.
The goal is to make tactics an integral part of draft strategy while keeping the options intuitive and easy to use.
Technical Aspects
So far, we've discussed the design direction of Teamfight Manager 2's match engine from a gameplay perspective. Now, let's dive into the technical challenges of implementing the match engine and how we're overcoming them. This section contains some technical details, so feel free to skip it if that's not your cup of tea!
Performance Issues
In Teamfight Manager, the game rules were simple and each match lasted only one minute, which made the simulation relatively straightforward. Even so, that simplicity still imposed a significant load—primarily due to data collection. The Teamfight Manager series features dynamic in-game rules. As patches are applied, champion performance continuously shifts, and our ban/pick AI needs to respond accordingly.
To address this, our system continuously runs background simulations to collect data and adjust the AI based on the current patch. This process requires running an enormous number of simulations, so every match simulation must run as fast as possible.
Teamfight Manager 2, however, features a far more complex simulation. With the shift to MOBA-style rules, matches now last much longer than one minute, include more in-game objects, and introduce obstacles like walls that necessitate pathfinding, as well as asymmetric vision elements like bushes. On top of that, the AI controlling players is considerably more complex than before, which increases the overall computational load by several orders of magnitude.
To meet these challenges and achieve maximum optimization, Teamfight Manager 2 is being developed on a custom engine built in Rust.
Deterministic Simulation
Saving every frame of a match would result in massive save file sizes. To avoid this, we ensure that if a match's initial state (seed, team strategies, champion selections, etc.) is identical, the simulation always yields the same outcome. This property, known as determinism, means that we only need to store the initial state to reliably replay any match—an enormous saving in storage space.
Moreover, for multiplayer, we only need to transmit the initial state to each client; each player can then run the simulation locally without sending the entire process over the network.
Achieving deterministic simulation requires careful handling of two key aspects:
- Randomness: Each match simulation uses its own random number generator initialized with a match-specific seed. While this isn’t overly challenging, care must be taken since third-party libraries can sometimes introduce unintended non-deterministic behavior.
- Floating-point Operations: Although floating-point math can be deterministic on the same PC, differences in hardware or environment can lead to discrepancies. Such discrepancies could cause players to see different outcomes in multiplayer, so we must eliminate these issues. Given that floating-point operations are also slower and the simulation doesn’t demand ultra-precise calculations, we’ve implemented all logic using integer-based fixed-point arithmetic.
Preprocessing Optimization
Pathfinding and vision calculations are inherently slow. To minimize the computational cost, we divide the entire map into 32×32 pixel cells and precompute data for each cell.
For example, in pathfinding, we precompute and store the “next cell” needed to move from cell (a, b) to cell (c, d), allowing instantaneous pathfinding during simulation. Similarly, for vision, we precompute whether a cell at (a, b) can see a cell at (c, d), so the simulation can retrieve this information without any extra computation. While storing this data consumes a few megabytes of memory, it’s negligible on modern systems. Admittedly, this approach sacrifices a bit of precision—since calculations are based on 32-pixel segments—but the difference isn’t noticeable during gameplay.
Memory Allocation Optimization
Our simulation demands frequent memory allocations and deallocations. Throughout a match, hundreds of projectiles are created and destroyed, and numerous buffs, champion deaths, and object respawns trigger continuous memory operations, which are computationally expensive.
Using a low-level language like Rust allows us to fine-tune memory management. We optimize the simulation by using a custom memory allocator that fits the unique needs of our game’s simulation structure.
Rendering Separation
If a match isn’t being observed by a player, much of the rendering data is unnecessary. When running background simulations to gather results and statistics, we can skip generating rendering-related information. By distinguishing between these scenarios, we can significantly speed up background simulations by omitting the creation of rendering data.
Parallel Processing
There’s a limit to the performance achievable on a single CPU core, so it’s crucial to utilize all available cores by running simulations in parallel. From the early stages of development, we designed the system to support smooth parallel processing.
Thanks to this approach, our current simulation can compute one minute of game time in about 0.05 to 0.1 seconds. While the exact time depends on PC performance and the number of parallel threads, on our current development machine, simulating 1,000 matches on 4 threads takes roughly 4 minutes (about 0.24 seconds per match). We continue to address technical challenges and optimize the match engine’s performance, staying true to our design vision while ensuring rapid execution.
Thank you for reading this lengthy post! We’ll see you again in the next development log!
