Files
2026-07-08 20:42:51 +08:00

167 lines
5.1 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
[DefaultExecutionOrder(-200)]
public class PresetFactsInstaller : MonoBehaviour
{
[Header("References")]
[SerializeField] private ContextMemoryManager contextMemory;
[Header("Experiment Control")]
[SerializeField] private bool allowPresetFactsInjection = true;
[Header("Preset Source")]
[SerializeField] private bool applyWhenNoSaveFile = true;
[SerializeField] private bool applyWhenSaveMissingContextMemory = true;
[SerializeField] private bool overwriteExistingFacts = false;
[SerializeField] private string streamingAssetsRelativePath = "LLM/preset_facts.json";
[Header("Debug")]
[SerializeField] private bool debugLogs = true;
[Serializable]
private class PresetMemoryData
{
public List<ContextMemoryManager.FactEntry> facts;
public int counter;
}
[Serializable]
private class SaveDataWrapper
{
public List<string> keys = new List<string>();
public List<string> values = new List<string>();
}
private void Awake()
{
if (contextMemory == null)
{
contextMemory = FindObjectOfType<ContextMemoryManager>(true);
}
if (contextMemory == null)
{
if (debugLogs) Debug.LogWarning("[PresetFactsInstaller] ContextMemoryManager not found.", this);
return;
}
if (!allowPresetFactsInjection)
{
if (debugLogs) Debug.Log("[PresetFactsInstaller] Preset facts injection disabled by experiment config.", this);
return;
}
if (!applyWhenNoSaveFile) return;
string savePath = Path.Combine(Application.persistentDataPath, "savegame.json");
bool saveExists = File.Exists(savePath);
bool shouldApply = !saveExists;
if (saveExists && applyWhenSaveMissingContextMemory)
{
if (!SaveFileHasKey(savePath, "ContextMemory"))
{
shouldApply = true;
}
}
if (!shouldApply) return;
if (!overwriteExistingFacts && contextMemory.facts != null && contextMemory.facts.Count > 0) return;
StartCoroutine(LoadAndApplyRoutine(saveExists));
}
private IEnumerator LoadAndApplyRoutine(bool saveExists)
{
string fullPath = Path.Combine(Application.streamingAssetsPath, streamingAssetsRelativePath);
string json = null;
if (fullPath.Contains("://") || fullPath.Contains(":///"))
{
using (UnityWebRequest req = UnityWebRequest.Get(fullPath))
{
yield return req.SendWebRequest();
if (req.result != UnityWebRequest.Result.Success)
{
if (debugLogs) Debug.LogWarning($"[PresetFactsInstaller] Failed to read preset from '{fullPath}': {req.error}", this);
yield break;
}
json = req.downloadHandler.text;
}
}
else
{
if (!File.Exists(fullPath))
{
if (debugLogs) Debug.LogWarning($"[PresetFactsInstaller] Preset file not found: {fullPath}", this);
yield break;
}
json = File.ReadAllText(fullPath);
}
if (string.IsNullOrWhiteSpace(json))
{
if (debugLogs) Debug.LogWarning("[PresetFactsInstaller] Preset JSON is empty.", this);
yield break;
}
PresetMemoryData data = null;
try
{
data = JsonUtility.FromJson<PresetMemoryData>(json);
}
catch (Exception e)
{
if (debugLogs) Debug.LogWarning($"[PresetFactsInstaller] Preset JSON parse failed: {e.Message}", this);
}
if (data == null || data.facts == null)
{
if (debugLogs) Debug.LogWarning("[PresetFactsInstaller] Preset JSON has no facts.", this);
yield break;
}
contextMemory.facts = data.facts ?? new List<ContextMemoryManager.FactEntry>();
contextMemory.messagesSinceLastSummary = Mathf.Max(0, data.counter);
contextMemory.UpdateSystemPrompt();
if (saveExists)
{
while (Core.SaveSystem.SaveManager.Instance == null)
{
yield return null;
}
Core.SaveSystem.SaveManager.Instance.SaveGame();
}
if (debugLogs) Debug.Log($"[PresetFactsInstaller] Applied preset facts: {contextMemory.facts.Count}", this);
}
private bool SaveFileHasKey(string savePath, string key)
{
try
{
string json = File.ReadAllText(savePath);
if (string.IsNullOrWhiteSpace(json)) return false;
SaveDataWrapper wrapper = JsonUtility.FromJson<SaveDataWrapper>(json);
if (wrapper == null || wrapper.keys == null) return false;
return wrapper.keys.Contains(key);
}
catch
{
return false;
}
}
public void SetPresetFactsInjectionEnabled(bool enabled)
{
allowPresetFactsInjection = enabled;
}
}