Modding:Advanced Items/ru: Difference between revisions

From Vintage Story Wiki
(Created page with "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)...")
Tags: Mobile edit Mobile web edit
No edit summary
 
(44 intermediate revisions by 2 users not shown)
Line 1: Line 1:
<languages/>
<languages/>
 
<!--T:1-->
__FORCETOC__
__FORCETOC__
{{GameVersion|1.19.3}}
{{GameVersion|1.19.3}}


Это руководство по ''код моду'' требует наличия среды разработки. Если у вас её нет, перейдите на страницу {{ll|Modding:Setting up your Development Environment|Настройка среды для разработки}} и следуйте инструкции. Также настоятельно рекомендуется прочитать руководство и закончить создание {{ll|Modding:Basic Item|Простого предмета}}.
<!--T:2-->
Этот руководство по '''code mod''' требует наличия среды разработки. Если у вас её еще нет, прочтите руководство по {{ll|Modding:Setting up your Development Environment|настройке среды для разработки}}. Также рекомендуется сначала прочитать про {{ll|Modding:Basic Item|Простые Предметы}} и изучить их устройство если вы не сделали этого ранее.


= Создание Тоннельной Кирки =
= Создание Туннельной Кирки = <!--T:3-->


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


== Активы Предмета ==
== Ассеты Предмета == <!--T:5-->


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


В json вашего itemtype есть только одно новое свойство, <code>class</code>. Это свойство указывает нашему новому элементу, что он будет управляться определенным классом C#.
<!--T:7-->
В json вашего itemtype есть только одно новое свойство, <code>class</code>. Это свойство указывает нашему новому предмету, что он будет управляться определенным классом C#.
<syntaxhighlight lang="json">
<syntaxhighlight lang="json">
class: "tunnler",
class: "tunnler",
</syntaxhighlight>
</syntaxhighlight>


Мы создадим этот класс, чтобы придать элементу желаемую функциональность.
<!--T:8-->
Мы создадим этот класс, чтобы придать предмету желаемую функциональность.


== Класс Предмета ==
== Класс Предмета == <!--T:9-->


Создание нашего элемента требует создания пары новых файлов <code>*.cs</code> в нашем проекте.
<!--T:10-->
Создание нашего предмета требует создания пары новых файлов <code>*.cs</code> в нашем проекте.


Если вы уже читали руководство - {{ll|Modding:Advanced Blocks|Продвинутые блоки}}, это должно быть вам знакомо.
<!--T:11-->
Если вы уже читали руководство - {{ll|Modding:Advanced Blocks|Функциональные Блоки}}, это должно быть вам знакомо.


=== Система Модов ===
=== Система Мода === <!--T:12-->
Для того чтобы зарегистрировать класс предмета, нам нужно создать мод, который представляет собой класс, расширяющий ModSystem:
Для того чтобы зарегистрировать ваш класс предмета, нам нужно создать мод, который представляет собой класс, наследующийся от ModSystem:


<!--T:13-->
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
public class TunnlerMod : ModSystem
public class TunnlerMod : ModSystem
Line 37: Line 45:
</syntaxhighlight>
</syntaxhighlight>


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


<!--T:15-->
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
public class TunnlerMod : ModSystem
public class TunnlerMod : ModSystem
Line 52: Line 62:
</syntaxhighlight>
</syntaxhighlight>


Это должно быть отмечено как синтаксическая ошибка, потому что класса <code>TunnlerItem</code> пока не существует.
<!--T:16-->
Так как класса <code>TunnlerItem</code> ещё не существует, это место будет отображаться как синтаксическая ошибка.


=== Класс Предмета ===
=== Класс Предмета === <!--T:17-->


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


<!--T:19-->
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
public class TunnlerItem : Item
public class TunnlerItem : Item
Line 65: Line 78:
</syntaxhighlight>
</syntaxhighlight>


<!--T:21-->
Это должно решить все синтаксические ошибки.
Это должно решить все синтаксические ошибки.




<!--T:22-->
'''Так что же должен делать наш инструмент?''' Когда игрок добывает блок с помощью этого инструмента, все блоки вокруг него также должны быть добыты.  
'''Так что же должен делать наш инструмент?''' Когда игрок добывает блок с помощью этого инструмента, все блоки вокруг него также должны быть добыты.  


Как обычно, мы можем обратиться к [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 расширяется.  
<!--T:23-->
Как обычно, мы можем обратиться к [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 наследуется.  


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


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


<!--T:26-->
<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 97: Line 116:
</syntaxhighlight>
</syntaxhighlight>


<!--T:27-->
Теперь мы можем реализовать <code>OnBlockBroken</code> довольно легко, позаботившись обо всех возможных осях, с которыми может столкнуться игрок:
Теперь мы можем реализовать <code>OnBlockBroken</code> довольно легко, позаботившись обо всех возможных осях, с которыми может столкнуться игрок:
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
Line 125: Line 145:
</syntaxhighlight>
</syntaxhighlight>


<!--T:28-->
----
----


Если вы все сделали правильно, ваш файл должен выглядеть примерно так:
<!--T:29-->
Если вы всё сделали правильно, то ваш файл должен быть похож на:
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
using Vintagestory.API.Common;
using Vintagestory.API.Common;
Line 138: Line 160:
     {
     {


        public override void Start(ICoreAPI api)
public override void Start(ICoreAPI api)
         {
         {
             base.Start(api);
             base.Start(api);
Line 144: Line 166:
         }
         }


    }
}


    public class TunnlerItem : Item
public class TunnlerItem : Item
     {
     {


        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 168: Line 190:
         }
         }


        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 193: Line 215:
         }
         }


    <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">
<!--T:38-->
You can also download the file directly: [https://wiki.vintagestory.at/images/a/ad/Tunnler.cs Tunnler.cs].
Вы также можете скачать файл напрямую: [https://wiki.vintagestory.at/images/a/ad/Tunnler.cs Tunnler.cs].
</div>


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


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


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


<div lang="en" dir="ltr" class="mw-content-ltr">
== Распространение == <!--T:42-->
== Distribution ==
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
=== Использование нового Шаблона Мода === <!--T:43-->
=== Using the new Mod Template ===
Если вы используете шаблон мода, следуйте инструкциям [[Modding:Setting up your Development Environment#Packaging the Mod|Настройка среды разработки]], чтобы упаковать ваш мод для дальнейшего распространения.
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 (старый способ) === <!--T:44-->
=== 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">
<!--T:45-->
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">
<!--T:46-->
{{Navbox/modding|Vintage Story}}
{{Navbox/modding|Vintage Story}}
</div>

Latest revision as of 15:20, 25 March 2024

Other languages:

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


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

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

В этом уроке мы создадим предмет с более продвинутой функциональностью: Кирка, которая позволяет вырыть туннель 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.

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

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

Распространение

Использование нового Шаблона Мода

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

Использование 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