How to Explore V Rising Game Code
V Rising's server code is compiled for IL2CPP, which means the original C# source isn't available. Instead you work with interop assemblies, thin managed wrappers generated by the IL2CPP build process. These contain all the types, method signatures, and fields you need to understand and hook into the game.
Tools: dnSpy and ILSpy
ILSpy and dnSpy are .NET decompilers that let you browse and search these assemblies as readable C#.
| Tool | Best for |
|---|---|
| ILSpy | Browsing types, reading decompiled code, fast search |
| dnSpy | Everything ILSpy does, plus a debugger |
ILSpy is a solid starting point. Both are free.
The Interop Assemblies
After installing BepInEx, the interop assemblies are generated in your server folder:
VRisingServer/
BepInEx/
interop/
ProjectM.dll
ProjectM.Shared.dll
Stunlock.Core.dll
Unity.Entities.dll
...Open these in ILSpy using File > Open. The key ones:
| Assembly | What it contains |
|---|---|
ProjectM.dll | Most gameplay systems, components, and types |
ProjectM.Shared.dll | Shared client/server types |
Stunlock.Core.dll | Core engine types including PrefabGUID |
Unity.Entities.dll | ECS base types: Entity, EntityManager, SystemBase |
Unity.Mathematics.dll | float2, float3, quaternion math types |
Identifying Systems
V Rising uses Unity's DOTS ECS. Systems are classes that process entities each frame. There are three categories:
ComponentSystemGroup: a container that holds and orders other systems. The Unity runtime calls the top-level groups each frame, which in turn call their children. Examples:SimulationSystemGroup,InitializationSystemGroup.ComponentSystemBase/SystemBase: the class-based system style.SystemBaseis a subclass ofComponentSystemBaseand is the most common concrete type in V Rising. OverrideOnUpdate()to run logic each frame. The System Update Tree labels both of these as CSB.ISystem: the newer struct-based interface. More lightweight than class-based systems since structs have no GC overhead. OverrideOnUpdate(ref SystemState state). When Harmony-patching an ISystem, target the concrete struct's method directly.
System names follow a consistent convention using suffixes to indicate where they run:
ProjectM.StatChangeSystem_Server // server only
ProjectM.BuffSystem_Shared // both client and server
ProjectM.HealthBarSystem_Client // client onlyTo find a system for a mechanic, search by keyword in ILSpy. Looking for how buffs apply? Search ApplyBuffSystem. Interested in death? Search DestroySystem or KillSystem. Browse the full update order in the System Update Tree reference.
Reading ECS Patterns
A few patterns appear repeatedly across systems once you know what to look for.
EntityQuery defines which entities a system operates on. It filters by component presence:
_query = GetEntityQuery(
ComponentType.ReadOnly<Health>(),
ComponentType.ReadWrite<DestroyData>()
);If a system queries for Health and DestroyData, it is almost certainly involved in death logic.
EntityCommandBuffer (ECB) queues structural changes: adding/removing components, spawning, and destroying entities. If you see _ecbSource.CreateCommandBuffer(), the system is scheduling work to happen at the end of the frame rather than immediately.
GetComponentDataFromEntity / GetComponentLookup are how systems reach out to entities they are not directly iterating. If you see these, the system is doing cross-entity lookups.
SystemAPI.GetSingleton<T>() reads a global singleton component. Common for game settings, server time, and world state.
Archetypes
An archetype is a unique combination of component types. Every entity with the same set of components shares an archetype and is stored together in memory. When you write an EntityQuery, you are essentially targeting one or more archetypes.
Reference dumps of the game's archetypes list every archetype and how many entities use it:
Archetype #2
Entity Count: 122474
Components:
- ProjectM.Health
- ProjectM.EntityCategory
- ProjectM.CollisionRadius
...Browsing archetypes helps you figure out exactly which components your query needs to include or exclude to hit the right entities without false positives.
EntityQuery Descriptions
The game has over a thousand systems. A query description dump maps each system to the components it reads or writes, without requiring you to decompile the full method body:
System: ProjectM.AbilityCastStarted_SetupAbilityTargetSystem_Shared
EntityQuery: _Query
All Components: ProjectM.AbilityCastStartedEvent [ReadOnly]This tells you the system reacts to AbilityCastStartedEvent. If you want to hook into ability casting, this is a system worth opening in ILSpy.
Browse the full dataset in the Entity Query Descriptions reference.
EntityState Files
Tools like KindredExtract can dump the component state of every prefab entity in the game. Each file lists the components on a prefab and their default field values:
Prefab CHAR_ArchMage_VBlood PrefabGuid(-2013903325)
Components
ProjectM.AggroConsumer
ProximityRadius: 35
DamageWeight: 10
RemoveDelay: 8This is useful for:
- Seeing what components a specific prefab has before touching it in code
- Checking default field values before you override them at runtime
- Comparing two similar prefabs to understand what makes them different
Component Naming Conventions
Component names follow predictable patterns once you know the namespaces:
| Namespace prefix | Source |
|---|---|
ProjectM. | V Rising gameplay components |
Stunlock.Core. | Core engine (PrefabGUID, etc.) |
Unity.Entities. | Unity ECS primitives |
Unity.Transforms. | Position, rotation, scale |
Within ProjectM, components are usually named after the data they hold: Health, UnitStats, EntityOwner, Buff, AbilityBar_Server, etc. When you find a component name, search for it in ILSpy to see every system that reads or writes it. That gives you the full flow of how that mechanic works end to end.
The System Update Tree
Systems in ECS run in a defined order inside ComponentSystemGroups. The full update hierarchy for the server world has around 1,000 systems organized into groups like StartSimulationGroup, UpdateGroup, and LateSimulationGroup.
Knowing where a system sits in the update order matters when you need to ensure your patch runs before or after another system. Browse the full hierarchy in the System Update Tree reference. The [UpdateBefore] and [UpdateAfter] attributes control ordering in your own systems:
[UpdateBefore(typeof(StatChangeSystem_Server))]
public partial class MySystem : SystemBase { ... }