A game about forced loneliness, made by TACStudios
1#if (ENABLE_INPUT_SYSTEM && INPUT_SYSTEM_INSTALLED)
2#define USE_INPUT_SYSTEM
3#endif
4
5using System.Collections.Generic;
6#if UNITY_EDITOR
7using UnityEditor;
8using UnityEngine.SceneManagement;
9using UnityEditor.SceneManagement;
10#endif
11using UnityEngine;
12using TMPro;
13using System.Collections;
14using UnityEngine.Rendering;
15using System.Text.RegularExpressions;
16#if USE_INPUT_SYSTEM
17using UnityEngine.InputSystem;
18#endif
19
20
21[ExecuteInEditMode]
22public class SamplesShowcase : MonoBehaviour
23{
24
25 public string headline = "Headline Goes Here";
26 // Color of the headline. light and dark theme variant.
27 public Color headlineLightColor = new Color(0.066f,0.066f,0.066f,1f);
28 public Color headlineDarkColor = new Color(0.82f,0.82f,0.82f,1f);
29 // Color of the text when a link is used to open an asset. light and dark theme variant.
30 public Color openLightColor = new Color(0.086f,0.427f,0.792f,1f);
31 public Color openDarkColor = new Color(0.478f,0.658f,0.933f,1f);
32 // Color of the text when a link is used to highlight an asset in the scene. light and dark theme variant.
33 public Color highlightLightColor = new Color(0.6f,0.4f,0f,1f);
34 public Color highlightDarkColor = new Color(1f,0.89f,0.45f,1f);
35 // Color for code markdown. light and dark theme variant.
36 public Color codeLightColor = new Color(0.76f,0.41f,0f,1f);
37 public Color codeDarkColor = new Color(0.91f,0.57f,0.17f,1f);
38 public TextAsset SamplesDescriptionsJson;
39 public enum Mode {Instantiation, Focus, TextOnly};
40 public GameObject[] samplesPrefabs;
41 public Mode PresentationMode = Mode.TextOnly;
42 public bool enableSelectButton = true;
43 public int currentIndex;
44 public GameObject currentPrefab;
45 int prefabIndex;
46 private Coroutine cameraCoroutine;
47
48 #if UNITY_EDITOR
49 [SerializeField]
50 public RequiredSettingsSO requiredSettingsSO;
51 #endif
52
53 //Variable containing TMPPro compatible sanitized text
54 public static string SanitizedIntroduction;
55 public static Dictionary<string, string> SanitizedDescriptions; //Key should be the prefabName, value is the description;
56 public static Dictionary<string, string> SanitizedTitles; //Key should be the prefabName, value is the title;
57
58 public TMP_Text gameobjectSamplesName; //if we want to have the samples name on a text mesh pro asset.
59 public TMP_Text gameobjectSamplesDescription; //if we want to have the samples name on a text mesh pro asset.
60
61 //Camera used to update view of samples focus in gameview
62 public Camera gameViewCamera;
63
64 private bool needUpdate;
65 private Vector3 savedPrefabPosition;
66
67 //Delegate to update every instance of samples showcase inspector UI
68 #if UNITY_EDITOR
69 public delegate void UpdateSamplesInspectorDelegate();
70 public static UpdateSamplesInspectorDelegate OnUpdateSamplesInspector;
71 void UpdateSamplesInspector()
72 {
73 if (OnUpdateSamplesInspector != null)
74 {
75 OnUpdateSamplesInspector();
76 }
77 }
78 #endif
79
80 void OnEnable()
81 {
82 // JSon data of the samples
83 if (SamplesDescriptionsJson != null)
84 {
85 string jsonText = CleanupJson(SamplesDescriptionsJson.text);
86
87 Samples sampleJsonObject = Samples.CreateFromJSON(jsonText, samplesPrefabs);
88
89 //Introduction, it's the first part of the Samples Description text asset
90 string introText = sampleJsonObject.introduction;
91 SamplesShowcase.SanitizedIntroduction = SanitizeText(introText);
92
93 SamplesShowcase.SanitizedDescriptions = new Dictionary<string, string>();
94 SamplesShowcase.SanitizedTitles = new Dictionary<string, string>();
95 foreach(GameObject prefab in samplesPrefabs)
96 {
97 Sample currentSample = sampleJsonObject.FindSampleWithPrefab(prefab);
98 if (currentSample == null)
99 continue;
100
101 string description = SanitizeText(currentSample.description);
102 SamplesShowcase.SanitizedDescriptions.Add(prefab.name, description);
103 SamplesShowcase.SanitizedTitles.Add(prefab.name, currentSample.title);
104 }
105 }
106 }
107
108 void OnValidate()
109 {
110 needUpdate = true;
111 }
112
113 void Update()
114 {
115 if (PresentationMode != Mode.TextOnly)
116 {
117 //Controls in GameMode
118 if (Application.isFocused && Application.isPlaying)
119 {
120#if ENABLE_LEGACY_INPUT_MANAGER
121 if (Input.GetKeyDown(KeyCode.RightArrow) || Input.GetKeyDown(KeyCode.UpArrow) )
122 {
123 SwitchEffect(currentIndex+1);
124 }
125 if (Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.DownArrow) )
126 {
127 SwitchEffect(currentIndex-1);
128 }
129#endif
130
131#if USE_INPUT_SYSTEM
132 if (Keyboard.current.rightArrowKey.wasPressedThisFrame || Keyboard.current.upArrowKey.wasPressedThisFrame)
133 {
134 SwitchEffect(currentIndex+1);
135 }
136
137 if(Keyboard.current.leftArrowKey.wasPressedThisFrame ||Keyboard.current.downArrowKey.wasPressedThisFrame)
138 {
139 SwitchEffect(currentIndex-1);
140 }
141#endif
142
143 }
144
145 if (needUpdate)
146 {
147 PresentSample(currentIndex);
148 needUpdate = false;
149 }
150 }
151
152
153 }
154
155 void SwitchEffect(int value)
156 {
157 currentIndex = value;
158 currentIndex = currentIndex > samplesPrefabs.Length - 1 ? 0 : currentIndex;
159 currentIndex = currentIndex < 0 ? samplesPrefabs.Length - 1 : currentIndex;
160 needUpdate = true;
161 }
162
163
164 void PresentSample(int index)
165 {
166 switch (PresentationMode)
167 {
168 case Mode.Instantiation:
169 if (index != prefabIndex)
170 {
171 CleanChildren();
172 if (index <= samplesPrefabs.Length && samplesPrefabs.Length > 0)
173 {
174 currentPrefab = samplesPrefabs[index];
175 }
176
177 // Instantiate the prefab as child
178 if (currentPrefab != null)
179 {
180 GameObject instantiatedPrefab = Instantiate(currentPrefab, transform.position, Quaternion.identity) as GameObject;
181 instantiatedPrefab.transform.parent = gameObject.transform;
182 instantiatedPrefab.transform.localRotation = Quaternion.identity;
183 currentPrefab = instantiatedPrefab;
184 prefabIndex = index;
185
186 // This is for keeping the prefab at the same position as before
187 instantiatedPrefab.transform.position = savedPrefabPosition;
188
189 }
190 }
191 break;
192
193 case Mode.Focus:
194 if (index <= samplesPrefabs.Length && samplesPrefabs.Length > 0)
195 {
196 currentPrefab = samplesPrefabs[index];
197 }
198
199 if (currentPrefab != null)
200 {
201 Transform viewPoint = currentPrefab.transform.Find("ViewPoint");
202 if (viewPoint != null)
203 {
204 // Align Scene View Camera
205 #if UNITY_EDITOR
206 SceneView view = SceneView.lastActiveSceneView;
207 if (view != null)
208 {
209 view.AlignViewToObject(viewPoint.transform);
210 }
211 #endif
212
213 // Align game view if a gameViewCamera is set
214 if (gameViewCamera != null)
215 {
216 if(cameraCoroutine !=null)
217 {
218 StopCoroutine(cameraCoroutine);
219 }
220 cameraCoroutine = StartCoroutine(lerpTransform(gameViewCamera.transform, viewPoint));
221 }
222 }
223 }
224 break;
225 }
226
227 #if UNITY_EDITOR
228 UpdateSamplesInspector();
229 #endif
230 }
231
232 private IEnumerator lerpTransform(Transform transformA, Transform transformB)
233 {
234 float startTime=Time.time;
235 while(Time.time-startTime<=1)//one second
236 {
237 transformA.position=Vector3.Lerp(transformA.position,transformB.position,Time.time-startTime);
238 transformA.rotation = Quaternion.Lerp(transformA.rotation,transformB.rotation, Time.time-startTime);
239 yield return 1; // wait for next frame
240 }
241 }
242
243
244 void CleanChildren()
245 {
246 //We just remove anything that has been spawn as child
247 if (transform.childCount > 0)
248 {
249 // This is for keeping the prefab at the same position as before
250 savedPrefabPosition = transform.GetChild(0).position;
251
252 foreach (Transform child in transform)
253 {
254 GameObject.DestroyImmediate(child.gameObject);
255 }
256 }
257 }
258
259 public static string GetSanitizedDescription(string prefabName)
260 {
261 if(SanitizedDescriptions == null) return "";
262
263 if(SanitizedDescriptions.ContainsKey(prefabName))
264 return SanitizedDescriptions[prefabName];
265
266 return "";
267 }
268
269 public static string GetSanitizedTitle(string prefabName)
270 {
271 if(SanitizedTitles == null) return "";
272
273 if(SanitizedTitles.ContainsKey(prefabName))
274 return SanitizedTitles[prefabName];
275
276 return "";
277 }
278
279 public static string GetSanitizedIntroduction()
280 {
281 return SanitizedIntroduction;
282 }
283
284 public static string SanitizeText(string text)
285 {
286 // Convert <br> to line break characters
287 text = text.Replace("<br>", "\n");
288
289 // Format <link> and <a>
290 text = Regex.Replace(text, @"<a[\s\S]*?>([\s\S]*?)<\/a>", $"$1");
291 text = Regex.Replace(text, @"<link[\s\S]*?>([\s\S]*?)<\/link>", $"$1");
292
293 // Add some offset to lists
294 text = text.Replace("�", " �");
295
296 // Remove text between <ignore> tags
297 text = Regex.Replace(text, @"<ignore>[\s\S]*?</ignore>", "");
298
299 return text;
300 }
301
302 public static string CleanupJson(string jsonString)
303 {
304 // Reformat json
305 // For text between triple quotes, remove \r \n \t characters
306
307 // Select text between triple quotes
308 string pattern = @"(\""\""\"")([\s\S]*?)(\""\""\"")";
309
310 // Clean it
311 jsonString = Regex.Replace(jsonString, pattern, m =>
312 {
313 string tripleQuotedText = m.Groups[2].Value;
314 // Replace newline by <br>
315 tripleQuotedText = tripleQuotedText.Replace("\n", "<br>");
316 // Escape quotes
317 tripleQuotedText = tripleQuotedText.Replace("\"", "\\\"");
318 // Remove carriage return and tabs
319 tripleQuotedText = Regex.Replace(tripleQuotedText, "[\r\t]", "");
320
321 return $"\"{tripleQuotedText}\"";
322 });
323
324 return jsonString;
325 }
326
327}