Modding:Code Tutorial Simple Item: Difference between revisions

From Vintage Story Wiki
m
mNo edit summary
Line 44: Line 44:
To keep the code organized, you should create a new folder called "Items". Right click on your project, hover over add, and select ''New Folder''.  
To keep the code organized, you should create a new folder called "Items". Right click on your project, hover over add, and select ''New Folder''.  


You need a name for the new item class. These follow the same convention as the Blocks, and most other types. In this case, our thorny blade item class, you should name this class "ItemThornsBlade".  
You also need a name for the new item class. These follow the same convention as the Blocks, and most other types. In this case, our thorny blade item class, you should name this class "ItemThornsBlade".  


Create your new class. Right click the new folder, hover over ''Add'', and select ''Class''. Ensure you have the standard ''Class'' selected in the template list, enter your class name, and click create.
Create your new class. Right click the new folder, hover over ''Add'', and select ''Class''. Ensure you have the standard ''Class'' selected in the template list, enter your class name, and click create.


The class you created needs to extend the 'Item'  
The class you created needs to extend the 'Item' class. This will allow you to use many of the available functions for items. Change the class definition to now be: <syntaxhighlight lang="csharp">
internal class ItemThornsBlade : Item
</syntaxhighlight>Most of the time, Visual Studio will automatically add 'using' statements. However, if this errors, click on "Item", press Alt+Enter, and select the "using Vintagestory.API.Common" option.
[[File:VisualStudioModdingTutorialAutoErrorSolving.png|center|frameless|623x623px]]
The ItemThornsBlade class now exists, but it does nothing. Time to override a function, I suppose.
 
Inside the empty class, type "override " and a list of methods we can use will be displayed. In this instance, you will want to override the 'OnAttackingWith' function. This function is called whenever our item is used to attack an entity. Search for this in the list and double click on it to automatically add the required code sample.
[[File:VisualStudioModdingTutorialOverrideOnAttackingWithFunction.png|center|frameless|767x767px]]
Your class should now look like this:
{| class="wikitable mw-collapsible mw-collapsed"
|ItemThornsBlade.cs
|-
|<syntaxhighlight lang="csharp">
using Vintagestory.API.Common;
using Vintagestory.API.Common.Entities;
 
namespace VSTutorial.Items
{
    internal class ItemThornsBlade : Item
    {
        public override void OnAttackingWith(IWorldAccessor world, Entity byEntity, Entity attackedEntity, ItemSlot itemslot)
        {
            base.OnAttackingWith(world, byEntity, attackedEntity, itemslot);
        }
    }
}
</syntaxhighlight>
|}
Note that the the sample code in ''<nowiki/>'OnAttackingWith' contains a function called 'base.OnAttackingWith'.'' This essentially runs any default behavior for the function. If you were to remove this line then any default behavior would not happen, and, in this case, the item will not lose any durability when used for attacking.
 
In the OnAttackingWith function, you are given access to the world, the entity who is attacking, the entity who is being attacked, and the itemslot that this item exists in. For testing purposes, add some code that outputs a message to the console when we attack an entity. You'll need to add the following code below the '''base''<nowiki/>' line:<syntaxhighlight lang="csharp">
world.Api.Logger.Event("Got attack with thorns blade!");
</syntaxhighlight>You can access the current game API from a lot of places. This particular line accesses the API through the world, however it can also be accessed through any entity with very similar code. You should be aware that this will create a message to the console when we attack an entity with the new item.


=== Registering the Item Class ===
=== Registering the Item Class ===
Line 75: Line 107:


== Testing the Block Class ==
== Testing the Block Class ==
Press F5 again to run the game with the mod. Remember to set the game to windowed mode by pressing F11. Find the trampoline in the creative menu, place one, and destroy it.
Press F5 again to run the game with the mod. Remember to set the game to windowed mode by pressing F11. Find the thorns blade in the creative menu, and use it to attack an entity.


After doing so, take a look at the console that opened when launching the game. You should be able to see the following logs:<syntaxhighlight>
[Client Event] Trampoline Block Placed!
[Server Event] Trampoline Block Placed!
[Client Event] Trampoline Block Broken!
[Server Event] Trampoline Block Broken!
</syntaxhighlight>Wait... what?
The trampoline block was placed once, and broken once, so why are there two entries? Notice that each entry tells you whether it came from the client or server, and in this case, we have one of each. Due to running a singleplayer instance, there is both a client and server running at the same time. The overriden functions are being called once on the client, and once on the server.


In many instances, this is exactly what is wanted. Most features are synced between the client and server, but it is important to remember that many functions get called twice in this system. There are a number of ways you can verify what 'side' is calling the function, or to limit certain code to one side.


Anyway, it's clear that the trampoline class is working, so close the game and go back to the ''BlockTrampoline'' class.
After doing so, take a look at the console that opened when launching the game. You should be able to see the following logs:<syntaxhighlight>
[Client Event] Got attack with thorns blade!
[Server Event] Got attack with thorns blade!
</syntaxhighlight>Remember what's going on here? Although you only attacked the entity once, there are two entries. One of these is sent to the console by the client, and the other is sent by the server. You should start to become aware that a lot of the code you write is going to happen on both the client and server. You'll be shown ways of controlling this later.


== Trampoline Functionality ==
The thorns blade class and function are working, so close the game and go back to the ItemThornsBlade class.  
You need to create the actual functionality for the trampoline. When an entity collides with this block, the entity's vertical velocity should be reversed and multiplied by a certain amount.  


The placed and break functions are unnecessary for this block, so you can remove them. Your script should look like the following:
== Thorns Blade Functionality ==
You now need to add the real functionality for the thorns blade. Remove the line of code that logs the attack event, since you don't need that anymore. Your code should look like the following. Feel free to copy and paste this, as it contains some useful code comments too.
{| class="wikitable mw-collapsible mw-collapsed"
{| class="wikitable mw-collapsible mw-collapsed"
|BlockTrampoline.cs
|ItemThornsBlade.cs
|-
|-
|<syntaxhighlight lang="csharp">
|<syntaxhighlight lang="csharp">
//Here are the imports for this script. Most of these will add automatically.
using Vintagestory.API.Common;
using Vintagestory.API.Common;
using Vintagestory.API.MathTools;
using Vintagestory.API.Common.Entities;


/*
namespace VSTutorial.Items
* The namespace the class will be in. This is essentially the folder the script is found in.
* If you need to use the BlockTrampoline class in any other script, you will have to add 'using VSTutorial.Blocks' to that script.
*/
namespace VSTutorial.Blocks
{
{
     /*
     /*
    * The class definition. Here, you define BlockTrampoline as a child of Block, which
    * As this is an item, you need to inherit the Item class. This gives access to functions within Item, and CollectibleObject.
     * means you can 'override' many of the functions within the general Block class.  
    * Take a look at https://apidocs.vintagestory.at/api/Vintagestory.API.Common.Item.html#methods and
    */
     *   https://apidocs.vintagestory.at/api/Vintagestory.API.Common.CollectibleObject.html#methods for all the methods that can be overriden.
     internal class BlockTrampoline : Block
    */
     internal class ItemThornsBlade : Item
     {
     {
          
         /*
        * This function is called whenever this item is used by an entity to attack another entity.
        * You have access to the world, the entity who is attacking, the entity who is being attacked, and the held item's data.
        */
        public override void OnAttackingWith(IWorldAccessor world, Entity byEntity, Entity attackedEntity, ItemSlot itemslot)
        {
            base.OnAttackingWith(world, byEntity, attackedEntity, itemslot);
        }
 
     }
     }
}
}
</syntaxhighlight>
</syntaxhighlight>
|}
|}
[[File:VisualStudioListBlockMethodsFromOverride.png|left|frameless|355x355px]]
=== Reflecting Damage ===
Click on the empty space, and type 'override ' (including the space). Visual Studio will show you a scrollable list of functions that can be overriden. If the menu closes, you can simply delete the space and replace it, and the menu will return.
To inflict damage on an entity, there are two small steps:
 
Feel free to scroll through this menu and take a look at what is available. The functions here are all listed in the API documentation mentioned earlier.
 
The function you need to use is called ''OnEntityCollide''. With the mentioned menu above, type 'collide', and you should see a single result in the list. Press enter, tab, or double click on the entry, and Visual Studio will generate the function for you.
 
Take a look at the supplied arguments for this function. You have access to the world, the entity, the block's position, the 'facing' position of the collision, the collision speed, and whether this is an impact.


=== Making it Bounce ===
# A ''DamageSource'' instance must be created.
The following points determine when an entity should bounce on the trampoline block.
# The damage source must be inflicted on the entity using the Entity.ReceiveDamage function.


# 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'' needs to be ''true''.
# The entity should be colliding vertically. The sides of the block shouldn't push an entity away. In effect, ''facing.IsVertical'' needs to be ''true''.


So, add the following block inside the function:<syntaxhighlight lang="csharp">
So, add the following block inside the function:<syntaxhighlight lang="csharp">
Confirmedusers
643

edits