Issue with Tree system

Hello! I have a slight problem with my tree system. Right now I say:

self._Trove:Add(Prompt.Triggered:Connect(function(Player)

       if not self.PlayersCooldown[Player.UserId] then
           self.PlayersCooldown[Player.UserId] = os.time() - self.CooldownTime
       end

       if os.time() - self.PlayersCooldown[Player.UserId] >= self.CooldownTime then
           self.ItemData[Player.UserId] = {} -- Needs to be outside of this.

           local RandomAmount = self.Random:NextInteger(1, 3)
       
           for _ = 1, RandomAmount do
               local Type = self:RollCollectable()

               if not self.ItemData[Player.UserId][Type] then
                   self.ItemData[Player.UserId][Type] = 0
                   self.ItemData[Player.UserId][Type] += 1
               else
                   self.ItemData[Player.UserId][Type] += 1
               end
           end
           
           print(self.ItemData)
           Generate:FireClient(Player, self.ItemData[Player.UserId], self.Instance)

           self.PlayersCooldown[Player.UserId] = os.time()
       end
   end))

Except, this line self.ItemData[Player.UserId] = {} -- Needs to be outside of this. Needs to be outside of the Triggered event. This is because:

function Tree:Construct()
    self._Trove = Trove.new()
    self.Random = Random.new()

    self.PlayersCooldown = {}
    self.ItemData = {}
    self.CooldownTime = 1
end

ItemData is set for every tree (each tree has its own item data), but because I have that line in the .Triggered event, new data is created each time and the collectables that are dropped from the tree is unable to be picked up.

Here is the full script in-case someone needs it:

local ReplicatedStorage = game:GetService"ReplicatedStorage"
local ServerScriptService = game:GetService"ServerScriptService"

local Knit = require(ReplicatedStorage.Packages.Knit)
local Component = require(ReplicatedStorage.Packages.Component)
local Trove = require(ReplicatedStorage.Packages.Trove)
local Collectables = require(ServerScriptService.Source.Modules.Collectables)

local Generate = ReplicatedStorage:WaitForChild "Remotes".Tree.Generate
local RemoveObject = ReplicatedStorage:WaitForChild "Remotes".Tree.RemoveObject

local Tree = Component.new {
    Tag = "Tree"
}

function Tree:Construct()
    self._Trove = Trove.new()
    self.Random = Random.new()

    self.PlayersCooldown = {}
    self.ItemData = {}
    self.CooldownTime = 1
end

function Tree:RollCollectable()
    local Counter = 0

    for Index, _ in Collectables do
        Counter += Collectables[Index][2]
    end

    local Chosen = self.Random:NextNumber(0, Counter)

    for Index, _ in Collectables do
        Counter -= Collectables[Index][2]
        if Chosen > Counter then
            return Collectables[Index][1]
        end
    end
end

function Tree:Start()
    local Prompt = self.Instance.PrimaryPart.Prompt.ShakePrompt
    local DataService = Knit.GetService("DataService")

     self._Trove:Add(Prompt.Triggered:Connect(function(Player)

        if not self.PlayersCooldown[Player.UserId] then
            self.PlayersCooldown[Player.UserId] = os.time() - self.CooldownTime
        end

        if os.time() - self.PlayersCooldown[Player.UserId] >= self.CooldownTime then
            self.ItemData[Player.UserId] = {} -- Needs to be outside of this.

            local RandomAmount = self.Random:NextInteger(1, 3)
        
            for _ = 1, RandomAmount do
                local Type = self:RollCollectable()

                if not self.ItemData[Player.UserId][Type] then
                    self.ItemData[Player.UserId][Type] = 0
                    self.ItemData[Player.UserId][Type] += 1
                else
                    self.ItemData[Player.UserId][Type] += 1
                end
            end
            
            print(self.ItemData)
            Generate:FireClient(Player, self.ItemData[Player.UserId], self.Instance)

            self.PlayersCooldown[Player.UserId] = os.time()
        end
    end))

    RemoveObject.OnServerInvoke = function(Player: Player, InstanceName: string)
        for Index, Data in self.ItemData[Player.UserId] do
            if Index == InstanceName then
                Data -= 1

                local Profile = DataService:Get(Player)
                DataService:Set(Player, "Test", Profile.Data.Test + 1)

                return true
            else
                return false
            end
        end
    end
end

function Tree:Stop()
    self._Trove:Clean()
end

return Tree

Any help is help, thank you. If you need more information, tell me!

Iā€™m a little confused on the issue. Are you saying any time that the triggered connection is fired ā†’ it resets the players data for said tree?

Also what activates the trigger event? Are you firing it once? Or can the player shake/trigger the tree multiple times to drop more items?

If I understand correctly, you want self.ItemData[Player.UserId] = {} to be executed only once per player and not on every call to the Triggered event. This can be achieved by initializing it in the Construct method instead. This would ensure that every tree has its own set of item data for each player.

function Tree:Construct()
    self._Trove = Trove.new()
    self.Random = Random.new()

    self.PlayersCooldown = {}
    self.ItemData = {}
    self.CooldownTime = 1

    -- For each player, create a unique table in ItemData.
    for _, player in pairs(game.Players:GetPlayers()) do
        self.ItemData[player.UserId] = {}
    end

    -- Listen for new players and create a unique table in ItemData for them.
    game.Players.PlayerAdded:Connect(function(player)
        self.ItemData[player.UserId] = {}
    end)
end

self._Trove:Add(Prompt.Triggered:Connect(function(Player)
    if not self.PlayersCooldown[Player.UserId] then
        self.PlayersCooldown[Player.UserId] = os.time() - self.CooldownTime
    end

    if os.time() - self.PlayersCooldown[Player.UserId] >= self.CooldownTime then
        -- Removed the line that resets self.ItemData[Player.UserId] every time.

        local RandomAmount = self.Random:NextInteger(1, 3)

        for _ = 1, RandomAmount do
            local Type = self:RollCollectable()

            if not self.ItemData[Player.UserId][Type] then
                self.ItemData[Player.UserId][Type] = 0
            end
            self.ItemData[Player.UserId][Type] += 1
        end

        print(self.ItemData)
        Generate:FireClient(Player, self.ItemData[Player.UserId], self.Instance)

        self.PlayersCooldown[Player.UserId] = os.time()
    end
end))

Please note that if players can leave the game, you might want to consider removing their data from self.ItemData and self.PlayersCooldown to prevent memory leaks. You can do this by listening to the PlayerRemoving event:

game.Players.PlayerRemoving:Connect(function(player)
    self.ItemData[player.UserId] = nil
    self.PlayersCooldown[player.UserId] = nil
end)

1 Like

Yes, that is true.

It is fired once the ProximityPrompt in the tree is Triggered, as of right now, the tree has a cooldown of one, so every one second, the player can activate it again.

This works, thank you for the blatantly obvious solution lol

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.