S&box Wiki

Custom ModelDoc nodes

This page describes how you can create custom ModelDoc nodes. This is useful for any gamemode-specific data you may want to attach to specific models.

There are currently 2 types of custom ModelDoc nodes you can create: Generic Game Data and Break Commands.

Generic Game Data

Generic Game Data nodes are just that - a node that can carry arbitrary data on the model and then retrieved in code when needed.

Here's the process for registering and using a custom game data node:

  1. Define a struct or class. Add the ModelDoc.GameData attribute.
/// <summary> /// Spawn a particle when the model is used on an entity. Support for this depends on the entity. /// </summary> [ModelDoc.GameData( "particle", AllowMultiple = true )] public class ModelParticle { [DisplayName( "Particle" ), ResourceType( "vpcf") ] public string Name { get; set; } [JsonPropertyName( "attachment_point" ), FGDType( "model_attachment" )] public string AttachmentPoint { get; set; } [JsonPropertyName( "attachment_type" )] public ParticleAttachment AttachmentType { get; set; } = ParticleAttachment.AttachmentFollow; [JsonPropertyName( "attachment_offset" )] public Vector3 AttachmentOffset { get; set; } }
  1. Let the gamemode (re)compile. This will make the new nodes appear in ModelDoc.

  2. Assign the node in ModelDoc to the GameDataList parent node, or use the node wizard if the node is not present. If you wish to know more, you can read this guide on importing a model.

  1. Compile the model.

  2. Now you can use this data in code like so.

// Get the custom data on the a model. Will return null if it not present on the model ModelParticle[] modelParticles = Model.GetData<ModelParticle[]>(); // Or like so if ( Model.TryGetData( out ModelParticle[] modelParticles ) { // Data exists on this model, use it.. }

Break Commands

Break commands are a more specific alternative to GenericGameData which allows code to be ran when an entity with a model that has a given node breaks via the Breakables class, such as doors, physics props and others.

They work identically to GenericGameData but the class markup looks a little different:

/// <summary> /// Spawn a particle system when this model breaks. /// </summary> [Library( "break_create_particle" )] public class ModelBreakParticle : IModelBreakCommand { /// <summary> /// The particle to spawn when the model breaks. /// </summary> [JsonPropertyName( "name" ), ResourceType( "vpcf" )] public string Particle { get; set; } // ... public void OnBreak( Sandbox.Breakables.Result res ) { if ( !(res.Source is ModelEntity ent) ) return; var part = Particles.Create( Particle, ent.Position ); // ... } }

The OnBreak callback will be called automatically when an entity breaks and has a model with (in this case) break_create_particle break command.

Other things you can do with this

There are multiple attributes that you can use in order to make your own custom designers/helpers for your custom nodes:

  • ModelDoc.Axis
  • ModelDoc.Box
  • ModelDoc.Sphere
  • ModelDoc.Capsule
  • ModelDoc.Cylinder
  • ModelDoc.Line
  • ModelDoc.HandPose
  • ModelDoc.EditorWidget