{"id":"playboymax/datamanager","name":"datamanager","scope":"playboymax","platform":"roblox","description":"Player Data System using ProfileStore: profiles, currency, leaderstats, and load callbacks.","version":"0.1.0","latest":"0.1.0","versions":["0.1.0"],"license":"MIT","licenseRating":"safe","licenseCaveats":[],"licenseVerified":true,"dependencies":{},"integrity":"71c714fb5516dd57fdc1f211d1d382c6176b03c77e55bdf8d7ae056ae2a88422","likes":0,"downloads":0,"install":"forest install playboymax/datamanager","url":"https://forest.dev/p/roblox/playboymax/datamanager","files":"https://api.forest.dev/ai/package/roblox/playboymax/datamanager/files","readme":"# DataManager\n\nModulo de servidor para cargar y guardar datos de jugadores con [ProfileStore](https://github.com/MadStudioRoblox/ProfileStore). Incluye bloqueo de sesiones, reconciliacion de plantillas, acceso a datos por rutas, callbacks al cargar el perfil y creacion opcional de `leaderstats`.\n\n## Requisitos\n\n- Roblox Studio y un juego publicado para probar DataStores reales.\n- Activar **Game Settings > Security > Enable Studio Access to API Services** si se quiere probar el acceso a DataStores desde Studio.\n- Usar este modulo desde scripts del servidor. No requiere ni expone perfiles al cliente.\n\nProfileStore usa el store `Test` por defecto en Studio y `Live` en servidores publicados. Los dos nombres permiten separar los datos de prueba y produccion.\n\n## Instalacion con Wally\n\nAgrega el paquete como dependencia del servidor en el `wally.toml` de tu juego:\n\n```toml\n[server-dependencies]\ndatamanager = \"playboymax/datamanager@0.1.0\"\n```\n\nEjecuta `wally install` y sincroniza la carpeta de paquetes con Rojo. El paquete tiene `realm = \"server\"`; coloca o mapea el paquete bajo `ServerScriptService`. El nombre exacto del hijo depende del alias y del mapeo que uses en tu proyecto.\n\n## Inicio\n\nCrea una plantilla propia en tu juego. Debe ser una tabla compatible con ProfileStore: usa tablas planas con claves de cadena o arreglos numericos densos, y valores booleanos, cadenas, numeros finitos u otras tablas compatibles. No incluyas `Instance`, funciones, userdata, ciclos, claves mixtas ni arreglos con huecos. Las tablas vacias como `Upgrades = {}` permiten agregar claves dinamicamente con `Set` siempre que exista la tabla contenedora.\n\n```lua\nreturn {\n\tCurrencies = {\n\t\tCoins = 0,\n\t\tDiamonds = 0,\n\t},\n\tStats = {\n\t\tTotalClicks = 0,\n\t},\n\tUpgrades = {},\n\tLastLogout = 0, -- opcional; se actualiza al salir si existe y es numerico\n}\n```\n\nDesde un unico `Script` dentro de `ServerScriptService`, requiere el paquete y la plantilla, y llama `Start` una vez:\n\n```lua\nlocal ServerScriptService = game:GetService(\"ServerScriptService\")\n\n-- Ajusta estos requires al lugar donde Rojo/Wally mapeo los modulos.\nlocal DataManager = require(ServerScriptService.Packages.datamanager)\nlocal Template = require(ServerScriptService.Data.Template)\n\nDataManager.Start(Template, {\n\tLeaderstats = { \"Currencies.Coins\", \"Currencies.Diamonds\" },\n\t-- StoreName = \"MiStoreDePrueba\", -- opcional: reemplaza Test/Live\n})\n```\n\n`Start` conecta `PlayerAdded` y `PlayerRemoving`, carga los perfiles como `Player_<UserId>`, reconcilia los datos con la plantilla y registra cada usuario con `AddUserId`. No llames `Start` desde un LocalScript ni mas de una vez por servidor.\n\n## API\n\nLas rutas usan segmentos separados por puntos. Las llamadas de escritura deben hacerse desde scripts del servidor.\n\n```lua\nDataManager.GetProfile(player) -- perfil activo o nil\nDataManager.Get(player, \"Currencies.Coins\") -- valor o nil\n\nDataManager.Set(player, \"Upgrades.Speed\", 3) -- fija o crea la clave final\nDataManager.Increment(player, \"Currencies.Coins\", 50) -- suma; devuelve el nuevo valor\n\nDataManager.OnProfileLoaded(player, function(profile)\n\tprint(profile.Data.Stats.TotalClicks)\nend)\n```\n\n- `GetProfile(player)` devuelve el perfil activo o `nil` si aun no ha cargado.\n- `Get(player, path)` devuelve el valor de la ruta o `nil` si el perfil o la ruta no existen.\n- `Set(player, path, value)` escribe una ruta cuyo contenedor existe. Puede crear una clave final nueva (por ejemplo, `Upgrades.Speed` cuando `Upgrades` es una tabla). Por eso, un error de escritura en una clave nueva como `Currencies.Coin` tambien crea esa clave; revisa las rutas y nombres. Si la clave ya existe, el valor debe conservar el mismo tipo. Rechaza `nil`, valores no finitos y valores que ProfileStore no puede guardar. En caso de error, avisa con `warn` y no cambia los datos.\n- `Increment(player, path, amount)` solo opera sobre numeros finitos y rechaza cantidades o resultados no finitos. Para rutas configuradas como `Leaderstats`, el resultado debe seguir siendo entero. Devuelve el nuevo valor o `nil` si no pudo actualizarlo.\n- `OnProfileLoaded(player, callback)` ejecuta el callback en una tarea separada cuando el perfil esta disponible. Si ya esta cargado, lo ejecuta de inmediato en una tarea separada.\n\n`Set` acepta valores serializables por ProfileStore: booleanos, cadenas, numeros finitos y tablas sin ciclos. Las tablas deben usar claves de cadena o arreglos numericos densos; no uses `Instance`, funciones, userdata ni tablas mixtas con claves de cadena y numero. La validacion de una tabla completa recorre todos sus elementos, asi que evita llamar `Set` repetidamente con tablas grandes dentro de bucles. Para actualizaciones de tablas grandes, puedes obtener la tabla con `Get` y modificarla directamente mientras el perfil este activo, pero esa modificacion omite la validacion de DataManager y no sincroniza leaderstats. Cambiar los datos directamente con `GetProfile(player).Data` tambien omite esas protecciones; usa `Set` e `Increment` para cambios normales.\n\n## Leaderstats\n\nPasa las rutas que quieres mostrar en `options.Leaderstats`. Cada ruta debe existir en la plantilla con un numero entero finito. Se crea un `IntValue` con el nombre del ultimo segmento; por eso las rutas no pueden terminar con el mismo nombre (por ejemplo, `Currencies.Coins` y `Stats.Coins`). Si la configuracion no cumple esos requisitos, `Start` genera un error claro en vez de iniciar con datos inconsistentes.\n\n`Set` e `Increment` mantienen el `IntValue` sincronizado. No incluyas valores decimales en `Leaderstats`; usa una ruta que no se muestre en el leaderboard para datos decimales.\n\n## Cierre y guardado\n\nProfileStore guarda los perfiles automaticamente, libera la sesion al salir el jugador y gestiona el cierre del servidor con `BindToClose`. DataManager actualiza `LastLogout` a `os.time()` durante `PlayerRemoving` solo cuando el perfil ya tiene un campo `LastLogout` numerico. Si no necesitas esa marca de tiempo, puedes omitirla de la plantilla.\n\nNo guardes el mismo perfil con otro sistema mientras esta activa la sesion de ProfileStore. El perfil solo se debe usar mientras este cargado y activo.\n\n## Licencias y atribucion\n\nDataManager se distribuye bajo la licencia MIT incluida en `LICENSE`. `ProfileStore.luau` es codigo de MAD STUDIO / loleris y conserva su licencia Apache 2.0 en `LICENSE-ProfileStore`. Revisa ambos archivos antes de redistribuir el paquete.\n","readmeTruncated":false}