Modding:Advanced Items/ru: Difference between revisions

From Vintage Story Wiki
(Created page with "Так как класса <code>TunnlerItem</code> ещё не существует, это место будет отображаться как синтаксическая ошибка.")
No edit summary
 
(18 intermediate revisions by 2 users not shown)
Line 65: Line 65:
Так как класса <code>TunnlerItem</code> ещё не существует, это место будет отображаться как синтаксическая ошибка.
Так как класса <code>TunnlerItem</code> ещё не существует, это место будет отображаться как синтаксическая ошибка.


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


<!--T:18-->
<!--T:18-->
<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>


<!--T:19-->
<!--T:19-->
Line 79: Line 75:
{
{


<!--T:20-->
}
}
</syntaxhighlight>
</syntaxhighlight>


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




<!--T:22-->
<!--T:22-->
<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>


<!--T:23-->
<!--T:23-->
<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>


<!--T:24-->
<!--T:24-->
<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>


<!--T:25-->
<!--T:25-->
<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>


<!--T:26-->
<!--T:26-->
Line 132: Line 117:


<!--T:27-->
<!--T:27-->
<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:
</div>
<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 166: Line 149:


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


<!--T:30-->
namespace ExampleMods
namespace ExampleMods
{
{
Line 180: Line 160:
     {
     {


        <!--T:31-->
public override void Start(ICoreAPI api)
public override void Start(ICoreAPI api)
         {
         {
Line 187: Line 166:
         }
         }


    <!--T:32-->
}
}


    <!--T:33-->
public class TunnlerItem : Item
public class TunnlerItem : Item
     {
     {


        <!--T:34-->
public void DestroyBlocks(IWorldAccessor world, BlockPos min, BlockPos max, IPlayer player)
public void DestroyBlocks(IWorldAccessor world, BlockPos min, BlockPos max, IPlayer player)
         {
         {
Line 214: Line 190:
         }
         }


        <!--T:35-->
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 240: Line 215:
         }
         }


    <!--T:36-->
}
}
}
}


<!--T:37-->
</syntaxhighlight>
</syntaxhighlight>


<!--T:38-->
<!--T:38-->
<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">
== Тестирование == <!--T:39-->
== Testing ==
</div> <!--T:39-->


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


<!--T:41-->
<!--T:41-->
<youtube>2MRzYKguVFY</youtube>
<youtube>2MRzYKguVFY</youtube>


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


<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|Настройка среды разработки]], чтобы упаковать ваш мод для дальнейшего распространения.
</div> <!--T:43-->
<div lang="en" dir="ltr" class="mw-content-ltr">
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>.
</div> <!--T:44-->
= Скачать Мод =
<div lang="en" dir="ltr" class="mw-content-ltr">
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.
</div>
<div lang="en" dir="ltr" class="mw-content-ltr">
= Mod Download =
</div>


<!--T:45-->
<!--T:45-->
<div lang="en" dir="ltr" class="mw-content-ltr">
Варианты мода из этого руководства:  
Here is my version:
</div>
* 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]

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