RIGHT BEFORE Gathering the Resources

[JUST SKIP TILL THE END PLEASE… THE VERY LAST EDIT HAS A PROBLEM I’M STILL TRYING TO SOLVE!]

[TLDR: I seek a solution to push out notifications to the player RIGHT BEFORE gathering Resources, rather than whenever he enters a trigger zone of a tree or something, because… well… in a forest, that’s not only a serious performance issue waiting to happen, but also a serious annoyance to the players]

OK so as I continue on my quest of implementing Notification Systems in my game, Resource Gathering is no slouch in this area either.

I did some research (and Debugging) through my code, trying to seek exactly where in the world do I place my code to trigger the action that calls the Resource Gathering behaviour, and I found it in ‘InputReader.cs’, as shown below (you may think that it doesn’t do the job for repeated animations with the new third-person architecture, but I assure you for my use cases it’ll work perfectly fine… Until I decide an object is no longer stackable):

public void OnInteractWithResource(InputAction.CallbackContext context) 
    {
        if (context.performed) {
            InteractWithResourceEvent?.Invoke();
            IsResourceGathering = true;
        }

        else if (context.canceled) IsResourceGathering = false;

    }

and this is the caller for the event trigger, in ‘PlayerFreeLookState.cs’:

        private void InputReader_HandleResourceGatheringEvent()
        {
            if (stateMachine.ResourceFinder.FindNearestTarget())
            {

// I know the code I want to implement goes in here, I just don't know how to get the resource to implement what I want here...

                PlayerGatheringState nextState = new PlayerGatheringState(stateMachine, stateMachine.ResourceFinder.CurrentTarget, stateMachine.GetComponent<ResourceGatherer>());
                stateMachine.SwitchState(new PlayerFacingState(stateMachine, stateMachine.ResourceFinder.CurrentTarget.transform.position, nextState));
            }
        }

But now I have a problem… To properly implement a notification RIGHT BEFORE gathering, I have to find a way to refer to the resource that he is about to interact with (and with many resources in the scene, a function like ‘FindObjectsOfType<…>()’ just won’t cut it!)… How do I do that?

(And yes, I tried implementing the notification system in ‘IsValid()’ (for our third person), but this one turned into pure catastrophe, because if the player goes into a forest of trees, a minefield, or maybe a popular fishing spot for this case, with resources surrounding them literally everywhere, you can imagine how crazy the Notification system will get).

1 Like

my current attempt was trying to tune the ‘InputReader_HandleResourceGatheringEvent()’ function, but that did not work…:

        private void InputReader_HandleResourceGatheringEvent()
        {
            if (stateMachine.ResourceFinder.FindNearestTarget())
            {
                var nearestTarget = stateMachine.ResourceFinder.GetNearestSource();
                var nearestTargetResource = nearestTarget.GetResourceToAccumulate();

                if (!Inventory.GetPlayerInventory().HasSpaceFor(nearestTargetResource)) {
                    MalbersAnimations.InventorySystem.NotificationManager.Instance.OpenNotification("Operation Invalid: \n", "Not enough Inventory Space"); // I got a bit lazy to make my own, so I outsourced it...
                    return;
                }

                PlayerGatheringState nextState = new PlayerGatheringState(stateMachine, stateMachine.ResourceFinder.CurrentTarget, stateMachine.GetComponent<ResourceGatherer>());
                stateMachine.SwitchState(new PlayerFacingState(stateMachine, stateMachine.ResourceFinder.CurrentTarget.transform.position, nextState));
            }
        }

This is one way to get the nearest resource, but… I still have to get out of the targeting range and then return… I don’t want my notification system to deal with that, just notify the player right before he starts trying to collect the resources, that’s all


Edit 1: I have to admit, this was the right place, but… it’s not responding to my commands of checking the players’ Inventory, SkillStore or what not. Right now I’m sure it’s just the wrong command call (but still, that’s one step ahead!). Testing this line works:

MalbersAnimations.InventorySystem.NotificationManager.Instance.OpenNotification("Test: \n", "Checking the Notification bar here...");

making the test function look like this:

        private void InputReader_HandleResourceGatheringEvent()
        {
            if (stateMachine.ResourceFinder.FindNearestTarget())
            {
                var nearestTarget = stateMachine.ResourceFinder.GetNearestSource();
                var nearestTargetResource = nearestTarget.GetResourceToAccumulate();

                MalbersAnimations.InventorySystem.NotificationManager.Instance.OpenNotification("Test: \n", "Checking the Notification bar here...");

                PlayerGatheringState nextState = new PlayerGatheringState(stateMachine, stateMachine.ResourceFinder.CurrentTarget, stateMachine.GetComponent<ResourceGatherer>());
                stateMachine.SwitchState(new PlayerFacingState(stateMachine, stateMachine.ResourceFinder.CurrentTarget.transform.position, nextState));
            }
        }

Edit 2: I just noticed that Resources won’t even get added to the targeter UNLESS we have Inventory Space apparently… they’ll get removed, but not added, unless we have inventory space (and I have NO IDEA where this is coming from…!)

EUREKA, I solved it!

Apparently here’s where I also went terribly wrong:

In ‘ResourceGathering.cs’, I have a function known as ‘IsValid()’ which does all the checking, and it looked like this:

bool ITarget.IsValid()
        {
            if (!Inventory.GetPlayerInventory().HasSpaceFor(resourceToAccumulate)) return false;
            if (skillStore.GetSkillLevel(associatedSkill) < LevelToUnlock()) return false; // place an 'or' ("||")statement later to count for holding a weapon associated to the skill (hatchet for trees, pickaxe for mining, etc), by checking the 'equipLocation.Weapon'
            // inject code here that checks if EquipLocation.Weapon has the required axe (level-based check) or not
            resourceGatherer.Gather(this);
            return true;
        }

Until now, that was perfectly fine.

However, the main problem with that, was that if a condition was not met, the player wouldn’t be able to interact with whatever he had to interact with, and this would leave them confused as they try to figure out what went wrong for them… if I wanted a check right before performing an action, that was NOT a feasable choice.

So what I did was, I deleted the checks from there, and placed them in the ‘InputReader_HandleResourceGatheringEvent()’, in ‘PlayerFreeLookState.cs’, and got it to work EXACTLY how I want it to work. For now, this is what my function looks like:


// Inventory variable introduction (not sure if that's the right way to do it, but so as not to include weird awake functions, I did it the straight way...):
private Inventory playerInventory = Inventory.GetPlayerInventory();


private void InputReader_HandleResourceGatheringEvent()
        {
            if (stateMachine.ResourceFinder.FindNearestTarget())
            {
                var nearestTarget = stateMachine.ResourceFinder.GetNearestSource();
                var nearestTargetResource = nearestTarget.GetResourceToAccumulate();
// my change (and believe it or not, it actually works :)):
                if (!playerInventory.HasSpaceFor(nearestTargetResource)) 
                {
                    MalbersAnimations.InventorySystem.NotificationManager.Instance.OpenNotification("Action Not Allowed: \n", "Not enough Inventory Space");
                    return;
                }

// the REAL Gathering Action begins here. Anything before this is just checking conditions and what not...
                PlayerGatheringState nextState = new PlayerGatheringState(stateMachine, stateMachine.ResourceFinder.CurrentTarget, stateMachine.GetComponent<ResourceGatherer>());
                stateMachine.SwitchState(new PlayerFacingState(stateMachine, stateMachine.ResourceFinder.CurrentTarget.transform.position, nextState));
            }
        }

Please do not lock this topic down yet, I may struggle with a few conditions and not want to mess the place up by having multiple topics of the same idea open


Edit: And… yup, I have a problem. How do I check for what’s in the players’ hand, so he doesn’t end up cutting a tree with a sword for example? I want to make sure he only cuts trees with axes, mines rocks with pickaxes, etc… (this one is quite hard for me, I don’t know what to track down or where. I really can use some help here)

Good job working through most of this.
I would add a fields to WeaponConfig, something like canMine, canHarvest, etc and expose them publicly. Then if you’re mining, just check with Fighter that the currentWeaponConfig.CanMine, etc.

Thank you, I’m trying my best :smiley:

booleans that can also be accessed through a getter function, right? I’m trying that as we speak

how do I perform this step? A little baffled what fighter has to do with all of this tbh… :sweat_smile: (PLEASE DON’T SAY THE ANSWER, I’m giving it a try first)

Ahh, I got it to work… it took a tiny bit of extra thinking, but you indeed guided me. Thank you Brian :slight_smile:

Here’s what I did (for anyone curious from the future):

  1. in ‘WeaponConfig.cs’, I placed two public booleans, ‘canMine’ and ‘canWoodcut’ (believe me, the computer doesn’t care about what weapon you got, it just cares about these two triggers), and two getter functions, each for each variable:
[SerializeField] bool canMine = false;
[SerializeField] bool canWoodcut = false;

public bool GetCanMine()
{
return canMine;
}

public bool GetCanWoodcut() 
{
return canWoodcut;
}
  1. in ‘Fighter.cs’, a script we chose because it’s a script that already has access to the current weapon in the players’ hand, here’s what I did:
public WeaponConfig GetCurrentWeaponConfig() 
{
return currentWeaponConfig;
}
  1. In ‘PlayerFreeLookState.cs’ (if you’re not performing the RPG to third person transition, you won’t follow along, otherwise you’ll know what I’m talking about), I integrated the fighter, and used the backroad from there to access the type of weapon I have, and whether it can mine or not, as follows:
// private variable
Fighter fighterPlayer = GameObject.FindGameObjectWithTag("Player").GetComponent<Fighter>();

// and then this goes in 'InputReader_HandleResourceGatheringEvent()' (this is my own unique function, you won't find it elsewhere):
// Check the weapon type being held (Mining):
                if (nearestTarget.GetAssociatedSkill() == Skill.Mining && !playerFighter.GetCurrentWeaponConfig().GetCanMine()) 
                {
                    MalbersAnimations.InventorySystem.NotificationManager.Instance.OpenNotification("Action Not Allowed: \n", "You need a Pickaxe to perform this operation"); // I'm using Malbers' Inventory System Notification system for this one
                    return;
                }

@Brian_Trotter one last question though. If I wanted to disable resource gathering for any weapon beneath a specific level (so for example a blue rock can only accept… idk… red, green and white pickaxes, because these are higher tier weapons for instance, but reject black, bronze and yellow pickaxes, because they are lower tier), how would I check for pickaxes more efficiently?

Change the bool to an int with the maximum level that the weapon will mine/woodcut… (hint: 0 or -1 is no joy) and compare it to the level required for the resource.

OK I’m probably burnt out because I’ve been coding (and playing with Cinemachine) all day, but…

How do we do this again? :sweat_smile:

Change

bool canMine;

to

int miningLevel = -1;
public int MiningLevel => miningLevel;

Then instead of relying simply on canMine, use currentWeaponConfig.MiningLevel.
MiningLevel must exceed the miningLevel.

Um… the StateMachine already has a reference to Fighter…

if(nearestTarget.GetAssociatedSkill()==Skill.Mining && stateMachine.Fighter.GetCurrentWeaponConfig().GetCanMine();

Privacy & Terms