Skip to content

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#.

ToolBest for
ILSpyBrowsing types, reading decompiled code, fast search
dnSpyEverything 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:

AssemblyWhat it contains
ProjectM.dllMost gameplay systems, components, and types
ProjectM.Shared.dllShared client/server types
Stunlock.Core.dllCore engine types including PrefabGUID
Unity.Entities.dllECS base types: Entity, EntityManager, SystemBase
Unity.Mathematics.dllfloat2, 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. SystemBase is a subclass of ComponentSystemBase and is the most common concrete type in V Rising. Override OnUpdate() 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. Override OnUpdate(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 only

To 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:

csharp
_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: 8

This 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 prefixSource
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:

csharp
[UpdateBefore(typeof(StatChangeSystem_Server))]
public partial class MySystem : SystemBase { ... }