RoInputs (Comprehensive ECS or Event based input handling system for Roblox)

Designed to handle various types of user inputs across different devices such as Keyboard and Mouse (KBM), TouchScreen, and Controller.

Inputs.Binds = {
    ["PlaceBlock"] = { KBM = {"UserInputType", "MouseButton1"}, TouchScreen = {"UserInputType", "Touch"}, Controller = {"KeyCode", "ButtonR1"}},
    ["PrimaryAttack"] = { KBM = {"UserInputType", "MouseButton1"}, TouchScreen = {"UserInputType", "Touch"}, Controller = {"KeyCode", "ButtonR1"}},

    ["ToggleInventory"] = { KBM = {"KeyCode", "E"}, TouchScreen = {"UiButton", "ToggleInventoryButton"}, Controller = {"KeyCode", "ButtonX"}, AllDevices = {"UiButton", "ToggleInventoryButton" }},
  

    ["HotbarSlot1"] = { KBM = {"KeyCode", "One"}, TouchScreen = {"UiButton", "HotbarSlot1Button"}, Controller = {"UiButton", "HotbarSlot1Button"}, AllDevices = {"UiButton", "HotbarSlot1Button" }   },
	["HotbarSlot2"] = { KBM = {"KeyCode", "Two"}, TouchScreen = {"UiButton", "HotbarSlot2Button"}, Controller = {"UiButton", "HotbarSlot2Button"}, AllDevices = {"UiButton", "HotbarSlot2Button" }},
	["HotbarSlot3"] = { KBM = {"KeyCode", "Three"}, TouchScreen = {"UiButton", "HotbarSlot3Button"}, Controller = {"UiButton", "HotbarSlot3Button"}, AllDevices = {"UiButton", "HotbarSlot3Button" } },
	["HotbarSlot4"] = { KBM = {"KeyCode", "Four"}, TouchScreen = {"UiButton", "HotbarSlot4Button"}, Controller = {"UiButton", "HotbarSlot4Button"}, AllDevices = {"UiButton", "HotbarSlot4Button" } },
	["HotbarSlot5"] = { KBM = {"KeyCode", "Five"}, TouchScreen = {"UiButton", "HotbarSlot5Button"}, Controller = {"UiButton", "HotbarSlot5Button"}, AllDevices = {"UiButton", "HotbarSlot5Button" } },

    ["NextHotbarSlot"] = { KBM = {"KeyCode", "Q"}, TouchScreen = {"UiButton", "NextHotbarSlotButton"}, Controller = {"KeyCode", "ButtonR2"}, AllDevices = {"UiButton", "NextHotbarSlotButton" } },
}

Here’s a high-level overview of its functionality:

  1. Input Binds: The module defines a table Inputs.Binds that maps various actions (like “PlaceBlock”, “PrimaryAttack”, etc.) to their corresponding inputs for each device type.
  2. Device Switching: The module allows for device switching, with specific binds defined for switching between devices.
  3. Device Types: The module defines a table Devices that maps device types to their names.
  4. Player Devices: The module keeps track of the current device for each player.
  5. Event Connections: The module provides functions to connect to input began and input ended events (RoInputs.Began, RoInputs.Ended). These functions handle the logic of checking if the input matches the binds for the current device and the action, and if so, they fire the corresponding event.
  6. ECS Systems: The module provides functions to handle inputs in an Entity Component System (ECS) style. It keeps a list of new inputs for each step, and provides functions to get these inputs (RoInputs.onInputBegan, RoInputs.onInputEnded). It also provides a function to clear these lists for the next step (RoInputs.nextstep).

Download Script (Source): Roblox Lua Input/Device module. This script makes creating inputs for all devices easier and communicating them. (Works with ECS or Event Based/OOP) · GitHub

Example Usage
Event-Based Structure:

Client:

local RoInputs = require(game.ReplicatedStorage.RoInputs)

RoInputs.Began("PlaceBlock", function() 
       if not MouseLocation then return end
       return true, MouseLocation --Send args to the server
end)

Server:

local RoInputs = require(game.ReplicatedStorage.RoInputs)

RoInputs.Began("PlaceBlock", function(player, MouseLocation) 
       if not MouseLocation then return end
       print(player, MouseLocation)
       --handle placing block here
end)

ECS-Based Structure (Matter):

Init System (Shared Server and Client):

local RoInputs = require(game.ReplicatedStorage.RoInputs)

local function Inputs()
    RoInputs.nextstep()
end

return {
    system = Inputs,
    priority = math.huge
}

Client:

local RoInputs = require(game.ReplicatedStorage.RoInputs)

local function placeBlock(world)
        for _, Input in next, RoInputs.onInputBegan("PlaceBlock") do
              if not MouseLocation then continue end
              Input.SendToServer(MouseLocation)
        end
end

return placeBlock

Server:

local RoInputs = require(game.ReplicatedStorage.RoInputs)

local function placeBlock(world)
        for _, Input in next, RoInputs.onInputBegan("PlaceBlock") do
              local player, MouseLocation = unpack(Input.args)
              if not MouseLocation then continue end
               print(player, MouseLocation)
               --handle placing block here
        end
end

return placeBlock

Other useful methods:

Devices
Inputs.GetDevice(player: Player): string]
Inputs.GetAllDevices(): {[Player]: "device string"}

Custom send inputs to the server
Inputs.SendInputBegan(InputName, ...)
Inputs.SendInputEnded(InputName, ...)

Checking input states
Inputs.isHolding(InputName, player):boolean

Overview:
This module is very expandable/easy to understand and can be modified to your liking. I would love input or any suggestions/issues that need to be fixed.

7 Likes

for further info: Any functionality you want to add go ahead and say it here not my private messages so other people can see

1 Like

NOTE:
For events to be listened to on the server, you must handle it on the client first.

This isn’t recommended but if you have to you can do this if you want to auto send to the server:

local AUTOSEND_INPUTS = {
    "InputName1",
    "Other Input name"
}

for _, inputName in AUTOSEND_INPUTS do
       RoInputs.Began(inputName, function() return true end)
       RoInputs.Ended(inputName, function() return true end)
end