Liberi
An exergame built for kids with CP!
All Classes Functions Variables Properties Events
Study.cs
1 using UnityEngine;
2 using System;
3 using System.Collections;
4 using System.Collections.Generic;
5 using System.IO;
6 using System.Linq;
7 using System.Reflection;
8 using System.Text;
9 
13 public partial class Study : MonoBehaviour
14 {
15  private delegate string LogColumnValueProvider ();
16 
20  public float MeasureLogInterval;
24  public string[] LogHeaderColumns;
28  public string[] LogColumns;
32  public string LogDateFormat = "yyyy-MM-dd";
36  public string LogTimeFormat = "HH:mm:ss";
40  public string LogTimeFileNameFormat = "HH-mm-ss";
41 
42  static Study _instance;
43  static ClientStudyConfig _studyConfig;
44  static Dictionary<Enum, string> _logEventFormats = new Dictionary<Enum, string>();
45  static List<StreamWriter> _logWriters = new List<StreamWriter>();
46  static List<LogColumnValueProvider> _logHeaderColumnValueProviders = new List<LogColumnValueProvider>();
47  static List<LogColumnValueProvider> _logColumnValueProviders = new List<LogColumnValueProvider>();
48  static int _logTypeColumnIndex = -1;
49  static int _logEventColumnIndex = -1;
50 
57  public static void LogEvent (Enum eventType, params object[] args)
58  {
59  if (!_studyConfig.LoggingEnabled)
60  return;
61 
62  string[] columnValues = GetLogColumnValues();
63 
64  if (_logTypeColumnIndex > -1 && _logTypeColumnIndex < columnValues.Length)
65  columnValues[_logTypeColumnIndex] = "E";
66 
67  if (_logEventColumnIndex > -1 && _logEventColumnIndex < columnValues.Length)
68  columnValues[_logEventColumnIndex] = string.Format(_logEventFormats[eventType], args);
69 
70  string line = string.Join("\t", columnValues);
71  WriteLogLine(line);
72  }
73 
74  void Awake ()
75  {
76  _instance = this;
77 
78  var assembly = Assembly.GetExecutingAssembly();
79 
80  foreach (var type in assembly.GetTypes())
81  {
82  if (!type.IsEnum)
83  continue;
84 
85  if (!type.Name.EndsWith("LogEvent"))
86  continue;
87 
88  foreach (MemberInfo enumMember in type.GetMembers())
89  {
90  var eventParamsAttrs = enumMember.GetCustomAttributes(typeof(LogEventAttribute), false);
91 
92  if (eventParamsAttrs.Length == 0)
93  continue;
94 
95  var eventType = (Enum)Enum.Parse(enumMember.DeclaringType, enumMember.Name);
96  var eventParamsAttr = (LogEventAttribute)eventParamsAttrs[0];
97  RegisterLogEventType(eventType, eventParamsAttr.ParamNames);
98  }
99  }
100 
101  var thisType = this.GetType();
102 
103  foreach (string columnHeading in LogHeaderColumns)
104  {
105  MethodInfo columnValueMethod = thisType.GetMethod(
106  "Get" + columnHeading.Replace(" ", "") + "HeaderColumnValue",
107  BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
108 
109  LogColumnValueProvider columnValueProvider = null;
110 
111  if (columnValueMethod != null)
112  {
113  try
114  {
115  columnValueProvider = Delegate.CreateDelegate(
116  typeof(LogColumnValueProvider), columnValueMethod) as LogColumnValueProvider;
117 
118  _logHeaderColumnValueProviders.Add(columnValueProvider);
119  }
120  catch { }
121  }
122  else _logHeaderColumnValueProviders.Add(null);
123  }
124 
125  foreach (string columnHeading in LogColumns)
126  {
127  MethodInfo columnValueMethod = thisType.GetMethod(
128  "Get" + columnHeading.Replace(" ", "") + "ColumnValue",
129  BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
130 
131  LogColumnValueProvider columnValueProvider = null;
132 
133  if (columnValueMethod != null)
134  {
135  try
136  {
137  columnValueProvider = Delegate.CreateDelegate(
138  typeof(LogColumnValueProvider), columnValueMethod) as LogColumnValueProvider;
139 
140  _logColumnValueProviders.Add(columnValueProvider);
141  }
142  catch { }
143  }
144  else _logColumnValueProviders.Add(null);
145  }
146 
147  _logTypeColumnIndex = Array.IndexOf(LogColumns, "Type");
148  _logEventColumnIndex = Array.IndexOf(LogColumns, "Event");
149 
150  _studyConfig = GameClient.Instance.Config.Study;
151  }
152 
153  void Start ()
154  {
155  GameClient.Instance.ConnectedToWorldServer += OnConnectedToWorldServer;
156  }
157 
158  void OnConnectedToWorldServer ()
159  {
160  if (_studyConfig.LoggingEnabled)
161  {
162  OpenLogs();
163  StartCoroutine(LogMeasures());
164  }
165  }
166 
167  void OnDestroy ()
168  {
169  StopAllCoroutines();
170  CloseLogs();
171  }
172 
173  private static void RegisterLogEventType (Enum eventType, params string[] paramNames)
174  {
175  for (int i = 0; i < paramNames.Length; i++)
176  {
177  var paramName = paramNames[i];
178 
179  if (paramName.Contains(":"))
180  {
181  int colonPos = paramName.IndexOf(":");
182  string actualParamName = paramName.Substring(0, colonPos);
183  string paramFormat = paramName.Substring(colonPos);
184  paramName = actualParamName + "={" + i + paramFormat + "}";
185  }
186  else paramName += "={" + i + "}";
187 
188  paramNames[i] = paramName;
189  }
190 
191  string eventTypeTypeName = eventType.GetType().Name;
192  eventTypeTypeName = eventTypeTypeName.Remove(eventTypeTypeName.IndexOf("LogEvent"));
193  string eventTypeFullName = eventTypeTypeName + "." + eventType.ToString();
194  _logEventFormats[eventType] = eventTypeFullName + ": {{ " + string.Join(", ", paramNames) + " }}";
195  }
196 
197  private static void OpenLogs ()
198  {
199  foreach (var logPathPattern in _studyConfig.LogPaths)
200  {
201  string logPath = logPathPattern;
202 
203  logPath = logPath
204  .Replace("<p>", Game.LocalPlayerID)
205  .Replace("<n>", Game.LocalPlayerProfile.Basic.Nickname)
206  .Replace("<d>", DateTime.Now.ToString(_instance.LogDateFormat))
207  .Replace("<t>", DateTime.Now.ToString(_instance.LogTimeFileNameFormat));
208 
209  Directory.CreateDirectory(GameClient.Instance.StudyLogsBase);
210 
211  try { _logWriters.Add(new StreamWriter(logPath)); }
212  catch { }
213  }
214 
215  WriteLogHeader();
216  }
217 
218  private static void CloseLogs ()
219  {
220  foreach (var logWriter in _logWriters)
221  {
222  if (logWriter != null)
223  logWriter.Dispose();
224  }
225 
226  _logWriters.Clear();
227  }
228 
229  private static void WriteLogHeader ()
230  {
231  WriteLogLine(string.Join("\t", _instance.LogHeaderColumns));
232  WriteLogLine(string.Join("\t", GetLogHeaderColumnValues()));
233  WriteLogLine(string.Join("\t", _instance.LogColumns));
234  }
235 
236  private static void WriteLogLine (string line)
237  {
238  foreach (var logWriter in _logWriters)
239  {
240  if (logWriter != null)
241  {
242  logWriter.WriteLine(line);
243  logWriter.Flush();
244  }
245  }
246  }
247 
248  IEnumerator LogMeasures ()
249  {
250  while (true)
251  {
252  yield return new WaitForSeconds(MeasureLogInterval);
253 
254  string[] columnValues = GetLogColumnValues();
255 
256  if (_logTypeColumnIndex > -1 && _logTypeColumnIndex < columnValues.Length)
257  columnValues[_logTypeColumnIndex] = "M";
258 
259  string line = string.Join("\t", columnValues);
260  WriteLogLine(line);
261  }
262  }
263 
264  private static string[] GetLogHeaderColumnValues ()
265  {
266  return _logHeaderColumnValueProviders.Select(p => p != null ? p.Invoke() : "").ToArray();
267  }
268 
269  private static string[] GetLogColumnValues ()
270  {
271  return _logColumnValueProviders.Select(p => p != null ? p.Invoke() : "").ToArray();
272  }
273 }
string LogDateFormat
Formatting for dates in logs.
Definition: Study.cs:32
Attribute to use on enumeration values, marking them as possible log event type.
Study configuration class for game client.
float MeasureLogInterval
The interval at which to log measures.
Definition: Study.cs:20
string LogTimeFileNameFormat
Formatting for times in logs.
Definition: Study.cs:40
string[] LogHeaderColumns
An array of strings representing the log header column headings.
Definition: Study.cs:24
string LogTimeFormat
Formatting for times in logs.
Definition: Study.cs:36
string[] LogColumns
An array of strings representing the log column headings.
Definition: Study.cs:28
ConnectedToWorldServerHandler ConnectedToWorldServer
Event fired when the game client successfully connects to the world server.
Definition: GameClient.cs:61
string StudyLogsBase
Gets the base path for study logs.
Definition: GameClient.cs:168
ClientConfig Config
Gets the configuration for this client.
Definition: GameClient.cs:176
static GameClient Instance
Gets the sole instance of the game client.
Definition: GameClient.cs:136
Main game client class.
Definition: GameClient.cs:16
Class for managing study-related game components.
Definition: Study.cs:13
static void LogEvent(Enum eventType, params object[] args)
Log a game event.
Definition: Study.cs:57