Confirmedusers
409
edits
m (Updated to 1.19.3.) |
No edit summary |
||
Line 1: | Line 1: | ||
<languages /> | <languages/> | ||
__FORCETOC__ | |||
<translate> | <translate> | ||
{{GameVersion|1.19.3}} | {{GameVersion|1.19.3}} | ||
</translate> | |||
= Introduction = | <translate> | ||
= Introduction = | |||
Block Behaviors are useful when you want different blocks to act in the same way, as you can attach one or more block behaviors to an arbitrary number of blocks. | Block Behaviors are useful when you want different blocks to act in the same way, as you can attach one or more block behaviors to an arbitrary number of blocks. | ||
You may want to have a look at the existing [[Block Json Properties#p_behaviors|block behaviors]] before implementing your own. | You may want to have a look at the existing [[Block Json Properties#p_behaviors|block behaviors]] before implementing your own. | ||
In this tutorial we'll create a new Behavior that we can attach to blocks to make them movable by right clicking them. | In this tutorial we'll create a new Behavior that we can attach to blocks to make them movable by right clicking them. | ||
</translate> | |||
== Setting up == | <translate> | ||
== Setting up == | |||
A [[Setting up your Development Environment|development workspace]] is required. Additionally you will need the assets (blocktype, texture and lang file). You can either create your one owns or use those pre-made ones: [https://wiki.vintagestory.at/images/2/2f/Moving_-_No_CS_File.zip Moving - No CS File.zip] | A [[Setting up your Development Environment|development workspace]] is required. Additionally you will need the assets (blocktype, texture and lang file). You can either create your one owns or use those pre-made ones: [https://wiki.vintagestory.at/images/2/2f/Moving_-_No_CS_File.zip Moving - No CS File.zip] | ||
</translate> | |||
== Creating the behavior == | <translate> | ||
== Creating the behavior == | |||
So first of all we need to create the behavior itself, which is a class extending BlockBehavior | So first of all we need to create the behavior itself, which is a class extending BlockBehavior | ||
</translate> | |||
<syntaxhighlight lang="csharp"> | <syntaxhighlight lang="csharp"> | ||
class Moving : BlockBehavior | class Moving : BlockBehavior | ||
Line 31: | Line 35: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
< | <translate> | ||
This class provides several methods we can override. When you use Visual Studio you can find a full list of a methods by hovering with the mouse of "BlockBehavior" and pressing "F12". | This class provides several methods we can override. When you use Visual Studio you can find a full list of a methods by hovering with the mouse of "BlockBehavior" and pressing "F12". | ||
---- | ---- | ||
The method <code>bool OnBlockInteractStart(IWorldAccessor world, IPlayer byPlayer, BlockSelection blockSel, ref EnumHandling handling)</code> looks to be ideal for our purpose. | The method <code>bool OnBlockInteractStart(IWorldAccessor world, IPlayer byPlayer, BlockSelection blockSel, ref EnumHandling handling)</code> looks to be ideal for our purpose. | ||
What should it do? | What should it do? | ||
# Calculate the new position to move the block to, based on the block face the player is looking at. | # Calculate the new position to move the block to, based on the block face the player is looking at. | ||
# Check if the block can be placed at this new position. | # Check if the block can be placed at this new position. | ||
Line 49: | Line 49: | ||
# Place the same type of block at the new position. | # Place the same type of block at the new position. | ||
# [[Modding:Behavior_Traversal|Skip]] the default logic that would otherwise place whatever item is held at the old position. | # [[Modding:Behavior_Traversal|Skip]] the default logic that would otherwise place whatever item is held at the old position. | ||
</translate> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public override bool OnBlockInteractStart(IWorldAccessor world, IPlayer byPlayer, BlockSelection blockSel, ref EnumHandling handling) | public override bool OnBlockInteractStart(IWorldAccessor world, IPlayer byPlayer, BlockSelection blockSel, ref EnumHandling handling) | ||
{ | { | ||
<translate> | |||
// Find the target position | // Find the target position | ||
</translate> | |||
BlockPos pos = blockSel.Position.AddCopy(blockSel.Face.Opposite); | BlockPos pos = blockSel.Position.AddCopy(blockSel.Face.Opposite); | ||
<translate> | |||
// Can we place the block there? | |||
// Can we place the block there? | </translate> | ||
if (world.BlockAccessor.GetBlock(pos).IsReplacableBy(block)) | if (world.BlockAccessor.GetBlock(pos).IsReplacableBy(block)) | ||
{ | { | ||
Line 65: | Line 67: | ||
world.BlockAccessor.SetBlock(block.BlockId, pos); | world.BlockAccessor.SetBlock(block.BlockId, pos); | ||
} | } | ||
<translate> | |||
// Notify the game engine other block behaviors that we handled the players interaction with the block. | |||
// Notify the game engine other block behaviors that we handled the players interaction with the block. | |||
// If we would not set the handling field the player would still be able to place blocks if he has them in hands. | // If we would not set the handling field the player would still be able to place blocks if he has them in hands. | ||
</translate> | |||
handling = EnumHandling.PreventDefault; | handling = EnumHandling.PreventDefault; | ||
return true; | return true; | ||
Line 74: | Line 76: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Register == | <translate> | ||
== Register == | |||
In order the register the BlockBehavior we need to create a mod class, override <code>Start(ICoreAPI)</code> and register it with the given name: | In order the register the BlockBehavior we need to create a mod class, override <code>Start(ICoreAPI)</code> and register it with the given name: | ||
</translate> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public class MovingBlocks : ModSystem | public class MovingBlocks : ModSystem | ||
{ | { | ||
public override void Start(ICoreAPI api) | public override void Start(ICoreAPI api) | ||
{ | { | ||
Line 91: | Line 92: | ||
} | } | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Distribution == | <translate> | ||
== 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. | 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. | ||
* for VS 1.9: [https://wiki.vintagestory.at/images/2/2a/Moving_v1.0.0.zip Moving_v1.0.0.zip] | * for VS 1.9: [https://wiki.vintagestory.at/images/2/2a/Moving_v1.0.0.zip Moving_v1.0.0.zip] | ||
* for VS 1.6: [https://wiki.vintagestory.at/images/c/cb/Moving.zip Moving.zip] | * for VS 1.6: [https://wiki.vintagestory.at/images/c/cb/Moving.zip Moving.zip] | ||
== Testing == < | == Testing == | ||
</translate> | |||
<youtube>8eVG0uQF2xs</youtube> | <youtube>8eVG0uQF2xs</youtube> | ||
= Advanced Behavior = | <translate> | ||
= Advanced Behavior = | |||
Our behavior is still rather simple, but there are a lot more possibilities. A behavior can have special properties, which can be defined by the blocktype itself. | Our behavior is still rather simple, but there are a lot more possibilities. A behavior can have special properties, which can be defined by the blocktype itself. | ||
</translate> | |||
== Example == | <translate> | ||
== Example == | |||
The behavior liquid supports some special properties as shown in this example of the water blocktype: | The behavior liquid supports some special properties as shown in this example of the water blocktype: | ||
</translate> | |||
<syntaxhighlight lang="json"> | <syntaxhighlight lang="json"> | ||
behaviors: [ | behaviors: [ | ||
Line 133: | Line 134: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Parsing properties == | <translate> | ||
== Parsing properties == | |||
In order to take care of special properties there is a method called <code>Initialize(JsonObject)</code>. Each blocktype creates a new instance of the behavior, so the method can be used to parse the properties. | In order to take care of special properties there is a method called <code>Initialize(JsonObject)</code>. Each blocktype creates a new instance of the behavior, so the method can be used to parse the properties. | ||
So what kind of properties could we add? | So what kind of properties could we add? | ||
* push distance | * push distance | ||
* pull block if player is sneaking | * pull block if player is sneaking | ||
First of all, we need to override the method in our block behavior class ... | First of all, we need to override the method in our block behavior class ... | ||
</translate> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public override void Initialize(JsonObject properties) | public override void Initialize(JsonObject properties) | ||
Line 154: | Line 153: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
< | <translate> | ||
Additionally we need to add two fields, one for the distance and another one if the player should pull the block while sneaking ... | Additionally we need to add two fields, one for the distance and another one if the player should pull the block while sneaking ... | ||
</translate> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public int distance = 1; | public int distance = 1; | ||
Line 163: | Line 162: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
< | <translate> | ||
Now we can parse the two properties like so: | Now we can parse the two properties like so: | ||
</translate> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
distance = properties["distance"].AsInt(1); | distance = properties["distance"].AsInt(1); | ||
Line 172: | Line 171: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
---- | ---- | ||
< | <translate> | ||
The next thing we need to change is the interact method itself, so that it takes care of the distance and the pull properties ... | The next thing we need to change is the interact method itself, so that it takes care of the distance and the pull properties ... | ||
</translate> | |||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
public override bool OnBlockInteractStart(IWorldAccessor world, IPlayer byPlayer, BlockSelection blockSel, ref EnumHandling handling) | public override bool OnBlockInteractStart(IWorldAccessor world, IPlayer byPlayer, BlockSelection blockSel, ref EnumHandling handling) | ||
{ | { | ||
<translate> | |||
// Find the target position | // Find the target position | ||
</translate> | |||
BlockPos pos = blockSel.Position.AddCopy(pull && byPlayer.WorldData.EntityControls.Sneak ? blockSel.Face : blockSel.Face.Opposite, distance); | BlockPos pos = blockSel.Position.AddCopy(pull && byPlayer.WorldData.EntityControls.Sneak ? blockSel.Face : blockSel.Face.Opposite, distance); | ||
<translate> | |||
// Can we place the block there? | // Can we place the block there? | ||
</translate> | |||
if (world.BlockAccessor.GetBlock(pos).IsReplacableBy(block)) | if (world.BlockAccessor.GetBlock(pos).IsReplacableBy(block)) | ||
{ | { | ||
<translate> | |||
// Remove the block at the current position and place it at the target position | // Remove the block at the current position and place it at the target position | ||
</translate> | |||
world.BlockAccessor.SetBlock(0, blockSel.Position); | world.BlockAccessor.SetBlock(0, blockSel.Position); | ||
world.BlockAccessor.SetBlock(block.BlockId, pos); | world.BlockAccessor.SetBlock(block.BlockId, pos); | ||
} | } | ||
<translate> | |||
// Notify the game engine other block behaviors that we handled the players interaction with the block. | // Notify the game engine other block behaviors that we handled the players interaction with the block. | ||
// If we would not set the handling field the player would still be able to place blocks if he has them in hands. | // If we would not set the handling field the player would still be able to place blocks if he has them in hands. | ||
</translate> | |||
handling = EnumHandling.PreventDefault; | handling = EnumHandling.PreventDefault; | ||
return true; | return true; | ||
Line 198: | Line 205: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Adding another block == | <translate> | ||
== Adding another block == | |||
Let's create another block using this behavior, but this time we will configure some additional properties ... | Let's create another block using this behavior, but this time we will configure some additional properties ... | ||
</translate> | |||
<syntaxhighlight lang="json"> | <syntaxhighlight lang="json"> | ||
behaviors: [ | behaviors: [ | ||
Line 216: | Line 223: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
< | <translate> | ||
The block will be pushed two blocks instead of one and the player can pull it by sneaking while right clicking. | The block will be pushed two blocks instead of one and the player can pull it by sneaking while right clicking. | ||
</translate> | |||
= Mod Download = | <translate> | ||
= Mod Download = | |||
* for VS 1.9: [https://wiki.vintagestory.at/images/7/7b/Advancedmoving_v1.0.0.zip AdvancedMoving_v1.0.0.zip] | * for VS 1.9: [https://wiki.vintagestory.at/images/7/7b/Advancedmoving_v1.0.0.zip AdvancedMoving_v1.0.0.zip] | ||
* for VS 1.6: [https://wiki.vintagestory.at/images/7/72/AdvancedMoving.zip AdvancedMoving.zip] | * for VS 1.6: [https://wiki.vintagestory.at/images/7/72/AdvancedMoving.zip AdvancedMoving.zip] | ||
</translate> | |||
{{Navbox/modding|Vintage Story}} | {{Navbox/modding|Vintage Story}} | ||