My roact app isn’t rendering after a bit, and I can’t figure out why. I’m dying to figure this out, and I can’t figure it out. Somebody who knows about Roact, please help me out. The rodux state is updating, but the tree isn’t. I need some reviewing of this code, because it may not be proper Roact code.
My structure:
Client
├── App
│ ├── AFK
│ ├── Inventory
│ ├── Money
│ ├── Shop
│ ├── Spectate
│ ├── Status
│ ├── Voting
Client
local Players = game:GetService("Players")
local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))
local GetRemoteEvent = require("GetRemoteEvent")
local TimeSyncService = require("TimeSyncService")
TimeSyncService:Init()
local Roact = require("Roact")
local RoactRodux = require("RoactRodux")
local Store = require("Store")
local TIMER_BEGIN_REMOTE = GetRemoteEvent("TimerBegin")
local STATUS_REMOTE = GetRemoteEvent("StatusRemote")
local App = require(script:WaitForChild("App"))
local PlayerGui = Players.LocalPlayer.PlayerGui
local ScreenGui = Instance.new("ScreenGui", PlayerGui)
ScreenGui.ResetOnSpawn = false
ScreenGui.ZIndexBehavior = Enum.ZIndexBehavior.Global
local app = Roact.createElement(RoactRodux.StoreProvider, {
store = Store,
}, {
App = Roact.createElement(App)
})
local handle = Roact.mount(app, ScreenGui, "UI")
App
local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))
-- Modules
local RoactRodux = require("RoactRodux")
local Roact = require("Roact")
local TimeSyncService = require("TimeSyncService")
local clock = TimeSyncService:WaitForSyncedClock()
local GetRemoteEvent = require("GetRemoteEvent")
local GetRemoteFunction = require("GetRemoteFunction")
-- Remotes
local TIMER_BEGIN_REMOTE = GetRemoteEvent("TimerBegin")
local STATUS_REMOTE = GetRemoteEvent("StatusRemote")
local DATA_CHANGED_EVENT = GetRemoteEvent("DataChanged")
local VOTE_REMOTE = GetRemoteEvent("VoteForGame")
local GET_ITEMS_EVENT = GetRemoteFunction("GetItems")
-- Local Modules
local Status = require(script:WaitForChild("Status"))
local Inventory = require(script:WaitForChild("Inventory"))
local Money = require(script:WaitForChild("Money"))
local Shop = require(script:WaitForChild("Shop"))
local Spectate = require(script:WaitForChild("Spectate"))
local AFK = require(script:WaitForChild("AFK"))
local Voting = require(script:WaitForChild("Voting"))
local itemTypes, shopItems = {"Swords"}, {}
for _, itemType in ipairs(itemTypes) do
shopItems[itemType] = GET_ITEMS_EVENT:InvokeServer(itemType)
end
-- Module
local App = Roact.PureComponent:extend("App")
function App:init()
STATUS_REMOTE.OnClientEvent:Connect(function(text)
self.props.setStatus(text)
end)
VOTE_REMOTE.OnClientEvent:Connect(function(type, data)
if type == "Initiate" then
self.props.setUI("VOTING", 2)
self.props.setVote(data)
end
if type == "Update" then
self.props.setVote(data)
end
if type == "Ended" then
self.props.setUI("GOD", 2)
self.props.setVote({})
end
end)
DATA_CHANGED_EVENT.OnClientEvent:Connect(function(data)
self.props.setData(data)
if self.props.data.Coins then
if self.props.data.Coins < data.Coins then
script.Cash:Play()
end
else
script.Cash:Play()
end
end)
TIMER_BEGIN_REMOTE.OnClientEvent:Connect(function(endTick)
self.endTick = endTick
self.props.roundStart(math.floor(self.endTick - clock:GetTime()))
end)
end
function App:didMount()
self.running = true
coroutine.wrap(function()
while self.running do
wait(1)
if self.props.time and self.endTick then
if self.props.time >= 0 then
self.props.roundStart(math.floor(self.endTick - clock:GetTime()))
end
end
end
end)()
end
function App:willUnmount()
self.running = false
end
function App:render()
return Roact.createElement("Frame", {
Size = UDim2.fromScale(1, 1),
BackgroundTransparency = 1
}, {
Status = Roact.createElement(Status, {
anchorPoint = Vector2.new(0.5, 0),
position = UDim2.fromScale(0.5, 0),
size = UDim2.fromScale(0.5, 0.1),
time = self.props.time,
status = self.props.status
}),
Shop = Roact.createElement(Shop, {
open = self.props.open,
setUI = self.props.setUI,
data = self.props.data,
shopItems = self.shopItems,
viewingShopItem = self.props.viewingShopItem,
changeShopItem = self.props.changeShopItem
}),
Inventory = Roact.createElement(Inventory, {
open = self.props.open,
setUI = self.props.setUI,
data = self.props.data,
shopItems = self.shopItems
}),
Money = Roact.createElement(Money, {
data = self.props.data
}),
Spectate = Roact.createElement(Spectate, {
open = self.props.open,
setUI = self.props.setUI,
index = self.props.index,
spectate = self.props.spectate,
setSpectate = self.props.setSpectate,
setIndex = self.props.setIndex
}),
AFK = Roact.createElement(AFK, {
data = self.props.data,
setData = self.props.setData
}),
Voting = Roact.createElement(Voting, {
open = self.props.open,
setUI = self.props.setUI,
vote = self.props.vote
}),
UIPadding = Roact.createElement("UIPadding", {
PaddingBottom = UDim.new(0, 5),
PaddingLeft = UDim.new(0, 5),
PaddingRight = UDim.new(0, 5),
PaddingTop = UDim.new(0, 5)
})
})
end
return RoactRodux.connect(
function(state, props)
return {
status = state.status,
data = state.data,
open = state.ui,
viewingShopItem = state.viewingShopItem,
index = state.index,
spectate = state.spectate,
vote = state.vote
}
end,
function(dispatch)
return {
roundStart = function(time)
dispatch({
type = "ROUND_START",
time = time
})
end,
setStatus = function(status)
dispatch({
type = "SET_STATUS",
text = status
})
end,
setShopItems = function(itemType, items)
dispatch({
type = "SET_SHOP_ITEMS",
items = items,
key = itemType
})
end,
setData = function(data)
dispatch({
type = "SET_DATA",
data = data
})
end,
setUI = function(type, key)
local ui, key = (key and type or nil), key or type
dispatch({
type = "OPEN_UI",
ui = ui,
key = key
})
end,
changeShopItem = function(item)
dispatch({
type = "CHANGE_SHOP_ITEM",
item = item
})
end,
setIndex = function(index)
dispatch({
type = "SET_INDEX",
index = index
})
end,
setSpectate = function(spectate)
dispatch({
type = "SET_SPECTATE",
spectate = spectate
})
end,
setVote = function(vote)
dispatch({
type = "SET_VOTE",
vote = vote
})
end
}
end
)(App)
AFK
local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))
-- Modules
local Roact = require("Roact")
local GetRemoteEvent = require("GetRemoteEvent")
-- Module
local AFK = Roact.Component:extend("AFK")
-- Events
local AFK_EVENT = GetRemoteEvent("ToggleAFK")
function AFK:init()
self.canvasSize, self.updateCanvasSize = Roact.createBinding(Vector2.new(0, 0))
end
function AFK:render()
return Roact.createFragment({
AFKButton = Roact.createElement("TextButton", {
-- Size/Position
Size = UDim2.fromScale(0.1, 0.075),
Position = UDim2.fromScale(0, 0.7), -- 0.15 y distance between side buttons
AnchorPoint = Vector2.new(0, 0.5),
-- Text
Text = "AFK:" .. (self.props.data.AFK and " On" or " Off"),
TextColor3 = Color3.new(1, 1, 1),
Font = Enum.Font.GothamBold,
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
TextScaled = true,
-- Color
BackgroundColor3 = (self.props.data.AFK and Color3.new(0.152941, 1, 0.0588235) or Color3.new(0.835294, 0.0980392, 0.0980392)),
-- Border
BorderSizePixel = 0,
-- Events
[Roact.Event.Activated] = function()
AFK_EVENT:FireServer()
end
}, {
UITextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 24
}),
UICorner = Roact.createElement("UICorner", {
CornerRadius = UDim.new(0, 5)
}),
}),
})
end
return AFK
Inventory
local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))
-- Modules
local Roact = require("Roact")
local GetRemoteEvent = require("GetRemoteEvent")
-- Variables
local ITEM_TYPE = "Swords"
-- Module
local Inventory = Roact.Component:extend("Inventory")
-- Events
local EQUIP_ITEM_EVENT = GetRemoteEvent("EquipItem")
function Inventory:init()
self.canvasSize, self.updateCanvasSize = Roact.createBinding(Vector2.new(0, 0))
end
function Inventory:render()
local inventory = self.props.data[ITEM_TYPE] or {}
local shopItems = self.props.shopItems[ITEM_TYPE] or {}
local equipped = (self.props.data.Equipped and self.props.data.Equipped[ITEM_TYPE] or "")
local i = 0
for _, _ in pairs(shopItems) do
i = i + 1
end
local FrameData = {}
FrameData.UIGridLayout = Roact.createElement("UIGridLayout", {
[Roact.Change.AbsoluteContentSize] = function(rbx)
self.updateCanvasSize(rbx.AbsoluteContentSize)
end,
CellSize = self.absoluteSize
})
FrameData.UIPadding = Roact.createElement("UIPadding", {
PaddingBottom = UDim.new(0, 5),
PaddingLeft = UDim.new(0, 5),
PaddingRight = UDim.new(0, 5),
PaddingTop = UDim.new(0, 5)
})
if i > 0 then
table.sort(inventory, function(a, b)
return (shopItems[a].Name > shopItems[b].Name)
end)
for _, name in ipairs(inventory) do
FrameData[name] = Roact.createElement("TextButton", {
Text = "",
ZIndex = 7,
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
BorderSizePixel = 0,
[Roact.Event.Activated] = function()
EQUIP_ITEM_EVENT:FireServer(name, ITEM_TYPE)
end
}, {
UIPadding = Roact.createElement("UIPadding", {
PaddingBottom = UDim.new(0, 5),
PaddingLeft = UDim.new(0, 5),
PaddingRight = UDim.new(0, 5),
PaddingTop = UDim.new(0, 5)
}),
UICorner = Roact.createElement("UICorner", {
CornerRadius = UDim.new(0, 5)
}),
TextLabel = Roact.createElement("TextLabel", {
AnchorPoint = Vector2.new(0.5, 1),
Size = UDim2.fromScale(0.8, 0.2),
Position = UDim2.fromScale(0.5, 1),
Font = Enum.Font.GothamSemibold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextScaled = true,
TextStrokeTransparency = 0.8,
BackgroundTransparency = 1,
Text = (shopItems[name] and shopItems[name].Name or ""),
ZIndex = 8
}, {
UITextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 32
}),
}),
ImageLabel = Roact.createElement("ImageLabel", {
AnchorPoint = Vector2.new(0.5, 0.25),
Size = UDim2.fromScale(0.7, 0.7),
Position = UDim2.fromScale(0.5, 0.25),
BackgroundTransparency = 1,
Image = (shopItems[name] and shopItems[name].Icon or ""),
ZIndex = 8
})
})
end
end
return Roact.createFragment({
InventoryButton = Roact.createElement("TextButton", {
-- Size/Position
Size = UDim2.fromScale(0.15, 0.075),
Position = UDim2.fromScale(0, 0.5), -- 0.15 y distance between side buttons
AnchorPoint = Vector2.new(0, 0.5),
-- Text
Text = "Inventory",
TextColor3 = Color3.new(1, 1, 1),
Font = Enum.Font.GothamBold,
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
TextScaled = true,
-- Color
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
-- Border
BorderSizePixel = 0,
-- Events
[Roact.Event.Activated] = function()
if self.props.open[1] == "INVENTORY" then
self.props.setUI(1)
else
self.props.setUI("INVENTORY", 1)
end
end
}, {
UITextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 24
}),
UICorner = Roact.createElement("UICorner", {
CornerRadius = UDim.new(0, 5)
}),
}),
InventoryFrame = Roact.createElement("Frame", {
-- Size/Position
Size = UDim2.fromScale(0.5, 0.75),
Position = UDim2.fromScale(0.5, 0.5),
AnchorPoint = Vector2.new(0.5, 0.5),
-- Color
BackgroundColor3 = Color3.new(1, 1, 1),
BackgroundTransparency = 1,
-- Border
BorderSizePixel = 0,
-- Visibility
ClipsDescendants = true,
Visible = (self.props.open[1] == "INVENTORY")
}, {
UIAspectRatioConstraint = Roact.createElement("UIAspectRatioConstraint", {
AspectRatio = 1.625
}),
TopbarFrame = Roact.createElement("Frame", {
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
Size = UDim2.fromScale(1, 0.1),
BorderSizePixel = 0,
ZIndex = 4
}, {
CloseButton = Roact.createElement("ImageButton", {
Size = UDim2.fromScale(1, 1),
Image = "rbxassetid://2419293754",
BackgroundColor3 = Color3.new(1, 1, 1),
BorderSizePixel = 0,
ZIndex = 5,
[Roact.Event.Activated] = function()
self.props.setUI(1)
end
}, {
UIAspectRatioConstraint = Roact.createElement("UIAspectRatioConstraint"),
UICorner = Roact.createElement("UICorner", {
CornerRadius = UDim.new(0, 5)
})
}),
UIPadding = Roact.createElement("UIPadding", {
PaddingBottom = UDim.new(0, 5),
PaddingLeft = UDim.new(0, 5),
PaddingRight = UDim.new(0, 5),
PaddingTop = UDim.new(0, 5)
}),
TextLabel = Roact.createElement("TextLabel", {
AnchorPoint = Vector2.new(0.5, 0),
Position = UDim2.fromScale(0.5, 0),
Size = UDim2.fromScale(0.75, 1),
BackgroundTransparency = 1,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
Text = "Inventory",
ZIndex = 5
})
}),
ScrollingFrame = Roact.createElement("ScrollingFrame", {
AnchorPoint = Vector2.new(0, 1),
Size = UDim2.fromScale(0.75, 0.9),
Position = UDim2.fromScale(0, 1),
CanvasSize = UDim2.fromOffset(self.canvasSize.X, self.canvasSize.Y),
BorderSizePixel = 0,
BackgroundColor3 = Color3.new(1, 1, 1),
ZIndex = 2,
[Roact.Change.AbsoluteSize] = function(rbx)
self.absoluteSize = UDim2.fromScale(100 / rbx.AbsoluteSize.X, 100 / rbx.AbsoluteSize.Y)
end
}, FrameData),
Sidebar = Roact.createElement("Frame", {
AnchorPoint = Vector2.new(1, 1),
Size = UDim2.fromScale(0.25, 0.9),
Position = UDim2.fromScale(1, 1),
BackgroundColor3 = Color3.new(240/255, 240/255, 240/255),
BorderSizePixel = 0,
ZIndex = 3,
}, {
UIPadding = Roact.createElement("UIPadding", {
PaddingBottom = UDim.new(0, 5),
PaddingLeft = UDim.new(0, 5),
PaddingRight = UDim.new(0, 5),
PaddingTop = UDim.new(0, 5)
}),
UIListLayout = Roact.createElement("UIListLayout", {
Padding = UDim.new(0, 5),
SortOrder = Enum.SortOrder.LayoutOrder
}),
Icon = Roact.createElement("ImageLabel", {
Image = ((i > 0 and equipped and shopItems[equipped]) and shopItems[equipped].Icon or ""),
Size = UDim2.fromScale(1, 1),
Position = UDim2.fromScale(0, 0),
BorderSizePixel = 0,
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
LayoutOrder = 1,
ZIndex = 4,
}, {
UIAspectRatioConstraint = Roact.createElement("UIAspectRatioConstraint")
}),
NameLabel = Roact.createElement("TextLabel", {
Text = ((i > 0 and equipped and shopItems[equipped]) and shopItems[equipped].Name or ""),
Size = UDim2.fromScale(1, 0.1),
Position = UDim2.new(0, 0, 0.45, 5),
BorderSizePixel = 0,
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
TextScaled = true,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
LayoutOrder = 2,
ZIndex = 4
}, {
UITextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 24
}),
}),
DescriptionLabel = Roact.createElement("TextLabel", {
Text = ((i > 0 and equipped and shopItems[equipped]) and shopItems[equipped].Description or ""),
Size = UDim2.fromScale(1, 0.2),
Position = UDim2.new(0, 0, 0.55, 10),
BorderSizePixel = 0,
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
TextScaled = true,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
LayoutOrder = 3,
ZIndex = 4
}, {
UITextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 24
}),
}),
})
})
})
end
return Inventory
Money
local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))
local Roact = require("Roact")
local Money = Roact.Component:extend("Money")
function Money:init()
end
function Money:render()
local coins = 0
if self.props.data.Coins then
coins = self.props.data.Coins
end
return Roact.createElement("TextLabel", {
Size = UDim2.fromScale(0.15, 0.075),
Position = UDim2.fromScale(0, 0.325), -- 0.15 y distance between side buttons
AnchorPoint = Vector2.new(0, 0.5),
BackgroundTransparency = 1,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
Text = coins .. " Coins"
})
end
return Money
Shop
local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))
-- Modules
local Roact = require("Roact")
-- Module
local Shop = Roact.Component:extend("Shop")
local GetRemoteEvent = require("GetRemoteEvent")
-- Variables
local ITEM_TYPE = "Swords"
-- Events
local BUY_ITEM_EVENT = GetRemoteEvent("BuyItemEvent")
function Shop:init()
self.canvasSize, self.updateCanvasSize = Roact.createBinding(Vector2.new(0, 0))
end
function Shop:render()
local inventory = self.props.data[ITEM_TYPE] or {}
local shopItems = self.props.shopItems[ITEM_TYPE] or {}
local viewingShopItem = self.props.viewingShopItem
local i = 0
for name, _ in pairs(shopItems) do
i = i + 1
end
local FrameData = {}
FrameData.UIGridLayout = Roact.createElement("UIGridLayout", {
[Roact.Change.AbsoluteContentSize] = function(rbx)
self.updateCanvasSize(rbx.AbsoluteContentSize)
end,
CellSize = self.absoluteSize
})
FrameData.UIPadding = Roact.createElement("UIPadding", {
PaddingBottom = UDim.new(0, 5),
PaddingLeft = UDim.new(0, 5),
PaddingRight = UDim.new(0, 5),
PaddingTop = UDim.new(0, 5)
})
if i > 0 then
local item = {}
for name, data in pairs(shopItems) do
if not table.find(inventory, name) then
if data.Price then
if typeof(data.Price) == "number" then
data.Id = name
table.insert(item, data)
end
end
end
end
table.sort(item, function(a, b)
local alphabet = a.Name > b.Name
local price = a.Price > b.Price
return alphabet and price
end)
if not viewingShopItem then
self.props.changeShopItem(item.Id)
end
for _, data in ipairs(item) do
FrameData[data.Id] = Roact.createElement("TextButton", {
Text = "",
ZIndex = 7,
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
BorderSizePixel = 0,
[Roact.Event.Activated] = function()
self.props.changeShopItem(data.Id)
end
}, {
UIPadding = Roact.createElement("UIPadding", {
PaddingBottom = UDim.new(0, 5),
PaddingLeft = UDim.new(0, 5),
PaddingRight = UDim.new(0, 5),
PaddingTop = UDim.new(0, 5)
}),
UICorner = Roact.createElement("UICorner", {
CornerRadius = UDim.new(0, 5)
}),
TextLabel = Roact.createElement("TextLabel", {
AnchorPoint = Vector2.new(0.5, 1),
Size = UDim2.fromScale(0.8, 0.2),
Position = UDim2.fromScale(0.5, 1),
Font = Enum.Font.GothamSemibold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextScaled = true,
TextStrokeTransparency = 0.8,
BackgroundTransparency = 1,
Text = data.Name,
ZIndex = 8
}, {
UITextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 32
}),
}),
ImageLabel = Roact.createElement("ImageLabel", {
AnchorPoint = Vector2.new(0.5, 0.25),
Size = UDim2.fromScale(0.7, 0.7),
Position = UDim2.fromScale(0.5, 0.25),
BackgroundTransparency = 1,
Image = data.Icon,
ZIndex = 8
})
})
end
end
print(self.props.open)
return Roact.createFragment({
ShopButton = Roact.createElement("TextButton", {
-- Size/Position
Size = UDim2.fromScale(0.15, 0.075),
Position = UDim2.fromScale(0, 0.4), -- 0.15 y distance between side buttons
AnchorPoint = Vector2.new(0, 0.5),
-- Text
Text = "Shop",
TextColor3 = Color3.new(1, 1, 1),
Font = Enum.Font.GothamBold,
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
TextScaled = true,
-- Color
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
-- Border
BorderSizePixel = 0,
-- Events
[Roact.Event.Activated] = function()
if self.props.open[1] == "SHOP" then
self.props.setUI(1)
else
self.props.setUI("SHOP", 1)
end
end
}, {
UITextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 24
}),
UICorner = Roact.createElement("UICorner", {
CornerRadius = UDim.new(0, 5)
}),
}),
ShopFrame = Roact.createElement("Frame", {
-- Size/Position
Size = UDim2.fromScale(0.5, 0.75),
Position = UDim2.fromScale(0.5, 0.5),
AnchorPoint = Vector2.new(0.5, 0.5),
-- Color
BackgroundColor3 = Color3.new(1, 1, 1),
BackgroundTransparency = 1,
-- Border
BorderSizePixel = 0,
-- Visibility
ClipsDescendants = true,
Visible = (self.props.open[1] == "SHOP")
}, {
UIAspectRatioConstraint = Roact.createElement("UIAspectRatioConstraint", {
AspectRatio = 1.625
}),
TopbarFrame = Roact.createElement("Frame", {
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
Size = UDim2.fromScale(1, 0.1),
BorderSizePixel = 0,
ZIndex = 4
}, {
CloseButton = Roact.createElement("ImageButton", {
Size = UDim2.fromScale(1, 1),
Image = "rbxassetid://2419293754",
BackgroundColor3 = Color3.new(1, 1, 1),
BorderSizePixel = 0,
ZIndex = 5,
[Roact.Event.Activated] = function()
self.props.setUI(1)
end
}, {
UIAspectRatioConstraint = Roact.createElement("UIAspectRatioConstraint"),
UICorner = Roact.createElement("UICorner", {
CornerRadius = UDim.new(0, 5)
})
}),
UIPadding = Roact.createElement("UIPadding", {
PaddingBottom = UDim.new(0, 5),
PaddingLeft = UDim.new(0, 5),
PaddingRight = UDim.new(0, 5),
PaddingTop = UDim.new(0, 5)
}),
TextLabel = Roact.createElement("TextLabel", {
AnchorPoint = Vector2.new(0.5, 0),
Position = UDim2.fromScale(0.5, 0),
Size = UDim2.fromScale(0.75, 1),
BackgroundTransparency = 1,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
Text = "Shop",
ZIndex = 5
})
}),
ScrollingFrame = Roact.createElement("ScrollingFrame", {
AnchorPoint = Vector2.new(0, 1),
Size = UDim2.fromScale(0.75, 0.9),
Position = UDim2.fromScale(0, 1),
CanvasSize = UDim2.fromOffset(self.canvasSize.X, self.canvasSize.Y),
BorderSizePixel = 0,
BackgroundColor3 = Color3.new(1, 1, 1),
ZIndex = 2,
[Roact.Change.AbsoluteSize] = function(rbx)
self.absoluteSize = UDim2.fromScale(100 / rbx.AbsoluteSize.X, 100 / rbx.AbsoluteSize.Y)
end
}, FrameData),
Sidebar = Roact.createElement("Frame", {
AnchorPoint = Vector2.new(1, 1),
Size = UDim2.fromScale(0.25, 0.9),
Position = UDim2.fromScale(1, 1),
BorderSizePixel = 0,
BackgroundColor3 = Color3.new(240/255, 240/255, 240/255),
ZIndex = 3
}, {
UIPadding = Roact.createElement("UIPadding", {
PaddingBottom = UDim.new(0, 5),
PaddingLeft = UDim.new(0, 5),
PaddingRight = UDim.new(0, 5),
PaddingTop = UDim.new(0, 5)
}),
UIListLayout = Roact.createElement("UIListLayout", {
Padding = UDim.new(0, 5),
SortOrder = Enum.SortOrder.LayoutOrder
}),
Icon = Roact.createElement("ImageLabel", {
Image = ((i > 0 and viewingShopItem and shopItems[viewingShopItem]) and shopItems[viewingShopItem].Icon or ""),
Size = UDim2.fromScale(1, 1),
BorderSizePixel = 0,
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
LayoutOrder = 1,
ZIndex = 4,
}, {
UIAspectRatioConstraint = Roact.createElement("UIAspectRatioConstraint")
}),
NameLabel = Roact.createElement("TextLabel", {
Text = ((i > 0 and viewingShopItem and shopItems[viewingShopItem]) and shopItems[viewingShopItem].Name or ""),
Size = UDim2.fromScale(1, 0.1),
BorderSizePixel = 0,
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
TextScaled = true,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
LayoutOrder = 2,
ZIndex = 4
}, {
UITextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 24
}),
}),
DescriptionLabel = Roact.createElement("TextLabel", {
Text = ((i > 0 and viewingShopItem and shopItems[viewingShopItem]) and shopItems[viewingShopItem].Description or ""),
Size = UDim2.fromScale(1, 0.2),
BorderSizePixel = 0,
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
TextScaled = true,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
LayoutOrder = 3,
ZIndex = 4
}, {
UITextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 24
}),
}),
PriceLabel = Roact.createElement("TextLabel", {
Text = ((i > 0 and viewingShopItem) and shopItems[viewingShopItem].Price .. " " .. (shopItems[viewingShopItem].Currency or "Coins") or ""),
Size = UDim2.fromScale(1, 0.1),
BorderSizePixel = 0,
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
TextScaled = true,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
LayoutOrder = 4,
ZIndex = 4
}, {
UITextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 24
}),
}),
BuyButton = Roact.createElement("TextButton", {
Text = ((i > 0 and viewingShopItem) and (inventory[viewingShopItem] and "OWNED" or "BUY") or "NO ITEM SELECTED"),
Size = UDim2.fromScale(1, 0.1),
BorderSizePixel = 0,
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
TextScaled = true,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
[Roact.Event.Activated] = function()
BUY_ITEM_EVENT:FireServer(viewingShopItem, ITEM_TYPE)
end,
LayoutOrder = 5,
ZIndex = 4
}, {
UITextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 24
}),
}),
})
})
})
end
return Shop
Spectate
local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))
-- Modules
local Roact = require("Roact")
-- Variable
local spectateFolder = game:GetService("ReplicatedStorage"):WaitForChild("Spectate")
-- Module
local Spectate = Roact.Component:extend("Spectate")
local function getSpectate()
local spectate = {}
for _, value in ipairs(spectateFolder:GetChildren()) do
table.insert(spectate, value.Value)
end
return spectate
end
function Spectate:init()
self.props.setSpectate(getSpectate())
spectateFolder.ChildAdded:Connect(function()
self.props.setSpectate(getSpectate())
end)
spectateFolder.ChildRemoved:Connect(function()
self.props.setSpectate(getSpectate())
end)
end
function Spectate:render()
local player = game.Players.LocalPlayer
if player then
local character = player.Character
if character then
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if humanoid then
workspace.CurrentCamera.CameraSubject = humanoid
end
end
end
if self.props.open[3] == "SPECTATE" then
local player, chosenPlayer = game.Players.LocalPlayer, (self.props.spectate[self.props.index] and self.props.spectate[self.props.index] or nil)
if chosenPlayer then
local character, chosenCharacter = player.Character, chosenPlayer.Character
if chosenCharacter then
local humanoid, chosenHumanoid = character:FindFirstChildWhichIsA("Humanoid"), chosenCharacter:FindFirstChildWhichIsA("Humanoid")
if chosenHumanoid then
workspace.CurrentCamera.CameraSubject = chosenHumanoid
end
end
end
end
if #self.props.spectate <= 0 then
if self.props.open[3] == "SPECTATE" then
self.props.setUI(3)
end
end
if table.find(self.props.spectate, game.Players.LocalPlayer) then
if self.props.open[3] == "SPECTATE" then
self.props.setUI(3)
end
end
return Roact.createFragment({
SpectateButton = Roact.createElement("TextButton", {
-- Size/Position
Size = UDim2.fromScale(0.15, 0.075),
Position = UDim2.fromScale(0, 0.6), -- 0.15 y distance between side buttons
AnchorPoint = Vector2.new(0, 0.5),
-- Text
Text = "Spectate",
TextColor3 = Color3.new(1, 1, 1),
Font = Enum.Font.GothamBold,
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
TextScaled = true,
-- Color
BackgroundColor3 = Color3.new(200/255, 200/255, 200/255),
-- Border
BorderSizePixel = 0,
-- Events
[Roact.Event.Activated] = function()
if self.props.open[3] == "SPECTATE" then
self.props.setUI(3)
else
if #self.props.spectate > 0 then
if not table.find(self.props.spectate, game.Players.LocalPlayer) then
self.props.setUI("SPECTATE", 3)
end
end
end
end
}, {
UITextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 24
}),
UICorner = Roact.createElement("UICorner", {
CornerRadius = UDim.new(0, 5)
}),
}),
SpectateFrame = Roact.createElement("Frame", {
-- Size/Position
Size = UDim2.fromScale(1, 0.2),
Position = UDim2.fromScale(0, 1),
AnchorPoint = Vector2.new(0, 1),
-- Color
BackgroundColor3 = Color3.new(0, 0, 0),
BackgroundTransparency = 0.5,
-- Border
BorderSizePixel = 0,
-- Visibility
ClipsDescendants = true,
Visible = (self.props.open[3] == "SPECTATE" and #self.props.spectate > 0 and not table.find(self.props.spectate, game.Players.LocalPlayer))
}, {
SpectateLabel = Roact.createElement("TextLabel", {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.fromScale(0.5, 0.5),
Size = UDim2.fromScale(0.35, 0.75),
BackgroundTransparency = 1,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
Text = (#self.props.spectate > 0 and self.props.spectate[self.props.index].Name or "")
}),
BackButton = Roact.createElement("TextButton", {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.fromScale(0.25, 0.5),
Size = UDim2.fromScale(0.1, 0.75),
BackgroundTransparency = 0,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
Text = "<<",
[Roact.Event.Activated] = function()
self.props.setIndex((self.props.index <= 1 and #self.props.spectate or self.props.index - 1))
end
}),
FowardButton = Roact.createElement("TextButton", {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.fromScale(0.75, 0.5),
Size = UDim2.fromScale(0.1, 0.75),
BackgroundTransparency = 0,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
Text = ">>",
[Roact.Event.Activated] = function()
self.props.setIndex((self.props.index >= #self.props.spectate and 1 or self.props.index + 1))
end
})
})
})
end
return Spectate
Status
local Roact = require("Roact")
local GetRemoteEvent = require("GetRemoteEvent")
local VOTE_EVENT
local Status = Roact.Component:extend("Status")
local function timeToTimer(time)
if time then
if time >= 0 then
local minutes = math.floor(time / 60)
local seconds = time % 60
if seconds <= 9 and seconds > 0 then
seconds = "0" .. seconds
elseif seconds == 0 then
seconds = "00"
end
return "(" .. minutes .. ":" .. seconds .. ")"
end
end
return ""
end
function Status:init()
end
function Status:render()
local status, time = self.props.status, timeToTimer(self.props.time)
self.text = status .. " " .. time
return Roact.createElement("TextLabel", {
AnchorPoint = self.props.anchorPoint,
Position = self.props.position,
Size = self.props.size,
BackgroundTransparency = 1,
FontSize = Enum.FontSize.Size32,
Font = Enum.Font.GothamBold,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
TextStrokeTransparency = 0.8,
Text = self.text
})
end
return Status
Voting
local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))
local Roact = require("Roact")
local GetRemoteEvent = require("GetRemoteEvent")
local VOTE_REMOTE = GetRemoteEvent("VoteForGame")
local Voting = Roact.Component:extend("Voting")
function Voting:init()
end
function Voting:render()
local elements = {}
elements.UIAspectRatioConstraint = Roact.createElement("UIAspectRatioConstraint", {
AspectRatio = 3,
})
elements.UIPadding = Roact.createElement("UIPadding", {
PaddingBottom = UDim.new(0, 5),
PaddingLeft = UDim.new(0, 5),
PaddingRight = UDim.new(0, 5),
PaddingTop = UDim.new(0, 5),
})
elements.UIListLayout = Roact.createElement("UIListLayout", {
FillDirection = Enum.FillDirection.Horizontal,
SortOrder = Enum.SortOrder.LayoutOrder,
Padding = UDim.new(0, 10),
})
for i, data in ipairs(self.props.vote or {}) do
elements[data.MapName .. data.GamemodeName] = Roact.createElement("ImageButton", {
Name = "Vote",
BackgroundColor3 = Color3.fromRGB(240, 240, 240),
BorderSizePixel = 0,
LayoutOrder = i,
Size = UDim2.new(1, 0, 1, 0),
ZIndex = 2,
Image = data.Map.Icon,
[Roact.Event.Activated] = function()
VOTE_REMOTE:FireServer(i)
end
}, {
UIAspectRatioConstraint = Roact.createElement("UIAspectRatioConstraint"),
TextLabel = Roact.createElement("TextLabel", {
BackgroundColor3 = Color3.fromRGB(255, 255, 255),
BackgroundTransparency = 1,
Size = UDim2.new(1, 0, 1, 0),
Font = Enum.Font.GothamBold,
TextColor3 = Color3.fromRGB(255, 255, 255),
TextScaled = true,
TextSize = 14,
TextStrokeTransparency = 0.8,
TextWrapped = true,
Text = data.GamemodeName .. " on " .. data.MapName .. " (" .. #data.Votes .. " votes)",
ZIndex = 3
}, {
Roact.createElement("UITextSizeConstraint", {
MaxTextSize = 16,
})
})
})
end
return Roact.createElement("Frame", {
AnchorPoint = Vector2.new(0.5, 1),
BackgroundColor3 = Color3.fromRGB(200, 200, 200),
BorderSizePixel = 0,
Position = UDim2.new(0.5, 0, 1, 0),
Size = UDim2.new(0.2, 0, 0.2, 0),
Visible = (self.props.vote and #self.props.vote > 0 and self.props.open[2] == "VOTING")
}, elements)
end
return Voting
Store
local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))
local Rodux = require("Rodux")
local defaultState = {
status = "",
time = -1,
shopItems = {},
data = '',
ui = {},
viewingShopItem = nil,
index = 1,
spectate = {},
vote = {}
}
function reducer(state, action)
local state = state or defaultState
-- Status
if action.type == "SET_STATUS" and action.text then
state.status = action.text
return state
end
-- Time
if action.type == "ROUND_START" and action.time then
state.time = action.time
return state
end
if action.type == "DECREMENT" and state.time >= 0 then
state.time = state.time - 1
return state
end
-- Shop
if action.type == "SET_SHOP_ITEMS" and action.items and action.key then
local items = state.shopItem
items[action.key] = action.items
state.shopItems = items
return state
end
if action.type == "SET_DATA" and action.data then
state.data = action.data
return state
end
-- Data
if action.type == "OPEN_UI" then
local open = state.ui
open[action.key] = action.ui or ""
state.ui = open
return state
end
if action.type == "CHANGE_SHOP_ITEM" and action.item then
state.viewingShopItem = action.item
return state
end
-- Spectate
if action.type == "SET_INDEX" and action.index then
state.index = action.index
return state
end
if action.type == "SET_SPECTATE" and action.spectate then
state.spectate = action.spectate
return state
end
-- Voting
if action.type == "SET_VOTE" then
state.vote = action.vote
return state
end
return state
end
return Rodux.Store.new(reducer)
This is what happens: