--!strict -- RailSide Hub -- Small hub for "RailSide [BETA]" on the Potassium executor. -- UI: Robly Airflow (bobloscript/Robly_Airflow), Robscript theme. -- -- Everything works on your own client: the hub only reads game attributes and sends the -- same remotes the normal client sends. Coins, injuries and grip stay server-side. ----- Services ----- local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local RunService = game:GetService("RunService") local UserInputService = game:GetService("UserInputService") local SoundService = game:GetService("SoundService") local StarterGui = game:GetService("StarterGui") local LocalPlayer = Players.LocalPlayer ----- UI library ----- local UI_SOURCES = { "https://raw.githubusercontent.com/bobloscript/Robly_Airflow/main/Source.luau", "https://raw.githubusercontent.com/PookiePepelsss/Airflow-UI/refs/heads/main/Source.luau", } local Airflow = nil for _, url in ipairs(UI_SOURCES) do local ok, library = pcall(function() return loadstring(game:HttpGet(url))() end) if ok and type(library) == "table" and type(library.CreateWindow) == "function" then Airflow = library break end end if not Airflow then error("[RailSide Hub] UI library did not load") end ----- Theme ----- local THEME = { Background = Color3.fromHex("#0A0A0C"), Surface = Color3.fromHex("#141418"), Surface2 = Color3.fromHex("#1A1A20"), Surface3 = Color3.fromHex("#2A2A33"), Stroke = Color3.fromHex("#26262E"), StrokeHover = Color3.fromHex("#3C3C49"), Accent = Color3.fromHex("#FF3B7F"), AccentDark = Color3.fromHex("#1A0710"), Text = Color3.fromHex("#F5F5F7"), Muted = Color3.fromHex("#8D8D99"), } Airflow.ThemePresets.Robscript = THEME Airflow:SetDefaultTheme(THEME) ----- Game constants ----- local ROLE_COLORS = { Citizen = Color3.fromRGB(75, 157, 255), Patrol = Color3.fromRGB(226, 63, 58), TB = Color3.fromRGB(246, 206, 40), Unknown = Color3.fromRGB(180, 180, 180), } local ROLE_LABELS = { Citizen = "Citizen", Patrol = "Anti-crouch", TB = "Security", Unknown = "Unknown", } local HOSTILE_TO_CITIZEN = { Patrol = true, TB = true } local HOSTILE_TO_STAFF = { Citizen = true } local BANDAGE_PRICE = 40 local PILLS_PRICE = 30 local DEFAULT_ESP_DISTANCE = 50 local MAX_ESP_DISTANCE = 2000 ----- Text ----- local TEXT = { en = { loading = "esp, radar, speed, teleports", main = "Main", lang_group = "Language", lang_hint = "Choose the language of the menu. It changes right away — no reload needed.", lang_status = "Now", lang_en = "English", lang_ru = "Русский", visuals = "Visuals", survival = "Survival", movement = "Movement", logs = "Logs", settings = "Settings", esp_group = "Player ESP", radar_group = "Radar", auto_group = "Automation", status_group = "Status", speed_group = "Speed", teleport_group = "Teleport", log_group = "Activity", about_group = "About", esp = "Player ESP", esp_desc = "See players through walls.", esp_bind = "ESP key", esp_bind_desc = "Turns ESP on and off.", roles = "Roles", roles_desc = "Who to show.", distance = "Distance", metres = "Show metres", metres_desc = "Adds the distance to the tag.", threat = "Enemy nearby", radius = "Alert radius", alert = "Sound alert", alert_desc = "Beeps when an enemy is close.", release = "Let go of the train", release_desc = "Drops the grip when an enemy is close.", panic = "Auto panic", panic_desc = "Clicks Resist for you.", cola = "Auto cola", cola_desc = "Drinks cola when stamina is low.", bandage = "Auto bandage", bandage_desc = "Heals you when you are hurt.", pills = "Auto pills", pills_desc = "Takes pills when fear is high.", coins = "Coins", stamina = "Stamina", fear = "Fear", sanity = "Sanity", injuries = "Injuries", walk = "WalkSpeed", walk_desc = "Makes you faster.", walk_bind = "Speed key", walk_value = "Speed", jump = "Jump", jump_desc = "Turns jumping on.", jump_bind = "Jump key", jump_value = "Jump power", noclip = "Noclip", noclip_desc = "Walk through walls.", noclip_bind = "Noclip key", fly = "Fly", fly_desc = "WASD to fly. Space up, Ctrl down.", fly_bind = "Fly key", fly_speed = "Fly speed", to_spawn = "To spawn", to_shop = "To shop", to_train = "To train", respawn = "Respawn", about_text = "Small hub for RailSide. RightControl hides the window.", unload = "Unload", lang = "Language", en = "EN", ru = "RU", nobody = "nobody near", none = "none", loaded = "Hub loaded", esp_on = "ESP on", esp_off = "ESP off", ready = "Press RightControl.", where_lang = "Language is on the Main tab.", danger = "Danger", teleported = "Teleported", not_found = "Not found", unloaded = "Hub closed", }, ru = { loading = "esp, радар, скорость, телепорты", main = "Главная", lang_group = "Язык", lang_hint = "Выбери язык меню. Он сменится сразу — перезапускать не надо.", lang_status = "Сейчас", lang_en = "English", lang_ru = "Русский", visuals = "Видео", survival = "Выживание", movement = "Движение", logs = "Логи", settings = "Настройки", esp_group = "ESP игроков", radar_group = "Радар", auto_group = "Автоматика", status_group = "Состояние", speed_group = "Скорость", teleport_group = "Телепорт", log_group = "События", about_group = "О хабе", esp = "ESP игроков", esp_desc = "Видно игроков через стены.", esp_bind = "Кнопка ESP", esp_bind_desc = "Включает и выключает ESP.", roles = "Роли", roles_desc = "Кого показывать.", distance = "Дальность", metres = "Показывать метры", metres_desc = "Пишет дистанцию на табличке.", threat = "Враг рядом", radius = "Радиус тревоги", alert = "Звук тревоги", alert_desc = "Пищит, когда враг близко.", release = "Отпускать зацеп", release_desc = "Бросает поезд, когда враг близко.", panic = "Авто-паника", panic_desc = "Сам жмёт «Сопротивляться».", cola = "Авто-кола", cola_desc = "Пьёт колу, когда мало сил.", bandage = "Авто-бинт", bandage_desc = "Лечит, когда ты ранен.", pills = "Авто-таблетки", pills_desc = "Пьёт таблетки при страхе.", coins = "Монеты", stamina = "Силы", fear = "Страх", sanity = "Рассудок", injuries = "Травмы", walk = "Скорость ходьбы", walk_desc = "Бегаешь быстрее.", walk_bind = "Кнопка скорости", walk_value = "Скорость", jump = "Прыжок", jump_desc = "Включает прыжки.", jump_bind = "Кнопка прыжка", jump_value = "Сила прыжка", noclip = "Сквозь стены", noclip_desc = "Проходишь через стены.", noclip_bind = "Кнопка ноклипа", fly = "Полёт", fly_desc = "WASD — лететь. Пробел вверх, Ctrl вниз.", fly_bind = "Кнопка полёта", fly_speed = "Скорость полёта", to_spawn = "На спавн", to_shop = "К ларьку", to_train = "К поезду", respawn = "Возродиться", about_text = "Маленький хаб для RailSide. RightControl скрывает окно.", unload = "Выключить", lang = "Язык", en = "EN", ru = "RU", nobody = "рядом никого", none = "нет", loaded = "Хаб загружен", esp_on = "ESP включён", esp_off = "ESP выключен", ready = "Нажми RightControl.", where_lang = "Язык меняется на вкладке «Главная».", danger = "Опасность", teleported = "Телепорт готов", not_found = "Не найдено", unloaded = "Хаб закрыт", }, } local Lang = "en" local function T(key: string): string local pack = TEXT[Lang] or TEXT.en return pack[key] or TEXT.en[key] or key end ----- Remotes ----- local function findChild(parent: Instance?, name: string, timeout: number): Instance? if not parent then return nil end local existing = parent:FindFirstChild(name) if existing then return existing end local ok, child = pcall(function() return parent:WaitForChild(name, timeout) end) return if ok then child else nil end local StationGameplay = findChild(ReplicatedStorage, "StationGameplay", 10) local GripFolder = findChild(ReplicatedStorage, "StationGrip", 10) local FearFolder = findChild(ReplicatedStorage, "StationFear", 10) local ShopFolder = findChild(ReplicatedStorage, "StationShop", 10) local CoinsFolder = findChild(ReplicatedStorage, "StationCoins", 10) local Remotes = { Interact = findChild(StationGameplay, "Interact", 5), Sprint = findChild(StationGameplay, "Sprint", 5), Crouch = findChild(StationGameplay, "Crouch", 5), Drink = findChild(StationGameplay, "Drink", 5), GripRelease = findChild(GripFolder, "Release", 5), FearResist = findChild(FearFolder, "Resist", 5), ShopRequest = findChild(ShopFolder, "Request", 5), CoinsEarned = findChild(CoinsFolder, "Earned", 5), Reset = findChild(ReplicatedStorage, "StationReset", 5), } ----- Role data ----- local roleConfig = nil do local rolesFolder = findChild(ReplicatedStorage, "StationRoles", 5) local configModule = findChild(rolesFolder, "Config", 5) if configModule and configModule:IsA("ModuleScript") then local ok, result = pcall(require, configModule) if ok and type(result) == "table" then roleConfig = result end end end if roleConfig and type(roleConfig.Roles) == "table" then for roleId, roleData in pairs(roleConfig.Roles) do if type(roleData) == "table" then if type(roleData.Color) == "table" and #roleData.Color >= 3 then ROLE_COLORS[roleId] = Color3.new(roleData.Color[1], roleData.Color[2], roleData.Color[3]) end if type(roleData.Short) == "string" then ROLE_LABELS[roleId] = roleData.Short end end end end ----- State ----- type EspEntry = { highlight: Highlight?, billboard: BillboardGui?, label: TextLabel?, role: string, } local State = { espEnabled = false, espMaxDistance = DEFAULT_ESP_DISTANCE, espShowDistance = true, espRoles = { Citizen = true, Patrol = true, TB = true, Unknown = true }, dangerAlert = true, dangerRadius = 60, autoPanic = false, autoDrink = false, autoBandage = false, autoPills = false, autoReleaseOnDanger = false, walkSpeedEnabled = false, walkSpeed = 34, jumpEnabled = false, jumpPower = 50, noclip = false, fly = false, flySpeed = 60, nearestThreatDistance = math.huge, nearestThreatName = "-", nearestThreatRole = "-", lastThreatNotice = 0, lastDrinkAt = 0, lastBandageAt = 0, lastPillsAt = 0, lastReleaseAt = 0, } local espEntries: { [Player]: EspEntry } = {} local Hub: any = {} local Ui: any = {} local Binds: { { handle: any, action: () -> () } } = {} -- Placeholders: the UI fires callbacks while the elements are being created. Hub.log = function(_: string) end Hub.notify = function(_: string, _: string, _: string?) end ----- Character helpers ----- local function getCharacter(): Model? local character = LocalPlayer.Character if character and character.Parent and character:FindFirstChildOfClass("Humanoid") then return character end return nil end local function getHumanoid(): Humanoid? local character = getCharacter() return if character then character:FindFirstChildOfClass("Humanoid") else nil end local function getRoot(): BasePart? local character = getCharacter() if not character then return nil end return character:FindFirstChild("HumanoidRootPart") :: BasePart? end local function attributeOf(instance: Instance?, name: string): any if not instance then return nil end local ok, value = pcall(function() return instance:GetAttribute(name) end) return if ok then value else nil end local INJURY_KEYS = { "StationInjury_Head", "StationInjury_Neck", "StationInjury_Chest", "StationInjury_Abdomen", "StationInjury_UpperBack", "StationInjury_LowerBack", "StationInjury_Pelvis", "StationInjury_LeftArm", "StationInjury_RightArm", "StationInjury_LeftLeg", "StationInjury_RightLeg", "StationInjury_LeftShoulder", "StationInjury_RightShoulder", } local function injuryCount(player: Player): number local count = 0 for _, key in ipairs(INJURY_KEYS) do local value = tonumber(attributeOf(player, key)) or 0 if value > 0 then count += 1 end end return count end local function roleOf(player: Player): string local role = attributeOf(player, "StationRole") if type(role) == "string" and role ~= "" and ROLE_COLORS[role] then return role end local team = player.Team if team then for roleId, roleData in pairs((roleConfig and roleConfig.Roles) or {}) do if type(roleData) == "table" and roleData.Team == team.Name then return roleId end end end return "Unknown" end ----- ESP ----- local function removeEsp(player: Player) local entry = espEntries[player] if not entry then return end if entry.highlight then entry.highlight:Destroy() end if entry.billboard then entry.billboard:Destroy() end espEntries[player] = nil end local function clearEsp() for player in pairs(espEntries) do removeEsp(player) end end local function buildEsp(player: Player, character: Model, role: string): EspEntry local color = ROLE_COLORS[role] or Color3.new(1, 1, 1) local highlight = Instance.new("Highlight") highlight.Name = "RailSideHubHighlight" highlight.FillColor = color highlight.FillTransparency = 0.7 highlight.OutlineColor = color highlight.OutlineTransparency = 0 highlight.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop highlight.Adornee = character highlight.Parent = character local entry: EspEntry = { highlight = highlight, billboard = nil, label = nil, role = role } local anchor = (character:FindFirstChild("Head") or character:FindFirstChild("HumanoidRootPart")) :: BasePart? if anchor then local billboard = Instance.new("BillboardGui") billboard.Name = "RailSideHubTag" billboard.AlwaysOnTop = true billboard.Size = UDim2.fromOffset(240, 40) billboard.StudsOffset = Vector3.new(0, 2.1, 0) billboard.MaxDistance = State.espMaxDistance billboard.Adornee = anchor local label = Instance.new("TextLabel") label.BackgroundTransparency = 1 label.Size = UDim2.fromScale(1, 1) label.Font = Enum.Font.GothamBold label.TextSize = 14 label.TextColor3 = color label.TextStrokeTransparency = 0.4 label.TextWrapped = true label.Text = player.Name label.Parent = billboard billboard.Parent = anchor entry.billboard = billboard entry.label = label end return entry end local function updateEsp() if not State.espEnabled then return end local root = getRoot() for _, player in ipairs(Players:GetPlayers()) do if player == LocalPlayer then continue end local character = player.Character local humanoid = character and character:FindFirstChildOfClass("Humanoid") local role = roleOf(player) local visible = character ~= nil and humanoid ~= nil and humanoid.Health > 0 and State.espRoles[role] == true if not visible then removeEsp(player) continue end local distance = 0 if root then local targetRoot = character:FindFirstChild("HumanoidRootPart") :: BasePart? if targetRoot then distance = (root.Position - targetRoot.Position).Magnitude end end if distance > State.espMaxDistance then removeEsp(player) continue end local entry = espEntries[player] if not entry or entry.role ~= role or not entry.highlight or not entry.highlight.Parent or (entry.billboard == nil and (character:FindFirstChild("Head") or character:FindFirstChild("HumanoidRootPart")) ~= nil) then removeEsp(player) entry = buildEsp(player, character, role) espEntries[player] = entry end if entry.label then local health = humanoid and math.max(0, math.floor(humanoid.Health)) or 0 local roleText = ROLE_LABELS[role] or role if State.espShowDistance then entry.label.Text = string.format("%s\n%s | %d hp | %d m", player.Name, roleText, health, math.floor(distance)) else entry.label.Text = string.format("%s\n%s | %d hp", player.Name, roleText, health) end end end for player in pairs(espEntries) do if not player.Parent then removeEsp(player) end end end ----- Survival helpers ----- local function fire(remote: Instance?, ...) if not remote then return false end local args = table.pack(...) local ok = pcall(function() (remote :: any):FireServer(table.unpack(args, 1, args.n)) end) return ok end local function invokeShop(action: string, payload: any): (boolean, any) if not Remotes.ShopRequest then return false, "no shop" end local ok, result = pcall(function() return (Remotes.ShopRequest :: any):InvokeServer(action, payload) end) return ok, result end local function nearestThreat() local myRole = roleOf(LocalPlayer) -- Passengers look for the patrol; the patrol and the guards look for passengers. local hostile = if myRole == "Citizen" then HOSTILE_TO_CITIZEN else HOSTILE_TO_STAFF local root = getRoot() local bestDistance = math.huge local bestPlayer: Player? = nil local bestRole = "-" if not root then return math.huge, nil, "-" end for _, player in ipairs(Players:GetPlayers()) do if player ~= LocalPlayer then local role = roleOf(player) if hostile[role] then local character = player.Character local humanoid = character and character:FindFirstChildOfClass("Humanoid") local targetRoot = character and character:FindFirstChild("HumanoidRootPart") :: BasePart? if targetRoot and humanoid and humanoid.Health > 0 then local distance = (root.Position - targetRoot.Position).Magnitude if distance < bestDistance then bestDistance = distance bestPlayer = player bestRole = role end end end end end return bestDistance, bestPlayer, bestRole end local function beep() local sound = Instance.new("Sound") sound.SoundId = "rbxasset://sounds/electronicpingshort.wav" sound.Volume = 0.4 sound.Parent = SoundService sound:Play() task.delay(1.5, function() sound:Destroy() end) end ----- Movement state ----- local noclipConnection: RBXScriptConnection? = nil local flyConnection: RBXScriptConnection? = nil local flyVelocity: BodyVelocity? = nil local function stopFly() if flyConnection then flyConnection:Disconnect() flyConnection = nil end if flyVelocity then flyVelocity:Destroy() flyVelocity = nil end local humanoid = getHumanoid() if humanoid then humanoid.PlatformStand = false end end local function startFly() stopFly() local root = getRoot() local humanoid = getHumanoid() if not root or not humanoid then return end humanoid.PlatformStand = true local velocity = Instance.new("BodyVelocity") velocity.Name = "RailSideHubFly" velocity.MaxForce = Vector3.new(1e5, 1e5, 1e5) velocity.Velocity = Vector3.zero velocity.Parent = root flyVelocity = velocity flyConnection = RunService.RenderStepped:Connect(function() if not State.fly then return end local camera = workspace.CurrentCamera if not getRoot() or not camera then return end local move = Vector3.zero if UserInputService:IsKeyDown(Enum.KeyCode.W) then move += camera.CFrame.LookVector end if UserInputService:IsKeyDown(Enum.KeyCode.S) then move -= camera.CFrame.LookVector end if UserInputService:IsKeyDown(Enum.KeyCode.A) then move -= camera.CFrame.RightVector end if UserInputService:IsKeyDown(Enum.KeyCode.D) then move += camera.CFrame.RightVector end if UserInputService:IsKeyDown(Enum.KeyCode.Space) then move += Vector3.yAxis end if UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) then move -= Vector3.yAxis end local speed = State.flySpeed if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) then speed *= 2 end velocity.Velocity = if move.Magnitude > 0 then move.Unit * speed else Vector3.zero end) end local function applyMovement() local humanoid = getHumanoid() if not humanoid then return end if State.walkSpeedEnabled and humanoid.WalkSpeed ~= State.walkSpeed then humanoid.WalkSpeed = State.walkSpeed end if State.jumpEnabled then humanoid.UseJumpPower = true if humanoid.JumpPower ~= State.jumpPower then humanoid.JumpPower = State.jumpPower end end if State.noclip and not noclipConnection then noclipConnection = RunService.Stepped:Connect(function() local character = getCharacter() if not character then return end for _, part in ipairs(character:GetDescendants()) do if part:IsA("BasePart") and part.CanCollide then part.CanCollide = false end end end) elseif not State.noclip and noclipConnection then noclipConnection:Disconnect() noclipConnection = nil end end ----- Teleport ----- local function teleport(position: Vector3): boolean local root = getRoot() if not root then return false end root.CFrame = CFrame.new(position + Vector3.new(0, 3, 0)) return true end local function findModelByName(namePart: string): Model? for _, descendant in ipairs(workspace:GetDescendants()) do if descendant:IsA("Model") and string.find(string.lower(descendant.Name), string.lower(namePart), 1, true) then return descendant end end return nil end local function teleportToSpawn(): boolean local spawnPart = workspace:FindFirstChild("SpawnLocation") if spawnPart and spawnPart:IsA("BasePart") then return teleport(spawnPart.Position + Vector3.new(0, 2, 0)) end return false end local function teleportToKiosk(): boolean local kiosk = findModelByName("Ларёк") if kiosk then return teleport(kiosk:GetPivot().Position) end return false end local function teleportToTrain(): boolean local trains = workspace:FindFirstChild("_LocalStationTrains") or workspace:FindFirstChild("StationTrainPresentation") if trains then for _, train in ipairs(trains:GetChildren()) do if train:IsA("Model") then local pivot = train:GetPivot() if pivot.Position.Y > -20 then return teleport(pivot.Position + Vector3.new(0, 6, 0)) end end end end return false end ----- UI ----- local function toggleHandle(handle: any) if handle then handle:Set(not handle:Get()) end end local function addBind(handle: any, action: () -> ()) Binds[#Binds + 1] = { handle = handle, action = action } end local function buildUi() for key in pairs(Ui) do Ui[key] = nil end for index = #Binds, 1, -1 do Binds[index] = nil end clearEsp() local Window = Airflow:CreateWindow({ Name = "RailSide Hub", LoadingSubtitle = T("loading"), ToggleUIKeybind = "RightControl", Size = UDim2.fromOffset(780, 540), Backdrop = { Weather = "Fireflies", Tint = 0.35 }, Theme = THEME, ConfigurationSaving = { Enabled = true, FolderName = "RailSideHub" }, Home = { Title = "RailSide Hub", Welcome = "Welcome back,", Tier = "v1.1", Stats = { "Players", "Session", "FPS", "Ping", "Game", "Executor" }, }, }) Ui.window = Window ----- Main ----- local MainTab = Window:CreateTab({ Name = T("main"), Icon = "house" }) local LangBox = MainTab:CreateGroupbox({ Name = T("lang_group"), Side = "Left" }) LangBox:CreateParagraph({ Title = T("lang_group"), Content = T("lang_hint"), }) LangBox:CreateButtonRow({ { Name = T("lang_en"), Style = if Lang == "en" then "Primary" else nil, Callback = function() Hub.setLanguage("en") end, }, { Name = T("lang_ru"), Style = if Lang == "ru" then "Primary" else nil, Callback = function() Hub.setLanguage("ru") end, }, }) LangBox:CreateStatus({ Name = T("lang_status"), Style = "Row", Update = function() return if Lang == "en" then "" .. T("lang_en") .. "" else "" .. T("lang_ru") .. "" end, }) ----- Visuals ----- local VisTab = Window:CreateTab({ Name = T("visuals"), Icon = "eye" }) local EspBox = VisTab:CreateGroupbox({ Name = T("esp_group"), Side = "Left" }) local RadarBox = VisTab:CreateGroupbox({ Name = T("radar_group"), Side = "Right" }) Ui.esp = EspBox:CreateToggle({ Name = T("esp"), Desc = T("esp_desc"), Flag = "EspEnabled", CurrentValue = false, Callback = function(enabled: boolean) State.espEnabled = enabled if not enabled then clearEsp() end Hub.log(if enabled then "" .. T("esp_on") .. "" else "" .. T("esp_off") .. "") end, }) local espBind = EspBox:CreateKeybind({ Name = T("esp_bind"), Desc = T("esp_bind_desc"), CurrentKeybind = "F1", Flag = "BindEsp", }) addBind(espBind, function() toggleHandle(Ui.esp) end) EspBox:CreateDropdown({ Name = T("roles"), Desc = T("roles_desc"), Options = { "Citizens", "Anti-crouch", "Security" }, MultipleOptions = true, CurrentOption = { "Citizens", "Anti-crouch", "Security" }, Flag = "EspRoles", Callback = function(options: { string }) State.espRoles = { Citizen = table.find(options, "Citizens") ~= nil, Patrol = table.find(options, "Anti-crouch") ~= nil, TB = table.find(options, "Security") ~= nil, Unknown = true, } end, }) EspBox:CreateSlider({ Name = T("distance"), Range = { DEFAULT_ESP_DISTANCE, MAX_ESP_DISTANCE }, Increment = 50, Suffix = " m", CurrentValue = DEFAULT_ESP_DISTANCE, Flag = "EspDistance", Callback = function(value: number) State.espMaxDistance = value for _, entry in pairs(espEntries) do if entry.billboard then entry.billboard.MaxDistance = value end end end, }) EspBox:CreateToggle({ Name = T("metres"), Desc = T("metres_desc"), Flag = "EspShowDistance", CurrentValue = true, Callback = function(enabled: boolean) State.espShowDistance = enabled end, }) RadarBox:CreateStatus({ Name = T("threat"), Style = "Row", Pin = true, UpdateRate = 0.4, Update = function() if State.nearestThreatDistance == math.huge then return "" .. T("nobody") .. "" end local color = if State.nearestThreatDistance <= State.dangerRadius then "Error" else "Warning" return string.format( "<%s>%s · %s · %d m", color, State.nearestThreatName, color, ROLE_LABELS[State.nearestThreatRole] or State.nearestThreatRole, math.floor(State.nearestThreatDistance) ) end, }) RadarBox:CreateSlider({ Name = T("radius"), Range = { 15, 200 }, Increment = 5, Suffix = " m", CurrentValue = 60, Flag = "DangerRadius", Callback = function(value: number) State.dangerRadius = value end, }) RadarBox:CreateToggle({ Name = T("alert"), Desc = T("alert_desc"), Flag = "DangerAlert", CurrentValue = true, Callback = function(enabled: boolean) State.dangerAlert = enabled end, }) RadarBox:CreateToggle({ Name = T("release"), Desc = T("release_desc"), Flag = "AutoReleaseGrip", CurrentValue = false, Callback = function(enabled: boolean) State.autoReleaseOnDanger = enabled end, }) ----- Survival ----- local SurvTab = Window:CreateTab({ Name = T("survival"), Icon = "heart-pulse" }) local AutoBox = SurvTab:CreateGroupbox({ Name = T("auto_group"), Side = "Left" }) local StatusBox = SurvTab:CreateGroupbox({ Name = T("status_group"), Side = "Right" }) AutoBox:CreateToggle({ Name = T("panic"), Desc = T("panic_desc"), Flag = "AutoPanic", CurrentValue = false, Callback = function(enabled: boolean) State.autoPanic = enabled end, }) AutoBox:CreateToggle({ Name = T("cola"), Desc = T("cola_desc"), Flag = "AutoDrink", CurrentValue = false, Callback = function(enabled: boolean) State.autoDrink = enabled end, }) AutoBox:CreateToggle({ Name = T("bandage"), Desc = T("bandage_desc"), Flag = "AutoBandage", CurrentValue = false, Callback = function(enabled: boolean) State.autoBandage = enabled end, }) AutoBox:CreateToggle({ Name = T("pills"), Desc = T("pills_desc"), Flag = "AutoPills", CurrentValue = false, Callback = function(enabled: boolean) State.autoPills = enabled end, }) StatusBox:CreateStatus({ Name = T("coins"), Style = "Row", UpdateRate = 0.5, Update = function() local coins = tonumber(attributeOf(LocalPlayer, "ZcpCoins")) or 0 return string.format("%d ZCP", coins) end, }) StatusBox:CreateStatus({ Name = T("stamina"), Style = "Bar", Max = 100, UpdateRate = 0.4, Update = function() return tonumber(attributeOf(LocalPlayer, "Stamina")) or 100 end, }) StatusBox:CreateStatus({ Name = T("fear"), Style = "Bar", Max = 100, UpdateRate = 0.4, Update = function() return tonumber(attributeOf(LocalPlayer, "Fear")) or 0 end, }) StatusBox:CreateStatus({ Name = T("sanity"), Style = "Bar", Max = 100, UpdateRate = 0.4, Update = function() return tonumber(attributeOf(LocalPlayer, "Sanity")) or 100 end, }) StatusBox:CreateStatus({ Name = T("injuries"), Style = "Row", UpdateRate = 1, Update = function() local count = injuryCount(LocalPlayer) if count == 0 then return "" .. T("none") .. "" end return string.format("%d", count) end, }) ----- Movement ----- local MoveTab = Window:CreateTab({ Name = T("movement"), Icon = "move" }) local SpeedBox = MoveTab:CreateGroupbox({ Name = T("speed_group"), Side = "Left" }) local TeleportBox = MoveTab:CreateGroupbox({ Name = T("teleport_group"), Side = "Right" }) Ui.walk = SpeedBox:CreateToggle({ Name = T("walk"), Desc = T("walk_desc"), Flag = "WalkSpeedEnabled", CurrentValue = false, Callback = function(enabled: boolean) State.walkSpeedEnabled = enabled end, }) addBind(SpeedBox:CreateKeybind({ Name = T("walk_bind"), CurrentKeybind = "F2", Flag = "BindWalk", }), function() toggleHandle(Ui.walk) end) SpeedBox:CreateSlider({ Name = T("walk_value"), Range = { 16, 120 }, Increment = 1, CurrentValue = 34, Flag = "WalkSpeedValue", DependsOn = "WalkSpeedEnabled", Callback = function(value: number) State.walkSpeed = value end, }) Ui.jump = SpeedBox:CreateToggle({ Name = T("jump"), Desc = T("jump_desc"), Flag = "JumpEnabled", CurrentValue = false, Callback = function(enabled: boolean) State.jumpEnabled = enabled local humanoid = getHumanoid() if humanoid and not enabled then humanoid.JumpPower = 0 end end, }) addBind(SpeedBox:CreateKeybind({ Name = T("jump_bind"), CurrentKeybind = "F3", Flag = "BindJump", }), function() toggleHandle(Ui.jump) end) SpeedBox:CreateSlider({ Name = T("jump_value"), Range = { 20, 120 }, Increment = 5, CurrentValue = 50, Flag = "JumpValue", DependsOn = "JumpEnabled", Callback = function(value: number) State.jumpPower = value end, }) Ui.noclip = SpeedBox:CreateToggle({ Name = T("noclip"), Desc = T("noclip_desc"), Flag = "Noclip", CurrentValue = false, Callback = function(enabled: boolean) State.noclip = enabled end, }) addBind(SpeedBox:CreateKeybind({ Name = T("noclip_bind"), CurrentKeybind = "F4", Flag = "BindNoclip", }), function() toggleHandle(Ui.noclip) end) Ui.fly = SpeedBox:CreateToggle({ Name = T("fly"), Desc = T("fly_desc"), Flag = "Fly", CurrentValue = false, Callback = function(enabled: boolean) State.fly = enabled if enabled then task.spawn(startFly) else task.spawn(stopFly) end end, }) addBind(SpeedBox:CreateKeybind({ Name = T("fly_bind"), CurrentKeybind = "F5", Flag = "BindFly", }), function() toggleHandle(Ui.fly) end) SpeedBox:CreateSlider({ Name = T("fly_speed"), Range = { 20, 300 }, Increment = 5, CurrentValue = 60, Flag = "FlySpeed", DependsOn = "Fly", Callback = function(value: number) State.flySpeed = value end, }) TeleportBox:CreateButton({ Name = T("to_spawn"), Icon = "map-pin", Callback = function() if teleportToSpawn() then Hub.log("" .. T("teleported") .. "") else Hub.log("" .. T("not_found") .. "") end end, }) TeleportBox:CreateButton({ Name = T("to_shop"), Icon = "shopping-basket", Callback = function() if teleportToKiosk() then Hub.log("" .. T("teleported") .. "") else Hub.log("" .. T("not_found") .. "") end end, }) TeleportBox:CreateButton({ Name = T("to_train"), Icon = "train-front", Callback = function() if teleportToTrain() then Hub.log("" .. T("teleported") .. "") else Hub.log("" .. T("not_found") .. "") end end, }) TeleportBox:CreateButton({ Name = T("respawn"), Icon = "rotate-ccw", Confirm = true, Callback = function() fire(Remotes.Reset) end, }) ----- Logs ----- local LogsTab = Window:CreateTab({ Name = T("logs"), Icon = "scroll-text" }) local LogsBox = LogsTab:CreateGroupbox({ Name = T("log_group"), Side = "Left" }) Ui.log = LogsBox:CreateLog({ Name = T("log_group"), MaxEntries = 300, MaxRows = 16, Timestamps = true, EmptyText = "", }) ----- Settings ----- local SettingsTab = Window:CreateTab({ Name = T("settings"), Icon = "settings" }) SettingsTab:CreateConfigManager({ Name = "Configs", Side = "Left" }) SettingsTab:CreateThemeManager({ Name = "Theme", Side = "Right" }) local AboutBox = LogsTab:CreateGroupbox({ Name = T("about_group"), Side = "Right" }) AboutBox:CreateParagraph({ Title = "RailSide Hub", Content = T("about_text"), }) AboutBox:CreateButton({ Name = T("unload"), Icon = "trash-2", Style = "Primary", Confirm = true, Callback = function() clearEsp() stopFly() if noclipConnection then noclipConnection:Disconnect() noclipConnection = nil end if Ui.window then Ui.window:Destroy() Ui.window = nil end Ui.log = nil local registry = getgenv() if registry then registry.RailSideHub = nil end end, }) Window:LoadAutoload() Window:SelectTab(MainTab) end function Hub.log(text: string) if Ui.log then Ui.log:Push(text) end end function Hub.notify(title: string, content: string, kind: string?) if Ui.window then Ui.window:Notify({ Title = title, Content = content, Type = kind or "Info" }) end end function Hub.setLanguage(language: string) if language == Lang or (TEXT[language] == nil) then return end Lang = language if Ui.window then pcall(function() Ui.window:Destroy() end) end buildUi() Hub.log("" .. T("loaded") .. "") end ----- Keybinds ----- UserInputService.InputBegan:Connect(function(input: InputObject, gameProcessed: boolean) if gameProcessed then return end if input.UserInputType ~= Enum.UserInputType.Keyboard then return end for _, bind in ipairs(Binds) do local handle = bind.handle if handle and not handle.Listening and handle.Value == input.KeyCode then task.spawn(bind.action) end end end) ----- Master loop ----- local accumulator = 0 local espWasEnabled = false local fearHeld = false RunService.Heartbeat:Connect(function(deltaTime: number) accumulator += deltaTime if accumulator < 0.15 then return end accumulator = 0 if State.espEnabled and not espWasEnabled then espWasEnabled = true elseif not State.espEnabled and espWasEnabled then espWasEnabled = false clearEsp() end updateEsp() local distance, threat, threatRole = nearestThreat() State.nearestThreatDistance = distance State.nearestThreatName = if threat then threat.Name else "-" State.nearestThreatRole = threatRole local now = os.clock() local inDanger = threat ~= nil and distance <= State.dangerRadius if inDanger and State.dangerAlert and now - State.lastThreatNotice > 6 then State.lastThreatNotice = now beep() Hub.notify( T("danger"), string.format("%s (%s) — %d m", threat.Name, ROLE_LABELS[threatRole] or threatRole, math.floor(distance)), "Warning" ) end if inDanger and State.autoReleaseOnDanger and now - State.lastReleaseAt > 2 then State.lastReleaseAt = now fire(Remotes.GripRelease) end local frozen = attributeOf(LocalPlayer, "StationFearFrozen") == true local fearEffect = tonumber(attributeOf(LocalPlayer, "StationFearEffect")) or 0 local fearUntil = tonumber(attributeOf(LocalPlayer, "StationFearEffectUntil")) or 0 if State.autoPanic then local shouldHold = frozen or (fearEffect > 0 and workspace:GetServerTimeNow() < fearUntil) if shouldHold and not fearHeld then fearHeld = true fire(Remotes.FearResist, true) elseif not shouldHold and fearHeld then fearHeld = false fire(Remotes.FearResist, false) end elseif fearHeld then fearHeld = false fire(Remotes.FearResist, false) end if State.autoDrink and now - State.lastDrinkAt > 8 then local stamina = tonumber(attributeOf(LocalPlayer, "Stamina")) or 100 local cola = tonumber(attributeOf(LocalPlayer, "ShopCola")) or 0 if stamina < 35 and cola > 0 then State.lastDrinkAt = now fire(Remotes.Drink) end end if State.autoBandage and now - State.lastBandageAt > 15 and injuryCount(LocalPlayer) > 0 then local coins = tonumber(attributeOf(LocalPlayer, "ZcpCoins")) or 0 if coins >= BANDAGE_PRICE then State.lastBandageAt = now task.spawn(function() invokeShop("buy", "Bandage") end) end end if State.autoPills and now - State.lastPillsAt > 25 then local fear = tonumber(attributeOf(LocalPlayer, "Fear")) or 0 local sanity = tonumber(attributeOf(LocalPlayer, "Sanity")) or 100 local coins = tonumber(attributeOf(LocalPlayer, "ZcpCoins")) or 0 if (fear >= 40 or sanity <= 60) and coins >= PILLS_PRICE then State.lastPillsAt = now task.spawn(function() invokeShop("buy", "Pills") end) end end end) RunService.Heartbeat:Connect(applyMovement) LocalPlayer.CharacterAdded:Connect(function() stopFly() State.fly = false task.delay(1, applyMovement) end) ----- Public API ----- Hub.state = State Hub.lang = function(): string return Lang end Hub.esp = function(enabled: boolean?) if not Ui.esp then return end local target = if enabled == nil then not Ui.esp:Get() else enabled if Ui.esp:Get() ~= target then Ui.esp:Set(target) end end Hub.teleport = teleport Hub.toSpawn = teleportToSpawn Hub.toKiosk = teleportToKiosk Hub.toTrain = teleportToTrain Hub.threat = nearestThreat Hub.stopFly = stopFly Hub.binds = Binds getgenv().RailSideHub = Hub ----- Boot ----- buildUi() Hub.log("RailSide Hub " .. T("loaded")) Hub.notify("RailSide Hub", T("ready") .. " " .. T("where_lang"), "Success") pcall(function() StarterGui:SetCore("SendNotification", { Title = "RailSide Hub", Text = T("ready"), Duration = 4, }) end)