Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
翻译准备中
Player data for Roblox that loses nothing, fails loudly, and never stutters a frame.
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Player data for Roblox that loses nothing, fails loudly, and never stutters a frame.
Documentation · Installation · Changelog
KeepBlox keeps session-locked player profiles on DataStore. It reads and writes the same records as
ProfileStore and speaks its lock protocol, so a game can switch by changing one require, run old and
new servers side by side during the rollout, and switch back.
Status: 0.9.6. Everything below is proven in the simulator, against ProfileStore, five other libraries and a game with no library. It is also checked on Roblox's real DataStore, MessagingService and MemoryStore in a private test experience (
tests/live), overload included. It runs in one live public game (Grabby Pit) since early October 2026. That is one game and a short time: try it in a test place first.
Each promise is a spec, and the simulation checks the data invariants after every write, across many virtual servers and random fault schedules:
loadTimeout in all.writeVersion).The checker is checked too: 31 small slips in the code that keeps these promises each make the suite
fail (tests/Mutate.luau), and the save check is fuzzed against the store's encoding.
store:edit), and offline messages (store:message).store:trade).KeepBlox.shared).KeepBlox.schedule).KeepBlox.tally).leaderboards).{ up, down }) and writeVersion, so the
release before reads everything, renames included. Lapis and DocumentService's backwardsCompatible
covers only changes old code can read as they are.KeepBlox.processReceipt, and version history with a safe restore that names the
purchases it takes back. Optional compression for large profiles, and Studio modes that never touch
live data.--!strict throughout) and roblox-ts (types/index.d.ts).Every library runs unmodified in the same simulator: the same fakes of DataStore, MemoryStore, MessagingService and the engine, the same players, faults and seeds (worst case over 20 seeds).
| Library | Violations | A crash loses (steps of play) | Slowest open (s) | Failed opens | Requests per player-hour |
|---|---|---|---|---|---|
| KeepBlox | 0 | 4 | 9.4 | 0 | 13.1 + 13.1 |
| ProfileStore | 0 | 287 | 46.6 | 20 | 13.6 + 13.6 |
| ProfileService | 0 | 29 | 65.8 | 27 | 122 + 122 |
| DocumentService | 0 | 0 (player locked out: 20 of 40 rejoins) | 15.9 | 389 | 25.9 + 25.9 |
| Lapis | 0 | 0 (player locked out: 20 of 40 rejoins) | 11.9 | 374 | 14 + 14 |
| DataStore2 | 61 | 287 | 8.8 | 0 | 0 + 1 |
| Suphi's DataStore Module | 1 | 0 (player locked out: 20 of 40 rejoins) | 0.5 | 355 | 1 + 120 |
| No library (GetAsync / SetAsync, as the Roblox guides teach) | 63 | 51 | 0.2 | 0 | 1 + 60.7 |
Requests are data store reads + writes. KeepBlox also spends 45 MemoryStore units per player-hour on its
server heartbeat, which is how a dead server is known within seconds and how a crash loses only one
beat of play. The full tables, every scenario and the methodology are in
bench/Benchmarks.md; luneblox run bench/Report 20 makes them.
KeepBlox is built to take over from the libraries games already use.
From ProfileStore or ProfileService, change one line; the keys and their format stay as they are:
local ProfileStore = require(path.to.KeepBlox.Compat.ProfileStore)
From DocumentService, Lapis, DataKeep, DataStore2 or Suphi's DataStore Module, point a store at the old data: each key moves on its first load, and the old data is only read.
local store = KeepBlox.store("Profiles", {
template = { coins = 0 },
import = KeepBlox.importers.DocumentService({ store = "PlayerData" }),
})
KeepBlox = "xopoiii/[email protected]" under [server-dependencies].pesde add xopoiii/keepblox -t roblox_server -a KeepBlox.KeepBlox.rbxm from the latest release.More in Installation.
rokit install # the pinned toolchain
lefthook install # the gates, before every commit
sh scripts/run-tests.sh
luneblox run tests/Mutate --yes # mutation adequacy: every slip must fail the suite (about 16 min)
luneblox run bench/download && luneblox run bench/Report 20 # the benchmarks
luneblox run tests/live/Serve # the live check, only in the test experience (tests/live/README.md)
npm ci --prefix docs && npm run build --prefix docs # the documentation site
Tests run on LuneBlox, which runs the Luau version and fast flags Roblox runs.
MIT. See LICENSE. Vendored reference code in tests/reference/ keeps its own license.