Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 100 additions & 39 deletions packages/webgl-jsbuild/upm/Editor/WebGLPostProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;

/**
* !!!!!!!!!!必读!!!!!!!
Expand All @@ -22,37 +23,39 @@
* 如果你的游戏里使用了自定义的Loader,那么我建议您自己重新实现一个PostProcessor,以和你的Loader配套。
*/

public class WebGLPuertsPostProcessor {
public class WebGLPuertsPostProcessor
{

public static List<string> fileGlobbers = new List<string>
public static List<string> fileGlobbers = new List<string>
{
Application.dataPath + "/**/Resources/**/*.mjs",
Application.dataPath + "/**/Resources/**/*.cjs",
Path.GetFullPath("Packages/com.tencent.puerts.core/") + "/**/Resources/**/*.mjs"
};

private static void run(string runEntry, string lastBuiltPath)
private static void RunBuild(string runEntry, string lastBuiltPath)
{
string PuertsWebglJSRoot = Path.GetFullPath("Packages/com.tencent.puerts.webgl.jsbuild/Javascripts~/");
if (lastBuiltPath != null) {
if (lastBuiltPath != null)
{
UnityEngine.Debug.Log("上一次构建路径:" + lastBuiltPath);

} else {
}
else
{
lastBuiltPath = PuertsWebglJSRoot + "dist/";
UnityEngine.Debug.Log("上一次构建路径为空,生成至:" + lastBuiltPath);
}


JsEnv jsenv = new JsEnv();

jsenv.UsingAction<string>();
jsenv.UsingAction<string, string>();
jsenv.UsingAction<string[], string>();
jsenv.UsingAction<BuildParameters>();

jsenv.Eval<Action<string>>(@"(function (requirePath) {
global.require = require('node:module').createRequire(requirePath)
})")(PuertsWebglJSRoot);

Action<string, string> cpRuntimeJS = jsenv.Eval<Action<string, string>>(@"
(function(puerRuntimeFilePath, targetPath) {
const { cp } = require('@puerts/shell-util');
Expand All @@ -61,24 +64,55 @@ private static void run(string runEntry, string lastBuiltPath)
});
");

Action<string[], string> globjs = jsenv.Eval<Action<string[], string>>(@"
(function(csFileGlobbers, targetPath) {
const fileGlobbers = [];
for (let i = 0; i < csFileGlobbers.Length; i++) {
fileGlobbers.push(csFileGlobbers.get_Item(i));
Action<BuildParameters> globjs = jsenv.Eval<Action<BuildParameters>>(@"
(function(buildParameters) {
function toJsArray(csArray) {
if (!csArray)
return null;
let results = [];
for (let i = 0; i < csArray.Length; i++) {
results.push(csArray.get_Item(i));
}
return results;
}
const globAllJS = require('.');
function toJsFunction(csDelegate) {
if (!csDelegate)
return null;
if (typeof (csDelegate) === 'function')
return csDelegate;
if (typeof (csDelegate.Invoke) === 'function') {
return function () {
return csDelegate.Invoke(...arguments);
}
}
return null;
}
let _buildParameters = {
outputpath: buildParameters.outputpath,
fileGlobbers: toJsArray(buildParameters.fileGlobbers),
customScripts: toJsArray(buildParameters.customScripts),
filterPath: toJsFunction(buildParameters.filterPath),
resolvePath: toJsFunction(buildParameters.resolvePath),
};

globAllJS." + runEntry + @"(fileGlobbers, targetPath);

const globAllJS = require('.');
globAllJS." + runEntry + @"(_buildParameters);
});
");

try {

try
{
cpRuntimeJS(Path.GetFullPath("Packages/com.tencent.puerts.webgl/Javascripts~/PuertsDLLMock/dist/puerts-runtime.js"), lastBuiltPath);
globjs(fileGlobbers.ToArray(), lastBuiltPath);
}
catch(Exception e)
globjs(new BuildParameters()
{
outputpath = lastBuiltPath,
fileGlobbers = fileGlobbers.ToArray(),
customScripts = CustomScript.From(WebGLUtils.GetBuildinScriptsFromConfigure()),
filterPath = WebGLUtils.GetBuildinFilterFunction(),
resolvePath = WebGLUtils.GetBuildinResolvePathFunction(),
});
}
catch (Exception e)
{
jsenv.Dispose();
throw;
Expand All @@ -87,23 +121,23 @@ private static void run(string runEntry, string lastBuiltPath)
}

[MenuItem("Tools/PuerTS/WebGL/build puerts-js for minigame", false, 11)]
public static void minigame()
public static void BuildMinigame()
{
run("buildForMinigame", GetLastBuildPath() != null ? GetLastBuildPath() + "/../minigame" : null);
RunBuild("buildForMinigame", GetLastBuildPath() != null ? GetLastBuildPath() + "/../minigame" : null);
}

[MenuItem("Tools/PuerTS/WebGL/build puerts-js for browser", false, 11)]
public static void browser()
public static void BuildBrowser()
{
run("buildForBrowser", GetLastBuildPath());
}
RunBuild("buildForBrowser", GetLastBuildPath());
}


[MenuItem("Tools/PuerTS/WebGL/install", false, 0)]
static void npmInstall()
static void NodeModulesInstall()
{
JsEnv jsenv = new Puerts.JsEnv();
jsenv.UsingAction<string>();
try
try
{
Action<string> npmInstaller = jsenv.Eval<Action<string>>(@"
(function(cwd) {
Expand All @@ -112,39 +146,66 @@ static void npmInstall()
");
npmInstaller(Path.GetFullPath("Packages/com.tencent.puerts.webgl.jsbuild/Javascripts~"));
}
catch(Exception e)
catch (Exception e)
{
UnityEngine.Debug.LogError("Npm install failed. you can cd into 'Packages/com.tencent.puerts.webgl.jsbuild/Javascripts~' to run 'npm install' by yourself");
}
}



[MenuItem("Tools/PuerTS/WebGL/build puerts-js for minigame", true)]
[MenuItem("Tools/PuerTS/WebGL/build puerts-js for browser", true)]
static bool NodeModulesInstalled()
static bool NodeModulesInstalled()
{
return Directory.Exists(Path.GetFullPath("Packages/com.tencent.puerts.webgl.jsbuild/Javascripts~/node_modules"));
}
[MenuItem("Tools/PuerTS/WebGL/install", true)]
static bool NodeModulesNotInstalled()
static bool NodeModulesInstallValidate()
{
return !NodeModulesInstalled();
}



protected static string GetLastBuildPath() {
protected static string GetLastBuildPath()
{
return EditorPrefs.GetString("PUER_WEBGL_LAST_BUILDPATH");
}

[PostProcessBuildAttribute(1)]
public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
{
if (target == BuildTarget.WebGL)
if (target == BuildTarget.WebGL)
{
EditorPrefs.SetString("PUER_WEBGL_LAST_BUILDPATH", pathToBuiltProject);
UnityEngine.Debug.Log("构建成功,请用puerts-webgl/build js构建js资源");
}
}
}


class CustomScript
{
public string resourceName;
public string code;
public CustomScript(string resourceName, string code)
{
this.resourceName = resourceName;
this.code = code;
}
public static CustomScript[] From(Dictionary<string, string> dict)
{
if (dict == null)
return null;
return dict.Keys
.Select(resourceName => new CustomScript(resourceName, dict[resourceName]))
.ToArray();
}
}
class BuildParameters
{
public string outputpath;
public string[] fileGlobbers;
public CustomScript[] customScripts;
public Func<string, bool> filterPath;
public Func<string, string> resolvePath;
}
}
163 changes: 163 additions & 0 deletions packages/webgl-jsbuild/upm/Editor/WebGLUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Codice.Utils;

public static class WebGLUtils
{
public static Dictionary<string, string> Concat(params Dictionary<string, string>[] dicts)
{
Dictionary<string, string> results = new Dictionary<string, string>();

foreach (var dict in dicts)
{
if (dict == null)
continue;
foreach (var member in dict)
{
results[member.Key] = member.Value;
}
}
return results;
}

public delegate string ResolvePathFunction(string path);
public static Func<string, string> GetBuildinResolvePathFunction()
{
var resolves = from assembly in AppDomain.CurrentDomain.GetAssemblies()
where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder)
from type in assembly.GetExportedTypes()
from method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
where method.IsDefined(typeof(WebGLResolvePath)) && !method.IsGenericMethod
where method.ReturnType == typeof(string) && method.GetParameters().Length == 1 && method.GetParameters()[0].ParameterType == typeof(string)
select (ResolvePathFunction)method.CreateDelegate(typeof(ResolvePathFunction), null);
if (resolves.Count() == 0)
return null;

return (path) =>
{
string result = null;
foreach (var resolve in resolves)
{
string newPath = resolve(path);
if (!string.IsNullOrEmpty(newPath) && newPath != path)
{
result = newPath;
}
}
return !string.IsNullOrEmpty(result) ? result : path;
};
}
public delegate bool FilterFunction(string path);
public static Func<string, bool> GetBuildinFilterFunction()
{
var filters = from assembly in AppDomain.CurrentDomain.GetAssemblies()
where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder)
from type in assembly.GetExportedTypes()
from method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
where method.IsDefined(typeof(WebGLResolvePath)) && !method.IsGenericMethod
where method.ReturnType == typeof(bool) && method.GetParameters().Length == 1 && method.GetParameters()[0].ParameterType == typeof(string)
select (FilterFunction)method.CreateDelegate(typeof(FilterFunction), null);
if (filters.Count() == 0)
return null;

return (path) =>
{
foreach (var filter in filters)
{
if (!filter(path))
return false;
}
return true;
};
}

public static Dictionary<string, string> GetBuildinScriptsFromConfigure()
{
var members = from assembly in AppDomain.CurrentDomain.GetAssemblies()
where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder)
from type in assembly.GetExportedTypes()
from method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
where method.IsDefined(typeof(WebGLScripts)) && !method.IsGenericMethod
where typeof(Dictionary<string, string>).IsAssignableFrom(method.ReturnType) && method.GetParameters().Length == 0
select (Dictionary<string, string>)method.Invoke(null, null);
if (members.Count() == 0)
return null;

return Concat(members.ToArray());
}
public static Dictionary<string, string> GetBuildinScriptsFromOutputPath(string outputRootPath, string extensioName)
{
if (string.IsNullOrEmpty(outputRootPath) || !Directory.Exists(outputRootPath))
return null;

Func<string, bool> filter = (string file) =>
{
return file != null && (file.EndsWith(".js") || file.EndsWith(".cjs") || file.EndsWith(".mjs"));
};

outputRootPath = outputRootPath.Replace("\\", "/");
if (!outputRootPath.EndsWith("/"))
{
outputRootPath += "/";
}

Dictionary<string, string> results = new Dictionary<string, string>();

foreach (string file in ScanFiles(outputRootPath, filter))
{
string resourceName = file.Replace("\\", "/").Replace(outputRootPath, "");
if (!string.IsNullOrEmpty(extensioName) && Path.GetExtension(resourceName) != extensioName)
{
resourceName = resourceName.Substring(0, resourceName.Length - Path.GetExtension(resourceName).Length) + extensioName;
}

results[resourceName] = System.Text.Encoding.UTF8.GetString(File.ReadAllBytes(file));
}
return results;
}
static List<string> ScanFiles(string dirPath, Func<string, bool> filter)
{
List<string> files = new List<string>();

DirectoryInfo directoryInfo = new DirectoryInfo(dirPath);

foreach (FileInfo fileInfo in directoryInfo.GetFiles())
{
if (filter != null && !filter(fileInfo.FullName))
continue;
files.Add(fileInfo.FullName);
}
foreach (DirectoryInfo dirInfo in directoryInfo.GetDirectories())
{
List<string> subFiles = ScanFiles(dirInfo.FullName, filter);
if (subFiles != null) files.AddRange(subFiles);
}

return files;
}
}
/// <summary>
/// 允许自定义处理js文件路径
/// </summary>
[AttributeUsageAttribute(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class WebGLResolvePath : Attribute
{
}
/// <summary>
/// 允许自定义过滤js文件
/// </summary>
[AttributeUsageAttribute(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class WebGLFilterPath : Attribute
{
}
/// <summary>
/// 允许自定义添加构建内容
/// </summary>
[AttributeUsageAttribute(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class WebGLScripts : Attribute
{

}
Loading