--!nonstrict
--[[
Star Fishing Hub
----------------
A single-file helper for Star Fishing:
1. Auto fishing
1.1 Perfect casts only - releases the cast at the top of the charge bar
1.2 Auto reel - holds the reel until every star is in
2. Selling stars with filters (rarity and star type)
Press RightControl to show or hide the window.
Everything starts off. Settings are saved in the StarFishingHub folder.
]]
----------------------------------------------------------------------
-- 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
for _, url in ipairs(UI_SOURCES) do
local ok, lib = pcall(function()
return loadstring(game:HttpGet(url))()
end)
if ok and type(lib) == "table" and type(lib.CreateWindow) == "function" then
Airflow = lib
break
end
end
if not Airflow then
error("[Star Fishing Hub] The UI library could not be loaded. Check your connection and retry.")
end
----------------------------------------------------------------------
-- Game access
----------------------------------------------------------------------
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LocalPlayer = Players.LocalPlayer
local Events = ReplicatedStorage:WaitForChild("Events", 30)
if not Events then
error("[Star Fishing Hub] This script only works in Star Fishing.")
end
local Data = Events:WaitForChild("Data", 30)
local LocalEvents = Events:WaitForChild("Local", 30)
local PlayerGui = LocalPlayer:WaitForChild("PlayerGui", 30)
local UseRodButton = LocalEvents:WaitForChild("UseRodButton", 30)
local GetStars = Data:WaitForChild("GetStars", 30)
local GetMoney = Data:WaitForChild("GetMoney", 30)
local ClientFavouriteItem = Data:WaitForChild("ClientFavouriteItem", 30)
local StarModule
pcall(function()
StarModule = require(ReplicatedStorage:WaitForChild("Scripts"):WaitForChild("Star"))
end)
----------------------------------------------------------------------
-- Helpers
----------------------------------------------------------------------
local function short(value)
if type(value) ~= "number" then
return "-"
end
local text = tostring(math.floor(value))
local grouped = text:reverse():gsub("(%d%d%d)", "%1 "):reverse()
return (grouped:gsub("^%s+", ""))
end
local function character()
local char = LocalPlayer.Character
if char and char.Parent then
return char
end
return nil
end
local function rootPosition()
local char = character()
if not char then
return nil
end
local root = char:FindFirstChild("HumanoidRootPart")
return root and root.Position or nil
end
local function goTo(position)
local char = character()
if not char then
return
end
pcall(function()
char:PivotTo(CFrame.new(position))
end)
end
local function rodTool()
local char = character()
if not char then
return nil
end
local inHand = char:FindFirstChild("Rod")
if inHand then
return inHand
end
local backpack = LocalPlayer:FindFirstChildOfClass("Backpack")
local stored = backpack and backpack:FindFirstChild("Rod")
if stored then
local hum = char:FindFirstChildOfClass("Humanoid")
if hum then
pcall(function()
hum:EquipTool(stored)
end)
task.wait(0.4)
return char:FindFirstChild("Rod")
end
end
return nil
end
local function rodGui()
local gui = PlayerGui:FindFirstChild("RodGui")
if gui and gui.Enabled then
return gui
end
return nil
end
local function inventoryFull()
local gui = PlayerGui:FindFirstChild("RodGui")
local flag = gui and gui.Frame:FindFirstChild("InventoryFull")
return flag ~= nil and flag.Visible == true
end
local function stars()
local ok, list = pcall(function()
return GetStars:InvokeServer()
end)
if ok and type(list) == "table" then
return list
end
return {}
end
local function money()
local ok, value = pcall(function()
return GetMoney:InvokeServer()
end)
return ok and tonumber(value) or 0
end
local function starRarity(name)
if StarModule then
local data = StarModule.Data and StarModule.Data[name]
if data and data.Rarity then
return data.Rarity
end
end
return "Unknown"
end
local function starValue(name)
if StarModule and type(StarModule.getSellValue) == "function" then
local ok, value = pcall(StarModule.getSellValue, name)
if ok and type(value) == "number" then
return value
end
end
return 0
end
----------------------------------------------------------------------
-- Settings
----------------------------------------------------------------------
local Settings = {
-- fishing
fishingOn = false,
perfectFlair = true,
castDelay = 0.35,
ignoreFull = false,
-- selling
keepFavourites = true,
sellRarities = {},
sellTypes = {},
dryRun = true,
autoSellOnFull = true,
}
local Window, Log
local UiRefs = {}
local function log(message, color)
if Log then
Log:Push(tostring(message), color)
end
end
local function notify(title, content, kind)
pcall(function()
Window:Notify({ Title = title, Content = content, Type = kind or "Info", Duration = 4 })
end)
end
getgenv().__StarFishingGen = (getgenv().__StarFishingGen or 0) + 1
local SCRIPT_GENERATION = getgenv().__StarFishingGen
local function scriptAlive()
return getgenv().__StarFishingGen == SCRIPT_GENERATION
end
local loops = {}
local function startLoop(name, step)
loops[name] = (loops[name] or 0) + 1
local mine = loops[name]
task.spawn(function()
while loops[name] == mine and scriptAlive() do
local ok, err = pcall(step)
if not ok then
log("" .. name .. ": " .. tostring(err) .. "")
task.wait(1)
end
if loops[name] ~= mine then
break
end
task.wait(0.05)
end
end)
end
local function stopLoop(name)
loops[name] = (loops[name] or 0) + 1
end
----------------------------------------------------------------------
-- 1. FISHING
----------------------------------------------------------------------
local GlobalEvents = Events:WaitForChild("Global", 30)
local NewFishing = GlobalEvents and GlobalEvents:WaitForChild("NewFishing", 30)
local ClientRecieveItems = GlobalEvents and GlobalEvents:WaitForChild("ClientRecieveItems", 30)
local fishStats = {
casts = 0,
catches = 0,
misses = 0,
startedAt = 0,
lastLog = 0,
}
--- Plays the same little flourish the game shows on a perfect cast.
local function perfectFlair()
local sounds = ReplicatedStorage:FindFirstChild("Sounds")
local cast = sounds and sounds:FindFirstChild("PerfectCast")
if cast then
local ok, clone = pcall(function()
local copy = cast:Clone()
copy.Parent = workspace.CurrentCamera
copy:Play()
game:GetService("Debris"):AddItem(copy, 3)
return copy
end)
end
pcall(function()
local dialogue = ReplicatedStorage:FindFirstChild("Dialogue")
local ev = dialogue and dialogue:FindFirstChild("Events")
local localEv = ev and ev:FindFirstChild("Local")
local speech = localEv and localEv:FindFirstChild("ClientSpeech")
if speech then
speech:Fire("Perfect!!!", Color3.new(1, 0.7768, 0.0013))
end
end)
end
--- One full cast, driven through the game's own events.
--- The game decides the catch when the cast is sent, then expects us to ask for
--- each star at its own pace. Doing it this way keeps working even if the rod's
--- own animation script has given up.
local function serverCast()
local char = character()
local hum = char and char:FindFirstChildOfClass("Humanoid")
local root = char and char:FindFirstChild("HumanoidRootPart")
local rod = rodTool()
local tip = rod and rod:FindFirstChild("Model")
local nodes = tip and tip:FindFirstChild("Nodes")
local rodTip = nodes and nodes:FindFirstChild("RodTip")
local attachment = rodTip and rodTip:FindFirstChild("Attachment")
if not (hum and root and attachment) then
return false, 0, "Rod is not in hand"
end
local answer
local connection = ClientRecieveItems.OnClientEvent:Connect(function(ok, position, castId, stars, model, timers)
answer = { ok = ok, castId = castId, stars = stars, timers = timers }
end)
NewFishing.CastRod:FireServer(hum, root.CFrame.Position, root.CFrame.LookVector, attachment)
local deadline = os.clock() + 6
while not answer and os.clock() < deadline do
task.wait(0.05)
end
if not answer then
connection:Disconnect()
return false, 0, "The game did not answer"
end
if not answer.ok or not answer.stars or #answer.stars == 0 then
connection:Disconnect()
return false, 0, "Nothing bit"
end
for index, star in ipairs(answer.stars) do
local waitTime = tonumber((answer.timers or {})[index]) or tonumber(star.interval) or 0.2
task.wait(math.clamp(waitTime, 0.05, 3))
NewFishing.RequestSpawn:FireServer(star.castID, star.starID)
end
task.wait(0.15)
GlobalEvents.WithdrawBobber:FireServer(hum)
connection:Disconnect()
return true, #answer.stars
end
--- The rod the game thinks is equipped. Needed when the rod's own script died,
--- because the server then never hears that a rod was put in hand.
local rodName = nil
task.spawn(function()
local updates = Data:FindFirstChild("UpdateClientRodsBobbers")
if not updates then
return
end
local connection
connection = updates.OnClientEvent:Connect(function(rods)
for _, rod in ipairs(rods or {}) do
if rod.isCurrentRod then
rodName = rod.name
end
end
end)
pcall(function()
updates:FireServer()
end)
task.wait(3)
connection:Disconnect()
end)
--- Puts the game back into a clean casting state.
local function recoverRod()
local char = character()
local hum = char and char:FindFirstChildOfClass("Humanoid")
rodTool()
if rodName then
pcall(function()
Data.Rods.RodEquipAbility:FireServer(true, rodName)
end)
end
if hum then
pcall(function()
GlobalEvents.WithdrawBobber:FireServer(hum)
end)
end
task.wait(0.5)
end
--- Set once the selling tab is built. Used when the backpack fills up mid-run.
local autoSellHook: (() -> number)? = nil
local function fishingStep()
if not character() then
return
end
if inventoryFull() then
if Settings.autoSellOnFull and autoSellHook then
local spot = rootPosition()
log("Backpack is full - selling the catch")
autoSellHook()
if spot then
goTo(spot)
task.wait(0.6)
end
return
end
if not Settings.ignoreFull then
if os.clock() - (fishStats.lastLog or 0) > 5 then
fishStats.lastLog = os.clock()
log("Backpack is full - sell some stars first")
end
task.wait(1)
return
end
end
local ok, count, reason = serverCast()
if ok then
fishStats.casts += 1
fishStats.catches += count
fishStats.missStreak = 0
if Settings.perfectFlair then
perfectFlair()
end
log(string.format("Cast %d: %d star(s)", fishStats.casts, count))
else
fishStats.misses += 1
fishStats.missStreak = (fishStats.missStreak or 0) + 1
-- A few misses in a row usually means the rod state is stale: put the rod
-- away and back, and tell the game which rod is equipped again.
if fishStats.missStreak == 3 or fishStats.missStreak == 8 then
recoverRod()
end
if fishStats.missStreak == 8 then
log("Nothing is biting at all - if it stays like this, rejoin the server")
elseif os.clock() - (fishStats.lastLog or 0) > 3 then
fishStats.lastLog = os.clock()
log("" .. tostring(reason) .. "")
end
task.wait(0.6)
end
task.wait(Settings.castDelay or 0.35)
end
local function fishingSet(on)
Settings.fishingOn = on
if on then
fishStats.startedAt = os.clock()
startLoop("Fishing", fishingStep)
log("Auto fishing on")
else
stopLoop("Fishing")
log("Auto fishing off")
end
if UiRefs and UiRefs.fishing then
UiRefs.fishing:Set(on, true)
end
end
----------------------------------------------------------------------
-- 2. SELLING
----------------------------------------------------------------------
local sellStats = { lastValue = 0, lastCount = 0, soldTotal = 0, moneyTotal = 0 }
local function rarityList()
local seen = {}
for _, star in ipairs(stars()) do
seen[starRarity(star.name)] = true
end
local list = {}
for rarity in pairs(seen) do
table.insert(list, rarity)
end
table.sort(list)
return list
end
local function typeList()
local seen = {}
for _, star in ipairs(stars()) do
if star.name then
seen[star.name] = true
end
end
local list = {}
for name in pairs(seen) do
table.insert(list, name)
end
table.sort(list)
return list
end
local function allowed(star)
if next(Settings.sellRarities) ~= nil and not Settings.sellRarities[starRarity(star.name)] then
return false
end
if next(Settings.sellTypes) ~= nil and not Settings.sellTypes[star.name] then
return false
end
if Settings.keepFavourites and star.isFavourite then
return false
end
return true
end
--- Stars that match the filters right now.
local function matchingStars()
local picked = {}
for _, star in ipairs(stars()) do
if allowed(star) then
local value = starValue(star.name) * (tonumber(star.size) or 1)
table.insert(picked, { star = star, value = value })
end
end
return picked
end
local function totalValue(picked)
local total = 0
for _, entry in ipairs(picked) do
total += entry.value
end
return total
end
----------------------------------------------------------------------
-- Merchant: the free way to sell stars
----------------------------------------------------------------------
local DialogueGlobal = ReplicatedStorage:WaitForChild("Dialogue", 30)
local DialogueEvents = DialogueGlobal
and DialogueGlobal:WaitForChild("Events", 30)
and DialogueGlobal.Events:WaitForChild("Global", 30)
local PresentOptions = DialogueEvents and DialogueEvents:WaitForChild("PresentClientDialogueOptions", 30)
local ChooseOption = DialogueEvents and DialogueEvents:WaitForChild("ClientChoosesDialogueOption", 30)
local function starMerchant()
local npcs = workspace:FindFirstChild("NonPlayableCharacters")
local npc = npcs and npcs:FindFirstChild("Star Merchant")
if not npc then
return nil, nil
end
local prompt
for _, d in ipairs(npc:GetDescendants()) do
if d:IsA("ProximityPrompt") then
prompt = d
break
end
end
return npc, prompt
end
--- Opens the merchant and returns the dialogue options he offers.
local function merchantOptions()
local npc, prompt = starMerchant()
if not (npc and prompt and PresentOptions) then
return nil
end
goTo(npc:GetPivot().Position + Vector3.new(0, 0, 4))
task.wait(1)
local captured
local connection = PresentOptions.OnClientEvent:Connect(function(_, _, options)
if type(options) == "table" and #options > 0 then
captured = options
end
end)
for _ = 1, 3 do
if captured then
break
end
pcall(function()
prompt:InputHoldBegin()
task.wait(math.max(0.2, (prompt.HoldDuration or 0) + 0.2))
prompt:InputHoldEnd()
end)
task.wait(1.4)
end
connection:Disconnect()
return captured
end
--- Sells everything the merchant will take. Favourites are skipped by the game.
local function sellEverything()
if not ChooseOption then
log("Dialogue system not found")
return 0
end
local options = merchantOptions()
if not options then
log("Could not reach the Star Merchant")
return 0
end
local sellAll
for _, option in ipairs(options) do
if option.id == "sell-all" then
sellAll = option
end
end
if not sellAll then
log("The merchant has nothing to buy right now")
return 0
end
local before = money()
ChooseOption:FireServer(sellAll)
task.wait(3)
local gained = math.max(0, money() - before)
if gained > 0 then
sellStats.soldTotal += 1
sellStats.moneyTotal += gained
log("Sold the catch for " .. short(gained) .. "")
else
log("Nothing was sold")
end
return gained
end
local saleBusy = false
--- Sells everything that matches the filters, protecting the rest with
--- favourites. Used by the Sell button and by the auto sell when the bag fills.
local function performSale()
if saleBusy then
return 0
end
local picked = matchingStars()
if #picked == 0 then
log("Nothing matches the filters - the bag will stay full")
return 0
end
saleBusy = true
-- The merchant buys the whole backpack at once, so everything that has to
-- stay is marked as a favourite first - the game never sells favourites.
-- Whatever we mark is un-marked again after the sale.
local marked = {}
local all = stars()
if #picked < #all and Settings.keepFavourites then
for _, entry in ipairs(all) do
if not allowed(entry) and not entry.isFavourite then
pcall(function()
ClientFavouriteItem:FireServer(entry.id)
end)
table.insert(marked, entry.id)
task.wait(0.03)
end
end
if #marked > 0 then
log("Protected " .. #marked .. " star(s) you wanted to keep")
task.wait(1)
end
end
local gained = sellEverything()
for _, id in ipairs(marked) do
pcall(function()
ClientFavouriteItem:FireServer(id)
end)
task.wait(0.02)
end
saleBusy = false
return gained
end
-- Lets the fishing loop sell when the backpack fills up.
autoSellHook = performSale
----------------------------------------------------------------------
-- WINDOW
----------------------------------------------------------------------
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)
Window = Airflow:CreateWindow({
Name = "Star Fishing Hub",
LoadingSubtitle = "casts, reels, sells",
ToggleUIKeybind = "RightControl",
Size = UDim2.fromOffset(780, 540),
Backdrop = { Weather = "Fireflies", Tint = 0.35 },
Theme = THEME,
ConfigurationSaving = { Enabled = true, FolderName = "StarFishingHub" },
Home = {
Title = "Star Fishing Hub",
Welcome = "Welcome back,",
Tier = "v1.0",
Stats = { "Players", "Session", "FPS", "Ping", "Game", "Executor" },
},
})
local LogTab = Window:CreateTab({ Name = "Logs", Icon = "scroll-text" })
local LogBox = LogTab:CreateGroupbox({ Name = "What the script is doing", Side = "Left" })
Log = LogBox:CreateLog({
Name = "Activity",
MaxEntries = 300,
MaxRows = 14,
Timestamps = true,
EmptyText = "Nothing yet",
})
----------------------------------------------------------------------
-- FISHING TAB
----------------------------------------------------------------------
local UiRefs = {}
local FishingTab = Window:CreateTab({ Name = "Fishing", Icon = "fish" })
local FishMain = FishingTab:CreateGroupbox({ Name = "Auto fishing", Side = "Left" })
local FishInfo = FishingTab:CreateGroupbox({ Name = "Status", Side = "Right" })
local FishFine = FishingTab:CreateGroupbox({ Name = "Fine tuning", Side = "Right" })
UiRefs.fishing = FishMain:CreateToggle({
Name = "Auto fishing",
Desc = "Casts non-stop and collects every star the game sends back",
Flag = "FishingOn",
CurrentValue = false,
Callback = function(on)
fishingSet(on)
end,
})
FishMain:CreateToggle({
Name = "Perfect cast flair",
Desc = "Shows the game's Perfect!!! effect on every cast (visual only)",
Flag = "PerfectFlair",
CurrentValue = true,
Callback = function(on)
Settings.perfectFlair = on
end,
})
FishMain:CreateToggle({
Name = "Keep going when the bag is full",
Desc = "The game stops handing out stars when the bag is full - turn this on only if you want to risk it",
Flag = "IgnoreFull",
CurrentValue = false,
Callback = function(on)
Settings.ignoreFull = on
end,
})
FishMain:CreateButton({
Name = "Equip the rod",
Icon = "hand",
Callback = function()
rodTool()
log("Rod equipped")
end,
})
FishMain:CreateButton({
Name = "Cast once",
Icon = "fish",
Callback = function()
task.spawn(function()
local ok, count, reason = serverCast()
if ok then
log(string.format("Cast: %d star(s)", count))
if Settings.perfectFlair then
perfectFlair()
end
else
log("" .. tostring(reason) .. "")
end
end)
end,
})
FishFine:CreateSlider({
Name = "Pause between casts",
Range = { 0.1, 3 },
Increment = 0.05,
Suffix = " s",
CurrentValue = 0.35,
Flag = "CastDelay",
Callback = function(value)
Settings.castDelay = value
end,
})
FishInfo:CreateStatus({
Name = "Casts",
Style = "Row",
Pin = true,
Update = function()
return tostring(fishStats.casts)
end,
})
FishInfo:CreateStatus({
Name = "Stars caught",
Style = "Row",
Update = function()
return "" .. tostring(fishStats.catches) .. ""
end,
})
FishInfo:CreateStatus({
Name = "Per hour",
Style = "Row",
Update = function()
local seconds = os.clock() - (fishStats.startedAt or os.clock())
if seconds < 5 or fishStats.catches == 0 then
return "-"
end
return short(fishStats.catches * (3600 / seconds))
end,
})
FishInfo:CreateStatus({
Name = "Inventory",
Style = "Row",
Update = function()
return inventoryFull() and "full" or "ok"
end,
})
FishInfo:CreateParagraph({
Title = "How fishing works",
Content = "The script casts, collects every star the game sends back and starts again. "
.. "It talks to the game directly, so a stuck rod animation cannot block it. "
.. "The Perfect!!! text and sound are a visual effect the game shows on a full-charge cast - "
.. "it does not change what bites, and the script can show it on every cast.",
})
----------------------------------------------------------------------
-- SELLING TAB
----------------------------------------------------------------------
local SellTab = Window:CreateTab({ Name = "Selling", Icon = "coins" })
local SellFilters = SellTab:CreateGroupbox({ Name = "Filters", Side = "Left" })
local SellAction = SellTab:CreateGroupbox({ Name = "Sell", Side = "Right" })
local SellInfo = SellTab:CreateGroupbox({ Name = "Status", Side = "Right" })
UiRefs.rarityDropdown = SellFilters:CreateDropdown({
Name = "Rarities to sell",
Desc = "Empty means every rarity",
Options = {},
MultipleOptions = true,
Searchable = true,
Flag = "SellRarities",
Callback = function(selected)
local map = {}
for _, rarity in ipairs(selected or {}) do
map[tostring(rarity)] = true
end
Settings.sellRarities = map
end,
})
UiRefs.typeDropdown = SellFilters:CreateDropdown({
Name = "Star types to sell",
Desc = "Empty means every type",
Options = {},
MultipleOptions = true,
Searchable = true,
Flag = "SellTypes",
Callback = function(selected)
local map = {}
for _, name in ipairs(selected or {}) do
map[tostring(name)] = true
end
Settings.sellTypes = map
end,
})
SellFilters:CreateToggle({
Name = "Never sell favourites",
Flag = "KeepFavourites",
CurrentValue = true,
Callback = function(on)
Settings.keepFavourites = on
end,
})
SellFilters:CreateToggle({
Name = "Dry run only",
Desc = "Shows what would be sold without selling",
Flag = "DryRun",
CurrentValue = true,
Callback = function(on)
Settings.dryRun = on
end,
})
SellFilters:CreateToggle({
Name = "Sell when the bag is full",
Desc = "Auto fishing sells the filtered catch for real when the backpack fills up (dry run is ignored)",
Flag = "AutoSellFull",
CurrentValue = true,
Callback = function(on)
Settings.autoSellOnFull = on
log(on and "Auto sell when full is on" or "Auto sell when full is off")
end,
})
SellAction:CreateButton({
Name = "Preview the selection",
Icon = "eye",
Callback = function()
task.spawn(function()
local picked = matchingStars()
sellStats.lastCount = #picked
sellStats.lastValue = totalValue(picked)
log(string.format("Selected %d star(s), about %s", #picked, short(sellStats.lastValue)))
end)
end,
})
SellAction:CreateButton({
Name = "Sell now",
Icon = "hand-coins",
Style = "Primary",
Callback = function()
task.spawn(function()
local picked = matchingStars()
if #picked == 0 then
log("Nothing matches the filters")
return
end
if Settings.dryRun then
log("[dry run] would sell " .. #picked .. " star(s) worth about " .. short(totalValue(picked)))
return
end
performSale()
end)
end,
})
SellInfo:CreateStatus({
Name = "Stars",
Style = "Row",
Pin = true,
Update = function()
return tostring(#stars())
end,
})
SellInfo:CreateStatus({
Name = "Selected",
Style = "Row",
Update = function()
local picked = matchingStars()
return #picked .. " / " .. short(totalValue(picked))
end,
})
SellInfo:CreateStatus({
Name = "Cash",
Style = "Row",
Update = function()
return "" .. short(money()) .. ""
end,
})
SellInfo:CreateParagraph({
Title = "How selling works",
Content = "Pick the rarities or star types you are happy to lose, then press Sell. "
.. "The Star Merchant buys in bulk, so the script marks everything you want to keep as a favourite "
.. "first - the game never sells favourites. Keep Dry run on until the preview looks right.",
})
----------------------------------------------------------------------
-- SETTINGS
----------------------------------------------------------------------
local SettingsTab = Window:CreateTab({ Name = "Settings", Icon = "settings" })
SettingsTab:CreateConfigManager({ Name = "Configs", Side = "Left" })
SettingsTab:CreateThemeManager({ Name = "Theme", Side = "Right" })
local HelpBox = SettingsTab:CreateGroupbox({ Name = "Quick guide", Side = "Right" })
HelpBox:CreateParagraph({
Title = "Star Fishing Hub",
Content = "Fishing: holds the rod, releases at the top of the charge bar and reels everything in.\n"
.. "Selling: filters by rarity or star type, keeps favourites, sells at the Star Merchant.\n\n"
.. "Everything starts off. RightControl hides the window.",
})
----------------------------------------------------------------------
-- Start
----------------------------------------------------------------------
task.spawn(function()
-- Fill the filter lists once the player data is in.
local deadline = os.clock() + 30
while os.clock() < deadline do
local rarities = rarityList()
if #rarities > 0 then
UiRefs.rarityDropdown:SetOptions(rarities, { KeepSelection = true })
UiRefs.typeDropdown:SetOptions(typeList(), { KeepSelection = true })
break
end
task.wait(1)
end
pcall(function()
Window:LoadAutoload()
end)
log("Loaded - " .. #stars() .. " stars, " .. short(money()) .. " cash")
end)
print("[Star Fishing Hub] loaded")