Saltar al contenido principal

Operaciones en Vivo

Las Operaciones en Vivo cubren eventos con límite de tiempo, tablas de clasificación, logros, guardado en la nube, copias de seguridad automáticas y soporte para mods. Estos sistemas permiten la entrega continua de contenido y la participación de los jugadores después del lanzamiento.

centro de LiveOps

Eventos, clasificaciones y logros en una sola pantalla. La cuenta atrás del evento activo es hora del servidor, no el reloj del cliente, y eso es lo que impide que un jugador termine un evento antes de tiempo cambiando la fecha de su sistema.

Descripción General de la Arquitectura​

ClaseArchivoResponsabilidad
EventServicePersistence/PersistenceAndSystems.csGestión de eventos estacionales/con tiempo limitado
LeaderboardServicePersistence/PersistenceAndSystems.csTablas de clasificación con envío de puntuaciones
AchievementServicePersistence/PersistenceAndSystems.csSistema de seguimiento y desbloqueo de logros
CloudSaveServicePersistence/PersistenceAndSystems.csSubida/descarga de guardado en la nube con detección de conflictos
BackupSchedulerAntiCheat/AntiCheatManager.csCopias de seguridad periódicas automatizadas en la nube
ModLoaderPersistence/PersistenceAndSystems.csCarga de mods de la comunidad en tiempo de ejecución

Acceso via NakamaManager.Instance:

var events = NakamaManager.Instance.Events;
var leaderboards = NakamaManager.Instance.Leaderboards;
var achievements = NakamaManager.Instance.Achievements;
var cloudSave = NakamaManager.Instance.CloudSave;
var mods = NakamaManager.Instance.Mods;

Servicio de Eventos​

EventService gestiona eventos en vivo con tiempo limitado (días comunitarios, contenido estacional, encuentros especiales).

Obtener Eventos Activos​

List<LiveEvent> activeEvents = await events.GetActiveEventsAsync();

foreach (var evt in activeEvents)
{
// evt.Id -- ID único del evento
// evt.Name -- nombre de visualización
// evt.Description -- detalles del evento
// evt.StartTime -- timestamp Unix (ms) de inicio
// evt.EndTime -- timestamp Unix (ms) de fin
// evt.RewardData -- configuración de recompensa codificada en JSON
}

Ciclo de Vida del Evento​

events.OnEventStarted += (LiveEvent evt) =>
{
Debug.Log($"Event started: {evt.Name}");
// Mostrar banner del evento, habilitar encuentros especiales, etc.
};

events.OnEventEnded += (string eventId) =>
{
Debug.Log($"Event ended: {eventId}");
// Eliminar contenido del evento, distribuir recompensas de participación
};

Modelo de Datos de LiveEvent​

CampoTipoDescripción
IdstringIdentificador único del evento
NamestringNombre de visualización
DescriptionstringTexto de descripción del evento
StartTimelongTimestamp de inicio (Unix ms)
EndTimelongTimestamp de fin (Unix ms)
RewardDatastringConfiguración de recompensa codificada en JSON

Los eventos se configuran del lado del servidor a través de la consola de Nakama. El cliente consulta eventos activos y reacciona a las notificaciones de inicio/fin.

Servicio de Tabla de Clasificación​

LeaderboardService proporciona tablas de clasificación con envío de puntuaciones y consultas de clasificación.

Enviar Puntuaciones​

await leaderboards.SubmitScoreAsync(
boardId: "pvp_season_1",
score: 1850);

await leaderboards.SubmitScoreAsync(
boardId: "dex_completion",
score: 151);

Consultar Clasificaciones​

// Obtener mejores jugadores
List<LeaderboardEntry> top100 = await leaderboards.GetTopPlayersAsync(
boardId: "pvp_season_1",
limit: 100);

foreach (var entry in top100)
{
// entry.Rank, entry.DisplayName, entry.Score, entry.UserId
}

// Obtener mi clasificación
LeaderboardEntry myRank = await leaderboards.GetMyRankAsync("pvp_season_1");

Refrescar Datos​

await leaderboards.RefreshAsync();

Modelo de Datos de LeaderboardEntry​

CampoTipoDescripción
UserIdstringID de usuario de Nakama del jugador
DisplayNamestringNombre de visualización del jugador
ScorelongValor de la puntuación
RankintPosición en la tabla de clasificación

Las tablas de clasificación soportan reinicios estacionales -- crea nuevos IDs de tabla por temporada (ej., pvp_season_2) y archiva los antiguos.

Servicio de Logros​

AchievementService rastrea los logros de los jugadores con soporte de progreso.

Listar Logros​

List<Achievement> all = await achievements.GetAchievementsAsync();

foreach (var ach in all)
{
// ach.Id, ach.Name, ach.Description
// ach.CurrentProgress, ach.MaxProgress
// ach.IsUnlocked, ach.RewardData
}

Desbloquear Logros​

// Desbloqueo instantáneo
await achievements.UnlockAsync("first_capture");

// Basado en progreso (ej., "Atrapa 100 monstruos")
await achievements.UpdateProgressAsync("centurion_catcher", progress: 47);

Eventos de Logros​

achievements.OnAchievementUnlocked += (Achievement ach) =>
{
Debug.Log($"Achievement unlocked: {ach.Name}!");
// Mostrar popup de desbloqueo, otorgar recompensa desde ach.RewardData
};

Refrescar Datos​

await achievements.RefreshAsync();

Modelo de Datos de Achievement​

CampoTipoDescripción
IdstringID único del logro
NamestringNombre de visualización
DescriptionstringDescripción del logro
CurrentProgressintValor de progreso actual
MaxProgressintProgreso objetivo para completar
IsUnlockedboolSi el logro está completado
RewardDatastringConfiguración de recompensa codificada en JSON

Servicio de Guardado en la Nube​

CloudSaveService conecta el sistema de guardado JSON existente de MCE con el almacenamiento del servidor Nakama, permitiendo el juego entre dispositivos.

Subir Guardados​

string saveJson = GetLocalSaveJson(); // Tu serialización de guardado
bool success = await cloudSave.UploadSaveAsync(saveJson);

// cloudSave.HasCloudSave -- true después de una subida exitosa
// cloudSave.LastSyncTimestamp -- timestamp Unix de la última sincronización

Descargar Guardados​

string saveJson = await cloudSave.DownloadSaveAsync();
// Deserializar y aplicar al estado local del juego

Detección de Conflictos​

Al guardar, el sistema puede detectar conflictos entre datos locales y en la nube:

SaveConflictInfo conflict = await cloudSave.CheckSaveConflictAsync(localTimestamp);

if (conflict.HasConflict)
{
// conflict.CloudTimestamp vs conflict.LocalTimestamp
// Presentar UI para que el jugador elija qué guardado conservar
}

Sincronización Especializada​

// Sincronizar cajas del PC (almacenamiento de monstruos)
await cloudSave.SyncPCStorageAsync(pcStorageJson);

// Sincronizar datos de progreso (medallas, Pokédex, misiones)
await cloudSave.SyncProgressionAsync(progressionJson);

Programador de Copias de Seguridad​

BackupScheduler es un MonoBehaviour que crea copias de seguridad automáticas periódicas en la nube.

Configuración​

CampoDefaultDescripción
autoSaveIntervalMinutes5Minutos entre copias de seguridad automáticas
maxBackupSlots10Tamaño máximo del historial de copias (rotación FIFO)

Qué respalda​

Una copia sube lo que devuelve el SaveDataProvider del planificador (un Func<string>). Cuando no estableces uno, el planificador usa LocalSaveDataProvider, que lee el guardado más reciente de SavegameManager que haya en disco. Si no hay proveedor, ni guardado en disco, ni conexión, la copia se omite y se dispara OnBackupFailed: no se sube nada y no se escribe ninguna entrada en el historial.

Copia de Seguridad Manual​

backupScheduler.CreateBackupAsync();

Restaurar desde Copia de Seguridad​

string saveJson = await backupScheduler.RestoreBackupAsync(backupId);

Eventos de Copia de Seguridad​

backupScheduler.OnBackupCreated += (BackupEntry entry) =>
{
// entry.Id, entry.Timestamp, entry.Type, entry.SizeBytes
};

backupScheduler.OnBackupFailed += (string reason) =>
{
Debug.LogWarning($"Backup failed: {reason}");
};

Tipos de Copia de Seguridad​

TipoDescripción
AutoCopia de seguridad periódica automática
ManualCopia de seguridad iniciada por el jugador
PreBattleInstantánea antes de entrar en batalla
PreTradeInstantánea antes de ejecutar un intercambio

Soporte de Mods​

ModLoader permite cargar paquetes de contenido creados por la comunidad en tiempo de ejecución. Esto está controlado por OnlineConfig.EnableModSupport (default: false).

Cargar Mods​

Los mods instalados se cargan automáticamente durante la conexión cuando el soporte de mods está habilitado:

await mods.LoadInstalledModsAsync();

Instalar y Eliminar Mods​

bool installed = await mods.InstallModAsync("/path/to/mod.zip");
bool removed = await mods.UninstallModAsync(modId);

Listar Mods Cargados​

IReadOnlyList<ModManifest> loadedMods = mods.LoadedMods;

foreach (var mod in loadedMods)
{
// mod.Id, mod.Name, mod.Author, mod.Version
// mod.Description, mod.IsEnabled
// mod.ContentTypes -- ej., ["monsters", "maps", "items", "moves"]
}

Eventos de Mods​

mods.OnModLoaded += (ModManifest manifest) =>
{
Debug.Log($"Mod loaded: {manifest.Name} v{manifest.Version}");
};

mods.OnModError += (string modId, string error) =>
{
Debug.LogError($"Mod error ({modId}): {error}");
};

Modelo de Datos de ModManifest​

CampoTipoDescripción
IdstringIdentificador único del mod
NamestringNombre de visualización
AuthorstringAutor del mod
VersionstringVersión semántica
DescriptionstringDescripción del mod
ContentTypesstring[]Tipos de contenido: "monsters", "maps", "items", "moves"
IsEnabledboolSi el mod está actualmente activo

Sistemas Anti-Trampas​

La capa anti-trampas funciona junto con las operaciones en vivo para mantener la integridad del juego. Consulta las clases dedicadas anti-trampas en AntiCheat/AntiCheatManager.cs:

  • SpeedValidator: Detecta hacks de velocidad comparando la velocidad de movimiento contra un máximo configurable (default: 8 tiles/segundo).
  • ActionRateLimiter: Previene el spam de acciones con un intervalo mínimo configurable (default: 0.3 segundos).
  • InventoryAuditor: Detecta duplicación de objetos y objetos ilegales comparando el inventario reportado por el cliente contra las instantáneas del servidor.
  • AntiCheatManager: Coordina todos los validadores con umbrales de violación -- 10 violaciones activan una expulsión, 25 activan una prohibición.