Modding Discussion [Guide] Storm API Modding Guide

Discussion in 'Mods' started by kodfod, Mar 16, 2016.

  1. kodfod

    kodfod Void-Bound Voyager

    So been lurking around the forums and see a lack of guides on how to make mods for Storm API so I decided to contribute what I know. Please feel free to ask questions or give some feedback.

    Video:






    What you will need to have and know:
    1. Have Storm Installed
    2. Have Visual Studio
    3. Know how to install mods (will lightly touch on this)
    4. Know basic c# (if you don't you can still follow along)
    Getting started:

    Create a new Project, Go to C# Templates, and select Class Library" and name your project.

    [​IMG]

    Once there, go to the "Solution Explorer" and Right Click "References" and click "Add Reference".

    [​IMG]
    Click "Browse" tab on the left, and click "Browse" on the bottom right, then navigate to your Stardew Valley Installation. Once there select all of these:
    • Microsoft.Xna.Framework.dll
    • Newtonsoft.Json.dll
    • StormLoader.exe
    [​IMG]

    Click "Add" and then click "OK". Next step is optional... Rename your class. I will make my class name TutorialMod.cs for simplicity. Now lets get coding!

    We will need to start off at the top and add:
    Code:
    using Storm;
    using Storm.ExternalEvent;
    using Storm.StardewValley.Event;
    using Newtonsoft.Json;
    using Microsoft.Xna.Framework.Input;
    using System.IO;
    This gives us access to all the events and the attributes needed for the next step. Next, just above our class name, we need to add "[Mod]". Then we will implement the "DiskResource" interface.

    [​IMG]

    Now Lets get a Init method to make sure our mod is loaded. To do this we need to make use of another attribute: "[Subscribe]" above our method. We also need our method to take an event, we will use "InitializeEvent".

    [​IMG]

    In this Init method is where you should load any assets and configs you may need. We will be using a config so lets create that now.

    To create your config you will need to make another class, I will make a sub-class to make things easier.

    [​IMG]

    Now inside this config we will hold a few Variables. We are going to use 5 int's and 1 boolean. We will also declare getters and setters too.

    [​IMG]


    Now that we have the config class fleshed out, we need to write the data and retrieve it inside the Init method. So we need a variable to store the config location. we will call it "configLocation". We will also need a global variable for our config class.

    [​IMG]

    Next we need to check if the config file already exists. If it doesn't, we need to create it. We will first create a new instance of the config class and assign default values. After that, write the config file to the file system.

    [​IMG]


    Now if it already exists, we need to load the file. We will do it similar to the way we wrote it.

    [​IMG]

    And that's all we need to do inside the Init method. Now we can start using another event. For this mod we need the "KeyReleasedEvent". So lets make another method for that and give it the "Subscribe" attribute.

    [​IMG]

    In here, we need to see if the key released is the '+' symbol (numpad), if it is, we need to grab the player maxHealth and maxStamina and save it.

    [​IMG]

    Now we need to see if we are already at the max health and stamina allowed by the config, and if not we need to increase them by the increment amount.

    [​IMG]

    Next we should refill the hp and stamina, if the config says we should.

    [​IMG]

    You can also do the same for the minus key and take it away (shown in video). But we will skip that and move on to the next file we need. "manifest.json"

    The manifest is a very picky file. You need to make this file as instructed. Create a new file called... "manifest.json" open the file and use this:

    Code:
    {
      "author": "YOUR_NAME",
      "version": "1.0",
      "description": "YOUR_DESCRIPTION",
      "displayName": "YOUR_MOD_NAME",
      "assemblyFileName": "YOUR_DLL_NAME_AFTER_YOU_BUILD"
    }
    Make sure that "assemblyFileName" is the .dll file you build. and make sure when you create your new folder you make it the same as the "displayName". (?) *Need to verify this.

    After that you can load the storm loader and use the mod!

    Code:
    using Storm;
    using Storm.ExternalEvent;
    using Storm.StardewValley.Event;
    using System.IO;
    using System.Text;
    using Newtonsoft.Json;
    using Microsoft.Xna.Framework.Input;
    
    namespace TutorialMod
    {
      [Mod]
      public class TutorialMod : DiskResource
      {
      public Config config;
    
      [Subscribe]
      public void Init(InitializeEvent e)
      {
      string configLocation = ParentPathOnDisk + Path.PathSeparator + "TutorialMod" + Path.PathSeparator + "Config.json";
      try
      {
      if (!File.Exists(configLocation))
      {
      config = new Config();
      config.increment = 10;
      config.maxHealth = 500;
      config.minHealth = 280;
      config.maxStamina = 750;
      config.minStamina = 280;
      config.shouldRefill = true;
    
      File.WriteAllBytes(configLocation, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(config)));
      }
      else
      {
      config = JsonConvert.DeserializeObject<Config>(Encoding.UTF8.GetString(File.ReadAllBytes(configLocation)));
      }
    
      } catch (IOException error)
      {
      Logging.DebugLog.Invoke(error.Message);
      }
      }
    
      [Subscribe]
      public void KeyReleased(KeyPressedEvent e)
      {
      if (e.Key == Keys.Add)
      {
      int maxHealth = e.LocalPlayer.MaxHealth;
      int maxStamina = e.LocalPlayer.MaxStamina;
    
      if (maxHealth < config.maxHealth)
      {
      e.LocalPlayer.MaxHealth = maxHealth + config.increment;
      if (config.shouldRefill)
      {
      e.LocalPlayer.Health = e.LocalPlayer.MaxHealth;
      }
      }
      if (maxStamina < config.maxStamina)
      {
      e.LocalPlayer.MaxStamina = maxStamina + config.increment;
      if (config.shouldRefill)
      {
      e.LocalPlayer.Stamina = e.LocalPlayer.MaxStamina;
      }
      }
      }
      }
      }
    
      public class Config
      {
      public int increment { get; set; }
      public int maxHealth { get; set; }
      public int minHealth { get; set; }
      public int maxStamina { get; set; }
      public int minStamina { get; set; }
      public bool shouldRefill { get; set; }
      }
    }
     
      Last edited: Mar 17, 2016
      XaviiKinz, Ristray, KingJoey and 4 others like this.
    • Advize

      Advize Cosmic Narwhal

      I don't have prior experience with C#, but I am familiar with programming languages in the C-family so I was able to follow this tutorial without issue (in theory, anyways, I didn't actually make a mod utilizing the API yet).

      Even for someone like me who hasn't installed Storm yet, this tutorial effectively explains how to structure a mod and compile a .dll library in order for it to be loaded by the Storm API.

      Things I didn't like:
      • Much of the video is just extra fluff to showcase the use of some of the hooks provided by the API and give proof of concept, but I can understand why this was included.
      Things I liked:
      • The necessity of the manifest and accuracy of its contents were explained very well. This truly is critical info for someone looking to make a mod using the API.
      • While the external configuration file is not needed, explaining how to create one is very helpful to both developers and consumers in the modding community. (Although I personally feel more error-handling should be used when reading/writing to the hard drive).

      Overall I felt this was a good tutorial and a great addition to the modding community. Thank you for taking the time to make this.
       
        kodfod likes this.
      • kodfod

        kodfod Void-Bound Voyager

        I'm sorry if some things felt like "Fluff". I have a tendency to get carried away. :D

        With the external config, I was debating whether or not to include it, but after looking at all the mods that don't offer one (or added one later) I decided it would be a good idea just in-case. I'm happy you thought so too! And yes, error handling can be done a lot better. I will make an edit later to add what would be "Good Practice" for that.

        Thanks for the feedback!

        EDIT: Added "Text" guide to OP.
         
          Last edited: Mar 17, 2016
        • aRandomRaven

          aRandomRaven Void-Bound Voyager

          Still trying to understand what can be done and how, as I am not familiar with C#.

          Risking to sound extremely stupid asking this but... Is there a way to override any of the game's methods using the API by chance?

          Great guide btw, I'm sure it'll be very useful for future reference as I go learning.
           
            Last edited: Mar 17, 2016
            Kenma likes this.
          • kodfod

            kodfod Void-Bound Voyager

            With StormAPI you don't get access directly to Stardew Valley's methods, so you wont be able to override anything. BUT the events do allow you to manipulate what's being loaded, changed, etc... Is there anything you were trying to do specifically?
             
            • Hazerofdoom

              Hazerofdoom Scruffy Nerf-Herder

              Thanks for this - I've been wanting to dabble in making mods for Stardew using Storm.
              However, as someone that has little to no C# knowledge I didn't know where to begin.
              This has given me a good start and now it's time to throw myself into the fire, and attempt to make something way harder for what I should aim for as my first mod.
              Are you open to further questions to modding and support? If not I understand.

              As for more content videos for modding - i'd love you to explain how to manipulate the events firing in a way -
              Like your previous post says "manipulate what's being loaded and changed".
              I think you have a knack at making tutorials judging by this video, simple, clear and easy to understand.
              I'd love to see more videos from you - be it either C# in general, modding or anything related. :p


              It's going to be a fishing mod which incorporates specific talent bars.
              I had a simple idea of just having a mod which adds fish when you capture them.
              Basically - extra fish per rod pull. So instead of just 1 you would get 1-3.
              However as I got more into the idea and started jotting notes, I thought it would be a fun idea to make it more content heavy (ugh big mistake, setting myself up like this lol)

              The plan ends up being:
              3 Mini-Skill / Talent bars -
              • Treasure Chest Chance
              • Extra Fish Chance
              • Extra Chest Chance
              Treasure Chest Chance would have 10 "bars" and would automatically come with 5 points put into it.
              You can remove the points from this to put into other things (extra fish, multiple chests, and hopefully more to come) however you would be sacrificing the chest chance as a penalty (it goes down to -50% of vanilla's chance) and if you choose to put points into it up to 10 - it would go up to +50% of vanillas chance.

              Extra Fish would have also 10 bars -
              Zero points put in = 0% chance of getting a fish
              5 Points put in = 50% chance of getting +1 fish
              10 Points put in = 100% chance of +1, 50% chance at +2
              Of course these would increment so 3 points would be 30%, 7 points would be 70% at +1 and 20% at +2.

              Extra Chests would have 5 points, ranging from 5% to 25% extra chance.

              To get points there will be the default you start with - minimum of 5pts but they go up depending on your difficulty (this is where I've probably screwed myself the most) :
              - Super Easy (Less Bobbling up and down and bigger bar) = 5 pts to begin with
              - Easy (Bigger Bar) = 10 pts to begin with
              - Normal = 15 pts to begin with (vanilla fishing)

              This would allow people who like easier fishing (like me) to enjoy it, but also would be able to reward others for slowly notching their difficulty up (allowing them to slowly increment their skill upwards to normal fishing) and be rewarded for it by points which they can spend into customized bars to change their fishing.
              Plus I was thinking of having 1 point per 2 fishing levels, so 5 free extra points at fishing level 10.

              SO that's the majority of my idea and at the moment I'm staring at these events:
              PullFishFromWaterEvent
              DoneFishingEvent

              and thinking to myself "what have I got myself into" haha.


              Also, I love the image tutorial however as it stretches the page - could you put it into spoiler tags?
               
                Last edited: Mar 17, 2016
              • kodfod

                kodfod Void-Bound Voyager

                I"m glad you were able to watch/read and follow along! I'm glad to hear that someone with no/little c# could use this. And yes, I am always open for further questions.

                I can do another one for this, I will most likely post it as a text version first then a video. Is there anything specific you would like to see?

                Thanks! Yes, I can continue to make more tutorials for Stardew Valley, as for C# there are LOADS of tutorials and, to be frank, some would be 1000 times better than mine.

                I have edited the OP to put the text version into spoilers. I was thinking about that while scrolling down to read your message!

                Good luck making your mod, looks great, if you need help I can try to steer you into the right direction :D
                 
                • Hazerofdoom

                  Hazerofdoom Scruffy Nerf-Herder

                  There are a few differences from my Storm and yours - and I just want to ask if they're important? (One difference appears to be).
                  For reference I downloaded the pre-built Storm from here (the one uploaded at "3/17/2016 10:40:03 PM").
                  In my Stardew Valley folder, there aren't any Microsoft Xna DLL's to be found, at all.
                  I've installed the Xna framework so I have the DLL elsewhere but I'm wondering If I would need to move it into the Stardew Folder.

                  Edit: I just went to "C:\Windows\Microsoft.Net\assembly\GAC_32\" and got my DLL's from there. :p

                  Second difference is the fact that when I open my Storm, a console doesn't appear - just the game.
                  This may just be me derping but I was wondering if this is due to me using the pre-built instead of building it myself?

                  EDIT 2: I'm an idiot, IGNORE MEEEE.

                  Other than those differences:
                  I've gotten my mod to load, which is nice - and it's made the config without error.
                  There isn't much to it at the moment other than the config, but I can tell it worked without the console (cant see the logs since the console is not there for me)
                  because of the config files generation. "{"superEasyPts":5,"easyPts":10,"normalPts":15,"infinitePts":false}"

                  To be fair, I'm not sure where to start, I'm going to try and figure most out for myself through a lot of trial and error because I don't want to bother you too much.
                  However at the moment, I'm wondering how I'm going to pull specific information that were gained via events, for later use.
                  For example - when a fish 'bites' your hook - I'm assuming it determines in that event the fish that will be caught.
                  I would need to take this value from that event - and use it in the event when you pull in the fish so I could add on the extra fish if need be.
                  That's just the main example, and I know this is probably common stuff to be asking - so I won't mind if you tell me just to go watch C# tutorials, but I thought it'd ask anyway. xD

                  Glad that you put them into spoilers, the page stretch was real. xD
                  Thank you! I'm good at ideas, terrible at execution though.
                  I'm more of a web developer and designer so I've only really dabbled in PHP, Javascript and some libraries for them.
                  So this is kind of a whole new playing field for me. :p
                  Thanks for the offer as well, I do really appreciate it. I don't want to pester you too much though!
                   
                    Last edited: Mar 18, 2016
                    kodfod likes this.
                  • aRandomRaven

                    aRandomRaven Void-Bound Voyager

                    In fact I was trying something, like, how would I go about stopping the game from prompting me an error and rather allowing the to perform an action I'm not supposed to be performing, such as let's say... plant seeds in the wrong season or trying to place a piece of furniture outside?

                    I'm assuming I'd have to catch the right event and write a new method to perform the action rather than overriding anything then? And even then, assumingly I'd still have the error because the original code would still run?
                     
                    • ThatNorthernMonkey

                      ThatNorthernMonkey Aquatic Astronaut

                      aRandomRaven: Seeds being planted in all seasons: cantorsdust has released this exact mod, so you might want to look over his code and see how he did it :)

                      http://community.playstarbound.com/...nt-and-harvest-any-crop-in-any-season.108526/

                      Hazerofdoom: None of matts release builds include the debug console. This is by design, as the debug console is in theory for developers and debugging - not for end users who just want to play modded stardew valley. To get started with modding you really need to clone the source from github and build it in visual studio. I havent got around to recording that video yet unfortunately! Maybe kodfod could :)
                       
                        Hazerofdoom likes this.
                      • Hazerofdoom

                        Hazerofdoom Scruffy Nerf-Herder

                        Good to know! I've already cloned the source - just need to build it and replace I guess.
                        Thanks for that - error debugging without a console was driving me nuts.
                         
                          ThatNorthernMonkey likes this.
                        • kodfod

                          kodfod Void-Bound Voyager

                          I've never used any binary releases... so yeah that makes since. You could always open a cmd prompt and launch the game that way. And yeah, I could make a video on how to clone and build it. ;D
                           

                          Share This Page