Skip to Content
DocsLoremind PlatformServer Integration Guide

Server Integration Guide

This guide shows how to integrate LoreMind with popular game server frameworks. Choose the pattern that matches your stack.

Server Mediated vs Direct Client

ConsiderationDirect ClientServer Mediated
Setup complexityLowerHigher
Player authenticationDevice-basedYour auth system
Rate limit controlLoreMind defaultsYour custom logic
Long-term memoryNot availableFull support (requires playerId)
Best forPrototypes, single-playerProduction, multiplayer

Nakama (TypeScript)

Nakama  is an open-source game server supporting realtime multiplayer, matchmaking, and server-side logic. LoreMind integrates via Nakama’s TypeScript runtime.

Register the RPC

// main.ts const InitModule: nkruntime.InitModule = function( ctx: nkruntime.Context, logger: nkruntime.Logger, nk: nkruntime.Nakama, initializer: nkruntime.Initializer ) { initializer.registerRpc('npc_interact', rpcNpcInteract); logger.info('LoreMind NPC module loaded'); }; const LOREMIND_URL = 'https://loremind.peekgames.dev/api/loremind/v1/npc/interact'; const LOREMIND_API_KEY = 'sk_server_your_key_here'; // Use env var in production

NPC Interaction RPC

const rpcNpcInteract: nkruntime.RpcFunction = function( ctx: nkruntime.Context, logger: nkruntime.Logger, nk: nkruntime.Nakama, payload: string ): string { const request = JSON.parse(payload); const playerId = ctx.userId; // Nakama user ID from authenticated session // Client sends context from Unity scene - server just forwards it const body = JSON.stringify({ text: request.message, entityMindId: request.entityMindId, playerId: playerId, // Server provides authenticated player ID memory: { retrieve: true }, context: request.context // Context comes from client (LocationZone, ContextTag, etc.) }); // Call LoreMind API const response = nk.httpRequest(LOREMIND_URL, 'post', { 'Content-Type': 'application/json', 'Authorization': `Bearer ${LOREMIND_API_KEY}` }, body, 30000); if (response.code !== 200) { logger.error(`LoreMind error: ${response.code} ${response.body}`); throw new Error('NPC service unavailable'); } const result = JSON.parse(response.body); logger.info(`NPC response for ${playerId}: ${result.metadata?.creditsUsed} credits`); return JSON.stringify({ response: result.response, character: result.character }); };

Unity Client (with Nakama)

The client gathers context from the scene using SDK components (LocationZone, ContextTag, etc.) and sends it to the server:

using Nakama; using Peek.LoreMind; public class NpcClient : MonoBehaviour { private IClient _client; private ISession _session; [SerializeField] private LoreMindNPC npc; public async Task<string> TalkToNpc(string message) { // Client builds context from scene state var payload = new { entityMindId = npc.EntityMindId, message = message, context = new { location = npc.Context.location, locationDetails = npc.Context.locationDetails, timeOfDay = npc.Context.timeOfDay, weather = npc.Context.weather, nearbyCharacters = npc.Context.nearbyCharacters, playerAppearance = npc.Context.playerAppearance, recentEvents = npc.Context.recentEvents } }; var response = await _client.RpcAsync(_session, "npc_interact", JsonConvert.SerializeObject(payload)); var result = JsonConvert.DeserializeObject<NpcResponse>(response.Payload); return result.response; } }

Resources:


PlayFab CloudScript

PlayFab  is Microsoft’s game backend with CloudScript for server-side logic.

CloudScript Function

// LoreMindNpc.js - PlayFab CloudScript handlers.NpcInteract = function(args, context) { const playerId = context.CallerEntityProfile.EntityId; // Client sends context from Unity scene - server adds playerId and forwards const requestBody = { text: args.message, entityMindId: args.entityMindId, playerId: playerId, // Server provides authenticated player ID memory: { retrieve: true }, context: args.context // Context comes from client }; const response = http.request( 'https://loremind.peekgames.dev/api/loremind/v1/npc/interact', 'POST', JSON.stringify(requestBody), 'application/json', { 'Authorization': 'Bearer ' + GetSecretValue('LOREMIND_API_KEY') } ); if (response.responseCode !== 200) { log.error('LoreMind error: ' + response.responseBody); return { error: 'NPC_UNAVAILABLE' }; } const result = JSON.parse(response.responseBody); // Track credits used server.WritePlayerEvent({ PlayFabId: playerId, EventName: 'npc_interaction', Body: { npcId: args.entityMindId, creditsUsed: result.metadata?.creditsUsed } }); return { response: result.response, character: result.character }; };

Unity Client (with PlayFab)

using PlayFab; using PlayFab.CloudScriptModels; using Peek.LoreMind; public class NpcClient : MonoBehaviour { [SerializeField] private LoreMindNPC npc; public async Task<string> TalkToNpc(string message) { // Client builds context from scene state var request = new ExecuteFunctionRequest { FunctionName = "NpcInteract", FunctionParameter = new { entityMindId = npc.EntityMindId, message = message, context = new { location = npc.Context.location, locationDetails = npc.Context.locationDetails, timeOfDay = npc.Context.timeOfDay, nearbyCharacters = npc.Context.nearbyCharacters, playerAppearance = npc.Context.playerAppearance } } }; var tcs = new TaskCompletionSource<string>(); PlayFabCloudScriptAPI.ExecuteFunction(request, result => { var response = JsonConvert.DeserializeObject<NpcResponse>( result.FunctionResult.ToString()); tcs.SetResult(response.response); }, error => tcs.SetException(new Exception(error.ErrorMessage)) ); return await tcs.Task; } }

Resources:


Custom Node.js

For studios with custom backends using Express, Fastify, or similar frameworks.

Express Server

// server.ts import express from 'express'; import { createClient } from 'redis'; const app = express(); const redis = createClient(); const LOREMIND_API_KEY = process.env.LOREMIND_API_KEY; app.use(express.json()); // Your auth middleware (Steam, Epic, custom JWT) app.use('/api/npc', authenticatePlayer); app.post('/api/npc/interact', async (req, res) => { const playerId = req.player.id; // From your auth middleware const { entityMindId, message, context } = req.body; // Context comes from client // Rate limiting const rateKey = `npc:rate:${playerId}`; const count = await redis.incr(rateKey); if (count === 1) await redis.expire(rateKey, 60); if (count > 10) { return res.status(429).json({ error: 'RATE_LIMITED' }); } // Client sends context from Unity scene - server adds playerId and forwards const response = await fetch( 'https://loremind.peekgames.dev/api/loremind/v1/npc/interact', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${LOREMIND_API_KEY}` }, body: JSON.stringify({ text: message, entityMindId: entityMindId, playerId: playerId, // Server provides authenticated player ID memory: { retrieve: true }, context: context // Context comes from client }) } ); if (!response.ok) { console.error('LoreMind error:', await response.text()); return res.status(503).json({ error: 'NPC_UNAVAILABLE' }); } const result = await response.json(); // Analytics analytics.track('npc_interaction', { playerId, entityMindId, creditsUsed: result.metadata?.creditsUsed }); res.json({ response: result.response, character: result.character }); });

Mirror + Dedicated Server

For games using Mirror  networking with a dedicated server that calls external APIs.

Dedicated Server (C#)

// NpcService.cs - runs on dedicated server public class NpcService { private readonly HttpClient _http; public NpcService(string apiKey) { _http = new HttpClient { BaseAddress = new Uri("https://loremind.peekgames.dev/api/loremind/v1/"), Timeout = TimeSpan.FromSeconds(30) }; _http.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}"); } public async Task<NpcResponse> GetResponse(NpcRequest request) { // Client sends context - server adds playerId and forwards var payload = new { text = request.Message, entityMindId = request.EntityMindId, playerId = request.PlayerId, // Server provides authenticated player ID memory = new { retrieve = true }, context = request.Context // Context comes from client }; var json = JsonSerializer.Serialize(payload); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await _http.PostAsync("npc/interact", content); var body = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { Debug.LogError($"LoreMind error: {response.StatusCode} {body}"); return null; } return JsonSerializer.Deserialize<NpcResponse>(body); } }

Mirror NetworkBehaviour

// NpcInteraction.cs using Peek.LoreMind; public class NpcInteraction : NetworkBehaviour { [SerializeField] private LoreMindNPC npc; private static NpcService _npcService; [Server] public static void InitializeService(string apiKey) { _npcService = new NpcService(apiKey); } // Client calls this Command, sending context from their scene [Command] public void CmdTalkToNpc(string message, RuntimeContext context) { var player = connectionToClient.identity.GetComponent<Player>(); StartCoroutine(HandleNpcRequest(player, message, context)); } [Server] private IEnumerator HandleNpcRequest(Player player, string message, RuntimeContext context) { var request = new NpcRequest { PlayerId = player.PlayerId, EntityMindId = npc.EntityMindId, Message = message, Context = context // Context came from client }; var task = _npcService.GetResponse(request); yield return new WaitUntil(() => task.IsCompleted); if (task.Result != null) { TargetReceiveResponse(connectionToClient, task.Result.response); } else { TargetReceiveResponse(connectionToClient, "*The character doesn't respond*"); } } [TargetRpc] private void TargetReceiveResponse(NetworkConnection conn, string response) { DialogueUI.Instance.ShowResponse(response); } } // Client-side: gather context and send to server public class NpcInteractionClient : MonoBehaviour { [SerializeField] private LoreMindNPC npc; [SerializeField] private NpcInteraction networkNpc; public void TalkToNpc(string message) { // Client builds context from scene state and sends to server networkNpc.CmdTalkToNpc(message, npc.Context); } }

Resources:


API Reference

Request Format

POST https://loremind.peekgames.dev/api/loremind/v1/npc/interact Authorization: Bearer sk_server_... Content-Type: application/json { "text": "What can you tell me about the dragon?", "entityMindId": "em_blacksmith_grom", "playerId": "steam_76561198012345678", "memory": { "retrieve": true }, "context": { "location": "Blacksmith Shop", "timeOfDay": "evening", "weather": "rainy", "playerReputation": "trusted ally", "recentEvents": ["Dragon spotted near village"] } }

Response Format

{ "success": true, "response": "The dragon? Aye, I've heard the rumors...", "character": "Grom the Blacksmith", "metadata": { "creditsUsed": 0.45, "creditsRemaining": 9543.20, "memoriesRetrieved": 2, "memoriesStored": 1 } }

Next Steps

Last updated on