Search Unity

  1. We want you to join us at GDC this year! Take a peek at all of the events we will be hosting during the week of GDC.
    Dismiss Notice
  2. Tell us about your experience here and you’ll get early access to the 2018 Game Studios report + more goodies.
    Dismiss Notice
  3. Unity 2017.3 has arrived! Read about it here.
    Dismiss Notice
  4. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice
  5. We've closed the job boards. If you're looking for work, or looking to hire check out Unity Connect. You can see more information here.
    Dismiss Notice

webGL Template

Discussion in 'Unity Cloud Build' started by Riolis, Oct 23, 2015.

  1. Riolis

    Riolis

    Joined:
    Aug 23, 2014
    Posts:
    8
    It seems like the cloud build doesn't use my selected template for building, and I can't seem find the setting for it to select it anywhere.

    Would be great if someone knows how to set this up could advice me. Else I would have to move tons of html and js code to jslib or eval it at the start scene which is not fun thing to do.

    Thanks.
     
  2. dannyd

    dannyd

    Unity Technologies

    Joined:
    Jun 3, 2014
    Posts:
    697
    This is not something we plan to support at the moment. We always build with the default template so that we can host the html properly and so the styling is consistent with the rest of our site, and the window sizing acts correctly. If your project requires more complex interaction with the page, unfortunately your only real option is to self host builds.

    Thinking about how this might work in the future - what kinds of things are you doing in your template?
     
    tonialatalo likes this.
  3. Riolis

    Riolis

    Joined:
    Aug 23, 2014
    Posts:
    8
    nothing fancy, just some bootstrap modal and input="file" forms since you can't seem to trigger it from unity itself (Being block by all browsers popup blocker by default), large file upload/download script, drag and drop file js event, parse.com js sdk and its custom helper script currently.

    In a nutshell we are experimenting with more of a commercial cms type of system rather then games (and to see how far we can go with it, and hoping to make a better user experience), which unfortunately needs more interaction with the pages.
     
    tonialatalo likes this.
  4. jinxed_byte

    jinxed_byte

    Joined:
    Mar 29, 2014
    Posts:
    10
    We would also like to select a WebGL template and connect to the javascript code. Especially, we are working on integration of Parse.com and PeerJS.

    Hope you can make the template available soon.
     
    tonialatalo likes this.
  5. samurai926

    samurai926

    Joined:
    Jun 30, 2014
    Posts:
    14
    +1 for option to use custom template during cloudbuild. Ours has a custom loading script and expands the canvas to full screen.
     
    tonialatalo likes this.
  6. Kmausser

    Kmausser

    Joined:
    Feb 17, 2016
    Posts:
    23
    Why aren't custom templates supported yet?
     
    chaosmaker likes this.
  7. PlayItSafe_Fries

    PlayItSafe_Fries

    Joined:
    Jan 17, 2018
    Posts:
    6
    After looking for a solution online but still getting nowhere, I decided to look into writing a workaround myself.

    Just put this code anywhere in your project (Preferrably under an /Editor folder) and don't forget to replace the <YOUR TEMPLATE NAME> part with your actual template name.

    Although this solution works for now, I still hope Unity will remove this limitation and let developers make the full use of their cloud build system.

    Code (CSharp):
    1. #if UNITY_EDITOR && UNITY_WEBGL
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor.Callbacks;
    5. using UnityEditor;
    6. using System.IO;
    7. using System;
    8. using System.Text.RegularExpressions;
    9. using System.Linq;
    10.  
    11. public class PostProcessWebGL
    12. {
    13.     //The name of the WebGLTemplate. Location in project should be Assets/WebGLTemplates/<YOUR TEMPLATE NAME>
    14.     const string __TemplateToUse = "<YOUR TEMPLATE NAME>";
    15.  
    16.     [PostProcessBuild]
    17.     public static void ChangeWebGLTemplate(BuildTarget buildTarget, string pathToBuiltProject)
    18.     {
    19.         if (buildTarget != BuildTarget.WebGL) return;
    20.  
    21.  
    22.         //create template path
    23.         var templatePath = Paths.Combine(Application.dataPath, "WebGLTemplates", __TemplateToUse);
    24.  
    25.         //Clear the TemplateData folder, built by Unity.
    26.         FileUtilExtended.CreateOrCleanDirectory(Paths.Combine(pathToBuiltProject, "TemplateData"));
    27.  
    28.         //Copy contents from WebGLTemplate. Ignore all .meta files
    29.         FileUtilExtended.CopyDirectoryFiltered(templatePath, pathToBuiltProject, true, @".*/\.+|\.meta$", true);
    30.  
    31.         //Replace contents of index.html
    32.         FixIndexHtml(pathToBuiltProject);
    33.     }
    34.  
    35.     //Replaces %...% defines in index.html
    36.     static void FixIndexHtml(string pathToBuiltProject)
    37.     {
    38.         //Fetch filenames to be referenced in index.html
    39.         string
    40.             webglBuildUrl,
    41.             webglLoaderUrl;
    42.      
    43.         if (File.Exists(Paths.Combine(pathToBuiltProject, "Build", "UnityLoader.js")))
    44.         {
    45.             webglLoaderUrl = "Build/UnityLoader.js";
    46.         }
    47.         else
    48.         {
    49.             webglLoaderUrl = "Build/UnityLoader.min.js";
    50.         }
    51.  
    52.         string buildName = pathToBuiltProject.Substring(pathToBuiltProject.LastIndexOf("/") + 1);
    53.         webglBuildUrl = string.Format("Build/{0}.json", buildName);
    54.  
    55.         //webglLoaderUrl = EditorUserBuildSettings.development? "Build/UnityLoader.js": "Build/UnityLoader.min.js";
    56.         Dictionary<string, string> replaceKeywordsMap = new Dictionary<string, string> {
    57.                 {
    58.                     "%UNITY_WIDTH%",
    59.                     PlayerSettings.defaultWebScreenWidth.ToString()
    60.                 },
    61.                 {
    62.                     "%UNITY_HEIGHT%",
    63.                     PlayerSettings.defaultWebScreenHeight.ToString()
    64.                 },
    65.                 {
    66.                     "%UNITY_WEB_NAME%",
    67.                     PlayerSettings.productName
    68.                 },
    69.                 {
    70.                     "%UNITY_WEBGL_LOADER_URL%",
    71.                     webglLoaderUrl
    72.                 },
    73.                 {
    74.                     "%UNITY_WEBGL_BUILD_URL%",
    75.                     webglBuildUrl
    76.                 }
    77.             };
    78.  
    79.         string indexFilePath = Paths.Combine(pathToBuiltProject, "index.html");
    80.        Func<string, KeyValuePair<string, string>, string> replaceFunction = (current, replace) => current.Replace(replace.Key, replace.Value);
    81.         if (File.Exists(indexFilePath))
    82.         {
    83.            File.WriteAllText(indexFilePath, replaceKeywordsMap.Aggregate<KeyValuePair<string, string>, string>(File.ReadAllText(indexFilePath), replaceFunction));
    84.         }
    85.  
    86.     }
    87.  
    88.     private class FileUtilExtended
    89.     {
    90.      
    91.         internal static void CreateOrCleanDirectory(string dir)
    92.         {
    93.             if (Directory.Exists(dir))
    94.             {
    95.                 Directory.Delete(dir, true);
    96.             }
    97.             Directory.CreateDirectory(dir);
    98.         }
    99.  
    100.         //Fix forward slashes on other platforms than windows
    101.         internal static string FixForwardSlashes(string unityPath)
    102.         {
    103.             return ((Application.platform != RuntimePlatform.WindowsEditor) ? unityPath : unityPath.Replace("/", @"\"));
    104.         }
    105.  
    106.  
    107.  
    108.         //Copies the contents of one directory to another.
    109.        public static void CopyDirectoryFiltered(string source, string target, bool overwrite, string regExExcludeFilter, bool recursive)
    110.         {
    111.             RegexMatcher excluder = new RegexMatcher()
    112.             {
    113.                 exclude = null
    114.             };
    115.             try
    116.             {
    117.                 if (regExExcludeFilter != null)
    118.                 {
    119.                     excluder.exclude = new Regex(regExExcludeFilter);
    120.                 }
    121.             }
    122.             catch (ArgumentException)
    123.             {
    124.                UnityEngine.Debug.Log("CopyDirectoryRecursive: Pattern '" + regExExcludeFilter + "' is not a correct Regular Expression. Not excluding any files.");
    125.                 return;
    126.             }
    127.             CopyDirectoryFiltered(source, target, overwrite, excluder.CheckInclude, recursive);
    128.         }
    129.        internal static void CopyDirectoryFiltered(string sourceDir, string targetDir, bool overwrite, Func<string, bool> filtercallback, bool recursive)
    130.         {
    131.             // Create directory if needed
    132.             if (!Directory.Exists(targetDir))
    133.             {
    134.                 Directory.CreateDirectory(targetDir);
    135.                 overwrite = false;
    136.             }
    137.  
    138.             // Iterate all files, files that match filter are copied.
    139.             foreach (string filepath in Directory.GetFiles(sourceDir))
    140.             {
    141.                 if (filtercallback(filepath))
    142.                 {
    143.                     string fileName = Path.GetFileName(filepath);
    144.                     string to = Path.Combine(targetDir, fileName);
    145.  
    146.                  
    147.                     File.Copy(FixForwardSlashes(filepath),FixForwardSlashes(to), overwrite);
    148.                 }
    149.             }
    150.  
    151.             // Go into sub directories
    152.             if (recursive)
    153.             {
    154.                 foreach (string subdirectorypath in Directory.GetDirectories(sourceDir))
    155.                 {
    156.                     if (filtercallback(subdirectorypath))
    157.                     {
    158.                         string directoryName = Path.GetFileName(subdirectorypath);
    159.                        CopyDirectoryFiltered(Path.Combine(sourceDir, directoryName), Path.Combine(targetDir, directoryName), overwrite, filtercallback, recursive);
    160.                     }
    161.                 }
    162.             }
    163.         }
    164.  
    165.         internal struct RegexMatcher
    166.         {
    167.             public Regex exclude;
    168.             public bool CheckInclude(string s)
    169.             {
    170.                 return exclude == null || !exclude.IsMatch(s);
    171.             }
    172.         }
    173.  
    174.     }
    175.  
    176.     private class Paths
    177.     {
    178.         //Combine multiple paths using Path.Combine
    179.         public static string Combine(params string[] components)
    180.         {
    181.             if (components.Length < 1)
    182.             {
    183.                 throw new ArgumentException("At least one component must be provided!");
    184.             }
    185.             string str = components[0];
    186.             for (int i = 1; i < components.Length; i++)
    187.             {
    188.                 str = Path.Combine(str, components[i]);
    189.             }
    190.             return str;
    191.         }
    192.     }
    193.  
    194. }
    195.  
    196. #endif
    Good luck!
     
    Last edited: Jan 25, 2018
  8. StaffanEk

    StaffanEk

    Joined:
    Jul 13, 2012
    Posts:
    361
    What are you talking about? I don't want you to host my WebGL build, I want you to build it. It's called Cloud Build not Cloud Host. What a ridiculous excuse.

    What the hell am I paying for?
     
    Last edited: Jan 25, 2018
  9. PlayItSafe_Fries

    PlayItSafe_Fries

    Joined:
    Jan 17, 2018
    Posts:
    6
    Exactly.
    I don't see why anyone would want to host their game on Unity using the default template.
    While cloud build is supposed to make a developer's life easier (quote: "Cloud Build - Build games faster") It's actually giving us more work because we'd have to:
    1. Press "Start Cloud Build"
    2. Wait 35 minutes for Unity to build the project.
    3. download and unzip the generated build
    4. replace the templatedata folder and index.html with the correct one
    5. Upload the contents to our ftp
    6. Hope that we didn't break anything and that we won't have to go back to 1.
    Anyway, right now we finally managed to fully automate our our build pipeline for WebGL and Android:
    After cloud build, Unity will notify a webhook I have set up, running in Azure, which will download and extract the .zip file and then upload it to our own FTP.
     
  10. Ponytech

    Ponytech

    Joined:
    Jun 13, 2016
    Posts:
    2
    Seriously? This makes either cloud build or custom templates useless.
    We use Cloud Build for building our WebGL version and webhooks to download and deploy the game on our own servers once the build is complete. Please remove this limitation.
     
    StaffanEk likes this.