local VotingHandlerServer = {} local ReplicatedStorage = game:GetService("ReplicatedStorage") local Players = game:GetService("Players") local Data = ReplicatedStorage:WaitForChild("Data") local OptionsData = require(Data:WaitForChild("OptionsData")) local Remote = ReplicatedStorage:WaitForChild("Remote") local rev_Vote = Remote:WaitForChild("Vote") local rev_StartVote = Remote:WaitForChild("StartVote") local rev_EndVote = Remote:WaitForChild("EndVote") local alreadyVoted = {} -- userId -> option local voteCounts = {} -- option -> count local currentOptions = {} local moduleData = nil local activeConnections = {} local touchDebounce = {} -- cleanup local function cleanupConnections() for _, conn in ipairs(activeConnections) do if conn then conn:Disconnect() end end table.clear(activeConnections) end -- pick random KEYS from dictionary local function pickRandomOptions(source, count) local keys = {} for key in pairs(source) do table.insert(keys, key) end local selected = {} for i = 1, math.min(count, #keys) do local index = math.random(1, #keys) table.insert(selected, keys[index]) table.remove(keys, index) end return selected end -- results local function calculateResults() local results = {} for _, option in ipairs(currentOptions) do results[option] = voteCounts[option] or 0 end return results end -- update stands local function updateVotingStands(votingStands, results) if not votingStands then return end for index, stand in ipairs(votingStands) do local option = currentOptions[index] if not option then continue end local data = moduleData[option] local gui = stand:FindFirstChild("IndicatorPart") if gui then gui = gui:FindFirstChild("VoteGui") end if not gui then continue end local votesLabel = gui:FindFirstChild("Votes") local mapLabel = gui:FindFirstChild("MapName") if mapLabel then mapLabel.Text = (data and data.DisplayName) or option end if votesLabel then votesLabel.Text = tostring(results[option] or 0) end local imagePart = stand:FindFirstChild("MapImagePart") if imagePart and imagePart:FindFirstChild("ImageGui") then local img = imagePart.ImageGui:FindFirstChild("Picture") if img then img.Image = (data and data.DisplayImage) or "" end end end end local function broadcast(votingStands) local results = calculateResults() rev_Vote:FireAllClients(results) updateVotingStands(votingStands, results) end -- voting logic local function registerVote(player, option, votingStands) if not player or not option then return end voteCounts[option] = voteCounts[option] or 0 local userId = player.UserId if alreadyVoted[userId] == option then return end local previous = alreadyVoted[userId] if previous and voteCounts[previous] then voteCounts[previous] -= 1 end alreadyVoted[userId] = option voteCounts[option] += 1 broadcast(votingStands) end -- START function VotingHandlerServer.StartVoting(optionCount, moduleKey, votingStands) cleanupConnections() alreadyVoted = {} voteCounts = {} touchDebounce = {} moduleData = OptionsData.Get(moduleKey) if not moduleData then warn("No moduleData for:", moduleKey) return end currentOptions = pickRandomOptions(moduleData, optionCount) -- remote voting table.insert(activeConnections, rev_Vote.OnServerEvent:Connect(function(player, option) registerVote(player, option, votingStands) end) ) -- stand voting if votingStands then for index, stand in ipairs(votingStands) do local option = currentOptions[index] if option then local conn = stand.ToVotePart.Touched:Connect(function(hit) local player = Players:GetPlayerFromCharacter(hit.Parent) if not player then return end local userId = player.UserId if touchDebounce[userId] then return end touchDebounce[userId] = true registerVote(player, option, votingStands) task.delay(0.5, function() touchDebounce[userId] = nil end) end) table.insert(activeConnections, conn) end end end updateVotingStands(votingStands, calculateResults()) rev_StartVote:FireAllClients(currentOptions, moduleKey) end -- END function VotingHandlerServer.EndVoting() cleanupConnections() rev_EndVote:FireAllClients() local results = calculateResults() local winner local highest = -1 for option, votes in pairs(results) do if votes > highest then highest = votes winner = option end end if not winner and #currentOptions > 0 then winner = currentOptions[math.random(1, #currentOptions)] end return winner, moduleData and moduleData[winner] end return VotingHandlerServer