Why does my for loop create a new table and why is my index changing values?

I have a module script that looks like this

local module = {
	Space = {
		isHeld = false,
		startTime = 0,
		holdTime = 0,
		endTime = 0,
	},
	Tab = {
		isHeld = false,
		startTime = 0,
		holdTime = 0,
		endTime = 0,
	},
}

function module:UpdateInput(input, state)
      --Irellevant
end

I would like to loop through the module and update each input (excluding the function) from another local script and update the value hold time to something else.

However for some reason my index is changing to a table when I print it.

RunService.RenderStepped:Connect(function()
	for i, v in pairs(PlayerInput) do
		print(i, PlayerInput[i]) -- prints:  â–¶ Space  â–¶ {...}

		if PlayerInput[i] ~= PlayerInput.UpdateInput then
			if PlayerInput[i].isHeld == true then
				print(i, PlayerInput[i]) -- prints: â–¶ {...} â–¶ {...}

				PlayerInput[i].holdTime = tick() - PlayerInput[i].startTime
			end	
		end
	end
end)

If I print the actual table itself after updating holdTime it returns this

â–Ľ  {
                    ["Space"] =  â–¶ {...},
                    ["Tab"] =  â–¶ {...},
                    ["UpdateInput"] = "function",
                    [Table(1615AD21188)] =  â–¶ {...}
                 }

What is [Table(1615AD21188)] and why is this happening?

I have tried using v instead of playerInput[i] but it’s the same result.

Check the three dots in the upper right of the output, make sure the log mode box is unchecked,
otherwise I would say it’s likely because you have a module script with a table, and it will default to the values every time as a module script does not change (if that makes sense0

Yep log mode is unchecked.

Also a question about module scripts, how come I can access module script values from multiple scripts like so?

PlayerInput.Tab.holdTime = 1

and then access that updated value elsewhere.

Also I might try moving the for loop into the module script itself.

I’m not sure I understand your question. A module script can be accesed by any local script when in Replicated Storage, and any Server Script when in ServerStorage. I reccomend changing the value on the server, as it will not update elsewhere.

As for moving the for loop, I’m not sure that would change anything but you can defo try

I mean this ^

Before I was updating holdTime by doing it manually and it was working. However, as I add more inputs I don’t really want to be doing this everytime. How come this works but a for loop isn’t?

if PlayerInput.Space.isHeld == true then
	PlayerInput.Space.holdTime = tick() - PlayerInput.Space.startTime
end

Also yeh, moving it into the module script gives the same result as before.

If I’m reading this right you want a datastore type of module script? I mean like something where you can call and change values with a single function or something?

To an extent yes, I need the module script to store when I’m pressing an input and how long.

local RunService = game:GetService("RunService")

local module = {
	Space = {
		isHeld = false,
		startTime = 0,
		holdTime = 0,
		endTime = 0,
	},
	Tab = {
		isHeld = false,
		startTime = 0,
		holdTime = 0,
		endTime = 0,
	},
}

function module:UpdateInput(input, state)
	if state then
		local values =
			{
				isHeld = true,
				startTime = tick(),
				holdTime = 0,
				endTime = 0,
			}

		module[input] = values
	else
		local values =
			{
				isHeld = false,
				startTime = 0,
				holdTime = 0,
				endTime = module[input].holdTime,
			}

		module[input] = values
	end
end
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")

local PlayerInput = require(ReplicatedStorage:WaitForChild("PlayerInput"))

--Where the for loop was

UserInputService.InputBegan:Connect(function(input, gameProcessedEvent)
	if input.KeyCode == Enum.KeyCode.Space and not gameProcessedEvent then
		PlayerInput:UpdateInput(PlayerInput.Space, true)
	end
	
	if input.KeyCode == Enum.KeyCode.Tab then
		PlayerInput:UpdateInput(PlayerInput.Tab, true)
	end
end)

UserInputService.InputEnded:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.Space then
		PlayerInput:UpdateInput(PlayerInput.Space, false)
	end
	
	if input.KeyCode == Enum.KeyCode.Tab then	
		PlayerInput:UpdateInput(PlayerInput.Tab, false)
	end
end)

My other scripts then reference these values in the module script and decide what to do from there. I got sick of checking UserInputService in multiple scripts.

My best suggestion is to use remote functions. It will allow you to make a custom function that you can call on the client and execute on the server. Another thing you can do is make a ton of custom states. I can write the state script yet as for the remote functions here is a link to the documentation on that: Remote Events and Functions | Roblox Creator Documentation I suggest looking at my model in studio for help with states. It’s a sonic engine mod but it has the jist of what you’re looking for. https://create.roblox.com/marketplace/asset/10858433431/Sonic-Dream-Engine-White-Boost-Wisp-Mod

Oh this is all being handled locally.

The server doesn’t need any of this information. I’m making this because I kept having to use UIS in multiple scripts that do the same thing (checking how long an input is held). The reason I have a local script is because I don’t think module scripts can access user input.

even if it’s all being handled locally you should consider using states or remote functions/events to call the usage of input from a module script.

How so, please elaborate, I’m a bit confused. Do you mean bindable events?

(sorry for the edits, I tend to think after I post)

I mean bindable functions. They will allow cross connection so you can just put the user input stuff into a localscript and use the function via that bindable function each time to call it. Bindable Events and Functions | Roblox Creator Documentation
Give me 5 mins to write down what you need to do and a script with where you should put your code

I understand how that could work but its just another hassle to subscribe to events in each script.

It would result in me having to
-Fire an event each frame
-Reference the event
-Set local variables for each input
-Subscribe to function
-Set variables to use elsewhere

I’d much prefer just
-Reference a module script
-Access values as needed

Yeah for that you would need to script a ton of custom functions and events which idk how to do. Just use a bindable function to call it each time or just keep writing it each time. sorry

The “[Table(1615AD21188)]” that you are seeing is a representation of a table reference in Lua. It’s not an actual key or value in your table, but rather a representation of the memory address of the table object.

The reason you are seeing this is because you are using pairs() to iterate through the PlayerInput table, which iterates through both the keys and the values in the table. When you print i and PlayerInput[i], you are seeing the key (i) and the corresponding value (PlayerInput[i]) in the table.

In Lua, tables can have any type of values as keys, including tables. So when you have nested tables like in your module table, PlayerInput[i] can be a table object representing the nested table. This is why you see the memory address representation like “[Table(1615AD21188)]” when you print it.

If you want to access the nested tables in your module table and update their values, you can do so using the key-value pairs of the nested tables, like this:

for i, v in pairs(PlayerInput) do
    if type(v) == "table" and v ~= module.UpdateInput then
        if v.isHeld == true then
            v.holdTime = tick() - v.startTime
        end
    end
end

Note that in the above code, v represents the values of the nested tables in PlayerInput, and you can directly update their values without using the PlayerInput[i] notation. Also, I’ve added a check to make sure the value v is a table and not the module.UpdateInput function, to avoid trying to update the function itself.

1 Like

I’ve kind of done this before but it’s not really relevant thank you though.

Actually turns out nothing was working and isHeld wasn’t actually being set. I reverted back to when it was working and it turns out it was this

function module:UpdateInput(input, state)
	if state then
		local values =
			{
				isHeld = true,
				startTime = tick(),
				holdTime = 0,
				endTime = 0,
			}

		module[input] = values
	else
		local values =
			{
				isHeld = false,
				startTime = 0,
				holdTime = 0,
				endTime = module[input].holdTime,
			}

		module[input] = values
	end
end

--local script
PlayerInput:UpdateInput(PlayerInput.Space, false) -- This doesn't work
PlayerInput:SetInput("Space", true) -- does work

Is there any way I can use PlayerInput.Space instead of a string?

Also your solution worked, heldTime is now being set thank you. I’ll mark yours solution but let me know if you know the answer to my other question.

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