The Initial Plan
I made an extension that automatically prevents gameplay decisions unless you've spent a specific amount of time on the move. It's a high impact training tool for E-sports players to manager their practice environment and replicate real-time conditions as much as possible. As of the writing of this article, the extension has over 1000 active users, clearly proving the demand for this tool. However, this extension was not as simple as it looks What seemed like a simple extension became quite involved. In this article I will go over the key technical obstacle and how I solved it.
The Challenge of State Management
The control logic for the extension is quite straightforward. For a particular game, the extension will check if the player has spent a minimum amount of time on the move. If not, the extension will prevent the player from making a decision. This time can be customized by the user and their are about a billion failsafes to make sure you never block someone from making a move and causing a loss by running out of time. The base case is simple, but the real technical challenge was managing multiple games and multiple games within a game. What happens if someone is playing multiple games at once? Each game has to manage its own state and timer. Each game has to be independent of the other games. This is not an oddball edge case either, many players train multiple games at once, play best of 3s, or play multiple games in a row without leaving old games. "Timer On, Timer Off" is not good enough to handle the edge cases.
Solution and Conclusion
To solve this, I built a dynamically operating array of "battles". Each battle managed its own state and timer. state and timer would be recalculated for a battle when that battle entered the active state. This works around JavaScript's asynchronous and single threaded nature without sacrificing any functionality. This approach is resilient to errors because changes to the array are atomic and state manipulations are restricted to their local scope. Even if a player is switching through games rapidly, maintaining a sort of psuedo-local context means that we avoid erroneous state changes.This modular approach ensures that the extension can scale seamlessly, regardless of how many games a player has open. By encapsulating each game's state and timer logic within its own battle object, the system avoids interference between games and remains robust even under rapid context switches. Additionally, I implemented thorough testing to account for edge cases, such as games starting or ending mid-session or multiple games sharing overlapping timers. This structure not only simplifies debugging but also ensures consistent performance across a variety of use cases. Ultimately, this design allows players to focus on improving their decision-making under real-world constraints, making the extension a powerful tool for competitive E-sports training.