DamnScript is a high-performance scripting language inspired by Ren'Py and Bash.
It is designed for writing game behavior logic with deep integration into C# and Unity.
Test | Lua | DamnScript | Compiled DS | .NET |
---|---|---|---|---|
🔁 Call C# from script | 861.3 µs | 8.9 µs | — | — |
📦 Load large script | 794.2 µs | 235.1 µs | 13.8 µs | — |
📌 Object pinning | — | 2.2 µs | — | 1.8 µs |
⚖️ DamnScript is ~96× faster than Lua when calling C#, and ~57× faster when loading large scripts.
👉 See full details in benchmarks
- ⚡ Lightning-fast execution and loading speed
- 💾 Minimal memory and resource consumption
- 🛠 JIT and AOT compilation
- 🧱 Minimal managed allocations (*when using unmanaged types and corresponding API)
- 🛡 High level of safety
- 🔗 Full support for calling C# methods (including async)
- 🔁 Control structures:
if
,else
,for
,while
- ✍️ Working with all C# data types
- ✉️ String support and interning
- 💾 State serialization and deserialization
- 🎮 Unity 2021.1.0f1+ support (not tested on versions below 2021.1.0f1)
- 🧬 Compatible with .NET 7.0+ (not tested on versions below 7.0)
Format: x.y.z
- x — Major version
- y — Release type (
0
— alpha,1
— beta,2
— stable release) - z — Build number
- Download the required version from the GitHub releases.
- Add to your project the files
DamnScript.dll
andAntlr4.Runtime.dll
. - Done! Ready to use.
- Clone the DamnScript repository.
- Import the
DamnScript/
folder (includingRuntimes
andParsing
) into your project. - Add Antlr4 (either as a binary file or a NuGet package).
- Done! You’re ready to go.
- Download the required version from the GitHub releases.
- Import the files from the archive into your Unity project.
- Done! Ready to use.
🔧 Possible Directives:
- ARCHITECTURES
DAMN_SCRIPT_ENABLE_MONO
— switches the mode to support Mono (for Unity auto appliesUNITY_5_3_OR_NEWER
).- ARCHITECTURES
DAMN_SCRIPT_ENABLE_TARGET_32BIT
— enables support for 32-bit platforms.- CONFIGS
DAMN_SCRIPT_STACK_SIZE_16
/DAMN_SCRIPT_STACK_SIZE_64
— sets the script stack size (default: 32 elements).- CONFIGS
DAMN_SCRIPT_ENABLE_16_BIT_OPCODES
/DAMN_SCRIPT_ENABLE_32_BIT_OPCODES
/
DAMN_SCRIPT_ENABLE_64_BIT_OPCODES
— sets the opcode size (default: 8 bits).
Does not disable compiler alignment, so the result may not be as expected.
When using this directive, it is recommended to also useDAMN_SCRIPT_DISABLE_ALIGNMENT_OPCODES
!- CONFIGS
DAMN_SCRIPT_DISABLE_ALIGNMENT_OPCODES
— disables opcode alignment (opcode size may be less than 8 bytes) from the compiler.- CONFIGS
DAMN_SCRIPT_ENABLE_ADDITIONAL_CHECKS
— enables additional safety checks.- CONFIGS
DAMN_SCRIPT_DISABLE_BUILTIN_METHODS
— disables built-in methods.- CONFIGS
DAMN_SCRIPT_DISABLE_RAW_METHOD_INFO
— disables the use of NoCopy methods for MethodInfo.- CONFIGS
DAMN_SCRIPT_DISABLE_ASYNC_PINNING
— allows the use of unpinned references in asynchronous methods in .NET (not applicable to Unity, where it is always allowed).- DEBUGS
DAMN_SCRIPT_ENABLE_EXECUTION_LOG
— enables execution debugging.- DEBUGS
DAMN_SCRIPT_ENABLE_MEMORY_DEBUG
— enables memory debugging.- DEBUGS
DAMN_SCRIPT_ENABLE_ASSEMBLER_DEBUG
— enables assembler debug messages.- DEBUGS
DAMN_SCRIPT_PINNING_DEBUG
— enables pinning debugging.
- Scripts are compiled into bytecode, executed by a virtual machine
- JIT and AOT are supported: you can interpret
.ds
or run pre-compiled.dsc
- Pseudo-multithreaded VM: each pseudo-thread executes its region independently
- Stack-based execution model + 4 registers are used
- Safe
ScriptValuePtr
structure stores any data (including pointers and references) - Callable C# methods work with
ScriptValuePtr
, including asyncTask<ScriptValuePtr>
- Assembler-like bytecode allows easy debugging and code optimization
region Main {
GoToWaypointAsync(GetActor(), "Way1");
PlaySound("OnWaypoint1");
GoToWaypoint(GetActor(), "Way2");
PlaySound("Shot");
Die();
if (IsDead(GetActor())) {
Print("Actor is dead");
}
elseif (IsAlive(GetActor())) {
Print("Actor is alive");
}
else {
Print("HOW?!");
}
}
region AnythingElse {
Print("Arrived at Waypoint 1");
}
public static void Print(ScriptValuePtr value)
{
Console.WriteLine(value.IntValue.ToString()); // This method will be called from the script
}
public static void TestRun()
{
ScriptEngine.RegisterNativeMethod((Action<ScriptValuePtr>)Log); // Register a native method
var fileStream = File.Open("Test1.ds", FileMode.Open); // Opening the stream to read the script
var scriptData = ScriptEngine.LoadScript(fileStream, "Test1"); // Loading the script into memory (JIT compilation in this case)
var thread = ScriptEngine.RunThread(scriptData, "Main"); // Starting the thread and executing the Main region
// Sending the machine a command to execute EVERY thread, as long as there is work to do or until it goes into a wait state
while (ScriptEngine.ExecuteNext())
{
// When a thread enters a wait state (during asynchronous calls), for example, wait for 15 ms.
// Then try to get the result again and continue execution
Thread.Sleep(15);
}
ScriptEngine.UnloadScript(scriptData); // Freeing memory used by the script if no other threads are using it
}
- ✍️ Write scripts in DamnScript and share them
- 📚 Create tutorials and guides
- 🐛 Open Issues with bugs and ideas
- 🔧 Make Pull Requests with improvements
- ✅ Basic functionality
- ✅ Unity and C# call support
- ✅ Conditions, loops, serialization
- ✅ Memory checks
- ✅ Manual saves
- ✅ Unit Tests
- 🔧 Auto-saves
- ⏳ Unloading inactive metadata
- ⏳ Migration when bytecode changes
- ⏳ Hot-reload
- 💡 And much more...
You can also support the project by buying me a coffee, so I can keep spending sleepless nights developing it.