Difference between revisions of "Modding:Advanced Blocks"

From Vintage Story Wiki
Jump to navigation Jump to search
 
(31 intermediate revisions by 5 users not shown)
Line 1: Line 1:
 
__FORCETOC__
 
__FORCETOC__
 +
{{GameVersion|1.9}}
  
This tutorial requires a development environment. If you don't have one or don't know how to setup up something like that read the tutorial [[Setting up a dev environment]].
+
It's highly recommended to read [[Basic Block]] first. Additionally this tutorial requires a development environment. If you don't have one already you should read the tutorial [[Setting up your Development Environment]].
  
= Tramopline =
+
= Trampoline =
 +
 
 +
In this tutorial will we create something more advanced. A block with functionality ... a trampoline!
  
 
== Block Assets ==
 
== Block Assets ==
  
The first thing we are going to need are the assets of the block. There is a separate tutorial covering all the stuff you need to know about [[Creating Blocks|block assets]], which you should read first if haven't already. You can download the assets (block json, texture) [http://wiki.vintagestory.at/images/c/cf/Trampoline-assets.zip here] and extract them into your assets folder inside the [[Vintagestory folder]].
+
The first thing we are going to need are the assets of the block. Those are pretty straight forward.  
  
If you want to use your own block, you have to add the class property, which should refer to the class we will register later on:
+
The only new property is the <code>class</code>:
 
<syntaxhighlight lang="json">
 
<syntaxhighlight lang="json">
 
class: "trampoline",
 
class: "trampoline",
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
We will create this class, to give the block the desired functionality, so make sure if you pick a different name it matches the one below.
 +
You can download the assets of the mod [https://wiki.vintagestory.at/images/b/b9/Trampoline_-_No_CS_FILE.zip here].
 +
All you need to do is to place this zip file in your <code>assets</code> directory in your development project.
  
 
== The Block Class ==
 
== The Block Class ==
  
So how can we implement a jumping functionality? First of all we need to create a new <code>*.cs</code> file in our project. I'm gonna name it <code>Trampoline.cs</code>.
+
Now we need to register our class and therefore we need to create a new <code>*.cs</code> file in our project. I'm gonna name it <code>Trampoline.cs</code>.
  
=== The Mod Base ===
+
=== The Mod System ===
  
Now we can create a new class which extends ModBase.
+
In order to create a mod your class needs to extend <code>ModSystem</code>. This will allow use to register all kinds of stuff, but for now we will stick to our block class example.
  
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
public class TrampolineMod : ModBase
+
public class TrampolineMod : ModSystem
 
{
 
{
 
      
 
      
Line 29: Line 36:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
This class can be used to register all kinds of stuff. For now we will stick to our trampoline. Therefore we have to override the <code>Start(ICoreAPI)</code> method and register your block class.
+
Now you need to override the <code>Start(ICoreAPI)</code> method and register the class. If you have picked a different class name you have to use that one instead of trampoline.
  
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
public class TrampolineMod : ModBase
+
public class TrampolineMod : ModSystem
 
{
 
{
 
     public override void Start(ICoreAPI api)
 
     public override void Start(ICoreAPI api)
Line 46: Line 53:
 
=== The Block Class ===
 
=== The Block Class ===
  
The next thing we have to do is to create another class, which should extend <code>Block</code>. This class must have the same name as you have implemented it before:
+
Let's create our block class itself which of course has to extend <code>Block</code>:
  
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
Line 55: Line 62:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
This will solve all syntax errors, but how do we implement a bouncy block? To figure out how to implement something like that, we can take a look at the [http://apidocs.vintagestory.at/Vintagestory.API/Block.htm api documentation].
+
This should solve all syntax errors.
 +
 
 +
So how do we implement a bouncy block? It's pretty helpful to take a look at the [https://apidocs.vintagestory.at/api/Vintagestory.API.Common.Block.html api documentation] to find a proper way to implement it.
  
This method seems to be a good way to implement a bouncy functionality: <code>void onEntityCollide(IWorldAccessor world, Entity entity, BlockPos pos, BlockFacing facing, bool isImpact)</code>
+
The method <code>void onEntityCollide(IWorldAccessor world, Entity entity, BlockPos pos, BlockFacing facing, bool isImpact)</code> seems to be a good way to implement a bouncy functionality.
  
 
'''When should an entity bounce?'''
 
'''When should an entity bounce?'''
Line 63: Line 72:
 
# If the entity is colliding vertically. The sides of the block shouldn't push an entity away. So the <code>axis</code> of the <code>facing</code> has to be <code>Y</code>.
 
# If the entity is colliding vertically. The sides of the block shouldn't push an entity away. So the <code>axis</code> of the <code>facing</code> has to be <code>Y</code>.
  
'''How the we make the entity bounce?'''
+
'''How can we make the entity bounce?'''
 
+
In order to make an entity bounce, we need to change its direction. Therefore we can simply revert its motion. The faster the entity will be when during the collision the further it will be pushed away. But simply reverting the motion wouldn't be ideal. The entity would never lose its motion and bounce endless. So let's go for something smaller and make the entity lose 20% of its motion each bounce:
We can revert its motion by doing the following:
 
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
 
entity.Pos.Motion.Y *= -0.8;
 
entity.Pos.Motion.Y *= -0.8;
Line 77: Line 85:
 
public class TrampolineBlock : Block
 
public class TrampolineBlock : Block
 
{
 
{
     public override void onEntityCollide(IWorldAccessor world, Entity entity, BlockPos pos, BlockFacing facing, bool isImpact)
+
     public override void OnEntityCollide(IWorldAccessor world, Entity entity, BlockPos pos, BlockFacing facing, Vec3d collideSpeed, bool isImpact)
 
     {
 
     {
 
         if (isImpact && facing.Axis == EnumAxis.Y)
 
         if (isImpact && facing.Axis == EnumAxis.Y)
 
         {
 
         {
 +
            world.PlaySoundAt(tickSound, entity.Pos.X, entity.Pos.Y, entity.Pos.Z);
 
             entity.Pos.Motion.Y *= -0.8;
 
             entity.Pos.Motion.Y *= -0.8;
 
         }
 
         }
Line 87: Line 96:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Although this code would work already, we should also add a sound to it:
+
Although this code works already, some sound effects would be rather nice. We can implement it by adding a sound link field to our block, which can use to play the <code>game:tick</code> sound.
 +
 
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
entity.PlayEntitySound("tick", EnumAppSide.Server);
+
public AssetLocation tickSound = new AssetLocation("game", "tick");
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
This <code>tickSound</code> will played every time an entity bounces:
  
If you have done everything right, your class should look similar to this:
 
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
using System;
+
world.PlaySoundAt(tickSound, entity.Pos.X, entity.Pos.Y, entity.Pos.Z);
using System.Collections.Generic;
+
</syntaxhighlight>
using System.Linq;
+
 
using System.Text;
+
----
using System.Threading.Tasks;
+
 
using Vintagestory.API;
+
If you have done everything right, your file should look similar to this:
 +
<syntaxhighlight lang="c#">
 
using Vintagestory.API.Common;
 
using Vintagestory.API.Common;
 
using Vintagestory.API.Common.Entities;
 
using Vintagestory.API.Common.Entities;
Line 107: Line 118:
 
namespace VSExampleMods
 
namespace VSExampleMods
 
{
 
{
     public class TrampolineMod : ModBase
+
     public class TrampolineMod : ModSystem
 
     {
 
     {
 +
 
         public override void Start(ICoreAPI api)
 
         public override void Start(ICoreAPI api)
 
         {
 
         {
Line 118: Line 130:
 
     public class TrampolineBlock : Block
 
     public class TrampolineBlock : Block
 
     {
 
     {
         public override void onEntityCollide(IWorldAccessor world, Entity entity, BlockPos pos, BlockFacing facing, bool isImpact)
+
        public AssetLocation tickSound = new AssetLocation("game", "tick");
 +
 
 +
         public override void OnEntityCollide(IWorldAccessor world, Entity entity, BlockPos pos, BlockFacing facing, Vec3d collideSpeed, bool isImpact)
 
         {
 
         {
 
             if (isImpact && facing.Axis == EnumAxis.Y)
 
             if (isImpact && facing.Axis == EnumAxis.Y)
 
             {
 
             {
                 entity.PlayEntitySound("tick", EnumAppSide.Server);
+
                 world.PlaySoundAt(tickSound, entity.Pos.X, entity.Pos.Y, entity.Pos.Z);
 
                 entity.Pos.Motion.Y *= -0.8;
 
                 entity.Pos.Motion.Y *= -0.8;
 
             }
 
             }
Line 130: Line 144:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Of course you can download the file directly [http://wiki.vintagestory.at/images/8/8a/Trampoline.cs Trampoline.cs].
+
Of course you can download the file directly [https://wiki.vintagestory.at/images/8/8a/Trampoline.cs Trampoline.cs].
  
 
== Testing ==
 
== Testing ==
 +
 +
Finally we can run our first test. Looks pretty good, right?
  
 
<youtube>Kg8J_rNOweU</youtube>
 
<youtube>Kg8J_rNOweU</youtube>
  
== Distributing a mod ==
+
'''Hint''': Use the client command <code>.tfedit</code> if you want to adjust the block position, rotation and scale in Hands, in GUI, when dropped on the ground or in third person mode.
 +
 
 +
== Distribution ==
 +
 
 +
In order to finish everything, 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 =
 +
 
 +
Here is my version:
 +
* for VS v1.9: [https://wiki.vintagestory.at/images/2/24/Trampoline_vs1.9_v1.0.0.zip Trampoline_vs1.9_v1.0.0.zip]
 +
* for VS v1.5: [https://wiki.vintagestory.at/images/c/ce/Trampoline.zip Trampoline.zip]
 +
 
 +
= Moving Forward =
 +
 
 +
Now that you've successfully made an advanced block you can go even further by learning how to utilize '''[[Modding:Block Entity| Block Entities]]''' and how to create your own '''[[Modding:Adding Block Behavior | Block Behaviors]]'''. Both of these tutorials will teach you how to add even more mechanics to your custom blocks.
 +
 
 +
Or, you can try out making an '''[[Modding:Advanced Items | Advanced Item]]''' if you haven't already.
 +
 
 +
{{Navbox/modding|Vintage Story}}

Latest revision as of 02:58, 15 May 2020

This page is written for Vintage Story version 1.9

It's highly recommended to read Basic Block first. Additionally this tutorial requires a development environment. If you don't have one already you should read the tutorial Setting up your Development Environment.

Trampoline

In this tutorial will we create something more advanced. A block with functionality ... a trampoline!

Block Assets

The first thing we are going to need are the assets of the block. Those are pretty straight forward.

The only new property is the class:

	class: "trampoline",

We will create this class, to give the block the desired functionality, so make sure if you pick a different name it matches the one below. You can download the assets of the mod here. All you need to do is to place this zip file in your assets directory in your development project.

The Block Class

Now we need to register our class and therefore we need to create a new *.cs file in our project. I'm gonna name it Trampoline.cs.

The Mod System

In order to create a mod your class needs to extend ModSystem. This will allow use to register all kinds of stuff, but for now we will stick to our block class example.

public class TrampolineMod : ModSystem
{
    
}

Now you need to override the Start(ICoreAPI) method and register the class. If you have picked a different class name you have to use that one instead of trampoline.

public class TrampolineMod : ModSystem
{
    public override void Start(ICoreAPI api)
    {
        base.Start(api);
        api.RegisterBlockClass("trampoline", typeof(TrampolineBlock));
    }
}

This should be marked as a syntax error because there is no TrampolineBlock class yet.

The Block Class

Let's create our block class itself which of course has to extend Block:

public class TrampolineBlock : Block
{

}

This should solve all syntax errors.

So how do we implement a bouncy block? It's pretty helpful to take a look at the api documentation to find a proper way to implement it.

The method void onEntityCollide(IWorldAccessor world, Entity entity, BlockPos pos, BlockFacing facing, bool isImpact) seems to be a good way to implement a bouncy functionality.

When should an entity bounce?

  1. The entity should bounce in the moment it lands on top of the block and not if it is standing on it already. Therefore isImpact has to be true
  2. If the entity is colliding vertically. The sides of the block shouldn't push an entity away. So the axis of the facing has to be Y.

How can we make the entity bounce? In order to make an entity bounce, we need to change its direction. Therefore we can simply revert its motion. The faster the entity will be when during the collision the further it will be pushed away. But simply reverting the motion wouldn't be ideal. The entity would never lose its motion and bounce endless. So let's go for something smaller and make the entity lose 20% of its motion each bounce:

entity.Pos.Motion.Y *= -0.8;

If we put everything together it should look like this:

public class TrampolineBlock : Block
{
    public override void OnEntityCollide(IWorldAccessor world, Entity entity, BlockPos pos, BlockFacing facing, Vec3d collideSpeed, bool isImpact)
    {
        if (isImpact && facing.Axis == EnumAxis.Y)
        {
            world.PlaySoundAt(tickSound, entity.Pos.X, entity.Pos.Y, entity.Pos.Z);
            entity.Pos.Motion.Y *= -0.8;
        }
    }
}

Although this code works already, some sound effects would be rather nice. We can implement it by adding a sound link field to our block, which can use to play the game:tick sound.

public AssetLocation tickSound = new AssetLocation("game", "tick");

This tickSound will played every time an entity bounces:

world.PlaySoundAt(tickSound, entity.Pos.X, entity.Pos.Y, entity.Pos.Z);

If you have done everything right, your file should look similar to this:

using Vintagestory.API.Common;
using Vintagestory.API.Common.Entities;
using Vintagestory.API.MathTools;

namespace VSExampleMods
{
    public class TrampolineMod : ModSystem
    {

        public override void Start(ICoreAPI api)
        {
            base.Start(api);
            api.RegisterBlockClass("trampoline", typeof(TrampolineBlock));
        }
    }

    public class TrampolineBlock : Block
    {
        public AssetLocation tickSound = new AssetLocation("game", "tick");

        public override void OnEntityCollide(IWorldAccessor world, Entity entity, BlockPos pos, BlockFacing facing, Vec3d collideSpeed, bool isImpact)
        {
            if (isImpact && facing.Axis == EnumAxis.Y)
            {
                world.PlaySoundAt(tickSound, entity.Pos.X, entity.Pos.Y, entity.Pos.Z);
                entity.Pos.Motion.Y *= -0.8;
            }
        }
    }
}

Of course you can download the file directly Trampoline.cs.

Testing

Finally we can run our first test. Looks pretty good, right?

Hint: Use the client command .tfedit if you want to adjust the block position, rotation and scale in Hands, in GUI, when dropped on the ground or in third person mode.

Distribution

In order to finish everything, 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

Here is my version:

Moving Forward

Now that you've successfully made an advanced block you can go even further by learning how to utilize Block Entities and how to create your own Block Behaviors. Both of these tutorials will teach you how to add even more mechanics to your custom blocks.

Or, you can try out making an Advanced Item if you haven't already.


Vintage Story: Modding
Basics Mod Types | Asset System | Textures | Items | Recipes | Blocks | Model Creator | Release
Advanced Setup(Windows,Linux) | Items (Code, JSON) | Blocks | Item-Block interactions | Block Behaviors | Block Entities | Particles | World Access
Worldgen Terrain | Ores | Trees | WorldGen API
Rendering Shaders and Renderers
Property Overview Item | Block | Block Behaviors | Block Classes | Block Entities | Block Entity Behaviors