Skip to content
This repository was archived by the owner on Sep 8, 2024. It is now read-only.

Commit 21e6f7d

Browse files
committed
Initial checkin
1 parent b1e81ff commit 21e6f7d

File tree

120 files changed

+21542
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+21542
-0
lines changed

Compiler/Compiler.cs

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Text.RegularExpressions;
6+
7+
namespace TextAdventures.Quest
8+
{
9+
public class CompileOptions
10+
{
11+
public string Filename { get; set; }
12+
public string OutputFolder { get; set; }
13+
public bool DebugMode { get; set; }
14+
public string Profile { get; set; }
15+
public bool Minify { get; set; }
16+
public bool Gamebook { get; set; }
17+
}
18+
19+
public class Compiler
20+
{
21+
public class CompilerResults : EventArgs
22+
{
23+
public bool Success { get; set; }
24+
public List<string> Errors { get; set; }
25+
public List<string> Warnings { get; set; }
26+
public string IndexHtml { get; set; }
27+
}
28+
29+
public class StatusUpdate : EventArgs
30+
{
31+
public string Message { get; set; }
32+
}
33+
34+
public class ProgressEventArgs : EventArgs
35+
{
36+
public int Progress { get; set; }
37+
}
38+
39+
public event EventHandler<CompilerResults> CompileFinished;
40+
public event EventHandler<StatusUpdate> StatusUpdated;
41+
public event EventHandler<ProgressEventArgs> Progress;
42+
43+
public List<string> GetValidProfiles()
44+
{
45+
return new List<string> { "Web" };
46+
}
47+
48+
public void StartCompile(CompileOptions compileOptions)
49+
{
50+
try
51+
{
52+
CompilerResults results = Compile(compileOptions);
53+
if (CompileFinished != null)
54+
{
55+
CompileFinished(this, results);
56+
}
57+
}
58+
catch (Exception ex)
59+
{
60+
CompilerResults results = new CompilerResults { Success = false, Errors = new List<string> { ex.ToString() } };
61+
if (CompileFinished != null)
62+
{
63+
CompileFinished(this, results);
64+
}
65+
}
66+
}
67+
68+
public CompilerResults Compile(CompileOptions compileOptions)
69+
{
70+
CompilerResults result = new CompilerResults();
71+
GameLoader loader = new GameLoader();
72+
UpdateStatus(string.Format("Compiling {0} to {1}", compileOptions.Filename, compileOptions.OutputFolder));
73+
if (!loader.Load(compileOptions.Filename))
74+
{
75+
result.Errors = loader.Errors;
76+
}
77+
else
78+
{
79+
UpdateStatus("Loaded successfully");
80+
result.Warnings = loader.Warnings;
81+
result.Success = true;
82+
var substitutionText = GetSubstitutionText(loader, compileOptions.Profile);
83+
UpdateStatus("Copying dependencies");
84+
result.IndexHtml = CopyDependenciesToOutputFolder(compileOptions.OutputFolder, substitutionText, compileOptions.DebugMode, compileOptions.Profile, compileOptions.Minify, loader, compileOptions);
85+
86+
string saveData = string.Empty;
87+
88+
UpdateStatus("Saving");
89+
GameSaver saver = new GameSaver(loader.Elements);
90+
saver.Progress += saver_Progress;
91+
saveData = saver.Save();
92+
93+
UpdateStatus("Copying resources");
94+
CopyResourcesToOutputFolder(loader.ResourcesFolder, compileOptions.OutputFolder);
95+
96+
saveData += GetEmbeddedHtmlFileData(loader.ResourcesFolder);
97+
string saveJs = System.IO.Path.Combine(compileOptions.OutputFolder, "game.js");
98+
99+
saveData = System.IO.File.ReadAllText(saveJs) + saveData;
100+
101+
if (compileOptions.Minify)
102+
{
103+
var minifier = new Microsoft.Ajax.Utilities.Minifier();
104+
saveData = minifier.MinifyJavaScript(saveData, new Microsoft.Ajax.Utilities.CodeSettings
105+
{
106+
MacSafariQuirks = true,
107+
RemoveUnneededCode = true,
108+
LocalRenaming = Microsoft.Ajax.Utilities.LocalRenaming.CrunchAll
109+
});
110+
111+
var encoding = (Encoding)Encoding.ASCII.Clone();
112+
encoding.EncoderFallback = new Microsoft.Ajax.Utilities.JSEncoderFallback();
113+
using (var writer = new System.IO.StreamWriter(saveJs, false, encoding))
114+
{
115+
writer.Write(saveData);
116+
}
117+
}
118+
else
119+
{
120+
System.IO.File.WriteAllText(saveJs, saveData);
121+
}
122+
123+
UpdateStatus("Finished");
124+
}
125+
return result;
126+
}
127+
128+
void saver_Progress(object sender, GameSaver.ProgressEventArgs e)
129+
{
130+
if (Progress != null)
131+
{
132+
Progress(this, new ProgressEventArgs { Progress = e.PercentComplete });
133+
}
134+
}
135+
136+
private Dictionary<string, string> GetSubstitutionText(GameLoader loader, string profile)
137+
{
138+
Dictionary<string, string> result = new Dictionary<string, string>();
139+
result.Add("BUILD", string.Format("{0:HH}{0:mm}{0:dd}{0:MM}{0:yy}", DateTime.Now));
140+
result.Add("PROFILE", profile);
141+
142+
foreach (string field in loader.GetSubstitutionFieldNames())
143+
{
144+
result.Add(field, loader.GetSubstitutionText(field));
145+
}
146+
147+
return result;
148+
}
149+
150+
// TO DO: Different profiles have different dependencies, so want to only copy the required files
151+
152+
private string CopyDependenciesToOutputFolder(string outputFolder, Dictionary<string, string> substitutionText, bool debugMode, string profile, bool minify, GameLoader loader, CompileOptions options)
153+
{
154+
string binFolder = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().CodeBase);
155+
binFolder = TextAdventures.Utility.Utility.RemoveFileColonPrefix(binFolder);
156+
string indexHtm = Copy("index.htm", binFolder, outputFolder, options, loader, substitutionText, debugMode: debugMode, outputFilename: "index.html");
157+
Copy("style.css", binFolder, outputFolder, options, loader, substitutionText);
158+
Copy("jquery-ui-1.8.16.custom.css", binFolder, outputFolder, options, loader, substitutionText);
159+
Copy("game.js", binFolder, outputFolder, options, loader, substitutionText, debugMode);
160+
string jsFolder = System.IO.Path.Combine(binFolder, "js");
161+
string outputJsFolder = System.IO.Path.Combine(outputFolder, "js");
162+
System.IO.Directory.CreateDirectory(outputJsFolder);
163+
Copy("jquery.min.js", jsFolder, outputJsFolder, options, loader);
164+
Copy("jquery-ui*.js", jsFolder, outputJsFolder, options, loader);
165+
Copy("xregexp*.js", jsFolder, outputJsFolder, options, loader);
166+
Copy("jjmenu.js", jsFolder, outputJsFolder, options, loader);
167+
Copy("bootstrap*.js", jsFolder, outputJsFolder, options, loader);
168+
Copy("*.css", jsFolder, outputJsFolder, options, loader);
169+
Copy("bootstrap*.css", binFolder, outputFolder, options, loader, substitutionText);
170+
string imagesFolder = System.IO.Path.Combine(binFolder, "images");
171+
string outputImagesFolder = System.IO.Path.Combine(outputFolder, "images");
172+
System.IO.Directory.CreateDirectory(outputImagesFolder);
173+
Copy("*.png", imagesFolder, outputImagesFolder, options, loader, binary: true);
174+
return indexHtm;
175+
}
176+
177+
private static Regex s_debugModeRegex = new Regex(@"//%%DEBUG START\r?\n?.*?//%%DEBUG END\r?\n?", RegexOptions.Singleline);
178+
private static Regex s_gamebookModeRegex = new Regex(@"//%%GAMEBOOK PROFILE\r?\n?.*?//%%END GAMEBOOK PROFILE\r?\n?", RegexOptions.Singleline);
179+
private static Regex s_textAdventureModeRegex = new Regex(@"//%%TEXTADVENTURE PROFILE\r?\n?.*?//%%END TEXTADVENTURE PROFILE\r?\n?", RegexOptions.Singleline);
180+
private static Dictionary<string, Regex> s_profileSpecificTextRegexes = new Dictionary<string, Regex> {
181+
{ "web", new Regex(@"//%%WEB PROFILE\r?\n?.*?//%%END WEB PROFILE\r?\n?", RegexOptions.Singleline) },
182+
};
183+
184+
private class MinMaxRegex
185+
{
186+
public Regex Min { get; set; }
187+
public Regex Max { get; set; }
188+
}
189+
190+
private static Dictionary<WorldModelVersion, MinMaxRegex> s_minMaxRegexes = null;
191+
192+
private static Dictionary<WorldModelVersion, MinMaxRegex> MinMaxRegexes
193+
{
194+
get
195+
{
196+
if (s_minMaxRegexes == null)
197+
{
198+
s_minMaxRegexes = new Dictionary<WorldModelVersion, MinMaxRegex>();
199+
foreach (WorldModelVersion v in GameLoader.PossibleVersions)
200+
{
201+
string versionName = v.ToString().ToUpper();
202+
s_minMaxRegexes.Add(v, new MinMaxRegex
203+
{
204+
Min = new Regex(@"//%%MIN " + versionName + "\r?\n?.*?//%%END MIN " + versionName + "\r?\n?", RegexOptions.Singleline),
205+
Max = new Regex(@"//%%MAX " + versionName + "\r?\n?.*?//%%END MAX " + versionName + "\r?\n?", RegexOptions.Singleline),
206+
});
207+
}
208+
}
209+
return s_minMaxRegexes;
210+
}
211+
}
212+
213+
private string Copy(string filename, string sourceFolder, string outputFolder, CompileOptions options, GameLoader loader, Dictionary<string, string> substitutionText = null, bool debugMode = false, string outputFilename = null, bool binary = false)
214+
{
215+
if (filename.Contains("*"))
216+
{
217+
string[] files = System.IO.Directory.GetFiles(sourceFolder, filename);
218+
foreach (string file in files)
219+
{
220+
string resultPath = System.IO.Path.Combine(outputFolder, System.IO.Path.GetFileName(file));
221+
CopyInternal(file, resultPath, substitutionText, debugMode, binary, options.Profile, loader, options.Gamebook);
222+
}
223+
return null;
224+
}
225+
else
226+
{
227+
if (outputFilename == null) outputFilename = filename;
228+
string sourcePath = System.IO.Path.Combine(sourceFolder, filename);
229+
string resultPath = System.IO.Path.Combine(outputFolder, outputFilename);
230+
return CopyInternal(sourcePath, resultPath, substitutionText, debugMode, binary, options.Profile, loader, options.Gamebook);
231+
}
232+
}
233+
234+
private string CopyInternal(string sourcePath, string resultPath, Dictionary<string, string> substitutionText, bool debugMode, bool binary, string profile, GameLoader loader, bool gamebook)
235+
{
236+
if (binary)
237+
{
238+
System.IO.File.Copy(sourcePath, resultPath, true);
239+
return resultPath;
240+
}
241+
242+
string text = System.IO.File.ReadAllText(sourcePath);
243+
244+
if (substitutionText != null)
245+
{
246+
foreach (var item in substitutionText)
247+
{
248+
text = text.Replace(string.Format("$${0}$$", item.Key), item.Value);
249+
}
250+
}
251+
if (gamebook)
252+
{
253+
text = s_textAdventureModeRegex.Replace(text, "");
254+
}
255+
else
256+
{
257+
text = s_gamebookModeRegex.Replace(text, "");
258+
}
259+
if (!debugMode)
260+
{
261+
text = s_debugModeRegex.Replace(text, "");
262+
}
263+
foreach (var profileRegex in s_profileSpecificTextRegexes)
264+
{
265+
// remove all profile-specific scripts, apart from the script specific to the current profile
266+
if (!IsProfileRegexValidForProfile(profileRegex.Key, profile))
267+
{
268+
text = profileRegex.Value.Replace(text, "");
269+
}
270+
}
271+
foreach (var minMaxRegex in MinMaxRegexes)
272+
{
273+
if (loader.Version > minMaxRegex.Key)
274+
{
275+
text = minMaxRegex.Value.Max.Replace(text, "");
276+
}
277+
if (loader.Version < minMaxRegex.Key)
278+
{
279+
text = minMaxRegex.Value.Min.Replace(text, "");
280+
}
281+
}
282+
System.IO.File.WriteAllText(resultPath, text);
283+
return resultPath;
284+
}
285+
286+
private bool IsProfileRegexValidForProfile(string profileRegex, string profile)
287+
{
288+
switch (profile)
289+
{
290+
case "Web":
291+
return (profileRegex == "web");
292+
default:
293+
throw new ArgumentOutOfRangeException();
294+
}
295+
}
296+
297+
public void UpdateStatus(string text)
298+
{
299+
if (StatusUpdated != null)
300+
{
301+
StatusUpdated(this, new StatusUpdate { Message = text });
302+
}
303+
}
304+
305+
private static List<string> s_resourceExtensionsToCopy = new List<string> { ".jpg", ".jpeg", ".png", ".gif", ".wav", ".mp3" };
306+
307+
private void CopyResourcesToOutputFolder(string resourcesFolder, string outputFolder)
308+
{
309+
foreach (string file in System.IO.Directory.GetFiles(resourcesFolder))
310+
{
311+
string ext = System.IO.Path.GetExtension(file).ToLower();
312+
if (s_resourceExtensionsToCopy.Contains(ext))
313+
{
314+
string resultFile = System.IO.Path.Combine(outputFolder, System.IO.Path.GetFileName(file));
315+
System.IO.File.Copy(file, resultFile, true);
316+
}
317+
}
318+
}
319+
320+
private string GetEmbeddedHtmlFileData(string resourcesFolder)
321+
{
322+
StringBuilder result = new StringBuilder();
323+
324+
foreach (string file in System.IO.Directory.GetFiles(resourcesFolder))
325+
{
326+
string ext = System.IO.Path.GetExtension(file).ToLower();
327+
if (ext == ".htm" || ext == ".html")
328+
{
329+
result.Append(string.Format("embeddedHtml[\"{0}\"] = {1};",
330+
System.IO.Path.GetFileName(file),
331+
Utility.EscapeString(System.IO.File.ReadAllText(file))));
332+
}
333+
if (ext == ".js")
334+
{
335+
result.Append(System.IO.File.ReadAllText(file));
336+
result.Append(Environment.NewLine);
337+
}
338+
}
339+
340+
return result.ToString();
341+
}
342+
}
343+
}

0 commit comments

Comments
 (0)