Events working

dev-ali-supabase
Ali Sharoz 2 weeks ago
parent ff8803ba68
commit 8db95e6d40

@ -22160,6 +22160,50 @@ Transform:
m_CorrespondingSourceObject: {fileID: 4270791331071568, guid: f0bfb58546547264682d6066f7947e72, type: 3}
m_PrefabInstance: {fileID: 71862592}
m_PrefabAsset: {fileID: 0}
--- !u!1 &292487261
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 292487263}
- component: {fileID: 292487262}
m_Layer: 0
m_Name: SupabaseTestInsert
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &292487262
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 292487261}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 619706b2e2fd4fe4eb36567a686c7da0, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!4 &292487263
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 292487261}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -0.0981338, y: 2.3009996, z: 3.8460662}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!4 &292591182 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 4940683387464080, guid: 1941338505201ed4b86d0fc32a45bdcc, type: 3}
@ -154096,6 +154140,65 @@ Transform:
m_CorrespondingSourceObject: {fileID: 4829453017703304, guid: 07751b6a4092629438c147af65e877b3, type: 3}
m_PrefabInstance: {fileID: 1574431602}
m_PrefabAsset: {fileID: 0}
--- !u!1 &2143540272
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2143540275}
- component: {fileID: 2143540274}
- component: {fileID: 2143540273}
m_Layer: 0
m_Name: SupabaseManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &2143540273
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2143540272}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 50b27839ecef84443a10112beb860a7a, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &2143540274
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2143540272}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ef01b27a4a6f3724a981d178a963c567, type: 3}
m_Name:
m_EditorClassIdentifier:
supabaseUrl: https://vihjspljbslozbjzxutl.supabase.co
supabaseKey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZpaGpzcGxqYnNsb3pianp4dXRsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDk1NDc4OTMsImV4cCI6MjA2NTEyMzg5M30.IYPvShgu5j3NnE5PHn-aFLCBJl1QQaVQvAjzxFt8tlA
--- !u!4 &2143540275
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2143540272}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -0.0981338, y: 2.3009996, z: 3.8460662}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &2143858061
PrefabInstance:
m_ObjectHideFlags: 0
@ -160336,3 +160439,5 @@ SceneRoots:
- {fileID: 401603027}
- {fileID: 72663021}
- {fileID: 1568526664}
- {fileID: 2143540275}
- {fileID: 292487263}

@ -53,6 +53,8 @@ public class BodyLinkHandler : MonoBehaviour, IPointerClickHandler, IPointerExit
string arabicLog = $"تم الضغط على الرابط '{linkID}' في البريد من '{email.senderName}'";
UserActionLogger.Instance?.Log(englishLog, arabicLog);
bool isOptimal = !email.isPhishing;
SupabaseEventLogger.Instance?.LogDecisionEvent(isOptimal);
}
else

@ -54,6 +54,7 @@ public class CharacterMovement : MonoBehaviour
{
animator.SetTrigger("StartWalking");
isStarted = true;
SupabaseEventLogger.Instance?.StartSession();
InstructionManager.Instance?.ShowScreenInstruction("mission_intro");
}
void Update()

@ -129,6 +129,14 @@ public class EmailOpenPanel : MonoBehaviour
SceneOutcomeManager.Instance.Ignored(emailData);
break;
}
SupabaseEventLogger.Instance?.CompleteSessionAndSubmitResult(
userId: "user123", // replace with real user ID if available
passed: isCorrect,
optimal: isCorrect ? 1 : 0,
suboptimal: isCorrect ? 0 : 1,
scenarioId: "scene_1"
);
}
void LocalizeTMP(TextMeshProUGUI tmp, string english, string arabic)

@ -61,6 +61,9 @@ public class MiniQuizManager : MonoBehaviour
// Prepend a ✅ to the selected label
answerLabels[selectedIndex].text = "✅ " + answerLabels[selectedIndex].text;
bool isCorrect = (selectedIndex == correctIndex);
SupabaseEventLogger.Instance?.LogDecisionEvent(isCorrect);
}
}

@ -0,0 +1,180 @@
using UnityEngine;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Supabase; // Make sure SupabaseManager initializes this correctly
using Postgrest.Models;
using Postgrest.Attributes;
public class SupabaseEventLogger : MonoBehaviour
{
public static SupabaseEventLogger Instance;
private DateTime sessionStartTime;
private void Awake()
{
if (Instance == null)
Instance = this;
else
Destroy(gameObject);
}
/// <summary>
/// Call this at the start of the game session.
/// </summary>
public async void StartSession()
{
sessionStartTime = DateTime.UtcNow;
var gameEvent = new GameEvent
{
Id = Guid.NewGuid(), // <== Ensure this is explicitly set
EventKey = "game_session_started",
Timestamp = sessionStartTime,
UserId = "user123"
};
await Client.Instance.From<GameEvent>().Insert(gameEvent);
Debug.Log("✅ Supabase Event: game_session_started");
}
/// <summary>
/// Logs optimal/suboptimal decisions at runtime.
/// </summary>
public async void LogDecisionEvent(bool isOptimal)
{
string eventKey = isOptimal ? "game_optimal_decision_made" : "game_suboptimal_decision_made";
var gameEvent = new GameEvent
{
Id = Guid.NewGuid(),
EventKey = eventKey,
Timestamp = DateTime.UtcNow,
UserId = "user123"
};
await Client.Instance.From<GameEvent>().Insert(gameEvent);
Debug.Log($"✅ Supabase Event: {eventKey}");
}
/// <summary>
/// Completes the session and submits full results to phishing_game_attempts table.
/// </summary>
public async void CompleteSessionAndSubmitResult(string userId, bool passed, int optimal, int suboptimal, string scenarioId, List<Decision> decisionLog = null)
{
var endTime = DateTime.UtcNow;
int duration = (int)(endTime - sessionStartTime).TotalSeconds;
// Log completion events
await Client.Instance.From<GameEvent>().Insert(new GameEvent
{
Id = Guid.NewGuid(),
EventKey = "game_session_completed",
Timestamp = endTime,
UserId = userId
});
await Client.Instance.From<GameEvent>().Insert(new GameEvent
{Id = Guid.NewGuid(),
EventKey = "game_score_recorded",
Timestamp = endTime,
UserId = userId
});
// Insert session result
var gameAttempt = new GameAttempt
{
GameId = "phishing-awareness-1",
ScenarioId = scenarioId,
UserId = userId,
AttemptNumber = 1,
StartTime = sessionStartTime,
EndTime = endTime,
DurationSeconds = duration,
Score = passed ? 100 : 50,
Passed = passed,
Optimal = optimal,
Suboptimal = suboptimal,
KeyDecisionsLogJson = decisionLog != null ? JsonUtility.ToJson(new DecisionLogWrapper { decisions = decisionLog }) : "[]"
};
await Client.Instance.From<GameAttempt>().Insert(gameAttempt);
Debug.Log("✅ Supabase Game Result Submitted");
}
[Serializable]
public class Decision
{
public string decisionId;
public string timestamp;
public bool optimal;
}
[Serializable]
public class DecisionLogWrapper
{
public List<Decision> decisions;
}
}
// Existing SupabaseEventLogger class here...
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
[Table("game_events")]
public class GameEvent : BaseModel
{
[PrimaryKey("id", false)]
public Guid Id { get; set; }
[Column("event_key")]
public string EventKey { get; set; }
[Column("timestamp")]
public DateTime Timestamp { get; set; }
[Column("user_id")]
public string UserId { get; set; }
}
[Table("phishing_game_attempts")]
public class GameAttempt : BaseModel
{
[PrimaryKey("id", false)]
public Guid Id { get; set; } = Guid.NewGuid();
[Column("game_id")]
public string GameId { get; set; }
[Column("scenario_id")]
public string ScenarioId { get; set; }
[Column("user_id")]
public string UserId { get; set; }
[Column("attempt_number")]
public int AttemptNumber { get; set; }
[Column("start_timestamp")]
public DateTime StartTime { get; set; }
[Column("end_timestamp")]
public DateTime EndTime { get; set; }
[Column("duration_seconds")]
public int DurationSeconds { get; set; }
[Column("final_score_percentage")]
public float Score { get; set; }
[Column("pass_fail_status")]
public bool Passed { get; set; }
[Column("optimal_decisions_count")]
public int Optimal { get; set; }
[Column("suboptimal_decisions_count")]
public int Suboptimal { get; set; }
[Column("key_decisions_log")]
public string KeyDecisionsLogJson { get; set; }
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 50b27839ecef84443a10112beb860a7a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,31 @@
using Supabase;
using UnityEngine;
using System.Threading.Tasks;
public class SupabaseManager : MonoBehaviour
{
public static Supabase.Client Client => Supabase.Client.Instance;
[Header("Supabase Settings")]
public string supabaseUrl = "https://vihjspljbslozbjzxutl.supabase.co";
public string supabaseKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZpaGpzcGxqYnNsb3pianp4dXRsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDk1NDc4OTMsImV4cCI6MjA2NTEyMzg5M30.IYPvShgu5j3NnE5PHn-aFLCBJl1QQaVQvAjzxFt8tlA";
private async void Awake()
{
if (Supabase.Client.Instance != null)
{
Debug.Log("✅ Supabase already initialized.");
return;
}
var options = new SupabaseOptions
{
AutoConnectRealtime = false,
ShouldInitializeRealtime = false
};
await Supabase.Client.InitializeAsync(supabaseUrl, supabaseKey, options);
Debug.Log("✅ Supabase Initialized via static method");
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ef01b27a4a6f3724a981d178a963c567
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,39 @@
using UnityEngine;
using Supabase;
using System;
using Postgrest.Models;
using Postgrest.Attributes;
public class SupabaseTestInsert : MonoBehaviour
{
async void Start()
{
var gameEvent = new GameEvent
{
Id = Guid.NewGuid(),
EventKey = "manual_test_event",
Timestamp = DateTime.UtcNow,
UserId = "test_user_1"
};
Debug.Log("🔍 Trying test insert...");
await Client.Instance.From<GameEvent>().Insert(gameEvent);
Debug.Log("✅ Test insert complete");
}
[Table("game_events")]
public class GameEvent : BaseModel
{
[PrimaryKey("id", false)]
public Guid Id { get; set; }
[Column("event_key")]
public string EventKey { get; set; }
[Column("timestamp")]
public DateTime Timestamp { get; set; }
[Column("user_id")]
public string UserId { get; set; }
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 619706b2e2fd4fe4eb36567a686c7da0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
Loading…
Cancel
Save