Modding:Block Entity: Difference between revisions
CreativeMD (talk | contribs) |
m (Updated navbox to new code navbox.) |
||
(20 intermediate revisions by 10 users not shown) | |||
Line 1: | Line 1: | ||
__FORCETOC__ | __FORCETOC__ | ||
{{GameVersion|1.19.3}} | |||
<languages/> | |||
<translate> | |||
= Introduction = <!--T:1--> | |||
<!--T:2--> | |||
A block entity is a construct that you can tack onto an existing block to give it additional functionality. Whenever a block should do something on a regular interval or store extra information, such as the contents of a chest block, you need a block entity. It's highly recommend to have read the tutorial about [[Basic Modding|Basic Blocks]] and [[Advanced Blocks|Block Class]] in order to understand this tutorial properly. | A block entity is a construct that you can tack onto an existing block to give it additional functionality. Whenever a block should do something on a regular interval or store extra information, such as the contents of a chest block, you need a block entity. It's highly recommend to have read the tutorial about [[Basic Modding|Basic Blocks]] and [[Advanced Blocks|Block Class]] in order to understand this tutorial properly. | ||
== The Texture Flipper == | == The Texture Flipper == <!--T:3--> | ||
<!--T:4--> | |||
Let's create a block which switches its texture every 3 seconds. It should have two variants <code>"on"</code> and <code>"off"</code>. Additionally we need to define the blockentity class like so: | Let's create a block which switches its texture every 3 seconds. It should have two variants <code>"on"</code> and <code>"off"</code>. Additionally we need to define the blockentity class like so: | ||
<syntaxhighlight lang="json"> | <syntaxhighlight lang="json"> | ||
Line 12: | Line 16: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
You can download the assets [ | <!--T:5--> | ||
You can download the assets [https://wiki.vintagestory.at/images/d/d4/Ticking_-_No_CS_File.zip here] and place it in your mods directory. | |||
== The BlockEntity == | == The BlockEntity == <!--T:6--> | ||
<!--T:7--> | |||
Now we need to register our blockentity class and therefore we need to create a new *.cs file in our project. Let's name it <code>Ticking.cs</code>. | Now we need to register our blockentity class and therefore we need to create a new *.cs file in our project. Let's name it <code>Ticking.cs</code>. | ||
<!--T:8--> | |||
First of all you need to create the blockentity class itself. Therefore you need to extend <code>BlockEntity</code>: | First of all you need to create the blockentity class itself. Therefore you need to extend <code>BlockEntity</code>: | ||
<!--T:9--> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public class TickingBlockEntity : BlockEntity | public class TickingBlockEntity : BlockEntity | ||
Line 27: | Line 35: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<!--T:10--> | |||
---- | ---- | ||
<!--T:11--> | |||
This class needs to have a timer, once the timer reaches 3 seconds it should replace the current block with the different state. | This class needs to have a timer, once the timer reaches 3 seconds it should replace the current block with the different state. | ||
<!--T:12--> | |||
In order to create a timer we need to register a tick listener. Therefore we need to override <code>Initialize(ICoreAPI)</code>: | In order to create a timer we need to register a tick listener. Therefore we need to override <code>Initialize(ICoreAPI)</code>: | ||
<!--T:13--> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public override void Initialize(ICoreAPI api) | public override void Initialize(ICoreAPI api) | ||
Line 40: | Line 52: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<!--T:14--> | |||
add a counter (which should increase per tick) ... | add a counter (which should increase per tick) ... | ||
<!--T:15--> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public | public float timer; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<!--T:16--> | |||
... and the actual ticking method ... | ... and the actual ticking method ... | ||
<!--T:17--> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public void | public void OnGameTick(float dt) | ||
{ | { | ||
Line 55: | Line 71: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
To register the ticking method we can use <code>RegisterGameTickListener</code> in <code> | <!--T:18--> | ||
To register the ticking method we can use <code>RegisterGameTickListener</code> in <code>Initialize</code> | |||
<!--T:19--> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public override void Initialize(ICoreAPI api) | public override void Initialize(ICoreAPI api) | ||
{ | { | ||
base.Initialize(api); | base.Initialize(api); | ||
RegisterGameTickListener( | RegisterGameTickListener(OnGameTick, 50); | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
The timer itself should | <!--T:20--> | ||
The timer itself should increment by dt, the time difference in seconds between the current tick and the previous tick. It ticks about every 50ms or less often if the game is slow. So if the timer is greater than 3, it should replace the block: | |||
<!--T:21--> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public void | public void OnGameTick(float dt) | ||
{ | { | ||
timer+ | timer += dt; | ||
if(timer > | if(timer >= 3) | ||
{ | { | ||
Block block = | Block block = Api.World.BlockAccessor.GetBlock(Pos); | ||
if (block.Code.Path.EndsWith("-on")) | if (block.Code.Path.EndsWith("-on")) | ||
block = | { | ||
block = Api.World.GetBlock(block.CodeWithParts("off")); | |||
} | |||
else | else | ||
block = | { | ||
block = Api.World.GetBlock(block.CodeWithParts("on")); | |||
} | |||
<!--T:22--> | |||
Api.World.BlockAccessor.SetBlock(block.BlockId, Pos); | |||
} | } | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<!--T:23--> | |||
---- | ---- | ||
<!--T:24--> | |||
Furthermore we need to save the current time: | Furthermore we need to save the current time: | ||
<!--T:25--> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public override void ToTreeAttributes(ITreeAttribute tree) | public override void ToTreeAttributes(ITreeAttribute tree) | ||
{ | { | ||
base.ToTreeAttributes(tree); | base.ToTreeAttributes(tree); | ||
tree. | tree.SetFloat("timer", timer); | ||
} | } | ||
public override void | <!--T:26--> | ||
public override void FromTreeAttributes(ITreeAttribute tree, IWorldAccessor worldForResolving) | |||
{ | { | ||
base. | base.FromTreeAttributes(tree, worldForResolving); | ||
timer = tree. | timer = tree.GetFloat("timer"); | ||
} | } | ||
<!--T:27--> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
== Registering the Block Entity == | == Registering the Block Entity == <!--T:28--> | ||
<!--T:29--> | |||
Registering the blockentity class is rather simple (rather similar to registering a block class). You need a mod class and override <code>Start(ICoreAPI)</code>: | Registering the blockentity class is rather simple (rather similar to registering a block class). You need a mod class and override <code>Start(ICoreAPI)</code>: | ||
<!--T:30--> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public class Ticking : | public class Ticking : ModSystem | ||
{ | { | ||
public override void Start(ICoreAPI api) | <!--T:31--> | ||
public override void Start(ICoreAPI api) | |||
{ | { | ||
base.Start(api); | base.Start(api); | ||
Line 115: | Line 150: | ||
} | } | ||
} | <!--T:32--> | ||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
== Testing == | == Testing == <!--T:33--> | ||
<!--T:34--> | |||
Now everything is ready to run the first test: | Now everything is ready to run the first test: | ||
<!--T:35--> | |||
<youtube>QQUibC4H9TI</youtube> | <youtube>QQUibC4H9TI</youtube> | ||
== Distribution == | == Distribution == <!--T:36--> | ||
=== Using the new Mod Template === | |||
If using the mod template setup, follow the instructions on [[Modding:Setting up your Development Environment#Packaging%20the%20Mod|Setting up your Development Environment]] to pack and distribute your mod. | |||
=== Using the (old) Modtools === | |||
If using the modtools program, open the modtools and type in <code>pack <your mod id></code>. Now you can take the zip file and share it with other people. It will work in the same way as ordinary mods, you can install it by copying it into the <code>mods</code> folder. | |||
= Mod Download = <!--T:38--> | |||
* for VS 1.12 (Source only): [https://github.com/anegostudios/vsmodexamples/tree/ac7eeaed597b8a25dcfc2366b9c51cd92850d2b9/Mods/Ticking GitHub] | |||
* for VS 1.9: [https://wiki.vintagestory.at/images/8/80/Ticking_v1.0.0.zip Ticking_v1.0.0.zip] | |||
* for VS 1.6: [https://wiki.vintagestory.at/images/6/65/Ticking.zip Ticking.zip] | |||
</translate> | |||
{{Navbox/ | {{Navbox/codemodding}} |
Latest revision as of 17:02, 27 March 2024
This page was last verified for Vintage Story version 1.19.3.
Introduction
A block entity is a construct that you can tack onto an existing block to give it additional functionality. Whenever a block should do something on a regular interval or store extra information, such as the contents of a chest block, you need a block entity. It's highly recommend to have read the tutorial about Basic Blocks and Block Class in order to understand this tutorial properly.
The Texture Flipper
Let's create a block which switches its texture every 3 seconds. It should have two variants "on"
and "off"
. Additionally we need to define the blockentity class like so:
entityClass: "tickingcounter",
You can download the assets here and place it in your mods directory.
The BlockEntity
Now we need to register our blockentity class and therefore we need to create a new *.cs file in our project. Let's name it Ticking.cs
.
First of all you need to create the blockentity class itself. Therefore you need to extend BlockEntity
:
public class TickingBlockEntity : BlockEntity
{
}
This class needs to have a timer, once the timer reaches 3 seconds it should replace the current block with the different state.
In order to create a timer we need to register a tick listener. Therefore we need to override Initialize(ICoreAPI)
:
public override void Initialize(ICoreAPI api)
{
base.Initialize(api);
}
add a counter (which should increase per tick) ...
public float timer;
... and the actual ticking method ...
public void OnGameTick(float dt)
{
}
To register the ticking method we can use RegisterGameTickListener
in Initialize
public override void Initialize(ICoreAPI api)
{
base.Initialize(api);
RegisterGameTickListener(OnGameTick, 50);
}
The timer itself should increment by dt, the time difference in seconds between the current tick and the previous tick. It ticks about every 50ms or less often if the game is slow. So if the timer is greater than 3, it should replace the block:
public void OnGameTick(float dt)
{
timer += dt;
if(timer >= 3)
{
Block block = Api.World.BlockAccessor.GetBlock(Pos);
if (block.Code.Path.EndsWith("-on"))
{
block = Api.World.GetBlock(block.CodeWithParts("off"));
}
else
{
block = Api.World.GetBlock(block.CodeWithParts("on"));
}
Api.World.BlockAccessor.SetBlock(block.BlockId, Pos);
}
}
Furthermore we need to save the current time:
public override void ToTreeAttributes(ITreeAttribute tree)
{
base.ToTreeAttributes(tree);
tree.SetFloat("timer", timer);
}
public override void FromTreeAttributes(ITreeAttribute tree, IWorldAccessor worldForResolving)
{
base.FromTreeAttributes(tree, worldForResolving);
timer = tree.GetFloat("timer");
}
Registering the Block Entity
Registering the blockentity class is rather simple (rather similar to registering a block class). You need a mod class and override Start(ICoreAPI)
:
public class Ticking : ModSystem
{
public override void Start(ICoreAPI api)
{
base.Start(api);
api.RegisterBlockEntityClass("tickingcounter", typeof(TickingBlockEntity));
}
}
Testing
Now everything is ready to run the first test:
Distribution
Using the new Mod Template
If using the mod template setup, follow the instructions on Setting up your Development Environment to pack and distribute your mod.
Using the (old) Modtools
If using the modtools program, open the modtools and type in pack <your mod id>
. Now you can take the zip file and share it with other people. It will work in the same way as ordinary mods, you can install it by copying it into the mods
folder.
Mod Download
- for VS 1.12 (Source only): GitHub
- for VS 1.9: Ticking_v1.0.0.zip
- for VS 1.6: Ticking.zip
Code Modding | |||||||
---|---|---|---|---|---|---|---|
Basics | Code Mods • Preparing For Code Mods • Creating A Code Mod | ||||||
Tutorials |
|
||||||
Advanced | Server-Client Considerations • Setting up your Development Environment • Advanced Blocks • Advanced Items • Block and Item Interactions • Block Behavior • Block Entity • Particle Effects • World Access • Inventory Handling • Commands • GUIs • Network API • Monkey patching (Harmony) | ||||||
Data Management | VCDBS format • Savegame Moddata • ModConfig File • Chunk Moddata • Serialization Formats • TreeAttribute | ||||||
Worldgen | WorldGen API • NatFloat • EvolvingNatFloat | ||||||
Rendering | Shaders and Renderers |
Wondering where some links have gone?
The modding navbox is going through some changes! Check out Navigation Box Updates for more info and help finding specific pages.
Modding | |
---|---|
Modding Introduction | Getting Started • Theme Pack |
Content Modding | Content Mods • Developing a Content Mod • Basic Tutorials • Intermediate Tutorials • Advanced Tutorials • Content Mod Concepts |
Code Modding | Code Mods • Setting up your Development Environment |
Property Overview | Item • Entity • Entity Behaviors • Block • Block Behaviors • Block Classes • Block Entities • Block Entity Behaviors • Collectible Behaviors • World properties |
Workflows & Infrastructure | Modding Efficiency Tips • Mod-engine compatibility • Mod Extensibility • VS Engine |
Additional Resources | Community Resources • Modding API Updates • Programming Languages • List of server commands • List of client commands • Client startup parameters • Server startup parameters Example Mods • API Docs • GitHub Repository |