-- ServerScriptService/PlaywaveIntegration (Script)
local Players = game:GetService("Players")
local HttpService = game:GetService("HttpService")
-----------------------------------------------------------------
-- Configuration
-----------------------------------------------------------------
local API_URL = "https://wave-api.playwave.dev/v1"
local API_KEY = "your-api-key-here"
local HEARTBEAT_INTERVAL = 120
-----------------------------------------------------------------
-- Per-player session data
-----------------------------------------------------------------
local activeSessions = {}
-----------------------------------------------------------------
-- OTT extraction
-----------------------------------------------------------------
local function extractOtt(player)
local success, joinData = pcall(function()
return player:GetJoinData()
end)
if not success or not joinData then
return nil
end
local launchData = joinData.LaunchData
if not launchData or type(launchData) ~= "string" then
return nil
end
return launchData
end
-----------------------------------------------------------------
-- API request helper
-----------------------------------------------------------------
local function apiRequest(method, path, body)
local requestInfo = {
Url = API_URL .. path,
Method = method,
Headers = {
["X-Api-Key"] = API_KEY,
["Content-Type"] = "application/json",
},
}
if body then
requestInfo.Body = HttpService:JSONEncode(body)
end
local success, response = pcall(function()
return HttpService:RequestAsync(requestInfo)
end)
if not success then
warn("[Playwave] HTTP request failed:", response)
return nil, "NETWORK_ERROR"
end
if response.StatusCode >= 400 then
local errorBody = nil
pcall(function()
errorBody = HttpService:JSONDecode(response.Body)
end)
return errorBody, "HTTP_" .. tostring(response.StatusCode)
end
local decodeSuccess, decoded = pcall(function()
return HttpService:JSONDecode(response.Body)
end)
if not decodeSuccess then
warn("[Playwave] JSON decode failed:", decoded)
return nil, "DECODE_ERROR"
end
return decoded, nil
end
-----------------------------------------------------------------
-- OTT verification + game session creation
-----------------------------------------------------------------
local function verifySession(player)
local ott = extractOtt(player)
if not ott then
return nil
end
local result, err = apiRequest("POST", "/game/session/verify", {
ott = ott,
provider_user_id = tostring(player.UserId),
})
if err then
warn("[Playwave] Verify failed for", player.Name, ":", err)
return nil
end
if result and result.success and result.data then
return result.data
end
return nil
end
-----------------------------------------------------------------
-- Heartbeat loop
-----------------------------------------------------------------
local function startHeartbeatLoop(userId, gameSessionId, providerUserId)
return task.spawn(function()
while activeSessions[userId] do
task.wait(HEARTBEAT_INTERVAL)
if not activeSessions[userId] then
break
end
local result, err = apiRequest("PATCH", "/game/session/heartbeat", {
game_session_id = gameSessionId,
provider_user_id = providerUserId,
})
if err then
if err == "HTTP_404" or err == "HTTP_410" then
warn("[Playwave] Session lost for UserId", userId, ":", err)
activeSessions[userId] = nil
local player = Players:GetPlayerByUserId(userId)
if player then
player:Kick("PlayWave session expired")
end
break
end
warn("[Playwave] Heartbeat error for UserId", userId, ":", err)
continue
end
if result and result.data then
local hbResult = result.data.result
if hbResult == "CHARGE_EXHAUSTED" then
local player = Players:GetPlayerByUserId(userId)
if player then
warn("[Playwave] Charge exhausted for", player.Name)
end
end
end
end
end)
end
-----------------------------------------------------------------
-- Session end
-----------------------------------------------------------------
local function endPlayerSession(userId)
local session = activeSessions[userId]
if not session then
return
end
activeSessions[userId] = nil
if session.heartbeatThread then
task.cancel(session.heartbeatThread)
end
local clientPlayDuration = math.floor(os.clock() - session.startTime)
local result, err = apiRequest("DELETE", "/game/session/end", {
game_session_id = session.gameSessionId,
play_duration_sec = clientPlayDuration,
})
if err then
if err ~= "HTTP_404" and err ~= "HTTP_409" then
warn("[Playwave] End session failed for UserId", userId, ":", err)
end
end
end
-----------------------------------------------------------------
-- Event connections
-----------------------------------------------------------------
Players.PlayerAdded:Connect(function(player)
local data = verifySession(player)
if not data or not data.is_valid then
if data and data.reason then
warn("[Playwave] Verify failed:", player.Name, data.reason)
end
return
end
local providerUserId = tostring(player.UserId)
activeSessions[player.UserId] = {
gameSessionId = data.game_session_id,
startTime = os.clock(),
heartbeatThread = nil,
}
activeSessions[player.UserId].heartbeatThread = startHeartbeatLoop(
player.UserId,
data.game_session_id,
providerUserId
)
-- Grant PC cafe benefits (implement per game)
if data.is_pc_cafe then
grantPcCafeBonus(player)
end
end)
Players.PlayerRemoving:Connect(function(player)
endPlayerSession(player.UserId)
end)
game:BindToClose(function()
for userId, _ in pairs(activeSessions) do
endPlayerSession(userId)
end
end)
-----------------------------------------------------------------
-- Per-game benefit logic (implement yourself)
-----------------------------------------------------------------
function grantPcCafeBonus(player)
-- Example: XP boost, bonus coins, exclusive items, etc.
print("[Playwave] PC cafe bonus granted to", player.Name)
end