Gameplay Video
Project Overview
Spell Conjurer is a technical exploration of runtime code compilation in Unity. Instead of defining spells as static assets, players can create spells using actual C# code that compiles and executes at runtime. This enables a level of flexibility impossible with traditional spell systems.
The project also explores AI-assisted content generation, where language models can generate valid spell code based on natural language descriptions. This creates a fascinating intersection of game design, compiler technology, and modern AI capabilities.
Key Technical Features
Runtime C# Compilation
Uses the Roslyn compiler API to compile C# code at runtime. Spells are written as classes implementing a spell interface, compiled into assemblies, and instantiated dynamically.
JSON Spell Definitions
Spell metadata stored in JSON files defining name, description, mana cost, cooldowns, and the C# code to compile. Easy to share, modify, and version control.
Sandboxed Execution
Compiled code runs in a restricted environment. Dangerous APIs are blocked, execution time is capped, and resource usage is monitored to prevent abuse or infinite loops.
AI Generation Pipeline
Integration with AI language models to generate spell code from natural language. Describe what you want a spell to do, and the system generates valid, compilable code.
Gallery
Technical Highlights
Roslyn Integration
The Microsoft.CodeAnalysis.CSharp library handles parsing, semantic analysis, and IL generation. Compilation errors are captured and displayed to users with helpful diagnostics. Assembly loading uses custom contexts for isolation.
Spell Interface Contract
All spells implement ISpell interface with methods for Cast(), Update(), and Cleanup(). The runtime provides a SpellContext with access to game systems like physics, VFX spawning, and targeting.
Security Considerations
Roslyn's analyzer API blocks access to System.IO, System.Net, and other dangerous namespaces. Execution runs on a separate thread with timeout enforcement. Memory allocation is tracked and capped per spell.
Example Spell Code
public class Fireball : ISpell
{
public void Cast(SpellContext ctx)
{
var projectile = ctx.SpawnProjectile("fireball");
projectile.SetDirection(ctx.Caster.Forward);
projectile.SetSpeed(15f);
projectile.OnHit += (target) =>
{
ctx.DealDamage(target, 25f);
ctx.SpawnVFX("explosion", target.Position);
};
}
}