core: loading screen, realism

This commit is contained in:
2026-01-08 22:49:48 +02:00
parent a3d316c673
commit da7de7b08a
14 changed files with 386 additions and 18 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "ThirdParty/Character-Realism"]
path = ThirdParty/Character-Realism
url = https://github.com/MaximumADHD/Character-Realism

View File

@@ -2,39 +2,55 @@
"name": "minecraft-roblox",
"tree": {
"$className": "DataModel",
"ReplicatedStorage": {
"$className": "ReplicatedStorage",
"$ignoreUnknownInstances": true,
"$path": "src/ReplicatedStorage",
"Packages": {
"$className": "Folder",
"$path": "Packages"
}
},
"ReplicatedFirst": {
"$className": "ReplicatedFirst",
"$ignoreUnknownInstances": true,
"$path": "src/ReplicatedFirst"
},
"ServerScriptService": {
"$className": "ServerScriptService",
"$ignoreUnknownInstances": true,
"$path": "src/ServerScriptService"
"$path": "src/ServerScriptService",
"RealismServer": {
"$path": "ThirdParty/Character-Realism/Realism.server.lua"
}
},
"StarterGui": {
"$className": "StarterGui",
"$ignoreUnknownInstances": true,
"$path": "src/StarterGui"
},
"StarterPlayer": {
"$className": "StarterPlayer",
"$ignoreUnknownInstances": true,
"StarterPlayerScripts": {
"$className": "StarterPlayerScripts",
"$ignoreUnknownInstances": true,
"$path": "src/StarterPlayer/StarterPlayerScripts"
},
"$ignoreUnknownInstances": true
"$path": "src/StarterPlayer/StarterPlayerScripts",
"RealismClient": {
"$path": "ThirdParty/Character-Realism/RealismClient"
}
}
},
"Workspace": {
"$className": "Workspace",
"$ignoreUnknownInstances": true,

View File

@@ -0,0 +1,13 @@
--!native
--!optimize 2
local ReplicatedStorage = game:GetService("ReplicatedStorage")
if not game:IsLoaded() then
game.Loaded:Wait()
end
local Bootstrap = require(ReplicatedStorage:WaitForChild("Client"):WaitForChild("Bootstrap"))
local objects = ReplicatedStorage:WaitForChild("Objects", 9e9)
objects:WaitForChild("MLLoaded", 9e9)
Bootstrap.start()

View File

@@ -0,0 +1,83 @@
--!native
--!optimize 2
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LoadingScreen = require(ReplicatedStorage.Client.LoadingScreen)
local ModLoader = require(ReplicatedStorage.Shared.ModLoader)
local ChunkManager = require(ReplicatedStorage.Shared.ChunkManager)
local PlacementManager = require(ReplicatedStorage.Shared.PlacementManager)
local Bootstrap = {}
local started = false
local function ensureFlag(name: string)
local objects = ReplicatedStorage:WaitForChild("Objects")
local existing = objects:FindFirstChild(name)
if existing and existing:IsA("BoolValue") then
return existing
end
local ready = Instance.new("BoolValue")
ready.Name = name
ready.Value = true
ready.Parent = objects
return ready
end
local contentProvider = game:GetService("ContentProvider")
local function waitForGameLoaded()
if game:IsLoaded() then
return
end
game.Loaded:Wait()
end
function Bootstrap.start()
if started then
return
end
started = true
contentProvider:PreloadAsync(game:GetDescendants())
ensureFlag("ClientReady")
local screen = LoadingScreen.mount()
screen.setStatus("Connecting...")
screen.setDetail("Waiting for server")
screen.setProgress(0.2)
task.wait(1)
waitForGameLoaded()
local modsFolder = ReplicatedStorage:WaitForChild("Mods")
local totalMods = #modsFolder:GetChildren()
local modProgressWeight = 0.6
ModLoader.loadModsC(function(index, total, modInstance, success)
total = total > 0 and total or math.max(totalMods, 1)
local ratio = index / total
screen.setStatus(`Modloading progress: {index}/{total}`)
screen.setDetail(`Loading {modInstance.Name}`)
screen.setProgress(0.05 + ratio * modProgressWeight)
if not success then
screen.setDetail(`Failed loading {modInstance.Name}; continuing`)
end
end)
ensureFlag("CSMLLoaded") -- needed
screen.setStatus("Joining world...")
screen.setDetail("Syncing with server")
screen.setProgress(0.7)
task.wait(0.5)
screen.close()
end
return Bootstrap

View File

@@ -0,0 +1,70 @@
--!native
--!optimize 2
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Roact = require(ReplicatedStorage.Packages.roact)
local ProgressBar = require(script.Parent.Components.ProgressBar)
local theme = {
background = Color3.fromRGB(17, 17, 27),
text = Color3.fromRGB(255, 255, 255),
subtext = Color3.fromRGB(205, 214, 244),
}
local function LoadingScreen(props)
local status = props.status or "Loading game..."
local detail = props.detail or "Preloading..."
local progress = props.progress or 0
local visible = props.visible
return Roact.createElement("ScreenGui", {
Name = "LoadingScreen",
DisplayOrder = 9999,
IgnoreGuiInset = true,
ResetOnSpawn = false,
ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
Enabled = visible ~= false,
}, {
Root = Roact.createElement("Frame", {
Size = UDim2.fromScale(1, 1),
BackgroundColor3 = theme.background,
BorderSizePixel = 0,
}, {
Title = Roact.createElement("TextLabel", {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.new(0.5, 0, 0.5, 0),
BackgroundTransparency = 1,
Font = Enum.Font.Code,
Text = status,
TextColor3 = theme.text,
TextSize = 32,
TextWrapped = true,
AutomaticSize = Enum.AutomaticSize.XY,
TextXAlignment = Enum.TextXAlignment.Center,
TextYAlignment = Enum.TextYAlignment.Center,
}, {
Gradient = Roact.createElement("UIGradient", {
Color = ColorSequence.new({
ColorSequenceKeypoint.new(0, Color3.fromRGB(245, 194, 231)),
ColorSequenceKeypoint.new(0.5, Color3.fromRGB(203, 166, 247)),
ColorSequenceKeypoint.new(1, Color3.fromRGB(137, 180, 250)),
}),
Rotation = 30,
Transparency = NumberSequence.new({
NumberSequenceKeypoint.new(0, 0),
NumberSequenceKeypoint.new(1, 0),
}),
}),
}),
Progress = Roact.createElement(ProgressBar, {
AnchorPoint = Vector2.new(0.5, 1),
Position = UDim2.new(0.5, 0, 1, -32),
progress = progress,
detail = detail,
}),
}),
})
end
return LoadingScreen

View File

@@ -0,0 +1,101 @@
--!native
--!optimize 2
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Roact = require(ReplicatedStorage.Packages.roact)
local theme = {
background = Color3.fromRGB(30, 30, 46),
text = Color3.fromHex("#cdd6f4"),
holder = Color3.fromRGB(17, 17, 27),
fill = Color3.fromRGB(255, 255, 255),
stroke = Color3.fromRGB(49, 50, 68),
holderStroke = Color3.fromRGB(108, 112, 134),
}
local function ProgressBar(props)
local function progressToTransparency(v: number)
local p = math.clamp(v or 0, 0, 1)
return NumberSequence.new({
NumberSequenceKeypoint.new(0, 0),
NumberSequenceKeypoint.new(p, 0),
NumberSequenceKeypoint.new(p, 1),
NumberSequenceKeypoint.new(1, 1),
})
end
local gradientTransparency: NumberSequence
if typeof(props.progress) == "table" and props.progress.map then
gradientTransparency = props.progress:map(progressToTransparency)
else
gradientTransparency = progressToTransparency(props.progress or 0)
end
return Roact.createElement("Frame", {
Name = "ProgressBar",
AnchorPoint = props.AnchorPoint or Vector2.new(0.5, 1),
Position = props.Position or UDim2.new(0.5, 0, 1, -32),
Size = props.Size or UDim2.new(0, 500, 0, 32),
BackgroundColor3 = theme.background,
BorderSizePixel = 0,
}, {
Label = Roact.createElement("TextLabel", {
AnchorPoint = Vector2.new(0, 0),
Position = UDim2.new(0, 16, 0, -32),
Size = UDim2.new(1, -32, 0, 18),
BackgroundTransparency = 1,
Font = Enum.Font.Code,
Text = props.detail,
TextColor3 = theme.text,
TextSize = 18,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
}),
Corner = Roact.createElement("UICorner", {
CornerRadius = UDim.new(0, 16),
}),
Stroke = Roact.createElement("UIStroke", {
Color = theme.stroke,
ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
Thickness = 1,
}),
FillHolder = Roact.createElement("Frame", {
Name = "FillHolder",
AnchorPoint = Vector2.new(0, 1),
Position = UDim2.new(0, 8, 1, -8),
Size = UDim2.new(1, -16, 0, 16),
BackgroundColor3 = theme.holder,
BorderSizePixel = 0,
}, {
Corner = Roact.createElement("UICorner", {
CornerRadius = UDim.new(0, 8),
}),
Stroke = Roact.createElement("UIStroke", {
Color = theme.holderStroke,
ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
Thickness = 1,
}),
Fill = Roact.createElement("Frame", {
AnchorPoint = Vector2.new(0, 0),
BackgroundColor3 = theme.fill,
BorderSizePixel = 0,
Size = UDim2.new(1, 0, 1, 0),
}, {
Corner = Roact.createElement("UICorner", {
CornerRadius = UDim.new(0, 8),
}),
Gradient = Roact.createElement("UIGradient", {
Color = ColorSequence.new({
ColorSequenceKeypoint.new(0, Color3.fromHex("#f5c2e7")),
ColorSequenceKeypoint.new(0.5, Color3.fromHex("#cba6f7")),
ColorSequenceKeypoint.new(1, Color3.fromHex("#89b4fa")),
}),
Transparency = gradientTransparency,
Rotation = 0,
}),
}),
}),
})
end
return ProgressBar

View File

@@ -0,0 +1,55 @@
--!native
--!optimize 2
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Roact = require(ReplicatedStorage.Packages.roact)
local Players = game:GetService("Players")
local App = require(script.App)
local LoadingScreen = {}
function LoadingScreen.mount(target: Instance?)
local playerGui = target or Players.LocalPlayer:WaitForChild("PlayerGui")
local statusBinding, setStatus = Roact.createBinding("Loading...")
local detailBinding, setDetail = Roact.createBinding("Preparing client")
local progressBinding, setProgress = Roact.createBinding(0)
local visibleBinding, setVisible = Roact.createBinding(true)
local handle = Roact.mount(Roact.createElement(App, {
status = statusBinding,
detail = detailBinding,
progress = progressBinding,
visible = visibleBinding,
}), playerGui, "RoactLoadingScreen")
local closed = false
local function close()
if closed then
return
end
closed = true
setVisible(false)
Roact.unmount(handle)
handle = nil
end
return {
setStatus = function(text: string)
setStatus(text)
end,
setDetail = function(text: string)
setDetail(text)
end,
setProgress = function(value: number)
setProgress(math.clamp(value or 0, 0, 1))
end,
show = function()
setVisible(true)
end,
hide = close,
close = close,
}
end
return LoadingScreen

View File

@@ -31,10 +31,13 @@ function ML.loadModsS()
end
end
function ML.loadModsC()
function ML.loadModsC(onProgress: ((number, number, Instance, boolean) -> ())?)
print("[CSModLoader] Loading Mods")
for _, m in pairs(ModsFolder:GetChildren()) do
local mods = ModsFolder:GetChildren()
local total = #mods
for i, m in ipairs(mods) do
local success, reason = pcall(function()
-- ignore type err
local mod: modContext = require(m)
@@ -44,6 +47,11 @@ function ML.loadModsC()
if not success then
warn(`[CSModLoader] Error loading {m.Name}: {reason}`)
end
if onProgress then
pcall(function()
onProgress(i, total, m, success)
end)
end
end
end

View File

@@ -10,7 +10,9 @@ local UIS = game:GetService("UserInputService")
local TXTS = game:GetService("TextChatService")
local TXTS_CIF = TXTS:FindFirstChildOfClass("ChatInputBarConfiguration")
ReplicatedStorage:WaitForChild("Objects"):WaitForChild("MLLoaded")
local objects = ReplicatedStorage:WaitForChild("Objects", 9e9)
objects:WaitForChild("MLLoaded", 9e9)
objects:WaitForChild("CSMLLoaded", 9e9)
game:GetService("Players").LocalPlayer.CameraMode = Enum.CameraMode.LockFirstPerson
UIS.MouseIconEnabled = false

View File

@@ -10,7 +10,13 @@ local ui = script.Parent
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PlacementState = require(ReplicatedStorage.Shared.PlacementState)
ReplicatedStorage:WaitForChild("Objects"):WaitForChild("MLLoaded")
local objects = ReplicatedStorage:WaitForChild("Objects", 9e9)
objects:WaitForChild("MLLoaded", 9e9)
objects:WaitForChild("CSMLLoaded", 9e9)
local clientReady = ReplicatedStorage.Objects:WaitForChild("ClientReady", 5)
if clientReady and not clientReady.Value then
clientReady:GetPropertyChangedSignal("Value"):Wait()
end
local cd = ReplicatedStorage.Objects.ChunkDebug:Clone()
local sky = ReplicatedStorage.Objects.Sky:Clone()

View File

@@ -9,7 +9,9 @@ local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UIS = game:GetService("UserInputService")
local TextChatService = game:GetService("TextChatService")
ReplicatedStorage:WaitForChild("Objects"):WaitForChild("MLLoaded")
local objects = ReplicatedStorage:WaitForChild("Objects", 9e9)
objects:WaitForChild("MLLoaded", 9e9)
objects:WaitForChild("CSMLLoaded", 9e9)
local Roact = require(ReplicatedStorage.Packages.roact)
local PM = require(ReplicatedStorage.Shared.PlacementManager)

View File

@@ -7,16 +7,16 @@ end
pcall(function()
task.synchronize()
game:GetService("Workspace"):WaitForChild("$blockscraft_server",5):Destroy()
task.defer(function()
game:GetService("Workspace"):WaitForChild("$blockscraft_server",9e9):Destroy()
end)
end)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
ReplicatedStorage:WaitForChild("Objects"):WaitForChild("MLLoaded")
local ML = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("ModLoader"))
ML.loadModsC()
local objects = ReplicatedStorage:WaitForChild("Objects", 9e9)
objects:WaitForChild("MLLoaded", 9e9)
objects:WaitForChild("CSMLLoaded", 9e9)
do
local PM = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("PlacementManager"))

View File

@@ -1,4 +1,9 @@
--!native
--!optimize 2
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local objects = ReplicatedStorage:WaitForChild("Objects", 9e9)
objects:WaitForChild("MLLoaded", 9e9)
objects:WaitForChild("CSMLLoaded", 9e9)
return

View File

@@ -4,5 +4,9 @@ until game:IsLoaded() == true
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local objects = ReplicatedStorage:WaitForChild("Objects", 9e9)
objects:WaitForChild("MLLoaded", 9e9)
objects:WaitForChild("CSMLLoaded", 9e9)
local Cmdr = require(ReplicatedStorage:WaitForChild("CmdrClient"))
Cmdr:SetActivationKeys({ Enum.KeyCode.F2 })