Jump to content

Better modding guide/tutorial?


JamesB

Recommended Posts

I'm trying to learn the C# modding process for the game but I'm finding the guide on the wiki to be not very helpful.  I'm a developer myself (mostly Python), so I thought I'd be able to pick this up pretty quickly.  But it feels like the guide assumes a lot of prior knowledge.  Especially when it comes to setting up a Visual Studio project and getting started with the mod.  It starts off with walking through how to code for a trampoline, but it doesn't mention importing the libraries.  It only shows that at the end with the full code example but doesn't explain why you need it.  Plus, it doesn't really walk you through how to test out this code in game.  Any ways, it's not a very comprehensive guide and seems to require some advanced knowledge.

Granted, I've only done a handful of C based projects in the past, so I am missing some knowledge.  But I was hoping for more of a basic step-by-step guide for writing a C# mod.  So does anyone know if a more comprehensive guide exists?  I'm really interested in learning the modding system as there are things I'd like to try and add.  But this has been a bit of a wall for me.  Maybe I need to go and take a few C# courses first?

Link to comment
Share on other sites

So let's talk about the trampoline mod in particular.  At the bottom of that page, download the for VS v1.9 version of that.  Now you can drop that zip file directly into your mods folder  (C:\Users\<user>\AppData\Roaming\VintagestoryData\Mods ) and take it for a spin, but since the code isn't compiled (no .dll files), I like to unzip it first and drop THAT unzipped folder into the Mods folder instead.

Untitled1.jpg.7fdc97bf71569768bb717716c3ecdde4.jpg 

 

Fire up Vintage Story, check the Mod Manager to ensure that the Trampoline mod has loaded successfully.  Start a new Single Player game (creative world), grab a couple of Trampolines and try them out.

Since the folder is unzipped, it's easy to point your favorite editor at that folder (Visual Studio Code works great for this), and quickly make changes to code, assets, whatever, save them, and see what happens when you restart the game.  CTRL-F1 for a quick restart.  Sometimes I save and exit to retain the stuff that I've been mucking with in game.

Untitled2.jpg.91e5f84f29a64e94982e1301a49839a6.jpg

You can do almost anything imaginable with code, so I can't possibly dive too deeply into that.  But a common use for code is attaching it to assets, just like the trampoline does.  If you look at trampoline.json, there's a

class:"trampoline"

that links the TrampolineBlock class to the trampoline.json asset.  That link is finalized by registering the class (usually in the Start function)

api.RegisterBlockClass("trampoline", typeof(TrampolineBlock));

In the json file, not only can you specify a class, but you can also link an entityclass, and one or more behaviors if need be.  Those all need to be registered in your Start function, but slightly differently depending on what they are, i.e
 

api.RegisterBlockBehaviorClass("RightClickPickupSpawnWorm", typeof(RightClickPickupSpawnWorm));
api.RegisterBlockEntityClass("bedeadfall", typeof(BEDeadfall));
api.RegisterItemClass("itemcordage", typeof(ItemCordage));
api.RegisterEntity("entityearthworm", typeof(EntityEarthworm));

The wiki talks about the purposes of these different classes so I'm not going to go into that.

----------------------------------------------------

If we want to migrate this trampoline mod into Capsup's template (so we can do a deep dive into the code, use modern c#, debug, automatically create deliverables, and more)...

https://gitlab.com/vsmods-public/foundation/vsmodtemplate

1.  Setup Visual Studio as per Cap's instructions
2.  Start a new project using his template
3.  I like to use a location that's not nested so deep, so like C:\repos

Untitled3.jpg.af5e28ca37b3aff7ce7d0b5c2ee5a7e6.jpg

4. Go with the defaults after that.

5. Once the solution is loaded up, it might be easiest to close Visual Studio and use File Explorer to move the stuff in.  In this case it's really only the contents of the assets folder.  So move the trampoline folder from C:\Users\<user>\AppData\Roaming\VintagestoryData\Mods\Trampoline_vs1.9_v1.0.0\assets to C:\repos\Trampoline\Trampoline\assets

The folder structure inside of assets has lots of naming conventions.  See the wiki for that, or look at the the folder structure of the vanilla survival mod, or any other mod.

6.  Copy the trampoline.cs file from C:\Users\<user>\AppData\Roaming\VintagestoryData\Mods\Trampoline_vs1.9_v1.0.0\src to C:\repos\Trampoline\Trampoline\ModSystem

The structure of your c# files has no rules.  You can put all the code in one file (like the trampoline mod does), but I like to break it up into a bunch of files, and even nest some of those files into folders based on what the code is doing.

7.  Now delete the entire trampoline mod (Trampoline_vs1.9_v1.0.0) from your mod folder C:\Users\Administrator\AppData\Roaming\VintagestoryData\Mods

If you leave that in there, or ever have two copies of the same mod accessible to the game at once you're in for a world of hurt.

8.  Fire up Visual Studio again and open your trampoline project.  You might see two projects (Trampoline.sln and Trampoline1.sln).  Remove that Trampoline1.sln from your recent list.  I don't know what the hell that is.  My Visual Studio looks like this.  I've expanded a bunch of folders on the left so you can get a look at what's where.

Untitled4.thumb.jpg.0b0c3e33fab70cd4528fe96c52d1c417.jpg

9. The first thing I *like* to do is tidy up RedirectLogs.cs so it doesn't complain about anything.  Then I collapse the VSModLauncher folder structure and never look at it again.  All of the "issues" are highlighted.  Visual Studio can walk you through most of the changes (i.e. hover, click on "show potential fixes", go with the first option).  Here's the result after the cleanup.  No more green squiggles.  Save that.
 

namespace VSModLauncher
{
    using Vintagestory.API.Client;
    using Vintagestory.API.Common;
    using Vintagestory.API.Server;
    /// <summary>
    /// Redirects all log entries into the visual studio output window. Only for your convenience during development and testing.
    /// </summary>
    public class RedirectLogs : ModSystem
    {

        public override bool ShouldLoad(EnumAppSide side)
        {
            return true;
        }

        public override void StartServerSide(ICoreServerAPI api)
        {
            api.Server.Logger.EntryAdded += this.OnServerLogEntry;
        }

        private void OnServerLogEntry(EnumLogType logType, string message, params object[] args)
        {
            if (logType == EnumLogType.VerboseDebug)
            { return; }
            System.Diagnostics.Debug.WriteLine("[Server " + logType + "] " + message, args);
        }

        public override void StartClientSide(ICoreClientAPI api)
        {
            api.World.Logger.EntryAdded += this.OnClientLogEntry;
        }

        private void OnClientLogEntry(EnumLogType logType, string message, params object[] args)
        {
            if (logType == EnumLogType.VerboseDebug)
            { return; }
            System.Diagnostics.Debug.WriteLine("[Client " + logType + "] " + message, args);
        }
    }
}

 

10.  A bit of an aside. Before you click the "start-debug-in-game" button to test things out, make sure that VSModLauncher is selected (see picture below).  Never change that dropdown.  Also, when you are ready to create your deliverable to share with the world, change the Debug dropdown to ReleaseAndZip.  Then when you click the "start-debug...." button it will create your finished product (trampoline.zip) in the folder C:\repos\trampoline\trampoline\bin\ReleaseAndZip

  image.png.84ccf7f10f230941f318df2d37e47ec7.png

 

11. Alright!  The only thing left to do is to tidy up the c# code. I prefer to leverage Capsup's existing file for that, and always have more than one code file, so I'll rip the start function out of trampoline.cs and stick it into TrampolineSystem.cs,  Here's my finished TrampolineSystem.cs:
 

namespace Trampoline.ModSystem
{
    using Vintagestory.API.Common;

    public class TrampolineSystem : ModSystem
    {
        public override void Start(ICoreAPI api)
        {
            base.Start(api);
            api.RegisterBlockClass("trampoline", typeof(TrampolineBlock));
        }
    }
}

12. Now trampoline.cs is a bit of a hot mess, but it only represents one thing - the block class for the trampoline.  So I'm renaming it arbitrarily to blocktrampoline.cs, giving it the same namespace as the one autogenerated by Capsup's template, and tidying it up a bit.  Now it looks like this:
 

namespace Trampoline.ModSystem
{
    using Vintagestory.API.Common;
    using Vintagestory.API.Common.Entities;
    using Vintagestory.API.MathTools;

    public class TrampolineBlock : Block
    {
        public AssetLocation tickSound = new AssetLocation("game", "sounds/tick");

        public override void OnEntityCollide(IWorldAccessor world, Entity entity, BlockPos pos, BlockFacing facing, Vec3d collideSpeed, bool isImpact)
        {
            if (isImpact && facing.Axis == EnumAxis.Y)
            {
                world.PlaySoundAt(tickSound, entity.Pos.X, entity.Pos.Y, entity.Pos.Z);
                entity.Pos.Motion.Y *= -0.8;
            }
        }
    }
}


13.  Click "start-debug-in-game" and with any luck it will just work! In my case (because I'm running Vintage Story 1.15.3) I needed to make one more change (I mentioned it on Discord)
Right click on VSModLauncher - Properties - change the Target Framework to 4.6.1

 

Untitled6.thumb.jpg.5597570877bc73c23349c875c67027d3.jpg
 

Now the real power of Visual Studio comes from the Class View and Object Browser and the Output window, autocomplete, and more, but I'm probably not the best person to explain all the intricacies of Visual Studio.

Edited by Spear and Fang
  • Like 3
Link to comment
Share on other sites

Here's a clue:  The TrampolineBlock iinherits Block 
 

public class TrampolineBlock : Block

And then we are overriding OnEntityCollide...

public override void OnEntityCollide

So if you search for onentitycollide in the Class View, we can get the deets...

Untitled6.thumb.jpg.abf3f3a66dc1810548218dda610c8ed4.jpg

Edited by Spear and Fang
  • Like 2
Link to comment
Share on other sites

I'm back.  So then the question becomes - where do I go for the deets?  If the class view - object browser isn't up your alley, you could look here instead.
http://apidocs.vintagestory.at/api/index.html

A lot of my learning is by example, so I've looked at a lot of vanilla code, and often the survivalmod, so I search here https://github.com/anegostudios
and/or downloaded the code and search it offline. Other mods have helped tremendously, as well as searching the Discord.  Oh, and autocomplete.

In my mind, a guide for code mods can't exist because it's pretty limitless as to what you can do.

 

Edited by Spear and Fang
  • Like 2
Link to comment
Share on other sites

Let me talk briefly about debugging.  In the first example (where you put your mod directly in the mods folder), debugging is hard.  Either the game crashes and you get a pop-up explaining why, or the issues are logged into C:\Users\<user>\AppData\Roaming\VintagestoryData\Logs, or both.  I always start by looking at server-main.txt

In the second example, the VSModLauncher intercepts a lot of that stuff and pukes it out into the Output - Debug window, so you can see what's going on behind the scenes while the game is running.  That's really all that VSModLauncher is doing which is why you can promptly ignore it.  You can add logging to your own code as well, i.e.
 

System.Diagnostics.Debug.WriteLine("This variable:" + thisvariable);

 

Edited by Spear and Fang
  • Like 3
Link to comment
Share on other sites

OK I think you got me on the path I want to be on.  I have the game running and the trampoline block in game and it's working.  After going through this I feel my biggest issues are the Visual Studio dev environment.  I'm so used to banging away with compiled languages like Python that I get confused when having to consider all the things required for C programming in VS.  I'm sure I'm going to continue having issues with it, but for now I know how to get some code working in the game via VS.

Thanks a megaton for this too! 

  • Like 1
Link to comment
Share on other sites

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.