Modding:Advanced Items/ru: Difference between revisions

From Vintage Story Wiki
(Created page with "== Класс Предмета ==")
(Created page with "{{Navbox/modding|Vintage Story}}")
(38 intermediate revisions by the same user not shown)
Line 4: Line 4:
{{GameVersion|1.19.3}}
{{GameVersion|1.19.3}}


Это руководство по ''код моду'' требует наличия среды разработки. Если у вас её нет, перейдите на страницу [[Настройка среды разработки]] и следуйте инструкции. Также настоятельно рекомендуется прочитать руководство и закончить создание [[Простого предмета]].
Это руководство по ''код моду'' требует наличия среды разработки. Если у вас её нет, перейдите на страницу {{ll|Modding:Setting up your Development Environment|Настройка среды для разработки}} и следуйте инструкции. Также настоятельно рекомендуется прочитать руководство и закончить создание {{ll|Modding:Basic Item|Простого предмета}}.


= Создание Тоннельной Кирки =
= Создание Тоннельной Кирки =
Line 12: Line 12:
== Активы Предмета ==
== Активы Предмета ==


Как и в случае с [[Простым Предметом]], нам нужно создать активы (ассеты) для нашего предмета, включая тип предмета, текстуру и lang-файл. Эти активы довольно просты, и вы можете скачать их [https://wiki.vintagestory.at/images/c/cd/Tunnler_-_No_CS_File.zip здесь]. Распакуйте файл в папку mods, и вы готовы приступить к программированию.
Как и в случае с {{ll|Modding:Basic Item|Простым предметом}}, нам нужно создать активы (ассеты) для нашего предмета, включая тип предмета, текстуру и lang-файл. Эти активы довольно просты, и вы можете скачать их [https://wiki.vintagestory.at/images/c/cd/Tunnler_-_No_CS_File.zip здесь]. Распакуйте файл в папку mods, и вы готовы приступить к программированию.


В json вашего itemtype есть только одно новое свойство, <code>class</code>. Это свойство указывает нашему новому элементу, что он будет управляться определенным классом C#.
В json вашего itemtype есть только одно новое свойство, <code>class</code>. Это свойство указывает нашему новому элементу, что он будет управляться определенным классом C#.
Line 23: Line 23:
== Класс Предмета ==
== Класс Предмета ==


<div lang="en" dir="ltr" class="mw-content-ltr">
Создание нашего элемента требует создания пары новых файлов <code>*.cs</code> в нашем проекте.
Creating our item requires a couple new <code>*.cs</code> files in our project.
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
Если вы уже читали руководство - {{ll|Modding:Advanced Blocks|Продвинутые блоки}}, это должно быть вам знакомо.
If you have read the [[Advanced Blocks]] Tutorial already, this should be familar to you.
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
=== Система Модов ===
=== The Mod System ===
Для того чтобы зарегистрировать класс предмета, нам нужно создать мод, который представляет собой класс, расширяющий ModSystem:
In order to register your item class, we need to create a mod, which is a class extending ModSystem:
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
public class TunnlerMod : ModSystem
public class TunnlerMod : ModSystem
Line 43: Line 36:
}
}
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
Переопределив метод <code>Start(ICoreAPI)</code>, мы можем зарегистрировать наш класс. Функция <code>RegisterItemClass</code> имеет два параметра:  
By overriding the <code>Start(ICoreAPI)</code> method, we can register our class. The <code>RegisterItemClass</code> function has two parameters: the first is our item class ID, noteably this is how we link to this class in our itemtype json files. Ensure that this is identical to the class we specified in our earlier asset file. The second parameter is the type of our item class.
Первый - идентификатор элемента класса, поскольку именно так мы будем ссылаться на этот класс в наших json-файлах itemtype. Убедитесь, что он идентичен классу, который мы указали в нашем предыдущем файле активов.  
</div>
Второй параметр - тип нашего элемента класса.


<div lang="en" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
public class TunnlerMod : ModSystem
public class TunnlerMod : ModSystem
Line 60: Line 51:
}
}
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
Это должно быть отмечено как синтаксическая ошибка, потому что класса <code>TunnlerItem</code> пока не существует.
This should be marked as a syntax error because there is no <code>TunnlerItem</code> class yet.
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
=== Класс Предмета ===
=== The Item Class ===
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
При наименовании скриптов предметов рекомендуется называть их в формате "{Name}Item". В случае с тоннельной киркой мы назовем наш скрипт <code>TunnlerItem.cs</code>. Любой itemclass должен расширять Item, предоставляя ему необходимую нам функциональность:
When naming item scripts, it is recommended to name them in the format "{Name}Item". In the case of the tunnler pickaxe, we shall name our script <code>TunnlerItem.cs</code>. Any itemclass has to extend Item, giving it the functionality we need to access:
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
public class TunnlerItem : Item
public class TunnlerItem : Item
{
{
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
}
}
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
Это должно решить все синтаксические ошибки.
This should solve all syntax errors.
</div>




<div lang="en" dir="ltr" class="mw-content-ltr">
'''Так что же должен делать наш инструмент?''' Когда игрок добывает блок с помощью этого инструмента, все блоки вокруг него также должны быть добыты.  
'''So what should our tool do?''' Once the player mines a block with this tool every block around it should be mined as well.
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
Как обычно, мы можем обратиться к [https://apidocs.vintagestory.at/api/Vintagestory.API.Common.Item.html#methods item api docs], чтобы найти функцию, которую мы можем использовать. Хотя сам класс item не содержит соответствующей функции, мы также можем обратиться к [https://apidocs.vintagestory.at/api/Vintagestory.API.Common.CollectibleObject.html CollectibleObject api docs], от которого класс item расширяется.  
As always, we can refer to the [https://apidocs.vintagestory.at/api/Vintagestory.API.Common.Item.html#methods item api docs] to find a function we can use. Although the item class itself does not contain an appropriate function, we can also check the [https://apidocs.vintagestory.at/api/Vintagestory.API.Common.CollectibleObject.html CollectibleObject api docs], which the item class extends from.
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
В нашем конкретном случае мы можем переопределить метод <code>bool OnBlockBrokenWith(IWorldAccessor world, Entity byEntity, ItemSlot itemslot, BlockSelection blockSel, float dropQuantityMultiplier = 1)</code>.
In our specific case, we can override the method <code>bool OnBlockBrokenWith(IWorldAccessor world, Entity byEntity, ItemSlot itemslot, BlockSelection blockSel, float dropQuantityMultiplier = 1)</code>.
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
Нам нужно знать, с какой стороны стоит игрок (на какую сторону он ориентируется) и находится ли он в творческом режиме или режиме выживания (нужно ли бросать предметы или нет). Прежде чем переопределять <code>OnBlockBrokenWith</code>, мы должны создать метод, который уничтожает все блоки между двумя позициями блока (min и max). Он также должен сбрасывать предметы, только если игрок находится в режиме выживания:
We need to be aware of the facing (which side the player is focusing) and if the player is in creative or survival mode (whether items should be dropped or not). Before we are going to override <code>OnBlockBrokenWith</code> we should create a method which destroys all blocks between two block positions (min & max). It should also only drop items if the player is in survival mode:
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
public void DestroyBlocks(IWorldAccessor world, BlockPos min, BlockPos max, IPlayer player)
public void DestroyBlocks(IWorldAccessor world, BlockPos min, BlockPos max, IPlayer player)
Line 127: Line 96:
}
}
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
Теперь мы можем реализовать <code>OnBlockBroken</code> довольно легко, позаботившись обо всех возможных осях, с которыми может столкнуться игрок:
Now we can implement <code>OnBlockBroken</code> rather easily, by taken care of every possible axis the player could face:
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
public override bool OnBlockBrokenWith(IWorldAccessor world, Entity byEntity, ItemSlot itemslot, BlockSelection blockSel, float dropQuantityMultiplier = 1)
public override bool OnBlockBrokenWith(IWorldAccessor world, Entity byEntity, ItemSlot itemslot, BlockSelection blockSel, float dropQuantityMultiplier = 1)
Line 157: Line 124:
}
}
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
----
----
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
Если вы все сделали правильно, ваш файл должен выглядеть примерно так:
If you have done everything right, your file should look similar to this:
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
using Vintagestory.API.Common;
using Vintagestory.API.Common;
using Vintagestory.API.Common.Entities;
using Vintagestory.API.Common.Entities;
using Vintagestory.API.MathTools;
using Vintagestory.API.MathTools;
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
namespace ExampleMods
namespace ExampleMods
{
{
     public class TunnlerMod : ModSystem
     public class TunnlerMod : ModSystem
     {
     {
</div>


         <div lang="en" dir="ltr" class="mw-content-ltr">
         public override void Start(ICoreAPI api)
public override void Start(ICoreAPI api)
         {
         {
             base.Start(api);
             base.Start(api);
             api.RegisterItemClass("tunnler", typeof(TunnlerItem));
             api.RegisterItemClass("tunnler", typeof(TunnlerItem));
         }
         }
</div>


     <div lang="en" dir="ltr" class="mw-content-ltr">
     }
}
</div>


     <div lang="en" dir="ltr" class="mw-content-ltr">
     public class TunnlerItem : Item
public class TunnlerItem : Item
     {
     {
</div>


         <div lang="en" dir="ltr" class="mw-content-ltr">
         public void DestroyBlocks(IWorldAccessor world, BlockPos min, BlockPos max, IPlayer player)
public void DestroyBlocks(IWorldAccessor world, BlockPos min, BlockPos max, IPlayer player)
         {
         {
             BlockPos tempPos = new BlockPos();
             BlockPos tempPos = new BlockPos();
Line 214: Line 167:
             }
             }
         }
         }
</div>


         <div lang="en" dir="ltr" class="mw-content-ltr">
         public override bool OnBlockBrokenWith(IWorldAccessor world, Entity byEntity, ItemSlot itemslot, BlockSelection blockSel, float dropQuantityMultiplier = 1)
public override bool OnBlockBrokenWith(IWorldAccessor world, Entity byEntity, ItemSlot itemslot, BlockSelection blockSel, float dropQuantityMultiplier = 1)
         {
         {
             if (base.OnBlockBrokenWith(world, byEntity, itemslot, blockSel))
             if (base.OnBlockBrokenWith(world, byEntity, itemslot, blockSel))
Line 241: Line 192:
             return false;  
             return false;  
         }
         }
</div>


     <div lang="en" dir="ltr" class="mw-content-ltr">
     }
}
}
}
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
Вы также можете скачать файл напрямую: [https://wiki.vintagestory.at/images/a/ad/Tunnler.cs Tunnler.cs].
You can also download the file directly: [https://wiki.vintagestory.at/images/a/ad/Tunnler.cs Tunnler.cs].
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
== Тестирование ==
== Testing ==
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
Вот как это выглядит в игре:
This is how it looks ingame:
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
<youtube>2MRzYKguVFY</youtube>
<youtube>2MRzYKguVFY</youtube>
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
== Распределение ==
== Distribution ==
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
=== Использование нового шаблона мода ===
=== Using the new Mod Template ===
При использовании шаблона мода следуйте инструкциям [[Modding:Setting up your Development Environment#Packaging%20the%20Mod|Setting up your Development Environment]], чтобы упаковать и распространить свой мод.
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.
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
=== Использование (старого) Modtools ===
=== Using the (old) Modtools ===
Если вы используете программу modtools, откройте ее и введите <code>pack <your mod id></code>. Теперь вы можете взять zip-файл и поделиться им с другими людьми. Он будет работать так же, как и обычные моды, вы можете установить его, скопировав в папку <code>mods</code>.
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 =
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
Вот моя версия:  
Here is my version:  
* for VS v1.9: [https://wiki.vintagestory.at/images/7/7b/Tunnler_vs1.9_v1.0.0.zip Tunnler_vs1.9_v1.0.0.zip]
* for VS v1.9: [https://wiki.vintagestory.at/images/7/7b/Tunnler_vs1.9_v1.0.0.zip Tunnler_vs1.9_v1.0.0.zip]
* for VS v1.8: [https://wiki.vintagestory.at/images/6/66/Tunnler.zip Tunnler.zip]
* for VS v1.8: [https://wiki.vintagestory.at/images/6/66/Tunnler.zip Tunnler.zip]
</div>




<div lang="en" dir="ltr" class="mw-content-ltr">
{{Navbox/modding|Vintage Story}}
{{Navbox/modding|Vintage Story}}
</div>

Revision as of 16:46, 24 March 2024

Other languages:


Эта страница проверялась в последний раз для версии Vintage Story 1.19.3.


Это руководство по код моду требует наличия среды разработки. Если у вас её нет, перейдите на страницу Настройка среды для разработки и следуйте инструкции. Также настоятельно рекомендуется прочитать руководство и закончить создание Простого предмета .

Создание Тоннельной Кирки

В этом уроке мы создадим предмет с более продвинутой функциональностью: Кирка, которая позволяет вырыть туннель 3x3, добыв всего один блок.

Активы Предмета

Как и в случае с Простым предметом , нам нужно создать активы (ассеты) для нашего предмета, включая тип предмета, текстуру и lang-файл. Эти активы довольно просты, и вы можете скачать их здесь. Распакуйте файл в папку mods, и вы готовы приступить к программированию.

В json вашего itemtype есть только одно новое свойство, class. Это свойство указывает нашему новому элементу, что он будет управляться определенным классом C#.

	class: "tunnler",

Мы создадим этот класс, чтобы придать элементу желаемую функциональность.

Класс Предмета

Создание нашего элемента требует создания пары новых файлов *.cs в нашем проекте.

Если вы уже читали руководство - Продвинутые блоки , это должно быть вам знакомо.

Система Модов

Для того чтобы зарегистрировать класс предмета, нам нужно создать мод, который представляет собой класс, расширяющий ModSystem:

public class TunnlerMod : ModSystem
{
    
}

Переопределив метод Start(ICoreAPI), мы можем зарегистрировать наш класс. Функция RegisterItemClass имеет два параметра: Первый - идентификатор элемента класса, поскольку именно так мы будем ссылаться на этот класс в наших json-файлах itemtype. Убедитесь, что он идентичен классу, который мы указали в нашем предыдущем файле активов. Второй параметр - тип нашего элемента класса.

public class TunnlerMod : ModSystem
{
    public override void Start(ICoreAPI api)
    {
        base.Start(api);
        api.RegisterItemClass("tunnler", typeof(TunnlerItem));
    }
}

Это должно быть отмечено как синтаксическая ошибка, потому что класса TunnlerItem пока не существует.

Класс Предмета

При наименовании скриптов предметов рекомендуется называть их в формате "{Name}Item". В случае с тоннельной киркой мы назовем наш скрипт TunnlerItem.cs. Любой itemclass должен расширять Item, предоставляя ему необходимую нам функциональность:

public class TunnlerItem : Item
{

}

Это должно решить все синтаксические ошибки.


Так что же должен делать наш инструмент? Когда игрок добывает блок с помощью этого инструмента, все блоки вокруг него также должны быть добыты.

Как обычно, мы можем обратиться к item api docs, чтобы найти функцию, которую мы можем использовать. Хотя сам класс item не содержит соответствующей функции, мы также можем обратиться к CollectibleObject api docs, от которого класс item расширяется.

В нашем конкретном случае мы можем переопределить метод bool OnBlockBrokenWith(IWorldAccessor world, Entity byEntity, ItemSlot itemslot, BlockSelection blockSel, float dropQuantityMultiplier = 1).

Нам нужно знать, с какой стороны стоит игрок (на какую сторону он ориентируется) и находится ли он в творческом режиме или режиме выживания (нужно ли бросать предметы или нет). Прежде чем переопределять OnBlockBrokenWith, мы должны создать метод, который уничтожает все блоки между двумя позициями блока (min и max). Он также должен сбрасывать предметы, только если игрок находится в режиме выживания:

public void DestroyBlocks(IWorldAccessor world, BlockPos min, BlockPos max, IPlayer player)
{
    BlockPos tempPos = new BlockPos();
    for (int x = min.X; x <= max.X; x++)
    {
        for (int y = min.Y; y <= max.Y; y++)
        {
            for (int z = min.Z; z <= max.Z; z++)
            {
                tempPos.Set(x, y, z);
                if (player.WorldData.CurrentGameMode == EnumGameMode.Creative)
                    world.BlockAccessor.SetBlock(0, tempPos);
                else
                    world.BlockAccessor.BreakBlock(tempPos, player);
            }
        }
    }
}

Теперь мы можем реализовать OnBlockBroken довольно легко, позаботившись обо всех возможных осях, с которыми может столкнуться игрок:

public override bool OnBlockBrokenWith(IWorldAccessor world, Entity byEntity, ItemSlot itemslot, BlockSelection blockSel, float dropQuantityMultiplier = 1)
{
    if (base.OnBlockBrokenWith(world, byEntity, itemslot, blockSel))
    {
        if (byEntity is EntityPlayer)
        {
            IPlayer player = world.PlayerByUid((byEntity as EntityPlayer).PlayerUID);
            switch (blockSel.Face.Axis)
            {
                case EnumAxis.X:
                    destroyBlocks(world, blockSel.Position.AddCopy(0, -1, -1), blockSel.Position.AddCopy(0, 1, 1), player);
                    break;
                case EnumAxis.Y:
                    destroyBlocks(world, blockSel.Position.AddCopy(-1, 0, -1), blockSel.Position.AddCopy(1, 0, 1), player);
                    break;
                case EnumAxis.Z:
                    destroyBlocks(world, blockSel.Position.AddCopy(-1, -1, 0), blockSel.Position.AddCopy(1, 1, 0), player);
                    break;
            }
        }
        return true;
    }
    return false; 
}

Если вы все сделали правильно, ваш файл должен выглядеть примерно так:

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

namespace ExampleMods
{
    public class TunnlerMod : ModSystem
    {

        public override void Start(ICoreAPI api)
        {
            base.Start(api);
            api.RegisterItemClass("tunnler", typeof(TunnlerItem));
        }

    }

    public class TunnlerItem : Item
    {

        public void DestroyBlocks(IWorldAccessor world, BlockPos min, BlockPos max, IPlayer player)
        {
            BlockPos tempPos = new BlockPos();
            for (int x = min.X; x <= max.X; x++)
            {
                for (int y = min.Y; y <= max.Y; y++)
                {
                    for (int z = min.Z; z <= max.Z; z++)
                    {
                        tempPos.Set(x, y, z);
                        if (player.WorldData.CurrentGameMode == EnumGameMode.Creative)
                            world.BlockAccessor.SetBlock(0, tempPos);
                        else
                            world.BlockAccessor.BreakBlock(tempPos, player);
                    }
                }
            }
        }

        public override bool OnBlockBrokenWith(IWorldAccessor world, Entity byEntity, ItemSlot itemslot, BlockSelection blockSel, float dropQuantityMultiplier = 1)
        {
            if (base.OnBlockBrokenWith(world, byEntity, itemslot, blockSel))
            {
                if (byEntity is EntityPlayer)
                {
                    IPlayer player = world.PlayerByUid((byEntity as EntityPlayer).PlayerUID);
                    switch (blockSel.Face.Axis)
                    {
                        case EnumAxis.X:
                            destroyBlocks(world, blockSel.Position.AddCopy(0, -1, -1), blockSel.Position.AddCopy(0, 1, 1), player);
                            break;
                        case EnumAxis.Y:
                            destroyBlocks(world, blockSel.Position.AddCopy(-1, 0, -1), blockSel.Position.AddCopy(1, 0, 1), player);
                            break;
                        case EnumAxis.Z:
                            destroyBlocks(world, blockSel.Position.AddCopy(-1, -1, 0), blockSel.Position.AddCopy(1, 1, 0), player);
                            break;
                    }
                }
                return true;
            }
            return false; 
        }

    }
}

Вы также можете скачать файл напрямую: Tunnler.cs.

Тестирование

Вот как это выглядит в игре:

Распределение

Использование нового шаблона мода

При использовании шаблона мода следуйте инструкциям Setting up your Development Environment, чтобы упаковать и распространить свой мод.

Использование (старого) Modtools

Если вы используете программу modtools, откройте ее и введите pack <your mod id>. Теперь вы можете взять zip-файл и поделиться им с другими людьми. Он будет работать так же, как и обычные моды, вы можете установить его, скопировав в папку mods.

Скачать Мод

Вот моя версия:


Icon Sign.png

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 Пакет тем
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 ItemEntityBlockBlock BehaviorsBlock ClassesBlock EntitiesBlock Entity BehaviorsWorld properties
Workflows & Infrastructure Modding Efficiency TipsMod-engine compatibilityMod ExtensibilityVS Engine
Additional Resources Community Resources Modding API Updates Programming Languages List of server commandsList of client commandsClient startup parametersServer startup parameters
Example ModsAPI DocsGitHub Repository