I’ve been working some on a Magic the Gathering client for Roblox. It’s at a point where you can actually play a game on it now. Place is Uncopylocked, feel free to take a look at the code.
Some Usage notes:
- You can undo mana ability activations by pressing “Z”
- You can pass until the next turn by pressing “A”
General Project Structure:
- MagicGameState in ReplicatedStorage is the central model class that runs everything
- MagicClientView → MagicGameView in ReplicatedStorage.View are the root view/controllerss that display the current state
- The network communication is all done through one RemoteEvent in ReplicatedStorage.MagicInterface
- The idea is that the client sends an “I’m ready” event to the server, when it’s done local loading, and then the server sends it all of the data it needs and starts sending it relevant game events once it has gotten that ready event
- The entry points are ServerScriptService.MagicServer for the server and MagicClient_ConnectionSetup and MagicClient_ViewSetup for the model and views respectively. MagicClientGameList ties the views and models together
Magic Related Stuff:
- ReplicatedStorage.CardDef is where the cards are defined
- “Information Privacy” is preserved, the clients don’t know any information that they shouldn’t be able to (even if you were to hack the client you couldn’t find out what’s in your opponents hand / deck)
- All of the spell casting / ability activation is done locally first before being replicated to the server for it to repeat, so that the interface feels perfectly responsive. The approach used is to perform all of the actions on the game state during casting / ability activation, whether on the client or server, through an “executeAction” method on the game state. When actions are executed on a client, they are just executed there. When actions are executed on the server, replicate the changes they make to each client. However, we don’t want the client who did some local actions in casting a spell or activating an ability to do those actions twice (once itself, once when the replication comes in), So, when the server is performing the actions it has an “current player to ignore”, which it doesn’t replicate actions to.
- The real meat of the MagicGameState is in “updateObjectsAndPlayers”, which takes and applies all static abilities and effects to all of the objects currently on the battlefield, in players hands, etc.
- Stuff that works right now: Static Abilities/Effects, Triggered Abilities/Effects, Activated Abilities and Casting Spells as long as the only require mana as a cost (they don’t have additional costs like sacrificing things) and have no targets.
- Stuff to still do: Spells / the targeting system. Replacement effects (the framework is there). Allowing card effects to make requests like searching your library or choosing things to sacrifice / discard. “Revealing” cards from opponents hands / libraries.