Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*

!.gitignore
!ignore.conf
!*.md

!Packages/
Expand All @@ -20,6 +21,9 @@
!Assets/Animation/
!Assets/Animation/**

!Assets/StreamingAssets/
!Assets/StreamingAssets/Models/

!PythonFiles/
!PythonFiles/**

Expand Down
41 changes: 25 additions & 16 deletions Assets/Scripts/Authentication/AuthManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,29 @@ public class AuthManager : MonoBehaviour

private void Awake()
{
Instance = this;
GenerateDynamicSecret();
GenerateSessionKey();
SetupAuthenticationPipe();

// CRITICAL: Register for domain reload cleanup
#if UNITY_EDITOR
UnityEditor.AssemblyReloadEvents.beforeAssemblyReload += OnBeforeDomainReload;
#endif
if (constData._tcp){
Instance = this;
GenerateDynamicSecret();
GenerateSessionKey();
SetupAuthenticationPipe();

// CRITICAL: Register for domain reload cleanup
#if UNITY_EDITOR
UnityEditor.AssemblyReloadEvents.beforeAssemblyReload += OnBeforeDomainReload;
#endif
}
}

#if UNITY_EDITOR
private void OnBeforeDomainReload()
{
Debug.Log("AuthManager: Domain reload detected - cleaning up immediately");
CleanupIPC();
UnityEditor.AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeDomainReload;
if (constData._tcp){
Debug.Log("AuthManager: Domain reload detected - cleaning up immediately");
CleanupIPC();
UnityEditor.AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeDomainReload;
}
}

#endif

private void GenerateDynamicSecret()
Expand Down Expand Up @@ -206,14 +211,18 @@ public bool ValidateResponse(string response)

private void OnApplicationQuit()
{
// Clean up IPC resources
CleanupIPC();
if (constData._tcp){
// Clean up IPC resources
CleanupIPC();
}
}

private void OnDestroy()
{
// Clean up IPC resources
CleanupIPC();
if (constData._tcp){
// Clean up IPC resources
CleanupIPC();
}
}

public static void ForceCleanupAllInstances()
Expand Down
2 changes: 1 addition & 1 deletion Assets/Scripts/Hasher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

public class Hasher : MonoBehaviour
{
Dictionary<GUID, ConnectionInfo> npcHash = new Dictionary<GUID, ConnectionInfo>();
private Dictionary<GUID, ConnectionInfo> npcHash = new Dictionary<GUID, ConnectionInfo>();
public static Hasher Instance { get; private set; }
private bool applicationOver = false;
public void Awake()
Expand Down
122 changes: 62 additions & 60 deletions Assets/Scripts/Killports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,73 +10,75 @@ public class Killports : MonoBehaviour
// Start is called once before the first execution of Update after the MonoBehaviour is created
void OnApplicationQuit()
{
UnityEngine.Debug.Log("Killing processes on port " + port);
try
{
// Use netstat to find processes using this port
Process process = new Process();
if (Application.platform == RuntimePlatform.WindowsEditor ||
Application.platform == RuntimePlatform.WindowsPlayer) {
// Windows netstat command
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = $"/c netstat -ano | findstr :{port}";
}
else{
// Unix netstat command
process.StartInfo.FileName = "/bin/bash";
process.StartInfo.Arguments = $"-c netstat -ano | grep {port}";
}
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;

process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();

UnityEngine.Debug.Log($"Netstat output: {output}");

// Extract PIDs using regex - only match lines where 25001 is the first port
Regex pidRegex = new Regex(@"TCP\s+\d+\.\d+\.\d+\.\d+:25001\s+\d+\.\d+\.\d+\.\d+:\d+\s+\w+\s+(\d+)", RegexOptions.Multiline);
MatchCollection matches = pidRegex.Matches(output);

UnityEngine.Debug.Log($"Found {matches.Count} listener processes on port {port}");

// Kill each process found
foreach (Match match in matches)
if (constData._tcp){
UnityEngine.Debug.Log("Killing processes on port " + port);
try
{
// The PID is in the first capture group
string pidString = match.Groups[1].Value.Trim();
if (int.TryParse(pidString, out int pid))
// Use netstat to find processes using this port
Process process = new Process();
if (Application.platform == RuntimePlatform.WindowsEditor ||
Application.platform == RuntimePlatform.WindowsPlayer) {
// Windows netstat command
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = $"/c netstat -ano | findstr :{port}";
}
else{
// Unix netstat command
process.StartInfo.FileName = "/bin/bash";
process.StartInfo.Arguments = $"-c netstat -ano | grep {port}";
}
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;

process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();

UnityEngine.Debug.Log($"Netstat output: {output}");

// Extract PIDs using regex - only match lines where 25001 is the first port
Regex pidRegex = new Regex(@"TCP\s+\d+\.\d+\.\d+\.\d+:25001\s+\d+\.\d+\.\d+\.\d+:\d+\s+\w+\s+(\d+)", RegexOptions.Multiline);
MatchCollection matches = pidRegex.Matches(output);

UnityEngine.Debug.Log($"Found {matches.Count} listener processes on port {port}");

// Kill each process found
foreach (Match match in matches)
{
// Skip PID 0 and other system processes
if (pid == 0 || pid == 4) // PID 4 is the System process on Windows
// The PID is in the first capture group
string pidString = match.Groups[1].Value.Trim();
if (int.TryParse(pidString, out int pid))
{
UnityEngine.Debug.Log($"Skipping system process with PID {pid}");
continue;
}
// Skip PID 0 and other system processes
if (pid == 0 || pid == 4) // PID 4 is the System process on Windows
{
UnityEngine.Debug.Log($"Skipping system process with PID {pid}");
continue;
}

// Also good to check against current process
if (pid == Process.GetCurrentProcess().Id)
{
UnityEngine.Debug.Log($"Skipping current process with PID {pid}");
continue;
}
try
{
Process.GetProcessById(pid).Kill();
UnityEngine.Debug.Log($"Killed process with PID {pid} hosting port {port}");
}
catch (Exception ex)
{
UnityEngine.Debug.LogError($"Failed to kill process {pid}: {ex.Message}");
// Also good to check against current process
if (pid == Process.GetCurrentProcess().Id)
{
UnityEngine.Debug.Log($"Skipping current process with PID {pid}");
continue;
}
try
{
Process.GetProcessById(pid).Kill();
UnityEngine.Debug.Log($"Killed process with PID {pid} hosting port {port}");
}
catch (Exception ex)
{
UnityEngine.Debug.LogError($"Failed to kill process {pid}: {ex.Message}");
}
}
}
}
}
catch (Exception ex)
{
UnityEngine.Debug.LogError($"Error killing processes on port {port}: {ex.Message}");
catch (Exception ex)
{
UnityEngine.Debug.LogError($"Error killing processes on port {port}: {ex.Message}");
}
}
}
}
22 changes: 19 additions & 3 deletions Assets/Scripts/NPC/LLM_NPCController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,26 @@ private string reformatDialog(List<string> dialog){
}

public async Task<string> getDialog(List<string> userSpeech, GUID npcID){
Debug.Log("Still connected to NPC: " + Hasher.Instance.getNPCConnection(npcID).Client.Connected);
string conversation = reformatDialog(userSpeech);
try{
string dialog = await ServerSocketC.Instance.NPCRequest(conversation, Hasher.Instance.getNPCConnection(npcID).Client, Hasher.Instance.getNPCConnection(npcID).Stream);
string dialog;
if (constData._tcp)
{
Debug.Log("Still connected to NPC: " + Hasher.Instance.getNPCConnection(npcID).Client.Connected);
string conversation = reformatDialog(userSpeech);
Debug.Log("Sending to TCP server ----------- " + conversation);
dialog = await ServerSocketC.Instance.NPCRequest(conversation, Hasher.Instance.getNPCConnection(npcID).Client, Hasher.Instance.getNPCConnection(npcID).Stream);
}
else
{
NPCContext_intf ctx = UnityLLMContextHasher.Instance.getNPCContext(npcID);
// On the very first turn dialog.Lines = [systemPrompt] only.
// Sending the system prompt as a User message confuses the model;
// use a neutral opener so the NPC introduces itself from its personality.
string userMsg = userSpeech.Count == 1 ? "Hello" : userSpeech[^1];
Debug.Log("Sending to LLM ----------- " + userMsg);
dialog = await UnityLLM.Instance.talk2LLMWithContext(ctx, userMsg);
}
Debug.Log("Got back from LLM --------- " + dialog);
return dialog;
}catch (System.Exception e){
Debug.Log(e.Message);
Expand Down
32 changes: 27 additions & 5 deletions Assets/Scripts/NPC/NPCController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class NPCController : MonoBehaviour, Interactable_intf

public enum NPCState { Idle, Walking, Speaking }
CharacterMove charMove;

NPCState state;
float idleTimer = 0f;
int currentPattern = 0;
Expand All @@ -33,6 +33,7 @@ public enum NPCState { Idle, Walking, Speaking }
public GUID npcID { get; private set; }

private bool stopRetrying = false;
private string npcPersonality;

public void Interact(Transform initiator)
{
Expand Down Expand Up @@ -80,8 +81,9 @@ public void Interact(Transform initiator)

private void dialogBecomesContext()
{
npcPersonality = LLM_NPCController.Instance.generatePersonality(ogAI);
dialog = new Dialog();
dialog.initFirst(LLM_NPCController.Instance.generatePersonality(ogAI));
dialog.initFirst(npcPersonality);
}

private void Awake()
Expand All @@ -99,7 +101,17 @@ private void Start()
{
isAI = true;
dialogBecomesContext();
establishAndStoreConnection();
if (constData._tcp)
{
#pragma warning disable CS0162
_ = establishAndStoreConnection();
#pragma warning restore CS0162
}
else
{
NPCContext ctx = UnityLLM.CreateNPCContext(npcID, npcPersonality);
UnityLLMContextHasher.Instance.HashNPC(npcID, ctx);
}
}

}
Expand Down Expand Up @@ -158,8 +170,18 @@ private void OnDestroy()

if (isAI)
{
Debug.Log("NPCController: OnDestroy - Stopping NPC connection");
stopRetrying = true;
if (constData._tcp)
{
#pragma warning disable CS0162
Debug.Log("NPCController: OnDestroy - Stopping NPC connection");
stopRetrying = true;
#pragma warning restore CS0162
}
else
{
UnityLLMContextHasher.Instance.getNPCContext(npcID)?.Close();
Debug.Log("NPCController: OnDestroy - Closed NPC llama.cpp context");
}
}
}
}
Loading