Why Is Overriding And Hiding Not Working For Mod?

Discuss modding questions and implementation details.
User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Why Is Overriding And Hiding Not Working For Mod?

Post by Magicono43 »

Alright, I just started working on my next mod that's going to change how skill "experience" is accumulated. But, I am not profoundly confused after trying out some basic things. I made my initial mod script that "initializes" the mod, but when I made another script that is going to be derived from "PlayerEntity.cs" is where things started to go down hill.

Here is the Github Repo so far: https://github.com/magicono43/DFU-Mod_S ... g-Improved

Here is the simple mod initialization script:

Code: Select all

// Project:         SkillLevelingImproved mod for Daggerfall Unity (http://www.dfworkshop.net)
// Copyright:       Copyright (C) 2019 JayH
// License:         MIT License (http://www.opensource.org/licenses/mit-license.php)
// Author:          Kirk.O
// Last Edited: 	6/3/2020, 9:30 AM
// Modifier:		

using DaggerfallWorkshop.Game;
using DaggerfallWorkshop.Game.Utility.ModSupport;
using UnityEngine;

namespace SkillLevelingImproved
{
    public class SkillLevelingImproved : MonoBehaviour
    {
        static Mod mod;

        [Invoke(StateManager.StateTypes.Start, 0)]
        public static void Init(InitParams initParams)
        {
            mod = initParams.Mod;
            var go = new GameObject("SkillLevelingImproved");
            go.AddComponent<SkillLevelingImproved>();
        }

        void Awake()
        {
            InitMod();

            mod.IsReady = true;
        }

        private static void InitMod()
        {
            Debug.Log("Begin mod init: SkillLevelingImproved");

            Debug.Log("Finished mod init: SkillLevelingImproved");
        }

        #region Stuff Here



        #endregion
    }
}
Nothing special here, but it appears to work as it shows up in the mod list and it says it launches fine in start-up.

Here is the code i'm trying to "override" a single method in the parent class "PlayerEntity.cs":

Code: Select all

using DaggerfallConnect;
using UnityEngine;
using System;
using DaggerfallWorkshop.Game.Entity;

namespace SkillLevelingImproved
//namespace DaggerfallWorkshop.Game.Entity
{
    public class SkillTallyOverride : PlayerEntity
    {
        #region Constructors

        public SkillTallyOverride(DaggerfallEntityBehaviour entityBehaviour)
            : base(entityBehaviour)
        {

        }

        #endregion

        #region Public Methods

        public override void TallySkill(DFCareer.Skills skill, short amount)
        {
            int skillId = (int)skill;

            try
            {
				Debug.Log("AHHHHHHHHHHHHHHHH!!!!!!!!!!");
				
                if(skillId == 3)
                {
                    Debug.Log("You just jumped! You idiot!");
                }

                if (skillId == 0)
                {
                    Debug.Log("You just slept for an hour! You coward!");
                }

                if (skillId == 18)
                {
                    Debug.Log("You just climbed! You monkey!");
                }

                if (skillId != 27)
                {
                    Debug.Log("You just did something other than Mysticism! You donkey!");
                }

                skillUses[skillId] += amount;
                if (skillUses[skillId] > 20000)
                    skillUses[skillId] = 20000;
                else if (skillUses[skillId] < 0)
                {
                    skillUses[skillId] = 0;
                }
            }
            catch (Exception ex)
            {
                string error = string.Format("Caught exception {0} with skillId {1}.", ex.Message, skillId);

                if (skillUses == null || skillUses.Length == 0)
                    error += " skillUses is null or empty.";

                Debug.Log(error);
            }
        }

        #endregion
    }
}
Here is a snippet from the parent class showing the method i'm trying to override in question:

Code: Select all

/// <summary>
        /// Tally skill usage.
        /// </summary>
        public override void TallySkill(DFCareer.Skills skill, short amount)
        {
            int skillId = (int)skill;

            try
            {
                skillUses[skillId] += amount;
                if (skillUses[skillId] > 20000)
                    skillUses[skillId] = 20000;
                else if (skillUses[skillId] < 0)
                {
                    skillUses[skillId] = 0;
                }
            }
            catch (Exception ex)
            {
                string error = string.Format("Caught exception {0} with skillId {1}.", ex.Message, skillId);

                if (skillUses == null || skillUses.Length == 0)
                    error += " skillUses is null or empty.";

                Debug.Log(error);
            }
        }
Sorry for the small code wall, but hopefully that makes it easier to understand what my issue is.

So when I have the mod loaded, I should see debug log text going by whenever an skill tally event happens, but i'm not getting anything, which is completely spinning my head as to why from what I have read that overriding virtual methods should do, or using "new" to hide them, neither has worked. If you look in visual studio, the "override" part of my script points to the parent class of PlayerEntity.cs, but even though my script is technically the most derived overriding child for this method, it's not getting any of the calls redirected to it, it's all still just being brought to the PlayerEntity.cs version.

What am I missing here? Maybe i'm oversimplifying how an override of something should work in terms of a mod in this code-base? Really the only overrides that have worked so far have been the ones that have been registered beforehand with some of the modding support that have been made, such as UIFactory and the overrides for FormulaHelper.

But yeah, can anyone see what i'm missing here? Because I have no clue at all and would love to understand how to do something seemingly so simple properly for once.

Edit 1: After reading this fairly well written article: https://www.c-sharpcorner.com/article/u ... n-c-sharp/

I'm thinking that I need to make a new instance of PlayerEntity or something, but in the context that i'm trying to just override a single method, how would I even do that and where would I put the code for the new instance?

Code: Select all

PlayerEntity player = GameManager.Instance.PlayerEntity;
This is how it's used in scripts like FormulaHelper, but i'm not sure how I would use that in this context, or if it's even necessary.

User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Re: Why Is Overriding And Hiding Not Working For Mod?

Post by Magicono43 »

Alright, after looking at a bunch of examples and doing some reading, it's clear i'm oversimplifying how I think this is supposed to work. Every other mod that does some sort of Override of something within the code base has some sort of "register" or "initialization" of some sort in the main-mod file. This makes enough sense in WHAT i'm missing here, but I don't know HOW to fix the problem.

Like in UIWindowFactory, FormulaHelper, and PlayerActivate with the custom activations. These are built in and allow many things to be overridden because of how they are integrated. But, in this case, is there any way to do this for a single method of a single script like i'm trying to do?

User avatar
BadLuckBurt
Posts: 948
Joined: Sun Nov 05, 2017 8:30 pm

Re: Why Is Overriding And Hiding Not Working For Mod?

Post by BadLuckBurt »

Magicono43 wrote: Thu Jun 04, 2020 1:28 pm Alright, after looking at a bunch of examples and doing some reading, it's clear i'm oversimplifying how I think this is supposed to work. Every other mod that does some sort of Override of something within the code base has some sort of "register" or "initialization" of some sort in the main-mod file. This makes enough sense in WHAT i'm missing here, but I don't know HOW to fix the problem.

Like in UIWindowFactory, FormulaHelper, and PlayerActivate with the custom activations. These are built in and allow many things to be overridden because of how they are integrated. But, in this case, is there any way to do this for a single method of a single script like i'm trying to do?

Code: Select all

        public PlayerEntity PlayerEntity
        {
            get { return (playerEntity != null) ? playerEntity : playerEntity = PlayerEntityBehaviour.Entity as PlayerEntity; }
            set { playerEntity = value; }
        }
So in your mod's init method:

Code: Select all

        GameManager.Instance.PlayerEntity = new MyPlayerEntityClass();
DFU on UESP: https://en.uesp.net/w/index.php?title=T ... fall_Unity
DFU Nexus Mods: https://www.nexusmods.com/daggerfallunity
My github repositories with mostly DFU related stuff: https://github.com/BadLuckBurt

.

User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Re: Why Is Overriding And Hiding Not Working For Mod?

Post by Magicono43 »

I'll post the Github repo for this so far: https://github.com/magicono43/DFU-Mod_S ... g-Improved


I tried to put the code you mentioned where I "think" you meant it to be, in this case the main script "SkillLevelingImproved.cs". I mostly understand what is trying to be done in this case, that being creating another instance of "PlayerEntity" and basically redirecting any references/calls to that class to go to the mod class instead that is intending to override it.

Problem is i'm not sure if I put the get set property in the correct class, or if it's supposed to go somewhere else, as well as what to fill in for "PlayerEntityBehaviour", as it currently does not exist in that context I have it in. Thanks.

User avatar
BadLuckBurt
Posts: 948
Joined: Sun Nov 05, 2017 8:30 pm

Re: Why Is Overriding And Hiding Not Working For Mod?

Post by BadLuckBurt »

Magicono43 wrote: Sat Jun 06, 2020 3:07 am I'll post the Github repo for this so far: https://github.com/magicono43/DFU-Mod_S ... g-Improved


I tried to put the code you mentioned where I "think" you meant it to be, in this case the main script "SkillLevelingImproved.cs". I mostly understand what is trying to be done in this case, that being creating another instance of "PlayerEntity" and basically redirecting any references/calls to that class to go to the mod class instead that is intending to override it.

Problem is i'm not sure if I put the get set property in the correct class, or if it's supposed to go somewhere else, as well as what to fill in for "PlayerEntityBehaviour", as it currently does not exist in that context I have it in. Thanks.
I'll fork it on Github later today and show you what I meant. Writing that quick example with a fried brain last night didn't make it as clear as it should've been :)
DFU on UESP: https://en.uesp.net/w/index.php?title=T ... fall_Unity
DFU Nexus Mods: https://www.nexusmods.com/daggerfallunity
My github repositories with mostly DFU related stuff: https://github.com/BadLuckBurt

.

User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Re: Why Is Overriding And Hiding Not Working For Mod?

Post by Magicono43 »

After trying the solution that Burt proposed, I thought it was going to work, but when I tried to have my overriding mod class (can be found at the same Github repo, https://github.com/magicono43/DFU-Mod_S ... g-Improved) write a debug string whenever a skill was tallied, but the override did not seem to go through and it just used the default "PlayerEntity.cs".

So then I tried copy pasting the entire "PlayerEntity.cs" code into my overriding script and changed the class name and constructor name, doing this lead to a few errors throughout though, all of them being related to casting type issues, where "PlayerEntity" was expected, not my new modded in version of that, here is what a few of those looked like.
Untitled.png
Untitled.png (15.77 KiB) Viewed 1225 times
Untitled1.png
Untitled1.png (14.62 KiB) Viewed 1225 times
So even though this seemed promising, unless I am clearly doing something wrong with my code, I still don't know how I can override a class such as "PlayerEntity" and put in my own modded version. Anyone know what is missing here? Thanks.

Here is the main mod file where we tried to create another instance of PlayerEntity and expecting that to work as an override essentially, "InitMod" being the primary section of interest.

Code: Select all

// Project:         SkillLevelingImproved mod for Daggerfall Unity (http://www.dfworkshop.net)
// Copyright:       Copyright (C) 2019 JayH
// License:         MIT License (http://www.opensource.org/licenses/mit-license.php)
// Author:          Kirk.O
// Last Edited: 	6/3/2020, 9:30 AM
// Modifier:		

using DaggerfallWorkshop.Game;
using DaggerfallWorkshop.Game.Entity;
using DaggerfallWorkshop.Game.Utility.ModSupport;
using UnityEngine;

namespace SkillLevelingImproved
{
    public class SkillLevelingImproved : MonoBehaviour
    {
        static Mod mod;

        [Invoke(StateManager.StateTypes.Start, 0)]
        public static void Init(InitParams initParams)
        {
            mod = initParams.Mod;
            var go = new GameObject("SkillLevelingImproved");
            go.AddComponent<SkillLevelingImproved>();
        }

        void Awake()
        {
            InitMod();

            mod.IsReady = true;
        }

        private static void InitMod()
        {
            Debug.Log("Begin mod init: SkillLevelingImproved");

            GameManager.Instance.PlayerEntity = new SkillTallyOverride(GameManager.GetComponentFromObject<DaggerfallEntityBehaviour>(GameManager.Instance.PlayerObject));

            Debug.Log("Finished mod init: SkillLevelingImproved");
        }

        #region Stuff Here



        #endregion
    }
}

User avatar
numidium3rd
Posts: 187
Joined: Sun Mar 25, 2018 12:34 am
Location: United States

Re: Why Is Overriding And Hiding Not Working For Mod?

Post by numidium3rd »

I'm guessing since you copied the entire original class, it's hiding the original RegionDataRecord[] PlayerEntity.regionData member. If that has a protection level above private then you should be able to use it without declaring it in your derived class and it should "just work" with the FormulaHelper methods.

Also, in the case of RollMaxHealth I think you should be able to use a cast like this: (PlayerEntity)this

User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Re: Why Is Overriding And Hiding Not Working For Mod?

Post by Magicono43 »

Also of note, when I copy the entire PlayerEntity class over and just change the class name to the modded class' name, like this:
Untitled5.png
Untitled5.png (49.83 KiB) Viewed 1210 times
I start getting compile errors for the new instance line in the main mod script, which also appear to be something being a type problem:
Untitled3.png
Untitled3.png (21.76 KiB) Viewed 1210 times
Untitled4.png
Untitled4.png (20.9 KiB) Viewed 1210 times
I would try as you said Numidium, but I have a feeling this problem could be even more of a problem, it only does this when I copy over the entire PlayerEntity class and change the class name to my modded version.

User avatar
Magicono43
Posts: 1141
Joined: Tue Nov 06, 2018 7:06 am

Re: Why Is Overriding And Hiding Not Working For Mod?

Post by Magicono43 »

numidium3rd wrote: Sun Jun 07, 2020 12:29 am I'm guessing since you copied the entire original class, it's hiding the original RegionDataRecord[] PlayerEntity.regionData member. If that has a protection level above private then you should be able to use it without declaring it in your derived class and it should "just work" with the FormulaHelper methods.

Also, in the case of RollMaxHealth I think you should be able to use a cast like this: (PlayerEntity)this
The original PlayerEntity class had RegionDataRecord[] as protected, after turning it to private it did not seem to fix that specific type errors. Also, unfortunately using the (PlayerEntity)this did not seem to work either, strangely enough. This stuff is certainly making a novice like me scratch my head, lol.

User avatar
numidium3rd
Posts: 187
Joined: Sun Mar 25, 2018 12:34 am
Location: United States

Re: Why Is Overriding And Hiding Not Working For Mod?

Post by numidium3rd »

Magicono43 wrote: Sun Jun 07, 2020 1:10 am
numidium3rd wrote: Sun Jun 07, 2020 12:29 am I'm guessing since you copied the entire original class, it's hiding the original RegionDataRecord[] PlayerEntity.regionData member. If that has a protection level above private then you should be able to use it without declaring it in your derived class and it should "just work" with the FormulaHelper methods.

Also, in the case of RollMaxHealth I think you should be able to use a cast like this: (PlayerEntity)this
The original PlayerEntity class had RegionDataRecord[] as protected, after turning it to private it did not seem to fix that specific type errors. Also, unfortunately using the (PlayerEntity)this did not seem to work either, strangely enough. This stuff is certainly making a novice like me scratch my head, lol.
Sorry, I meant that if regionData is less restricted than private (i.e. protected or public) then it will be accessible by your derived class. I don't recommend copying over the whole class as that will cause more problems such as members being hidden when you don't need them to be and keeping an obsolete version of the class if/when it gets updated later.

Also, on second thought, (PlayerEntity)this shouldn't be necessary if SkillTallyOverride inherits from PlayerEntity (like this: public class SkillTallyOverride : PlayerEntity).

Inheritance can be tricky for newcomers. You might want to give this a read: https://docs.microsoft.com/en-us/dotnet ... nheritance

Post Reply