Voxels
Texture and Model related APIs are only available on clients.
In Cubivox, voxels serve as the fundamental building blocks of the game world. These tiny, cubic units of space make up nearly every element in the game, from terrain to structures and objects. Each voxel represents the smallest possible division of the environment, and together, they form a rich and dynamic, fully interactive world for players to shape.
Voxel vs VoxelDef
When working with voxels, there are two key object types: Voxel
and VoxelDef
.
A VoxelDef
(Voxel Definition) is responsible for defining the properties of a voxel, such as its name, texture, and functionality.
Each type of voxel has exactly one corresponding VoxelDef instance.
On the other hand, a Voxel
represents a specific voxel at the moment it is retrieved. Voxel objects are immutable and cannot be modified.
There is only a single voxel definition object instance for each type of voxel.
Accessing and Setting Voxels
A Voxel
can be accessed through a World
or Chunk
object:
// World:
Voxel vox = Cubivox.GetWorlds()[0].GetVoxel(15, 20, 15);
// Chunk:
Voxel chunkVoxel = chunk.GetVoxel(6, 3, 5);
It is important to note that World#GetVoxel()
uses global coordinates while Chunk#GetVoxel()
uses local coordinates. This means that the x, y, and z parameters of Chunk#GetVoxel()
can
only range between 0 and 15 (since chunks are 16x16x16 in size). The API modulates the input by 16, so inputing a value outside of that range will still have an effect.
Like accessing a Voxel, setting a Voxel is done through a World
or Chunk
object. Voxels are set by setting the VoxelDef
for that voxel.
VoxelDefs can be retrived from the item registry by using the ControllerKey that represents the voxel definition.
var voxelDefKey = ControllerKey.Create("testmod", "custom_voxel");
VoxelDef customVoxel = Cubivox.GetItemRegistry().GetVoxelDefinition( voxelDefKey );
Since there is only ever one instance of a voxel definiton object, it is recommended to store the instance in a member variable to prevent needing to fetch it multiple times. This can help performance in certain scenarios.
You can then use that voxel definition to set a specific voxel:
// World:
Cubivox.GetWorlds()[0].SetVoxel(15, 20, 15, customVoxel);
// Chunk:
chunk.SetVoxel(6, 3, 5, customVoxel);
The same note about the coordinate systems above applies to setting voxels as well.
Creating Custom Voxels
Custom voxels ares made by defining a new voxel definition that defines the looks and behavior of the new voxel. This is done by extending the ModVoxel
abstract class:
[Name("Custom Voxel")]
[Key("CUSTOM_VOXEL")]
[Texture("custom_voxel.png")]
public class CustomVoxel : ModVoxel
{
public CustomVoxel(Mod mod) : base(mod)
{
}
}
The properties of a voxel are defined using attributes above the class definition. Three attributes are required to create a custom voxel:
[Name("Custom Voxel")]
: This defines the display name that the voxel will show in the game.[Key("CUSTOM_VOXEL")]
: This defines the key portion of the ControllerKey that is used to reference the voxel.[Texture("custom_voxel.png")]
: This defines what texture the voxel will use. See the section on textures below to learn more about voxel textures.
There is only a single instance of a voxel definition. Don't store information about individual voxels in the voxel defintion object.
Texturing
The image above is an example of a voxel texture. Each colored square represents a face of the voxel. The pink area is the void area and will not be visible.
The size of the image is not important as long as the ratios are maintained. Each voxel face must have a width that is 1/4 the width of the image and 1/3 the height.
Similar to the mod.json
, the texture for a voxel is to be bundled with the mod's dll file.
The best way to accomplish that is to add your image to the project:
Then, right click the image and select Properties
. Then change Build Action
to Embedded resource
.
The image will not be put in a Resources
folder within the dll. So the texture attribute on the voxel should just be [Texture("custom_voxel.png")]
.
Transparent Textures
If there is any sort of transparency in the texture the [Transparent]
attribute should be added with the other attributes. This prevents the mesh optimization that Cubivox performs on chunks from optimizing away the voxel faces around this voxel. Not adding this will cause players to be able to see inside chunks.
Voxel Events
Voxel events are a way to perform actions when a player interacts with a voxel. These events are known as local events, since they only trigger for a specific voxel type. Local events function similarly to global events, but are slightly different in the way they are registered.
public class CustomVoxel : ModVoxel
{
public CustomVoxel(Mod mod) : base(mod)
{
this.PlaceEvent += OnVoxelPlaced;
}
public void OnVoxelPlaced(VoxelDefPlaceEvent evt)
{
mod.GetLogger().Info($"Player {evt.Player.GetName()} placed a Custom Voxel!");
}
}
Local events use the C# event system, so to register an event of a certain type, the +=
operator is used on the desired event ModVoxel member veriable.
The general format is {Event} += {HandlerMethod}
. Only member methods should be registered to a local event.
Here is a table of all local events available to voxel definitions and their related event object:
Event Name | Event Object |
---|---|
PlaceEvent | VoxelDefPlaceEvent |
BreakEvent | VoxelDefBreakEvent |
Similiarly to global events, the [ServerOnly]
and [ClientOnly]
attributes can be used to only exectue the event on the server or clients respectively.
Registering Custom Voxels
To register a custom voxel for use, you must override the LoadItemsStage
loading method within your main CubivoxMod
class:
public class TestMod : CubivoxMod
{
public TestMod(ModDescriptionFile modDescriptionFile, Logger logger) : base(modDescriptionFile, logger)
{
}
public override void OnEnable()
{
}
public override void LoadItemsStage(ItemRegistry registry)
{
registry.RegisterItem(new CustomVoxel(this));
}
}
The voxel definition can then be accessed with:
var voxelDefKey = ControllerKey.Create("testmod", "custom_voxel");
VoxelDef customVoxel = Cubivox.GetItemRegistry().GetVoxelDefinition( voxelDefKey );