Modding:Расширяемость модов

From Vintage Story Wiki
Revision as of 10:41, 16 June 2022 by Mirotworez (talk | contribs) (Created page with "Два мода, которые мы будем создавать, называются «TipMod» и «SpawnMod». * «TipMod» будет хранить полезные п...")
Other languages:

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


Для этой статьи требуется установка среды разработки. Если у вас его нет, прочитайте учебник на настройка вашей среды разработки. Для краткости эта статья предполагает некоторое знакомство с моддингом кода VintageStory, в первую очередь как упакованы моды и Setting_up_your_Development_Environment#Project_Setup_.28Compiled_Zip.29 как настроить скомпилированный проект мода. Если вы хотите создать свой первый мод кода, мы рекомендуем вместо этого начать здесь.

Введение

VintageStory делает все загруженные моды доступными через обширный API, который вы можете изучить в документации по API. Это позволяет модам кода взаимодействовать друг с другом и получать доступ к общедоступным свойствам друг друга. Однако это делает любой мод, включающий другой мод, зависимым от этого мода. Если включаемый мод отсутствует или отключен, включаемый мод не будет работать.

Загрузка и извлечение модов осуществляется через IModLoader, который мы получаем из [http:/ /apidocs.vintagestory.at/api/Vintagestory.API.Common.ICoreAPI.html ICoreAPI]. Мы можем получить как полный Mod, со всеми его полезными данными, так и содержащийся [ http://apidocs.vintagestory.at/api/Vintagestory.API.Common.ModSystem.html ModSystems].

Это очень полезно в нескольких сценариях, например:

  • Разделение большого мода на более мелкие логические части, которые сообщаются друг с другом - модпак.
  • Например, расширяемые моды — творческий инструмент с графическим интерфейсом для выращивания деревьев, который позволяет регистрировать новые типы деревьев и легко их тестировать.

В этой статье мы будем создавать два мода. Наш первый мод предоставит метод для взаимодействия с нашим вторым модом. Мы продемонстрируем использование ModLoader, а также объясним, как ссылаться на внешний мод и получить эту ссылку. решить во время игры.

Обратите внимание, что, за исключением использования отражения или использования промежуточной библиотеки, что выходит за рамки этой статьи, только скомпилированные моды могут взаимодействовать друг с другом.

TipMod & SpawnMod

Два мода, которые мы будем создавать, называются «TipMod» и «SpawnMod».

  • «TipMod» будет хранить полезные подсказки по геймплею и периодически выводить их в чат. Он также предоставит метод, который другие моды могут использовать для добавления своих собственных советов.
  • "SpawnMod" зарегистрирует команду, которая телепортирует игрока в заданную или заданную по умолчанию точку возрождения. Он также получит доступ к «TipMod» и добавит свои собственные советы по команде.

Preparation

We start by setting up two empty mods, "TipMod" and "SpawnMod". In each mod, we add a new *.cs source file - we will be naming these files TipMod.cs and SpawnMod.cs respectively. In our .cs files, we do the following:

  • Add the necessary using directives.
  • Create a class named after the mod it's contained in - TipMod and SpawnMod.
  • Have our classes inherit ModSystem - the base for any VintageStory code mod.
  • Override the StartServerSide method to access ICoreServerAPI.
  • Make the TipMod class public so that it's accessible by other mods.
// In TipMod.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Vintagestory.API.Common;
using Vintagestory.API.Server;

namespace tipmod.src
{
    public class TipMod : ModSystem
    {
        public override void StartServerSide(ICoreServerAPI api)
        {
            base.StartServerSide(api);
        }
    }
}
// In SpawnMod.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Vintagestory.API.Common;
using Vintagestory.API.Server;

namespace spawnmod.src
{
    class SpawnMod : ModSystem
    {
        public override void StartServerSide(ICoreServerAPI api)
        {
            base.StartServerSide(api);
        }
    }
}

This concludes setting up the basis of our mods. Lastly, in "TipMod", we create an additional file called Tip.cs, where we will define the data structure for tips, called Tip.

// In Tip.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace tipmod.src
{
    public class Tip
    {
        string author;
        string tip;

        public Tip(string author, string tip)
        {
            this.author = author;
            this.tip = tip;
        }

        public override string ToString() {
            return "Tip by \"" + author + "\": " + tip; 
        }
    }
}

Our resulting folder structure looks like this.

ModdableModFolderStructure.png

We are now ready to extend our mods, starting with "TipMod" - our moddable mod.

Setting up TipMod

For "TipMod", we do the following:

  • Store the ICoreServerAPI object as a field so that we can access it throughout our class.
  • Define a List that stores Tip objects.
  • Define a method that selects a random Tip from the List and prints it in chat for all players, printing a default message if the List is empty.
  • Register that method to be called at set intervals by the Timer, which is available in the IServerEventAPI.
  • Define a public method for adding new Tip objects.
    // In TipMod.cs
    public class TipMod : ModSystem
    {
        ICoreServerAPI api;

        List<Tip> tips = new List<Tip>();
        double tipInterval = 10;

        public override void StartServerSide(ICoreServerAPI api)
        {
            base.StartServerSide(api);
            this.api = api;

            api.Event.Timer(OnInterval, tipInterval);
        }

        private void OnInterval()
        {
            int tipCount = tips.Count();
            string message = "There aren't any listed tips";

            if (tipCount > 0)
            {
                // Select a random number in the range of [0-1]
                double random = api.World.Rand.NextDouble();
                // Make the number relative to the size of our tips list
                int randomTip = (int)Math.Floor(random * tipCount);

                Tip tip = tips[randomTip];

                message = tip.ToString();
            } 


            api.SendMessageToGroup(GlobalConstants.GeneralChatGroup, message, EnumChatType.AllGroups);
        }

        public void AddTip(Tip tip)
        {
            tips.Add(tip);
        }
    }

For testing purposes, we set the interval to be very short (10 seconds). Feel free to change this accordingly.

Remember, both classes and methods which other mods will interact with have to be declared public. In C#, classes and methods are not public by default. You can read more about this here.

We can now compile our mod, add it to our VintageStory mod folder and test it ingame. If the there are occasional chat messages saying "There aren't any listed tips", our mod is working. We are ready to move on to the next step - setting up "SpawnMod" and then having it interact with "TipMod".

Setting up SpawnMod

Let's first setup our mods functionality. We register a command which teleports the player to spawn. Conveniently, the IServerPlayer object stores it's spawn position, as well as the IPlayerEntity, which defines a method for teleporting itself to a location.

    // In SpawnMod.cs
    class SpawnMod : ModSystem
    {
        public override void StartServerSide(ICoreServerAPI api)
        {
            base.StartServerSide(api);

            api.RegisterCommand("spawn", "Teleport to spawn", "", OnCmdSpawn);
        }

        private void OnCmdSpawn(IServerPlayer player, int groupId, CmdArgs args)
        {
            player.Entity.TeleportTo(player.SpawnPosition);
        }
    }

"SpawnMod" is ready. Let's test it. The command /spawn should now teleport us to spawn. If our mods are working, we're ready to make "SpawnMod" interact with "TipMod".

Mods interacting

Before we get started, we have to add a reference in "SpawnMod" to "TipMod".

Adding a reference to an external mod

If you are using Visual Studio, in your Solution Explorer, directly under your project, right-click "References" and select "Add Reference".

ADDINGAREFERENCERIGHTCLICK.png

Here we locate either the "TipMod" project or the compiled .dll file, and add it.

FindingReference.png

After adding the reference, make sure it is not copying the file to the output folder when compiling - having multiple .dll files with ModSystems in them will break your mod.

SettingCopyLocalToFalse.png

Accessing the ModLoader

Now we're ready to have "SpawnMod" add tips. Let's go ahead and do the following.

  • Add a using directive for the namespace tipmod.src.
  • Retrieve TipMod through the ModLoader by passing it's type.
  • Call the AddTip method provided by TipMod and add a variety of tips.
        public override void StartServerSide(ICoreServerAPI api)
        {
            base.StartServerSide(api);

            api.RegisterCommand("spawn", "Teleport to spawn", "", OnCmdSpawn);

            using tipmod.src;
            TipMod tipMod = api.ModLoader.GetModSystem<TipMod>();
            tipMod.AddTip(new Tip("codemeister32", "To quickly return to spawn, type /spawn"));
            tipMod.AddTip(new Tip("codemeister32", "Can't find your way home? Type /spawn"));
            tipMod.AddTip(new Tip("codemeister32", "Being chased by wolves? Quick, type /spawn"));
        }

Conclusion

Following the steps in this article, this is what our resulting code looks like, spread across two mods.

// In TipMod.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Vintagestory.API.Common;
using Vintagestory.API.Config;
using Vintagestory.API.Server;

namespace tipmod.src
{
    public class TipMod : ModSystem
    {
        ICoreServerAPI api;

        List<Tip> tips = new List<Tip>();
        double tipInterval = 10;

        public override void StartServerSide(ICoreServerAPI api)
        {
            base.StartServerSide(api);
            this.api = api;

            api.Event.Timer(OnInterval, tipInterval);
        }

        private void OnInterval()
        {
            int tipCount = tips.Count();
            string message = "There aren't any listed tips";

            if (tipCount > 0)
            {
                // Select a random number in the range of [0-1]
                double random = api.World.Rand.NextDouble();
                // Make the number relative to the size of our tips list
                int randomTip = (int)Math.Floor(random * tipCount);

                Tip tip = tips[randomTip];

                message = tip.ToString();
            } 


            api.SendMessageToGroup(GlobalConstants.GeneralChatGroup, message, EnumChatType.AllGroups);
        }

        public void AddTip(Tip tip)
        {
            tips.Add(tip);
        }
    }
}
// In Tip.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace tipmod.src
{
    public class Tip
    {
        string author;
        string tip;

        public Tip(string author, string tip)
        {
            this.author = author;
            this.tip = tip;
        }

        public override string ToString() {
            return "Tip by \"" + author + "\": " + tip; 
        }
    }
}
// In SpawnMod.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Vintagestory.API.Common;
using Vintagestory.API.Server;
using tipmod.src;

namespace spawnmod.src
{
    class SpawnMod : ModSystem
    {
        public override void StartServerSide(ICoreServerAPI api)
        {
            base.StartServerSide(api);

            api.RegisterCommand("spawn", "Teleport to spawn", "", OnCmdSpawn);

            TipMod tipMod = api.ModLoader.GetModSystem<TipMod>();

            tipMod.AddTip(new Tip("codemeister32", "To quickly return to spawn, type /spawn"));
            tipMod.AddTip(new Tip("codemeister32", "Can't find your way home? Type /spawn"));
            tipMod.AddTip(new Tip("codemeister32", "Being chased by wolves? Quick, type /spawn"));
        }

        private void OnCmdSpawn(IServerPlayer player, int groupId, CmdArgs args)
        {
            player.Entity.TeleportTo(player.SpawnPosition);
        }
    }
}

We're now ready to test our mods to see if they're interacting successfully. After placing both our compiled mods in the mods folder and booting into a world, we should see a random tip pop up in the chat every 10 seconds.

ModdableModSuccess.png

If so, well done! You've successfully followed the article and have created a moddable mod.

Troubleshooting

If you've ran into problems setting up either mod, check the error logs located at VintagestoryData/Logs in server-main.txt. Possible causes for either mod not working:

  • It's a .cs (source) mod and not a .dll (compiled) mod. Refer here for how to set a compiled mod.
  • It's missing modinfo.json.
  • Your version of VintageStory is outdated.
  • You have multiple .dll files containing ModSystems in your mod folder.
  • The referenced mod, "TipMod", is not present in the mod folder.

Distribution

To distribute this mod, run the following command in the vsmodtools cli pack <your mod id>, then copy the .zip file into your VintageStory mods folder.

Here are the official versions:

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