Skip to content

Instantly share code, notes, and snippets.

@CheezusChrust
Last active April 16, 2023 21:02
Show Gist options
  • Save CheezusChrust/e30ae2cf0a0001bb013218f63aae62e0 to your computer and use it in GitHub Desktop.
Save CheezusChrust/e30ae2cf0a0001bb013218f63aae62e0 to your computer and use it in GitHub Desktop.
A Starfall script to make setting up joystick-like devices easier. Requires the joystick module, binaries can be found here: https://github.com/thegrb93/StarfallEx
--@name Joystick Controller
--@shared
--[[
INSTRUCTIONS/INFO:
1. Spawn this chip on a Starfall screen and move your input device around/press buttons on it
2. Fill the axes and buttons tables below using the formats described below
- Wire outputs will automatically be created based on table names
- DeviceID is displayed on the top of the screen
- AxisID/ButtonID is the number displayed next to each axis/button
- Invert is a boolean (true or false) which, when true, will invert the output (-1 to 1 becomes 1 to -1)
- MinValue is what the chip outputs when the axis is at its LOWEST value
- MaxValue is what the chip outputs when the axis is at its HIGHEST value
--]]
-- FORMAT: WireOutputName = {DeviceID, AxisID, Invert, MinValue, MaxValue}
local axes = {
Pitch = {1, 1, false, -1, 1},
Yaw = {0, 3, false, -1, 1},
Roll = {1, 0, false, -1, 1},
Throttle = {1, 2, true, 0, 100},
}
-- FORMAT: WireOutputName = {DeviceID, ButtonID}
local buttons = {
Fire = {1, 21}
}
-- Don't edit anything below here
if SERVER then
local names = {}
local types = {}
for outputName in pairs(axes) do
table.insert(names, outputName)
table.insert(types, "number")
end
for outputName in pairs(buttons) do
table.insert(names, outputName)
table.insert(types, "number")
end
wire.adjustOutputs(names, types)
net.receive("joystickData", function()
local count = net.readUInt(8)
for _ = 1, count do
local outputName = net.readString()
local value = net.readFloat()
wire.ports[outputName] = value
end
end)
local ent = chip():isWeldedTo()
if isValid(ent) and ent:getClass() == "starfall_screen" then
ent:linkComponent(chip())
end
else
if not joystick then
print(Color(255, 0, 0), "Joystick module not installed!")
print(Color(255, 0, 0), "Get the binaries here: https://github.com/thegrb93/StarfallEx")
return
end
local joystickGetAxis, joystickGetButton = joystick.getAxis, joystick.getButton
local remap = math.remap
local function getDiff(old, new)
local diff = {}
for k, v in pairs(new) do
if old[k] ~= v then
diff[k] = v
end
end
return diff
end
local function getJoystickData()
local data = {}
for outputName, outputData in pairs(axes) do
local value = joystickGetAxis(outputData[1], outputData[2])
if outputData[3] then
value = 65535 - value
end
if outputData[4] and outputData[5] then
value = remap(value, 0, 65535, outputData[4], outputData[5])
end
data[outputName] = value
end
for outputName, outputData in pairs(buttons) do
local value = joystickGetButton(outputData[1], outputData[2]) > 0 and 1 or 0
data[outputName] = value
end
return data
end
if player() == owner() then
local oldData = {}
hook.add("tick", "getJoystickData", function()
local data = getJoystickData()
local diff = getDiff(oldData, data)
if next(diff) then
local count = table.count(diff)
net.start("joystickData")
net.writeUInt(count, 8)
for outputName, value in pairs(diff) do
net.writeString(outputName)
net.writeFloat(value)
end
net.send(nil, true)
end
oldData = data
end)
end
-- Joystick helper functionality
local function getJoystickDataHelper(deviceID)
local data = {}
data.axes = {}
data.buttons = {}
data.povs = {}
for i = 0, 31 do
data.axes[i] = joystick.getAxis(deviceID, i)
end
for i = 0, 31 do
data.buttons[i] = joystick.getButton(deviceID, i)
end
for i = 0, 31 do
data.povs[i] = joystick.getPov(deviceID, i)
end
return data
end
local devices = {}
-- Get default device values to compare against later
for i = 0, 2 do
devices[i] = {}
devices[i].joystickData = getJoystickDataHelper(i)
local detectedInputs = {}
detectedInputs.axes = {}
detectedInputs.buttons = {}
detectedInputs.povs = {}
devices[i].detectedInputs = detectedInputs
end
timer.create("detectAxes", 0.1, 0, function()
for deviceID, device in pairs(devices) do
local newData = getJoystickDataHelper(deviceID)
local axesDiff = getDiff(device.joystickData.axes, newData.axes)
local buttonsDiff = getDiff(device.joystickData.buttons, newData.buttons)
--local povsDiff = getDiff(device.joystickData.povs, newData.povs)
for k, v in pairs(axesDiff) do
device.detectedInputs.axes[k] = v
end
for k, v in pairs(buttonsDiff) do
device.detectedInputs.buttons[k] = v
end
--for k, v in pairs(povsDiff) do
-- device.detectedInputs.povs[k] = v
--end
end
end)
local WHITE = Color(255, 255, 255)
local RED = Color(255, 100, 100)
local GREEN = Color(100, 255, 100)
--local BLUE = Color(100, 100, 255)
hook.add("render", "data", function()
for deviceID, device in pairs(devices) do
render.setColor(WHITE)
render.drawText(deviceID * 256, 0, "Device " .. deviceID, deviceID)
render.drawText(deviceID * 256, 14, joystick.getName(deviceID), deviceID)
render.drawLine(0, 30, 512, 30)
local row = 0
for dataSetName, dataSet in pairs(device.detectedInputs) do
for inputID in pairs(dataSet) do
local value
if dataSetName == "axes" then
value = string.format("Axis %s: %d", inputID, joystick.getAxis(deviceID, inputID))
render.setColor(RED)
elseif dataSetName == "buttons" then
value = string.format("Button %s: %d", inputID, joystick.getButton(deviceID, inputID) > 0 and 1 or 0)
render.setColor(GREEN)
end --elseif dataSetName == "povs" then
-- value = string.format("POV %s: %d", inputID, joystick.getPov(deviceID, inputID))
-- render.setColor(BLUE)
--end
render.drawText(deviceID * 256, 32 + row * 12, value, deviceID)
row = row + 1
end
end
end
end)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment