Initial commit: Client Doc docs Server Tools
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"components": [
|
||||
"Microsoft.VisualStudio.Workload.ManagedGame"
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53026a02bf95f5848aa29d2700fc4cd8
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5666e57228dbc54f9c293db24d7b72b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,126 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
public class AESManager
|
||||
{
|
||||
private static readonly byte[] Key = Encoding.UTF8.GetBytes("01fsd56#@9AB183F"); // 16字节的密钥
|
||||
private static readonly byte[] IV = Encoding.UTF8.GetBytes("01fsd56789A*%#3F"); // 16字节的初始向量
|
||||
private static byte[] XWKey = Encoding.UTF8.GetBytes("183F01fsd56#@9AB"); // 16字节的密钥
|
||||
private static byte[] XWIV = Encoding.UTF8.GetBytes("h1O2Y7d689A*%#0X"); // 16字节的初始向量
|
||||
|
||||
//与 XGame.AESManager 对齐:静态构造里自动用口令初始化 XWKey/XWIV,
|
||||
//避免某条路径(如 WebGL 加载)忘了显式 Set() 而退化到上面写死的默认 key,导致解密全错。
|
||||
static AESManager()
|
||||
{
|
||||
Set(ChangeBytes(Encoding.UTF8.GetBytes("#@pOrhgf2026091211325890vciu%c-X")));
|
||||
}
|
||||
|
||||
public static byte[] ChangeBytes(byte[] src, byte xor = 0xb4)
|
||||
{
|
||||
for (int i = 0; i < src.Length; i++)
|
||||
{
|
||||
src[i] = (byte)(src[i] ^ xor);
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
public static void Set(byte[] data)
|
||||
{
|
||||
if (data.Length != 32)
|
||||
throw new Exception("AES Key or IV length must be 32 characters");
|
||||
else
|
||||
{
|
||||
XWKey = new byte[16];
|
||||
Array.Copy(data, 0, XWKey, 0, 16);
|
||||
XWIV = new byte[16];
|
||||
Array.Copy(data, 16, XWIV, 0, 16);
|
||||
}
|
||||
}
|
||||
public static string Encrypt(string plainText)
|
||||
{
|
||||
string encryptedText = Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(plainText)));
|
||||
return encryptedText;
|
||||
}
|
||||
public static byte[] Encrypt(byte[] plainBytes, bool bXW = true)
|
||||
{
|
||||
using (Aes aes = Aes.Create())
|
||||
{
|
||||
if (bXW)
|
||||
{
|
||||
aes.Key = XWKey;
|
||||
aes.IV = XWIV;
|
||||
}
|
||||
else
|
||||
{
|
||||
aes.Key = Key;
|
||||
aes.IV = IV;
|
||||
}
|
||||
|
||||
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
|
||||
|
||||
byte[] encryptedBytes = null;
|
||||
using (var ms = new System.IO.MemoryStream())
|
||||
{
|
||||
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
|
||||
{
|
||||
cs.Write(plainBytes, 0, plainBytes.Length);
|
||||
cs.FlushFinalBlock();
|
||||
}
|
||||
encryptedBytes = ms.ToArray();
|
||||
}
|
||||
return encryptedBytes;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Decrypt(byte[] encryptedBytes, bool bXW = true)
|
||||
{
|
||||
using (Aes aes = Aes.Create())
|
||||
{
|
||||
if (bXW)
|
||||
{
|
||||
aes.Key = XWKey;
|
||||
aes.IV = XWIV;
|
||||
}
|
||||
else
|
||||
{
|
||||
aes.Key = Key;
|
||||
aes.IV = IV;
|
||||
}
|
||||
|
||||
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
|
||||
|
||||
byte[] decryptedBytes = null;
|
||||
using (var ms = new System.IO.MemoryStream(encryptedBytes))
|
||||
{
|
||||
using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
|
||||
{
|
||||
byte[] decryptedData = new byte[encryptedBytes.Length];
|
||||
int bytesRead = cs.Read(decryptedData, 0, decryptedData.Length);
|
||||
|
||||
if (bytesRead == decryptedData.Length)
|
||||
return decryptedData;
|
||||
// 如果你知道解密后的数据的确切大小,你可以根据需要进行截取
|
||||
byte[] trimmedData = new byte[bytesRead];
|
||||
Array.Copy(decryptedData, trimmedData, bytesRead);
|
||||
|
||||
return trimmedData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static string Decrypt(string encryptedText)
|
||||
{
|
||||
string decryptedText = Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(encryptedText)));
|
||||
return decryptedText;
|
||||
}
|
||||
}
|
||||
|
||||
// 使用示例:
|
||||
//string originalText = "Hello, World!";
|
||||
//string encryptedText = AESExample.Encrypt(originalText);
|
||||
//string decryptedText = AESExample.Decrypt(encryptedText);
|
||||
|
||||
//Console.WriteLine("Original Text: " + originalText);
|
||||
//Console.WriteLine("Encrypted Text: " + encryptedText);
|
||||
//Console.WriteLine("Decrypted Text: " + decryptedText);
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cdb9a8c28654f854a912f1aa0df066a5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "Base",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:13ba8ce62aa80c74598530029cb2d649",
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 460855e1f37306f4889afbf96eb004f0
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
#if UNITY_WEBGL
|
||||
using WeChatWASM;
|
||||
#endif
|
||||
|
||||
public class XWBase
|
||||
{
|
||||
public static void StartScanQRCode(Action<string> callback)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eadfee1a6daccca42bc16821fb4bf3c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class ConsoleToSceen : MonoBehaviour
|
||||
{
|
||||
const int maxLines = 50;
|
||||
const int maxLineLength = 120;
|
||||
private string _logStr = "";
|
||||
|
||||
private readonly List<string> _lines = new List<string>();
|
||||
|
||||
public int fontSize = 15;
|
||||
|
||||
void OnEnable() { Application.logMessageReceived += Log; }
|
||||
void OnDisable() { Application.logMessageReceived -= Log; }
|
||||
void Update() { }
|
||||
|
||||
public void Log(string logString, string stackTrace, LogType type)
|
||||
{
|
||||
foreach (var line in logString.Split('\n'))
|
||||
{
|
||||
if (line.Length <= maxLineLength)
|
||||
{
|
||||
_lines.Add(line);
|
||||
continue;
|
||||
}
|
||||
var lineCount = line.Length / maxLineLength + 1;
|
||||
for (int i = 0; i < lineCount; i++)
|
||||
{
|
||||
if ((i + 1) * maxLineLength <= line.Length)
|
||||
{
|
||||
_lines.Add(line.Substring(i * maxLineLength, maxLineLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
_lines.Add(line.Substring(i * maxLineLength, line.Length - i * maxLineLength));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_lines.Count > maxLines)
|
||||
{
|
||||
_lines.RemoveRange(0, _lines.Count - maxLines);
|
||||
}
|
||||
_logStr = string.Join("\n", _lines);
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity,
|
||||
new Vector3(Screen.width / 1200.0f, Screen.height / 800.0f, 1.0f));
|
||||
GUI.Label(new Rect(10, 10, 800, 370), _logStr, new GUIStyle() { fontSize = Math.Max(10, fontSize) });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66b835502f6eddc43b33fbb7755912b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using UnityEngine;
|
||||
|
||||
// 内网联调配置:开发机探测 IP 的本地持久化(persistentDataPath/dev_server.txt,单行 IPv4)。
|
||||
// 跨网段时广播/组播都出不了网段(路由器不转发),只能向已知开发机 IP 单播——该 IP 由本文件持久化,
|
||||
// 首次由 DevServerPrompt 弹框录入并验证成功后写入(见 LoadDll.CoLocalDiscoverThenDownload)。
|
||||
// 注意:Application.persistentDataPath 只能在主线程访问,故 Load/Save 只能在主线程调;
|
||||
// 发现线程(后台)需要的值由调用方在主线程读好传入。
|
||||
// 热更层 DevServerDiscovery 内联了同语义的读取(XWorld.Link 未引用 Base 程序集),改格式时两边须同步。
|
||||
public static class DevServerConfig
|
||||
{
|
||||
public static string FilePath => Path.Combine(Application.persistentDataPath, "dev_server.txt");
|
||||
|
||||
// 读配置:文件不存在/IO 异常/内容不是合法 IPv4 → null(静默,等同"无配置")。
|
||||
public static string Load()
|
||||
{
|
||||
try
|
||||
{
|
||||
string path = FilePath;
|
||||
if (!File.Exists(path)) return null;
|
||||
string line = File.ReadAllText(path).Trim();
|
||||
if (line.Length == 0) return null;
|
||||
if (!IPAddress.TryParse(line, out IPAddress ip)) return null;
|
||||
if (ip.AddressFamily != AddressFamily.InterNetwork) return null; // 只认 IPv4
|
||||
return ip.ToString();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 写配置:单行覆盖;IO 异常静默吞(写不进只是下次还弹框,不致命)。
|
||||
public static void Save(string ip)
|
||||
{
|
||||
try { File.WriteAllText(FilePath, ip ?? ""); }
|
||||
catch (Exception) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f87f0551c5fcd924cb1849d77c03db5d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,42 @@
|
||||
using UnityEngine;
|
||||
|
||||
// 内网联调:发现失败时的开发机 IP 输入框(纯 IMGUI,风格同热更层 DevServerSwitchUI)。
|
||||
// 只负责输入与三态状态机,不做网络/文件 IO——探测与写配置由 LoadDll.CoLocalDiscoverThenDownload 编排:
|
||||
// [确定] → Confirmed,外部拿 InputIp 去探测;失败则外部调 ResetToWaiting(错误文案) 拨回弹框;
|
||||
// [跳过] → Skipped,外部走 127.0.0.1 回退。
|
||||
public sealed class DevServerPrompt : MonoBehaviour
|
||||
{
|
||||
public enum PromptState { Waiting, Confirmed, Skipped }
|
||||
|
||||
public PromptState State { get; private set; } = PromptState.Waiting;
|
||||
public string InputIp = "";
|
||||
public string Error = ""; // 非空则红字显示
|
||||
|
||||
// 外部探测失败后调用:显示错误并回到可输入状态。
|
||||
public void ResetToWaiting(string error)
|
||||
{
|
||||
Error = error ?? "";
|
||||
State = PromptState.Waiting;
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (State != PromptState.Waiting) return;
|
||||
const int W = 560, H = 190;
|
||||
GUILayout.BeginArea(new Rect((Screen.width - W) / 2, (Screen.height - H) / 3, W, H), GUI.skin.box);
|
||||
GUILayout.Label("内网发现失败:请输入开发机 IP(网关须 --lan --devToken xw-dev)");
|
||||
InputIp = GUILayout.TextField(InputIp ?? "", GUILayout.Height(44));
|
||||
if (!string.IsNullOrEmpty(Error))
|
||||
{
|
||||
GUI.color = new Color(1f, 0.4f, 0.3f);
|
||||
GUILayout.Label(Error);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("确定", GUILayout.Height(44))) { Error = ""; State = PromptState.Confirmed; }
|
||||
if (GUILayout.Button("跳过", GUILayout.Height(44), GUILayout.Width(120))) State = PromptState.Skipped;
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d11782d9f393fc49b80d320bc59ac38
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
//查找局域网内的节点地址
|
||||
using System;
|
||||
|
||||
class FindLocalNode
|
||||
{
|
||||
public static void FindNode(Action<string> Result)
|
||||
{
|
||||
string rs = "";
|
||||
|
||||
Result(rs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf3b253ffaaa1854f82d8f8b4e7c395a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,142 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
/// <summary>
|
||||
/// 用于处理文件下载
|
||||
/// </summary>
|
||||
internal class GYDownloadHandler: DownloadHandlerScript
|
||||
{
|
||||
string m_SavePath = "";
|
||||
string m_TempFilePath = "";
|
||||
FileStream fs;
|
||||
|
||||
public long totalFileLen { get; private set; }
|
||||
public long downloadedFileLen { get; private set; }
|
||||
public string fileName { get; private set; }
|
||||
public string dirPath { get; private set; }
|
||||
|
||||
#region 事件
|
||||
|
||||
/// <summary>
|
||||
/// 每次下载到数据后回调进度
|
||||
/// </summary>
|
||||
public Action<float,float> OnProgress = null;
|
||||
|
||||
/// <summary>
|
||||
/// 当下载完成后回调下载的文件位置
|
||||
/// </summary>
|
||||
public Action<int> OnFinish = null;
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 初始化下载句柄,定义每次下载的数据上限为1M
|
||||
/// </summary>
|
||||
/// <param name="filePath">保存到本地的文件路径</param>
|
||||
public GYDownloadHandler(string filePath) : base(new byte[1024 * 1024])
|
||||
{
|
||||
m_SavePath = filePath.Replace('\\', '/');
|
||||
fileName = m_SavePath.Substring(m_SavePath.LastIndexOf('/') + 1);
|
||||
dirPath = m_SavePath.Substring(0, m_SavePath.LastIndexOf('/'));
|
||||
m_TempFilePath = Path.Combine(dirPath, fileName + ".temp");
|
||||
if (!Directory.Exists(dirPath))
|
||||
{
|
||||
Directory.CreateDirectory(dirPath);
|
||||
}
|
||||
|
||||
fs = new FileStream(m_TempFilePath, FileMode.Append, FileAccess.Write);
|
||||
downloadedFileLen = fs.Length;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从网络获取数据时候的回调,每帧调用一次
|
||||
/// </summary>
|
||||
/// <param name="data">接收到的数据字节流,总长度为构造函数定义的200kb,并非所有的数据都是新的</param>
|
||||
/// <param name="dataLength">接收到的数据长度,表示data字节流数组中有多少数据是新接收到的,即0-dataLength之间的数据是刚接收到的</param>
|
||||
/// <returns>返回true为继续下载,返回false为中断下载</returns>
|
||||
protected override bool ReceiveData(byte[] data, int dataLength)
|
||||
{
|
||||
if (data == null || data.Length == 0)
|
||||
{
|
||||
Debug.LogFormat("【下载中】 下载文件{0}中,没有获取到数据,下载终止", fileName);
|
||||
return false;
|
||||
}
|
||||
fs?.Write(data, 0, dataLength);
|
||||
downloadedFileLen += dataLength;
|
||||
|
||||
OnProgress?.Invoke(downloadedFileLen, totalFileLen);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当接受数据完成时的回调
|
||||
/// </summary>
|
||||
protected override void CompleteContent()
|
||||
{
|
||||
OnDispose();
|
||||
//Debug.LogFormat("【下载完成】 完成对{0}文件的下载,保存路径为{1}", fileName, m_SavePath);
|
||||
|
||||
if (File.Exists(m_TempFilePath))
|
||||
{
|
||||
if (File.Exists(m_SavePath))
|
||||
File.Delete(m_SavePath);
|
||||
File.Move(m_TempFilePath, m_SavePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogFormat("【下载失败】 下载文件{0}时失败", fileName);
|
||||
}
|
||||
OnFinish?.Invoke((int)downloadedFileLen);
|
||||
}
|
||||
|
||||
public void OnDispose()
|
||||
{
|
||||
fs?.Close();
|
||||
fs?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求下载时的第一个回调函数,会返回需要接收的文件总长度
|
||||
/// </summary>
|
||||
/// <param name="contentLength">如果是续传,则是剩下的文件大小;本地拷贝则是文件总长度</param>
|
||||
protected override void ReceiveContentLengthHeader(ulong contentLength)
|
||||
{
|
||||
if (contentLength == 0)
|
||||
{
|
||||
Debug.Log("【下载已经完成】");
|
||||
CompleteContent();
|
||||
}
|
||||
base.ReceiveContentLengthHeader(contentLength);
|
||||
totalFileLen = (long)contentLength + downloadedFileLen;
|
||||
}
|
||||
|
||||
public void ErrorDispose()
|
||||
{
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
if (File.Exists(m_TempFilePath))
|
||||
{
|
||||
File.Delete(m_TempFilePath);
|
||||
}
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
OnFinish = null;
|
||||
OnProgress = null;
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc9b1a210663c5948aabe89b2224ece2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30e4f9ab3fb289843847ccf1e751c22c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,228 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
// 底包(AOT)专用:内网 CDN 广播发现。
|
||||
// 真机内网测试时 CDN 跑在开发机上,客户端写死的 127.0.0.1 在真机上指向手机自身、连不到开发机;
|
||||
// 故用 UDP 广播问开发机网关要它的 LAN CDN 根地址(形如 http://<开发机IP>:15081/)。
|
||||
//
|
||||
// 协议与热更层 XWorld.Framework.Protocol.DevDiscovery / DevServerDiscovery 完全一致
|
||||
// (magic "XWDL"、UDP 48923、LEB128 varuint + UTF8 长度前缀字符串、token=xw-dev),
|
||||
// 但 Base 程序集不能引用热更程序集(XWorld.Framework.Shared,运行时才由 LoadDll 加载),
|
||||
// 所以这里内联一份最小编解码,改协议时两边须同步。
|
||||
public static class LocalCdnDiscovery
|
||||
{
|
||||
private const int Port = 48923; // = DevDiscovery.Port
|
||||
private const uint ProtoVersion = 1; // = DevDiscovery.ProtoVersion
|
||||
private static readonly byte[] Magic = { 0x58, 0x57, 0x44, 0x4C }; // "XWDL" = DevDiscovery.Magic
|
||||
private const byte TypeQuery = 1; // = DevDiscovery.TypeQuery
|
||||
private const byte TypeReply = 2; // = DevDiscovery.TypeReply
|
||||
|
||||
// 阻塞式发现,须在后台线程调用(会最多阻塞 durationMs)。
|
||||
// 在窗口内周期重发查询(向广播 + 127.0.0.1 单播),收到首个合法应答即返回其 ResourceBaseUrl(CDN 根);超时返回 null。
|
||||
// extraProbeIp:额外单播探测目标(跨网段联调用,来自 dev_server.txt 或弹框输入,见 DevServerConfig/DevServerPrompt)。
|
||||
// 广播/定向广播不被路由器转发(RFC 2644),组播亦已实测不通(路由器未开组播路由),跨网段只能靠单播已知 IP。
|
||||
// 注意:本方法跑在后台线程,不能碰 Unity 主线程 API(如 persistentDataPath),配置由调用方在主线程读好传入。
|
||||
public static string Discover(string token, int durationMs = 1500, string extraProbeIp = null)
|
||||
{
|
||||
UdpClient udp = null;
|
||||
try
|
||||
{
|
||||
udp = new UdpClient(AddressFamily.InterNetwork);
|
||||
udp.EnableBroadcast = true;
|
||||
udp.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
udp.Client.Bind(new IPEndPoint(IPAddress.Any, 0));
|
||||
udp.Client.ReceiveTimeout = 250;
|
||||
|
||||
uint nonce = unchecked((uint)Guid.NewGuid().GetHashCode());
|
||||
byte[] query = EncodeQuery(nonce, token);
|
||||
// 同机广播常收不到(取决于网卡是否回环广播),故同时向 127.0.0.1 单播;并周期重发防网关刚起未监听。
|
||||
// 255.255.255.255(限制广播)在部分 Android WiFi 驱动上会被丢弃,故再按各网卡 IP|~mask 补发子网定向广播(如 192.168.1.255)。
|
||||
List<IPEndPoint> targetList = new List<IPEndPoint>
|
||||
{
|
||||
new IPEndPoint(IPAddress.Broadcast, Port),
|
||||
new IPEndPoint(IPAddress.Loopback, Port),
|
||||
};
|
||||
foreach (IPAddress bc in GetDirectedBroadcasts())
|
||||
targetList.Add(new IPEndPoint(bc, Port));
|
||||
if (!string.IsNullOrEmpty(extraProbeIp) && IPAddress.TryParse(extraProbeIp, out IPAddress extra))
|
||||
targetList.Add(new IPEndPoint(extra, Port));
|
||||
IPEndPoint[] targets = targetList.ToArray();
|
||||
UnityEngine.Debug.Log("[Discovery] targets(" + targets.Length + "): " + string.Join(", ", Array.ConvertAll(targets, t => t.ToString())));
|
||||
|
||||
DateTime deadline = DateTime.UtcNow.AddMilliseconds(durationMs);
|
||||
DateTime nextSend = DateTime.MinValue;
|
||||
while (DateTime.UtcNow < deadline)
|
||||
{
|
||||
if (DateTime.UtcNow >= nextSend)
|
||||
{
|
||||
foreach (IPEndPoint t in targets)
|
||||
{
|
||||
try { udp.Send(query, query.Length, t); } catch { }
|
||||
}
|
||||
nextSend = DateTime.UtcNow.AddMilliseconds(300);
|
||||
}
|
||||
|
||||
IPEndPoint from = new IPEndPoint(IPAddress.Any, 0);
|
||||
byte[] data;
|
||||
try { data = udp.Receive(ref from); }
|
||||
catch (SocketException) { continue; } // 250ms 接收超时,继续重发/等待
|
||||
if (TryDecodeReply(data, nonce, token, out string resourceBaseUrl)
|
||||
&& !string.IsNullOrEmpty(resourceBaseUrl))
|
||||
{
|
||||
return resourceBaseUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 忽略:发现失败由调用方处理(弹框输入或回退 127.0.0.1)
|
||||
}
|
||||
finally
|
||||
{
|
||||
try { udp?.Close(); } catch { }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 枚举本机所有 Up 状态 IPv4 网卡,按 broadcast = ip | ~mask 算出各自的子网定向广播地址。
|
||||
// 关键:Android/Mono 下 IPv4Mask 常拿不到(返回 null/0.0.0.0 甚至抛异常),故对私有网段按 /24 兜底,
|
||||
// 且逐地址 try/catch,任何一块网卡取掩码失败都不中断整体枚举(否则会连累外层 return null)。
|
||||
private static List<IPAddress> GetDirectedBroadcasts()
|
||||
{
|
||||
List<IPAddress> list = new List<IPAddress>();
|
||||
NetworkInterface[] nics;
|
||||
try { nics = NetworkInterface.GetAllNetworkInterfaces(); }
|
||||
catch (Exception e) { UnityEngine.Debug.LogWarning("[Discovery] GetAllNetworkInterfaces failed: " + e.Message); return list; }
|
||||
|
||||
foreach (NetworkInterface ni in nics)
|
||||
{
|
||||
if (ni.OperationalStatus != OperationalStatus.Up) continue;
|
||||
if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback) continue;
|
||||
|
||||
IPInterfaceProperties props;
|
||||
try { props = ni.GetIPProperties(); }
|
||||
catch { continue; }
|
||||
|
||||
foreach (UnicastIPAddressInformation ua in props.UnicastAddresses)
|
||||
{
|
||||
if (ua.Address.AddressFamily != AddressFamily.InterNetwork) continue; // 只处理 IPv4
|
||||
byte[] ip = ua.Address.GetAddressBytes();
|
||||
if (ip.Length != 4) continue;
|
||||
|
||||
byte[] mk = null;
|
||||
try { IPAddress m = ua.IPv4Mask; if (m != null) mk = m.GetAddressBytes(); }
|
||||
catch { mk = null; } // Android 上访问 IPv4Mask 可能抛,兜住
|
||||
|
||||
// 掩码不可用(null/长度不对/全 0)时,私有网段按 /24 兜底(最常见的家用/办公 WiFi),公网地址不猜。
|
||||
bool maskBad = mk == null || mk.Length != 4 || (mk[0] == 0 && mk[1] == 0 && mk[2] == 0 && mk[3] == 0);
|
||||
if (maskBad)
|
||||
{
|
||||
if (!IsPrivateV4(ip)) continue;
|
||||
mk = new byte[] { 255, 255, 255, 0 };
|
||||
}
|
||||
|
||||
byte[] bc = new byte[4];
|
||||
for (int i = 0; i < 4; i++) bc[i] = (byte)(ip[i] | (~mk[i] & 0xFF));
|
||||
IPAddress bcAddr = new IPAddress(bc);
|
||||
list.Add(bcAddr);
|
||||
UnityEngine.Debug.Log("[Discovery] nic=" + ni.Name + " ip=" + ua.Address + " mask=" + string.Join(".", mk) + " bc=" + bcAddr);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static bool IsPrivateV4(byte[] ip)
|
||||
{
|
||||
if (ip[0] == 10) return true; // 10.0.0.0/8
|
||||
if (ip[0] == 192 && ip[1] == 168) return true; // 192.168.0.0/16
|
||||
if (ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) return true; // 172.16.0.0/12
|
||||
return false;
|
||||
}
|
||||
|
||||
private static byte[] EncodeQuery(uint nonce, string token)
|
||||
{
|
||||
var buf = new List<byte>(32);
|
||||
for (int i = 0; i < Magic.Length; i++) buf.Add(Magic[i]);
|
||||
buf.Add(TypeQuery);
|
||||
WriteVarUInt(buf, ProtoVersion);
|
||||
WriteVarUInt(buf, nonce);
|
||||
WriteString(buf, token);
|
||||
return buf.ToArray();
|
||||
}
|
||||
|
||||
private static bool TryDecodeReply(byte[] data, uint expectNonce, string expectToken, out string resourceBaseUrl)
|
||||
{
|
||||
resourceBaseUrl = null;
|
||||
try
|
||||
{
|
||||
int pos = 0;
|
||||
for (int i = 0; i < Magic.Length; i++)
|
||||
if (ReadByte(data, ref pos) != Magic[i]) return false;
|
||||
if (ReadByte(data, ref pos) != TypeReply) return false;
|
||||
if (ReadVarUInt(data, ref pos) != ProtoVersion) return false;
|
||||
if (ReadVarUInt(data, ref pos) != expectNonce) return false;
|
||||
ReadString(data, ref pos); // ServerName(忽略)
|
||||
ReadString(data, ref pos); // GatewayUrl(忽略,LoadDll 只要 CDN)
|
||||
string resBase = ReadString(data, ref pos); // ResourceBaseUrl(CDN 根)
|
||||
string token = ReadString(data, ref pos);
|
||||
if (token != expectToken) return false;
|
||||
resourceBaseUrl = resBase;
|
||||
return true;
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- LEB128 varuint + UTF8 长度前缀字符串:与 PacketWriter/PacketReader 对齐 ----
|
||||
|
||||
private static void WriteVarUInt(List<byte> buf, uint v)
|
||||
{
|
||||
while (v >= 0x80) { buf.Add((byte)(v | 0x80)); v >>= 7; }
|
||||
buf.Add((byte)v);
|
||||
}
|
||||
|
||||
private static void WriteString(List<byte> buf, string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s)) { WriteVarUInt(buf, 0); return; }
|
||||
byte[] b = Encoding.UTF8.GetBytes(s);
|
||||
WriteVarUInt(buf, (uint)b.Length);
|
||||
buf.AddRange(b);
|
||||
}
|
||||
|
||||
private static byte ReadByte(byte[] d, ref int pos)
|
||||
{
|
||||
if (pos >= d.Length) throw new FormatException("read past end");
|
||||
return d[pos++];
|
||||
}
|
||||
|
||||
private static uint ReadVarUInt(byte[] d, ref int pos)
|
||||
{
|
||||
uint result = 0;
|
||||
int shift = 0;
|
||||
while (true)
|
||||
{
|
||||
if (shift > 28) throw new FormatException("varuint too long");
|
||||
byte b = ReadByte(d, ref pos);
|
||||
result |= (uint)(b & 0x7F) << shift;
|
||||
if ((b & 0x80) == 0) break;
|
||||
shift += 7;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string ReadString(byte[] d, ref int pos)
|
||||
{
|
||||
uint len = ReadVarUInt(d, ref pos);
|
||||
if (len == 0) return string.Empty;
|
||||
if (pos + len > d.Length) throw new FormatException("string length exceeds buffer");
|
||||
string s = Encoding.UTF8.GetString(d, pos, (int)len);
|
||||
pos += (int)len;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27dfac6726f533c47b6ecf0b928245a2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
|
||||
public class MsvcStdextWorkaround : IPreprocessBuildWithReport
|
||||
{
|
||||
const string kWorkaroundFlag = "/D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS";
|
||||
|
||||
public int callbackOrder => 0;
|
||||
|
||||
public void OnPreprocessBuild(BuildReport report)
|
||||
{
|
||||
var clEnv = Environment.GetEnvironmentVariable("_CL_");
|
||||
|
||||
if (string.IsNullOrEmpty(clEnv))
|
||||
{
|
||||
Environment.SetEnvironmentVariable("_CL_", kWorkaroundFlag);
|
||||
}
|
||||
else if (!clEnv.Contains(kWorkaroundFlag))
|
||||
{
|
||||
clEnv += " " + kWorkaroundFlag;
|
||||
Environment.SetEnvironmentVariable("_CL_", clEnv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // UNITY_EDITOR
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5ecc79a541cad34a9d4d208b7723e20
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f55d59eeda44a4749a04dd20d40bfb74
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,182 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2678de581933a474fbbca174e6ff8374
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMasterTextureLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 1024
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 50
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: iPhone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WeixinMiniGame
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: OpenHarmony
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,98 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!74 &7400000
|
||||
AnimationClip:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: CloseScan
|
||||
serializedVersion: 7
|
||||
m_Legacy: 0
|
||||
m_Compressed: 0
|
||||
m_UseHighQualityCurve: 1
|
||||
m_RotationCurves: []
|
||||
m_CompressedRotationCurves: []
|
||||
m_EulerCurves: []
|
||||
m_PositionCurves: []
|
||||
m_ScaleCurves: []
|
||||
m_FloatCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_IsActive
|
||||
path: icon
|
||||
classID: 1
|
||||
script: {fileID: 0}
|
||||
m_PPtrCurves: []
|
||||
m_SampleRate: 60
|
||||
m_WrapMode: 0
|
||||
m_Bounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 0, y: 0, z: 0}
|
||||
m_ClipBindingConstant:
|
||||
genericBindings:
|
||||
- serializedVersion: 2
|
||||
path: 1704208859
|
||||
attribute: 2086281974
|
||||
script: {fileID: 0}
|
||||
typeID: 1
|
||||
customType: 0
|
||||
isPPtrCurve: 0
|
||||
pptrCurveMapping: []
|
||||
m_AnimationClipSettings:
|
||||
serializedVersion: 2
|
||||
m_AdditiveReferencePoseClip: {fileID: 0}
|
||||
m_AdditiveReferencePoseTime: 0
|
||||
m_StartTime: 0
|
||||
m_StopTime: 0
|
||||
m_OrientationOffsetY: 0
|
||||
m_Level: 0
|
||||
m_CycleOffset: 0
|
||||
m_HasAdditiveReferencePose: 0
|
||||
m_LoopTime: 1
|
||||
m_LoopBlend: 0
|
||||
m_LoopBlendOrientation: 0
|
||||
m_LoopBlendPositionY: 0
|
||||
m_LoopBlendPositionXZ: 0
|
||||
m_KeepOriginalOrientation: 0
|
||||
m_KeepOriginalPositionY: 1
|
||||
m_KeepOriginalPositionXZ: 0
|
||||
m_HeightFromFeet: 0
|
||||
m_Mirror: 0
|
||||
m_EditorCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_IsActive
|
||||
path: icon
|
||||
classID: 1
|
||||
script: {fileID: 0}
|
||||
m_EulerEditorCurves: []
|
||||
m_HasGenericRootTransform: 0
|
||||
m_HasMotionFloatCurves: 0
|
||||
m_Events: []
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce610a4580ab0624ba1cf2204bb1c579
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6dfca4f2b0bd9c547ba36ec8e3a42989
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,211 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!74 &7400000
|
||||
AnimationClip:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: OpenScan
|
||||
serializedVersion: 7
|
||||
m_Legacy: 0
|
||||
m_Compressed: 0
|
||||
m_UseHighQualityCurve: 1
|
||||
m_RotationCurves: []
|
||||
m_CompressedRotationCurves: []
|
||||
m_EulerCurves: []
|
||||
m_PositionCurves: []
|
||||
m_ScaleCurves: []
|
||||
m_FloatCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
- serializedVersion: 3
|
||||
time: 2
|
||||
value: 0
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
- serializedVersion: 3
|
||||
time: 3
|
||||
value: 0
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_IsActive
|
||||
path: icon
|
||||
classID: 1
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 220
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 2
|
||||
value: -185
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_AnchoredPosition.y
|
||||
path: icon
|
||||
classID: 224
|
||||
script: {fileID: 0}
|
||||
m_PPtrCurves: []
|
||||
m_SampleRate: 60
|
||||
m_WrapMode: 0
|
||||
m_Bounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 0, y: 0, z: 0}
|
||||
m_ClipBindingConstant:
|
||||
genericBindings:
|
||||
- serializedVersion: 2
|
||||
path: 1704208859
|
||||
attribute: 2086281974
|
||||
script: {fileID: 0}
|
||||
typeID: 1
|
||||
customType: 0
|
||||
isPPtrCurve: 0
|
||||
- serializedVersion: 2
|
||||
path: 1704208859
|
||||
attribute: 538195251
|
||||
script: {fileID: 0}
|
||||
typeID: 224
|
||||
customType: 28
|
||||
isPPtrCurve: 0
|
||||
pptrCurveMapping: []
|
||||
m_AnimationClipSettings:
|
||||
serializedVersion: 2
|
||||
m_AdditiveReferencePoseClip: {fileID: 0}
|
||||
m_AdditiveReferencePoseTime: 0
|
||||
m_StartTime: 0
|
||||
m_StopTime: 3
|
||||
m_OrientationOffsetY: 0
|
||||
m_Level: 0
|
||||
m_CycleOffset: 0
|
||||
m_HasAdditiveReferencePose: 0
|
||||
m_LoopTime: 1
|
||||
m_LoopBlend: 0
|
||||
m_LoopBlendOrientation: 0
|
||||
m_LoopBlendPositionY: 0
|
||||
m_LoopBlendPositionXZ: 0
|
||||
m_KeepOriginalOrientation: 0
|
||||
m_KeepOriginalPositionY: 1
|
||||
m_KeepOriginalPositionXZ: 0
|
||||
m_HeightFromFeet: 0
|
||||
m_Mirror: 0
|
||||
m_EditorCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
- serializedVersion: 3
|
||||
time: 2
|
||||
value: 0
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
- serializedVersion: 3
|
||||
time: 3
|
||||
value: 0
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_IsActive
|
||||
path: icon
|
||||
classID: 1
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 220
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 2
|
||||
value: -185
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_AnchoredPosition.y
|
||||
path: icon
|
||||
classID: 224
|
||||
script: {fileID: 0}
|
||||
m_EulerEditorCurves: []
|
||||
m_HasGenericRootTransform: 0
|
||||
m_HasMotionFloatCurves: 0
|
||||
m_Events:
|
||||
- time: 1
|
||||
functionName: CheckQRCode
|
||||
data:
|
||||
objectReferenceParameter: {fileID: 0}
|
||||
floatParameter: 0
|
||||
intParameter: 0
|
||||
messageOptions: 0
|
||||
- time: 2
|
||||
functionName: CheckQRCode
|
||||
data:
|
||||
objectReferenceParameter: {fileID: 0}
|
||||
floatParameter: 0
|
||||
intParameter: 0
|
||||
messageOptions: 0
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8458476133f302a4c9979e44c985f5d4
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,182 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f3261fa010350d4999fb44b43f5dc39
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMasterTextureLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 1024
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 50
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: iPhone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 50
|
||||
textureCompression: 1
|
||||
compressionQuality: 100
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WeixinMiniGame
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: OpenHarmony
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,130 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1102 &-4687405366764051200
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: OpenScan
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 7400000, guid: 92a0728491840cd4abe2cb366ca6130e, type: 2}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: ScanQRCode
|
||||
serializedVersion: 5
|
||||
m_AnimatorParameters: []
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Base Layer
|
||||
m_StateMachine: {fileID: 8553602833493306391}
|
||||
m_Mask: {fileID: 0}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
--- !u!1102 &276816421219941405
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: CloseScan
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 7400000, guid: 9f46eb24c60b1bb469704d37bae22270, type: 2}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1102 &7425443740970095782
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: New State
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 0}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1107 &8553602833493306391
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Base Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -4687405366764051200}
|
||||
m_Position: {x: 510, y: 60, z: 0}
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 276816421219941405}
|
||||
m_Position: {x: 520, y: 160, z: 0}
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 7425443740970095782}
|
||||
m_Position: {x: 260, y: 120, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: 7425443740970095782}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 205a6eed700d24d46a02ce684196b212
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f0083e732e26de4ea144815f9b4fea0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1f6aea4ed570d64fb9e730856d777ba
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2828089647f82149aaa09b83a0268d6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,85 @@
|
||||
# Unity 项目规则
|
||||
|
||||
## 美术资源目录
|
||||
通用资源目录:
|
||||
- Shader 目录:`Client\Assets\Game\shader`
|
||||
- UI 资源贴图目录:`Assets\Game\Art\UI\Texture`
|
||||
- 通用控件贴图目录:`Assets\Game\Art\UI\Texture\Common`
|
||||
- UI 预设目录:`Assets\Game\Art\UI\Prefab`
|
||||
- UI 字体目录:`Assets\Game\Art\UI\Font`
|
||||
- UI 默认字体:思源黑体 CN Regular,源文件 `Assets\Game\Art\UI\Font\SourceHanSansCN-Regular.otf`
|
||||
- 场景资源目录:`Assets\Game\Art\Scene`
|
||||
- 角色资源目录:`Assets\Game\Art\Actor`
|
||||
- 物件资源目录:`Assets\Game\Art\Object`
|
||||
- 特效资源目录:`Assets\Game\Art\Effect`
|
||||
- 声音资源目录:`Assets\Game\Art\Sound`
|
||||
|
||||
小游戏资源目录是以上通用资源目录中的Game换为小游戏名
|
||||
|
||||
## 小游戏代码规则
|
||||
|
||||
1. 小游戏的逻辑代码全部用 C# 实现(热更 C#,通过 HybridCLR 加载更新),不使用 Lua;小游戏专属逻辑以 C# 脚本(MonoBehaviour 控制器等)组织。
|
||||
2. UI 由 C# 直接访问 Unity 组件驱动:用 `transform.Find(路径)`,或 `Transform.childCount` + `transform.GetChild(i)` 递归按名查找节点(可使用 `Utility.FindTransform` 等 C# 扩展方法),再用 `GetComponent<类型>()` 获取 `TextMeshProUGUI`/`Button`/`Image`/`RectTransform` 等组件,按钮点击用 `button.onClick.AddListener(回调)` 绑定。
|
||||
3. Prefab 的 JSON(`Doc/UIPrefabCreater`)可声明指向小游戏 C# 控制器的 `MonoBehaviour` 组件(通过 `typeName` 指定,例如 `"typeName": "XGame.XxxController"`);运行时由该 MonoBehaviour 驱动界面与业务逻辑。
|
||||
4. 通用基础设施(资源加载、网络、协程等)继续复用引擎已有的 C# 框架。
|
||||
|
||||
## 资源加载规则
|
||||
|
||||
1. **本项目所有游戏资源加载一律用异步**,禁止同步加载。原因:本项目 DLL 与资源是两套独立更新机制,资源包只在**异步加载**时按需从 CDN 下载;**同步加载只读本地、不下载**,会读到旧 APK 底包里的旧资源(编辑器走 AssetDatabase 看不出问题,真机才暴露)。
|
||||
2. 协程上下文里用 `XResLoader.coLoadRes(path, type, obj => {...})`(`yield return`);非协程/纯逻辑层用回调版 `XResLoader.LoadRes(path, type, Action<UObject[]>)`(内部自驱动协程,fire-and-forget)。
|
||||
3. 同步 `XResLoader.LoadRes(path,type)` / `LoadResAB(path,type)` 已标记 `[Obsolete]`,**禁止新用**(新写会触发编译警告)。
|
||||
4. 路径前缀:异步接口带不带 `Assets/` 前缀都可(内部自动剥离),如 `"Assets/Game/Art/UI/Prefab/X.prefab"` 或 `"Game/Art/UI/Prefab/X.prefab"`。
|
||||
5. 加载从"同帧返回"变为"延迟若干帧返回":把"加载完成后才用资源"的逻辑放进回调/协程续接里;对必须立即可见的对象,先放占位再在回调里替换为真实资源(参考 `LobbyWorldController` 角色胶囊占位→真实角色的升级方式)。
|
||||
6. 小游戏框架 `IAssetLoader.Load(path, onLoaded)` 也是异步回调式(`MiniGameDownloader` 已预下载全部包,回调里返回对象)。唯一例外:启动期一次性读本地的 Lua 字节码/config(`LoadLuaAB`),不涉热更资源更新,不在本规则约束内。
|
||||
|
||||
## UI 挂载规则
|
||||
|
||||
UI 预设统一挂在 `UIRoot` 节点下对应的子节点,按界面类型分层:
|
||||
|
||||
- **HUD**:抬头信息(血条、状态、摇杆、小地图等常驻 HUD)
|
||||
- **Normal**:普通功能界面(背包、设置、商城等常规面板)
|
||||
- **Dialog**:弹出对话框(确认框、二次确认等模态弹窗)
|
||||
- **Tips**:弹出的文字信息(飘字、轻提示 Toast 等)
|
||||
|
||||
层级从下到上一般为 HUD → Normal → Dialog → Tips,越靠上的层显示在越上层。新建界面时按其类型挂到对应节点,不要直接挂到 `UIRoot` 或随意父节点下。
|
||||
|
||||
## UI 制作规则
|
||||
|
||||
1. 设计分辨率:2048X1024,ui设计的时候考虑能适配多种分辨率
|
||||
2. 设计新界面时,先使用 UI 通用控件(有MeshTextPro版本的只用MeshTextPro版本)贴图生成 JSON 界面描述文件,并记录 Unity 所使用的控件类型、层级、RectTransform、资源、文本、事件和业务绑定。
|
||||
3. 保存 JSON 后切回或重新激活 Unity 编辑器,由 Unity 自动检测新增或变更的 JSON 并生成对应 Prefab,Layer设置为UI。
|
||||
4. 根据功能说明,使用 Prefab 和相关资源开发游戏功能。
|
||||
5. 设计风格参考Doc\Design\ui_design.jpg
|
||||
6. 如果有需要生成新的贴图,使用gptimage2技能生成到对应目录中;小游戏使用的贴图必须放回小游戏自己的目录结构下(即通用资源目录中的 `Game` 换为小游戏名),不要生成到通用 `Game` 目录。
|
||||
|
||||
## JSON 转 Unity Prefab 参数规则
|
||||
|
||||
- JSON 界面描述文件统一放在 `Doc/UIPrefabCreater` 目录,文件名使用界面名,例如 `MatchWaitingControls.json`。
|
||||
- JSON 根对象必须声明 `schemaVersion`、`prefabName`、`prefabPath`、`canvas`、`assets`、`nodes`;`bindings` 和 `events` 按业务需要声明。
|
||||
- `canvas.referenceResolution` 使用 `[2048, 1024]` 作为设计分辨率,后置工具按该设计分辨率换算 RectTransform;特殊界面需要使用其他分辨率时必须在 `description` 中说明原因。
|
||||
- 每个需要转换成 Unity 节点的对象必须放入 `nodes` 数组,并声明 `name`、`parent`、`active`、`rect`、`components`。
|
||||
- 节点层级由 `parent` 指定;同一父节点下按 `nodes` 数组顺序生成,同级越靠后的节点显示在越上层。
|
||||
- `components.type` 可选值:`Canvas`、`CanvasScaler`、`GraphicRaycaster`、`Image`、`Button`、`TextMeshProUGUI`、`TMP_InputField`、`TMP_Dropdown`、`Toggle`、`Slider`、`Scrollbar`、`ScrollView`、`Empty`、`MonoBehaviour`。
|
||||
- `rect` 使用 Unity RectTransform 参数,优先声明 `anchorMin`、`anchorMax`、`pivot`、`anchoredPosition`、`sizeDelta`;全屏拉伸节点可使用 `offsetMin` 和 `offsetMax`。
|
||||
- 图片资源统一在 `assets.sprites` 中登记短名,节点 `Image` 组件使用 `sprite` 引用短名;资源路径由转换工具按项目资源目录解析,例如 `ui_button_primary_normal` 对应 `Assets/Game/Art/UI/Texture/Common/ui_button_primary_normal.png`;小游戏专属贴图按小游戏目录结构解析(即路径中的 `Game` 换为小游戏名),不解析到通用 `Game` 目录。
|
||||
- 九宫格图片必须声明 `"imageType": "Sliced"`;普通图片使用 `"imageType": "Simple"`;进度填充可使用 `"imageType": "Filled"`。
|
||||
- 文字节点统一使用 `TextMeshProUGUI`,文本内容使用 `text`,字体大小使用 `fontSize`,颜色使用 `color`,对齐使用 `alignment`。
|
||||
- 浅色文字在复杂背景、图片背景、半透明面板或高亮按钮上必须使用深色描边或阴影保证可读性;描边颜色优先使用深蓝或深灰,例如 `#0B1724`、`#102033`,不默认使用纯黑。
|
||||
- 标题、按钮文字、状态提示、倒计时等关键 UI 文本可使用轻描边或阴影;普通正文、列表、输入框文本不默认加描边,优先通过背景对比度保证可读性。
|
||||
- TextMeshProUGUI 描边建议保持轻量,常规 UI 使用较小 Outline Width,避免粗黑边导致界面变脏。
|
||||
- 按钮节点使用 `Button` 组件,`transition` 优先使用 `SpriteSwap`;需要点击事件时在组件中声明 `onClick`,并在根对象 `events` 中登记事件名和节点名。
|
||||
- 输入框节点使用 `TMP_InputField`,必须声明 `placeholder`、`characterLimit`、`contentType`;密码输入使用 `"contentType": "Password"`。
|
||||
- Toggle 节点必须声明 `toggleGroup`、`isOn`,并分别用子节点声明背景和选中标记。
|
||||
- 需要业务绑定的控件必须加入根对象 `bindings`,例如 `login.username`、`register.password`;事件统一加入根对象 `events`,例如 `{ "name": "Auth.Login", "node": "Btn_Login" }`。
|
||||
- 需要挂载运行时脚本时使用 `MonoBehaviour` 组件,并声明 `typeName`,例如 `"typeName": "XGame.MatchWaitingController"`。
|
||||
- Unity 编辑器重新激活时,自动转换工具应只读取新增或变更的 JSON 文件生成 Prefab;JSON 字段冲突时以节点 `components` 内显式声明的参数为准。
|
||||
|
||||
## UI 通用控件贴图
|
||||
|
||||
- 目录:`Assets\Game\Art\UI\Texture\Common`
|
||||
- 风格:轻松、扁平化游戏风格,色彩饱和度略高,圆角轮廓,轻微高光和阴影。
|
||||
- 导入设置:贴图类型使用 `Sprite (2D and UI)`,启用 Alpha 透明,通用拉伸背景使用 `Sliced` 九宫格。
|
||||
- 命名规则:统一使用 `ui_控件类型_状态或用途.png`,例如 `ui_button_primary_normal.png`。
|
||||
|
||||
### 控件贴图清单
|
||||
Doc\UI_Pic_Set.md
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47077ff07c308f348a48dcf7a4d18a49
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4bc1bf3eaf048334cbb915dab356d7e3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e6914217da6edb34baad8872f8642df3, type: 3}
|
||||
m_Name: GroundToolConfig
|
||||
m_EditorClassIdentifier:
|
||||
randOffset: 0
|
||||
randJitter: 0.1
|
||||
width: 128
|
||||
length: 128
|
||||
height: 30
|
||||
perlinScale: 0.05
|
||||
groundIncline: 0.01
|
||||
matSplit1: 0.25
|
||||
matSplit2: 0.5
|
||||
matSplit3: 0.75
|
||||
power: 2
|
||||
texGround1: {fileID: 0}
|
||||
texGround2: {fileID: 0}
|
||||
texGround3: {fileID: 0}
|
||||
texGround4: {fileID: 0}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ffcafc0382981e4ea66da337163c171
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55b10dbb5dfe31b41ad1150327f5c12d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,152 @@
|
||||
|
||||
using HybridCLR.Editor.Commands;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HybridCLR.Editor
|
||||
{
|
||||
public static class BuildAssetsCommand
|
||||
{
|
||||
public static string HybridCLRBuildCacheDir => Application.dataPath + "/HybridCLRBuildCache";
|
||||
|
||||
public static string AssetBundleOutputDir => $"{HybridCLRBuildCacheDir}/AssetBundleOutput";
|
||||
|
||||
public static string AssetBundleSourceDataTempDir => $"{HybridCLRBuildCacheDir}/AssetBundleSourceData";
|
||||
|
||||
|
||||
public static string GetAssetBundleOutputDirByTarget(BuildTarget target)
|
||||
{
|
||||
return $"{AssetBundleOutputDir}/{target}";
|
||||
}
|
||||
|
||||
public static string GetAssetBundleTempDirByTarget(BuildTarget target)
|
||||
{
|
||||
return $"{AssetBundleSourceDataTempDir}/{target}";
|
||||
}
|
||||
|
||||
public static string ToRelativeAssetPath(string s)
|
||||
{
|
||||
return s.Substring(s.IndexOf("Assets/"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将HotFix.dll和HotUpdatePrefab.prefab打入common包.
|
||||
/// 将HotUpdateScene.unity打入scene包.
|
||||
/// </summary>
|
||||
/// <param name="tempDir"></param>
|
||||
/// <param name="outputDir"></param>
|
||||
/// <param name="target"></param>
|
||||
private static void BuildAssetBundles(string tempDir, string outputDir, BuildTarget target)
|
||||
{
|
||||
Directory.CreateDirectory(tempDir);
|
||||
Directory.CreateDirectory(outputDir);
|
||||
|
||||
List<AssetBundleBuild> abs = new List<AssetBundleBuild>();
|
||||
|
||||
{
|
||||
var prefabAssets = new List<string>();
|
||||
string testPrefab = $"{Application.dataPath}/Prefabs/HotUpdatePrefab.prefab";
|
||||
prefabAssets.Add(testPrefab);
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
|
||||
abs.Add(new AssetBundleBuild
|
||||
{
|
||||
assetBundleName = "prefabs",
|
||||
assetNames = prefabAssets.Select(s => ToRelativeAssetPath(s)).ToArray(),
|
||||
});
|
||||
}
|
||||
|
||||
BuildPipeline.BuildAssetBundles(outputDir, abs.ToArray(), BuildAssetBundleOptions.None, target);
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
public static void BuildAssetBundleByTarget(BuildTarget target)
|
||||
{
|
||||
BuildAssetBundles(GetAssetBundleTempDirByTarget(target), GetAssetBundleOutputDirByTarget(target), target);
|
||||
}
|
||||
|
||||
[MenuItem("HybridCLR/Build/BuildAssetsAndCopyToStreamingAssets")]
|
||||
public static void BuildAndCopyABAOTHotUpdateDlls()
|
||||
{
|
||||
BuildAssetBundleByTarget(EditorUserBuildSettings.activeBuildTarget);
|
||||
CopyAssetBundlesToStreamingAssets();
|
||||
CompileDllCommand.CompileDllActiveBuildTarget();
|
||||
CopyAOTAssembliesToStreamingAssets();
|
||||
CopyHotUpdateAssembliesToStreamingAssets();
|
||||
}
|
||||
|
||||
//[MenuItem("HybridCLR/Build/Copy_AB_AOT_HotUpdateDlls")]
|
||||
public static void Copy_AB_AOT_HotUpdateDlls()
|
||||
{
|
||||
CopyAOTAssembliesToStreamingAssets();
|
||||
CopyHotUpdateAssembliesToStreamingAssets();
|
||||
CopyAssetBundlesToStreamingAssets();
|
||||
}
|
||||
|
||||
|
||||
//[MenuItem("HybridCLR/Build/BuildAssetbundle")]
|
||||
public static void BuildSceneAssetBundleActiveBuildTargetExcludeAOT()
|
||||
{
|
||||
BuildAssetBundleByTarget(EditorUserBuildSettings.activeBuildTarget);
|
||||
}
|
||||
|
||||
public static void CopyAOTAssembliesToStreamingAssets()
|
||||
{
|
||||
var target = EditorUserBuildSettings.activeBuildTarget;
|
||||
string aotAssembliesSrcDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
|
||||
string aotAssembliesDstDir = Application.streamingAssetsPath+"/xaot";//改为aot目录
|
||||
if (!Directory.Exists(aotAssembliesDstDir))
|
||||
Directory.CreateDirectory(aotAssembliesDstDir);
|
||||
foreach (var dll in Packager.AOTMetaAssemblyNames)
|
||||
{
|
||||
string srcDllPath = $"{aotAssembliesSrcDir}/{dll}";
|
||||
if (!File.Exists(srcDllPath))
|
||||
{
|
||||
Debug.LogError($"ab中添加AOT补充元数据dll:{srcDllPath} 时发生错误,文件不存在。裁剪后的AOT dll在BuildPlayer时才能生成,因此需要你先构建一次游戏App后再打包。");
|
||||
continue;
|
||||
}
|
||||
string dllBytesPath = $"{aotAssembliesDstDir}/{dll}";
|
||||
File.Copy(srcDllPath, dllBytesPath, true);
|
||||
Debug.Log($"[CopyAOTAssembliesToStreamingAssets] copy AOT dll {srcDllPath} -> {dllBytesPath}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void CopyHotUpdateAssembliesToStreamingAssets()
|
||||
{
|
||||
var target = EditorUserBuildSettings.activeBuildTarget;
|
||||
|
||||
string hotfixDllSrcDir = SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target);
|
||||
string hotfixAssembliesDstDir = Application.streamingAssetsPath+"/xhotfix";//改为hotfix目录
|
||||
if (!Directory.Exists(hotfixAssembliesDstDir))
|
||||
Directory.CreateDirectory(hotfixAssembliesDstDir);
|
||||
foreach (var dll in SettingsUtil.HotUpdateAssemblyFilesExcludePreserved)
|
||||
{
|
||||
string dllPath = $"{hotfixDllSrcDir}/{dll}";
|
||||
string dllBytesPath = $"{hotfixAssembliesDstDir}/{dll}";
|
||||
File.Copy(dllPath, dllBytesPath, true);
|
||||
Debug.Log($"[CopyHotUpdateAssembliesToStreamingAssets] copy hotfix dll {dllPath} -> {dllBytesPath}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void CopyAssetBundlesToStreamingAssets()
|
||||
{
|
||||
var target = EditorUserBuildSettings.activeBuildTarget;
|
||||
string streamingAssetPathDst = Application.streamingAssetsPath;
|
||||
Directory.CreateDirectory(streamingAssetPathDst);
|
||||
string outputDir = GetAssetBundleOutputDirByTarget(target);
|
||||
var abs = new string[] { "prefabs" };
|
||||
foreach (var ab in abs)
|
||||
{
|
||||
string srcAb = ToRelativeAssetPath($"{outputDir}/{ab}");
|
||||
string dstAb = ToRelativeAssetPath($"{streamingAssetPathDst}/{ab}");
|
||||
Debug.Log($"[CopyAssetBundlesToStreamingAssets] copy assetbundle {srcAb} -> {dstAb}");
|
||||
AssetDatabase.CopyAsset( srcAb, dstAb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7417143702c594642ba8d9a138dbfa1d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,79 @@
|
||||
#if EngineEditor
|
||||
using HybridCLR.Editor.Commands;
|
||||
using HybridCLR.Editor.Installer;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HybridCLR.Editor
|
||||
{
|
||||
public class BuildPlayerCommand
|
||||
{
|
||||
public static void CopyAssets(string outputDir)
|
||||
{
|
||||
Directory.CreateDirectory(outputDir);
|
||||
|
||||
foreach(var srcFile in Directory.GetFiles(Application.streamingAssetsPath))
|
||||
{
|
||||
string dstFile = $"{outputDir}/{Path.GetFileName(srcFile)}";
|
||||
File.Copy(srcFile, dstFile, true);
|
||||
}
|
||||
}
|
||||
private static string[] FindEnabledEditorScenes()
|
||||
{
|
||||
List<string> EditorScenes = new List<string>();
|
||||
foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
|
||||
{
|
||||
if (!scene.enabled) continue;
|
||||
EditorScenes.Add(scene.path);
|
||||
}
|
||||
return EditorScenes.ToArray();
|
||||
}
|
||||
|
||||
[MenuItem("HybridCLR/Build/Win64")]
|
||||
public static void Build_Win64()
|
||||
{
|
||||
BuildTarget target = BuildTarget.StandaloneWindows64;
|
||||
BuildTarget activeTarget = EditorUserBuildSettings.activeBuildTarget;
|
||||
if (activeTarget != BuildTarget.StandaloneWindows64 && activeTarget != BuildTarget.StandaloneWindows)
|
||||
{
|
||||
Debug.LogError("请先切到Win平台再打包");
|
||||
return;
|
||||
}
|
||||
// Get filename.
|
||||
string outputPath = $"{SettingsUtil.ProjectDir}/Release-Win64";
|
||||
|
||||
var buildOptions = BuildOptions.CompressWithLz4;
|
||||
|
||||
string location = $"{outputPath}/HybridCLRTrial.exe";
|
||||
|
||||
PrebuildCommand.GenerateAll();
|
||||
Debug.Log("====> Build App");
|
||||
BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions()
|
||||
{
|
||||
scenes = FindEnabledEditorScenes(),//new string[] { "Assets/Scenes/SimpleScene.unity" },
|
||||
locationPathName = location,
|
||||
options = buildOptions,
|
||||
target = target,
|
||||
targetGroup = BuildTargetGroup.Standalone,
|
||||
};
|
||||
|
||||
var report = BuildPipeline.BuildPlayer(buildPlayerOptions);
|
||||
if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
|
||||
{
|
||||
Debug.LogError("打包失败");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("====> 复制热更新资源和代码");
|
||||
BuildAssetsCommand.BuildAndCopyABAOTHotUpdateDlls();
|
||||
BashUtil.CopyDir(Application.streamingAssetsPath, $"{outputPath}/HybridCLRTrial_Data/StreamingAssets", true);
|
||||
#if UNITY_EDITOR
|
||||
Application.OpenURL($"file:///{location}");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9fc09201239ded843a793c9167e0ff6a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 227b11ce7187c9b4da274d4119b36597
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,136 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace XGame.Editor
|
||||
{
|
||||
// publish.json 视图(JsonUtility:C# 字段名须与 json 键一致,故小写开头)
|
||||
[Serializable]
|
||||
public sealed class MiniGamePublishSpec
|
||||
{
|
||||
public string gameId;
|
||||
public string serverSrcDir; // 相对 Server/games-src/
|
||||
public string serverProject; // 相对 serverSrcDir
|
||||
public string serverAssembly;
|
||||
public string serverEntryType;
|
||||
public string clientProject; // 相对仓库根
|
||||
public string coreDll;
|
||||
public string clientDll;
|
||||
public string clientEntryType;
|
||||
public int minFrameworkVersion = 1;
|
||||
public int playerCount = 2;
|
||||
public int tickRateHz = 10;
|
||||
}
|
||||
|
||||
public static class MiniGamePublishMenu
|
||||
{
|
||||
[MenuItem("XWorld/生成小游戏更新", false, 802)]
|
||||
public static void Open() => MiniGamePublishWindow.Open();
|
||||
}
|
||||
|
||||
public sealed class MiniGamePublishWindow : EditorWindow
|
||||
{
|
||||
private string[] _gameDirs = Array.Empty<string>();
|
||||
private string[] _gameNames = Array.Empty<string>();
|
||||
private int _selected;
|
||||
private int _version = 1;
|
||||
private bool _pc, _android, _ios, _webgl;
|
||||
private Vector2 _scroll;
|
||||
|
||||
public static void Open()
|
||||
{
|
||||
var w = GetWindow<MiniGamePublishWindow>("生成小游戏更新");
|
||||
w.minSize = new Vector2(360, 320);
|
||||
w.RefreshGames();
|
||||
w.Show();
|
||||
}
|
||||
|
||||
private void RefreshGames()
|
||||
{
|
||||
string root = Path.Combine(Application.dataPath, "MiniGames");
|
||||
_gameDirs = Directory.Exists(root)
|
||||
? Directory.GetDirectories(root).Where(d => File.Exists(Path.Combine(d, "publish.json"))).ToArray()
|
||||
: Array.Empty<string>();
|
||||
_gameNames = _gameDirs.Select(Path.GetFileName).ToArray();
|
||||
_selected = Mathf.Clamp(_selected, 0, Mathf.Max(0, _gameDirs.Length - 1));
|
||||
|
||||
// 默认平台 = 当前激活 BuildTarget
|
||||
_pc = _android = _ios = _webgl = false;
|
||||
switch (EditorUserBuildSettings.activeBuildTarget)
|
||||
{
|
||||
case BuildTarget.Android: _android = true; break;
|
||||
case BuildTarget.iOS: _ios = true; break;
|
||||
case BuildTarget.WebGL: _webgl = true; break;
|
||||
default: _pc = true; break;
|
||||
}
|
||||
RefreshDefaultVersion();
|
||||
}
|
||||
|
||||
private void RefreshDefaultVersion()
|
||||
{
|
||||
if (_gameDirs.Length == 0) return;
|
||||
var spec = LoadSpec(_gameDirs[_selected]);
|
||||
_version = (spec == null || string.IsNullOrEmpty(spec.gameId))
|
||||
? 1 : MiniGamePublishPipeline.NextVersion(spec.gameId);
|
||||
}
|
||||
|
||||
private static MiniGamePublishSpec LoadSpec(string gameDir)
|
||||
{
|
||||
try { return JsonUtility.FromJson<MiniGamePublishSpec>(File.ReadAllText(Path.Combine(gameDir, "publish.json"))); }
|
||||
catch (Exception e) { Debug.LogError("[MiniGamePublish] publish.json 解析失败: " + e.Message); return null; }
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (_gameDirs.Length == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Assets/MiniGames 下没有含 publish.json 的小游戏目录。", MessageType.Warning);
|
||||
if (GUILayout.Button("刷新")) RefreshGames();
|
||||
return;
|
||||
}
|
||||
|
||||
_scroll = EditorGUILayout.BeginScrollView(_scroll);
|
||||
EditorGUILayout.LabelField("小游戏", EditorStyles.boldLabel);
|
||||
int sel = GUILayout.SelectionGrid(_selected, _gameNames, 1, EditorStyles.radioButton);
|
||||
if (sel != _selected) { _selected = sel; RefreshDefaultVersion(); }
|
||||
|
||||
EditorGUILayout.Space();
|
||||
_version = Mathf.Max(1, EditorGUILayout.IntField("版本号", _version));
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("平台(AB 按平台构建)", EditorStyles.boldLabel);
|
||||
_pc = EditorGUILayout.ToggleLeft("PC (StandaloneWindows64)", _pc);
|
||||
_android = EditorGUILayout.ToggleLeft("Android", _android);
|
||||
_ios = EditorGUILayout.ToggleLeft("iOS", _ios);
|
||||
_webgl = EditorGUILayout.ToggleLeft("WebGL", _webgl);
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
using (new EditorGUI.DisabledScope(!(_pc || _android || _ios || _webgl)))
|
||||
{
|
||||
if (GUILayout.Button("生成", GUILayout.Height(32)))
|
||||
{
|
||||
var spec = LoadSpec(_gameDirs[_selected]);
|
||||
if (spec == null || string.IsNullOrEmpty(spec.gameId))
|
||||
{
|
||||
EditorUtility.DisplayDialog("生成小游戏更新", "publish.json 无效(缺 gameId)", "OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
var targets = new List<MiniGamePublishPipeline.PlatformChoice>();
|
||||
if (_pc) targets.Add(new MiniGamePublishPipeline.PlatformChoice("pc", BuildTarget.StandaloneWindows64));
|
||||
if (_android) targets.Add(new MiniGamePublishPipeline.PlatformChoice("android", BuildTarget.Android));
|
||||
if (_ios) targets.Add(new MiniGamePublishPipeline.PlatformChoice("ios", BuildTarget.iOS));
|
||||
if (_webgl) targets.Add(new MiniGamePublishPipeline.PlatformChoice("webgl", BuildTarget.WebGL));
|
||||
MiniGamePublishPipeline.Run(spec, _gameDirs[_selected], _version, targets);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0582fda2162516d46b2e207152dd6b35
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,299 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace XGame.Editor
|
||||
{
|
||||
// 生成小游戏更新的流水线:dotnet build 两端 DLL → 打代码/资源 AB → PublishTool.Cli 落位。
|
||||
// 产物:CDN/minigame/<id>/<ver>/<platform>/(客户端)、deploy/minigame/<id>/<ver>/(服务器)。
|
||||
public static class MiniGamePublishPipeline
|
||||
{
|
||||
public struct PlatformChoice
|
||||
{
|
||||
public string Name; public BuildTarget Target;
|
||||
public PlatformChoice(string name, BuildTarget target) { Name = name; Target = target; }
|
||||
}
|
||||
|
||||
// resolved-spec.json(交给 PublishTool.Cli;字段小写对齐 GameSpecJson 大小写不敏感解析)
|
||||
[Serializable]
|
||||
private sealed class ResolvedSpecJson
|
||||
{
|
||||
public string gameId; public int version; public int minFrameworkVersion;
|
||||
public int playerCount; public int tickRateHz;
|
||||
public string serverAssembly; public string serverEntryType;
|
||||
public string coreDll; public string clientDll; public string clientEntryType;
|
||||
public string codeAb; public List<string> assets;
|
||||
}
|
||||
|
||||
private const string CodeAbName = "code.unity3d";
|
||||
private const string ResAbName = "res.unity3d";
|
||||
// staging 不能用 '~' 隐藏目录:隐藏资产不入 AssetDatabase,进不了 AB
|
||||
private const string StagingAssetDir = "Assets/MiniGameStaging";
|
||||
private const string CliProject = "Server/PublishTool.Cli/PublishTool.Cli.csproj";
|
||||
private const string CliDll = "Server/PublishTool.Cli/bin/Release/net10.0/XWorld.PublishTool.Cli.dll";
|
||||
private const string PrivateKeyRel = "Tools/keys/minigame-private.pem";
|
||||
|
||||
private static string RepoRoot => Path.GetFullPath(Path.Combine(Application.dataPath, "../.."));
|
||||
|
||||
// 当前 Editor 安装目录(…/Editor),传给 RPS.Client.csproj 的 UnityEditorPath 以定位 UnityEngine dll
|
||||
private static string UnityEditorDir => Path.GetDirectoryName(EditorApplication.applicationPath);
|
||||
|
||||
// 默认版本号 = CDN/minigame/<gameId>/ 下已有数字目录 max+1
|
||||
public static int NextVersion(string gameId)
|
||||
{
|
||||
string dir = Path.Combine(RepoRoot, "CDN/minigame", gameId);
|
||||
int max = 0;
|
||||
if (Directory.Exists(dir))
|
||||
foreach (var d in Directory.GetDirectories(dir))
|
||||
if (int.TryParse(Path.GetFileName(d), out int v) && v > max) max = v;
|
||||
return max + 1;
|
||||
}
|
||||
|
||||
public static void Run(MiniGamePublishSpec spec, string gameDir, int version, List<PlatformChoice> platforms)
|
||||
{
|
||||
string cdnVerDir = Path.Combine(RepoRoot, "CDN/minigame", spec.gameId, version.ToString());
|
||||
string deployVerDir = Path.Combine(RepoRoot, "deploy/minigame", spec.gameId, version.ToString());
|
||||
if ((Directory.Exists(cdnVerDir) || Directory.Exists(deployVerDir)) &&
|
||||
!EditorUtility.DisplayDialog("生成小游戏更新",
|
||||
$"版本 {spec.gameId}/{version} 已存在,覆盖重发?\n{cdnVerDir}\n{deployVerDir}", "覆盖", "取消"))
|
||||
return;
|
||||
|
||||
// 覆盖重发只勾部分平台时,未勾的旧平台 AB 会与新服务器 DLL 不一致——需用户明确确认
|
||||
if (Directory.Exists(cdnVerDir))
|
||||
{
|
||||
var known = new[] { "pc", "android", "ios", "webgl" };
|
||||
var chosen = new HashSet<string>(platforms.Select(p => p.Name));
|
||||
var stale = Directory.GetDirectories(cdnVerDir)
|
||||
.Select(Path.GetFileName)
|
||||
.Where(n => known.Contains(n) && !chosen.Contains(n))
|
||||
.ToArray();
|
||||
if (stale.Length > 0 &&
|
||||
!EditorUtility.DisplayDialog("生成小游戏更新",
|
||||
$"版本 {spec.gameId}/{version} 下这些平台不在本次勾选中,将保留旧包并与新服务器 DLL 不一致:\n{string.Join(", ", stale)}\n\n继续?(建议全平台重发或换新版本号)", "继续", "取消"))
|
||||
return;
|
||||
}
|
||||
|
||||
string tmp = Path.Combine(RepoRoot, "Temp/MiniGamePublish", spec.gameId);
|
||||
string keyPath = Path.Combine(RepoRoot, PrivateKeyRel);
|
||||
bool signed = File.Exists(keyPath);
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(tmp)) Directory.Delete(tmp, true);
|
||||
Directory.CreateDirectory(tmp);
|
||||
|
||||
// 1) 服务器 DLL
|
||||
Progress("dotnet build (server)", 0.05f);
|
||||
string serverProj = Path.Combine(RepoRoot, "Server/games-src", spec.serverSrcDir, spec.serverProject);
|
||||
RunOrThrow("dotnet build (server)", "dotnet", $"build \"{serverProj}\" -c Release -nologo");
|
||||
string serverBin = Path.Combine(Path.GetDirectoryName(serverProj), "bin/Release/netstandard2.1");
|
||||
RequireFile(Path.Combine(serverBin, spec.serverAssembly));
|
||||
RequireFile(Path.Combine(serverBin, spec.coreDll));
|
||||
|
||||
// 2) 客户端 DLL(Core 取服务器构建产物——两端同一 IL;UnityEditorPath 用当前 Editor)
|
||||
Progress("dotnet build (client)", 0.15f);
|
||||
string clientProj = Path.Combine(RepoRoot, spec.clientProject);
|
||||
RunOrThrow("dotnet build (client)", "dotnet",
|
||||
$"build \"{clientProj}\" -c Release -nologo -p:UnityEditorPath=\"{UnityEditorDir}\"");
|
||||
string clientBin = Path.Combine(Path.GetDirectoryName(clientProj), "bin/Release/netstandard2.1");
|
||||
RequireFile(Path.Combine(clientBin, spec.clientDll));
|
||||
|
||||
// 3) DLL → Assets staging(.bytes 才能作为 TextAsset 进 AB)
|
||||
Progress("导入 DLL 为 TextAsset", 0.25f);
|
||||
string stagingFull = Path.Combine(Application.dataPath, "MiniGameStaging/code");
|
||||
Directory.CreateDirectory(stagingFull);
|
||||
File.Copy(Path.Combine(serverBin, spec.coreDll), Path.Combine(stagingFull, spec.coreDll + ".bytes"), true);
|
||||
File.Copy(Path.Combine(clientBin, spec.clientDll), Path.Combine(stagingFull, spec.clientDll + ".bytes"), true);
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
|
||||
string[] codeAssets =
|
||||
{
|
||||
$"{StagingAssetDir}/code/{spec.coreDll}.bytes",
|
||||
$"{StagingAssetDir}/code/{spec.clientDll}.bytes",
|
||||
};
|
||||
|
||||
// 4) 每平台打 AB
|
||||
string[] resAssets = CollectResAssets(Path.GetFileName(gameDir));
|
||||
var builds = new List<AssetBundleBuild>
|
||||
{
|
||||
new AssetBundleBuild { assetBundleName = CodeAbName, assetNames = codeAssets },
|
||||
};
|
||||
if (resAssets.Length > 0)
|
||||
builds.Add(new AssetBundleBuild { assetBundleName = ResAbName, assetNames = resAssets });
|
||||
else
|
||||
Debug.LogWarning($"[MiniGamePublish] {gameDir}/res 为空,跳过资源 AB(仅发代码 AB)");
|
||||
|
||||
foreach (var pf in platforms)
|
||||
{
|
||||
Progress($"BuildAssetBundles ({pf.Name})", 0.35f);
|
||||
string abOut = Path.Combine(tmp, "ab", pf.Name);
|
||||
Directory.CreateDirectory(abOut);
|
||||
var manifest = BuildPipeline.BuildAssetBundles(
|
||||
abOut, builds.ToArray(), BuildAssetBundleOptions.ChunkBasedCompression, pf.Target);
|
||||
if (manifest == null) throw new Exception($"BuildAssetBundles 失败: {pf.Name}");
|
||||
RequireFile(Path.Combine(abOut, CodeAbName));
|
||||
}
|
||||
|
||||
// 5) resolved-spec.json
|
||||
var resolved = new ResolvedSpecJson
|
||||
{
|
||||
gameId = spec.gameId, version = version, minFrameworkVersion = spec.minFrameworkVersion,
|
||||
playerCount = spec.playerCount, tickRateHz = spec.tickRateHz,
|
||||
serverAssembly = spec.serverAssembly, serverEntryType = spec.serverEntryType,
|
||||
coreDll = spec.coreDll, clientDll = spec.clientDll, clientEntryType = spec.clientEntryType,
|
||||
codeAb = CodeAbName,
|
||||
assets = resAssets.Length > 0 ? new List<string> { ResAbName } : new List<string>(),
|
||||
};
|
||||
string specPath = Path.Combine(tmp, "resolved-spec.json");
|
||||
File.WriteAllText(specPath, JsonUtility.ToJson(resolved, true), new UTF8Encoding(false));
|
||||
|
||||
// 6) PublishTool.Cli 落位(先临时目录,成功后整体 Move,防 Cdn.Runner 提供半成品)
|
||||
Progress("dotnet build (PublishTool.Cli)", 0.55f);
|
||||
RunOrThrow("dotnet build (PublishTool.Cli)", "dotnet",
|
||||
$"build \"{Path.Combine(RepoRoot, CliProject)}\" -c Release -nologo");
|
||||
string cliDll = Path.Combine(RepoRoot, CliDll);
|
||||
RequireFile(cliDll);
|
||||
string keyArg = signed ? $" --key \"{keyPath}\"" : "";
|
||||
|
||||
// 6a) 服务器:只汇集需要的两个 DLL 作为 src
|
||||
Progress("发布 server", 0.65f);
|
||||
string serverSrc = Path.Combine(tmp, "server-src");
|
||||
Directory.CreateDirectory(serverSrc);
|
||||
File.Copy(Path.Combine(serverBin, spec.serverAssembly), Path.Combine(serverSrc, spec.serverAssembly), true);
|
||||
File.Copy(Path.Combine(serverBin, spec.coreDll), Path.Combine(serverSrc, spec.coreDll), true);
|
||||
string outServer = Path.Combine(tmp, "out-server");
|
||||
RunOrThrow("PublishTool.Cli (server)", "dotnet",
|
||||
$"\"{cliDll}\" --mode server --src \"{serverSrc}\" --out \"{outServer}\" --spec \"{specPath}\"{keyArg}");
|
||||
|
||||
// 6b) 客户端:每平台一次,src = 该平台 AB 输出目录
|
||||
var outClients = new List<KeyValuePair<string, string>>();
|
||||
foreach (var pf in platforms)
|
||||
{
|
||||
Progress($"发布 client ({pf.Name})", 0.75f);
|
||||
string outClient = Path.Combine(tmp, "out-client-" + pf.Name);
|
||||
RunOrThrow($"PublishTool.Cli (client {pf.Name})", "dotnet",
|
||||
$"\"{cliDll}\" --mode client --src \"{Path.Combine(tmp, "ab", pf.Name)}\" --out \"{outClient}\" --spec \"{specPath}\"{keyArg}");
|
||||
outClients.Add(new KeyValuePair<string, string>(pf.Name, outClient));
|
||||
}
|
||||
|
||||
// 7) 原子落位:客户端全部就位后才落服务器——服务器 game.json 是新版本"生效"开关,
|
||||
// 先落它而客户端 Move 失败会导致网关广播新版本但 CDN 缺包
|
||||
Progress("落位 CDN/deploy", 0.9f);
|
||||
foreach (var kv in outClients)
|
||||
MoveIntoPlace(kv.Value, Path.Combine(cdnVerDir, kv.Key));
|
||||
MoveIntoPlace(outServer, deployVerDir);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"生成完成:{spec.gameId} v{version}" + (signed ? "(已签名)" : "(未签名:无 " + PrivateKeyRel + ")"));
|
||||
sb.AppendLine("服务器: " + deployVerDir);
|
||||
foreach (var kv in outClients)
|
||||
sb.AppendLine($"客户端[{kv.Key}]: " + Path.Combine(cdnVerDir, kv.Key));
|
||||
Debug.Log("[MiniGamePublish] " + sb);
|
||||
EditorUtility.DisplayDialog("生成小游戏更新", sb.ToString(), "OK");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError("[MiniGamePublish] 失败: " + e);
|
||||
EditorUtility.DisplayDialog("生成小游戏更新失败", e.Message, "OK");
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
CleanupStaging();
|
||||
try { if (Directory.Exists(tmp)) Directory.Delete(tmp, true); } catch { /* 被占用时留给下次 Run 清 */ }
|
||||
}
|
||||
}
|
||||
|
||||
private static void Progress(string info, float p)
|
||||
=> EditorUtility.DisplayProgressBar("生成小游戏更新", info, p);
|
||||
|
||||
private static string[] CollectResAssets(string gameDirName)
|
||||
{
|
||||
string resPath = $"Assets/MiniGames/{gameDirName}/res";
|
||||
if (!AssetDatabase.IsValidFolder(resPath)) return Array.Empty<string>();
|
||||
return AssetDatabase.FindAssets("", new[] { resPath })
|
||||
.Select(AssetDatabase.GUIDToAssetPath)
|
||||
.Distinct()
|
||||
.Where(p => !AssetDatabase.IsValidFolder(p))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
// 备份交换式落位:先把旧版挪到 .old,Move 新版成功后再删 .old;失败则回滚,避免"删旧后搬新失败"两头皆空
|
||||
private static void MoveIntoPlace(string src, string dst)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(dst));
|
||||
string backup = dst + ".old";
|
||||
if (Directory.Exists(backup)) Directory.Delete(backup, true);
|
||||
bool hadOld = Directory.Exists(dst);
|
||||
if (hadOld) Directory.Move(dst, backup);
|
||||
try
|
||||
{
|
||||
Directory.Move(src, dst);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (hadOld && !Directory.Exists(dst)) Directory.Move(backup, dst); // 回滚旧版
|
||||
throw;
|
||||
}
|
||||
if (hadOld) Directory.Delete(backup, true);
|
||||
}
|
||||
|
||||
private static void RequireFile(string p)
|
||||
{ if (!File.Exists(p)) throw new Exception("缺少构建产物: " + p); }
|
||||
|
||||
private static void CleanupStaging()
|
||||
{
|
||||
try
|
||||
{
|
||||
string full = Path.Combine(Application.dataPath, "MiniGameStaging");
|
||||
bool dirty = false;
|
||||
if (Directory.Exists(full)) { Directory.Delete(full, true); dirty = true; }
|
||||
string meta = full + ".meta";
|
||||
if (File.Exists(meta)) { File.Delete(meta); dirty = true; }
|
||||
if (dirty) AssetDatabase.Refresh();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogWarning("[MiniGamePublish] 清理 staging 失败(不影响产物): " + e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// 起进程并收敛 stdout/stderr(事件式读取避免缓冲区互锁);非 0 退出码抛异常带输出尾部
|
||||
private static string RunOrThrow(string step, string file, string args)
|
||||
{
|
||||
var psi = new System.Diagnostics.ProcessStartInfo
|
||||
{
|
||||
FileName = file, Arguments = args, WorkingDirectory = RepoRoot,
|
||||
UseShellExecute = false, CreateNoWindow = true,
|
||||
RedirectStandardOutput = true, RedirectStandardError = true,
|
||||
StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8,
|
||||
};
|
||||
var sb = new StringBuilder();
|
||||
using (var p = new System.Diagnostics.Process { StartInfo = psi })
|
||||
{
|
||||
p.OutputDataReceived += (_, e) => { if (e.Data != null) lock (sb) sb.AppendLine(e.Data); };
|
||||
p.ErrorDataReceived += (_, e) => { if (e.Data != null) lock (sb) sb.AppendLine(e.Data); };
|
||||
p.Start();
|
||||
p.BeginOutputReadLine();
|
||||
p.BeginErrorReadLine();
|
||||
if (!p.WaitForExit(600_000))
|
||||
{
|
||||
try { p.Kill(); } catch { }
|
||||
throw new Exception($"{step} 超时(>600s),已终止进程");
|
||||
}
|
||||
p.WaitForExit(); // 排干异步输出缓冲(有超时版 WaitForExit 不等 BeginOutputReadLine 完成)
|
||||
string output = sb.ToString();
|
||||
if (p.ExitCode != 0)
|
||||
{
|
||||
string tail = output.Length > 4000 ? output.Substring(output.Length - 4000) : output;
|
||||
throw new Exception($"{step} 失败 (exit {p.ExitCode}):\n{tail}");
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 78411d4c938b22d4199fff6531c2920f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ce88e84dc949614a82238427013eaec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
[InitializeOnLoad]
|
||||
public static class CustomPlayModeHandler
|
||||
{
|
||||
static DateTime m_lastModified;
|
||||
static bool m_enterPlayAfterServerReady;
|
||||
static double m_waitServerStartTime;
|
||||
const double WAIT_SERVER_TIMEOUT_SECONDS = 20.0;
|
||||
|
||||
static CustomPlayModeHandler()
|
||||
{
|
||||
string strLastTime = PlayerPrefs.GetString("LastModifiedTime");
|
||||
if (strLastTime != null && strLastTime != "")
|
||||
{
|
||||
m_lastModified = DateTime.Parse(strLastTime);
|
||||
//Debug.Log($"LastEditTime : {strLastTime}");
|
||||
}
|
||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||
|
||||
}
|
||||
|
||||
//[MenuItem("Tools/Run External Exe")]
|
||||
public static void RunExe()
|
||||
{
|
||||
System.Diagnostics.Process pro;
|
||||
string exePath = "../XDevNode/XNode.exe"; // �滻Ϊ���exe�ļ�·��
|
||||
string curPath = System.IO.Directory.GetCurrentDirectory();
|
||||
string runPath = $"{curPath}/{exePath}";//@"D:\UD\XWorld\XWorldClient\60s\..\XDevNode\XNode.exe";
|
||||
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo();
|
||||
info.FileName = runPath;
|
||||
info.Arguments = "xid3278136192177 param2=488";//XID
|
||||
info.WorkingDirectory = $"{curPath}/../XDevNode";
|
||||
try
|
||||
{
|
||||
//Thread.Sleep(500);
|
||||
pro = System.Diagnostics.Process.Start(info);
|
||||
pro.EnableRaisingEvents = true;
|
||||
//pro.Exited += new EventHandler(myProcess_Exited);
|
||||
}
|
||||
catch (System.ComponentModel.Win32Exception ex)
|
||||
{
|
||||
Console.WriteLine("ϵͳ�Ҳ���ָ�����ļ���/r{0}", ex.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool IsProcessRunning(string processName)
|
||||
{
|
||||
// ��ȡ����ͬ������
|
||||
Process[] processes = Process.GetProcessesByName(processName);
|
||||
|
||||
// ����ҵ�����һ�����̣��� true
|
||||
return processes.Length > 0;
|
||||
}
|
||||
|
||||
static void StartProcess(string executablePath)
|
||||
{
|
||||
RunExe();
|
||||
}
|
||||
private static void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||
{
|
||||
if (state == PlayModeStateChange.ExitingEditMode)
|
||||
{
|
||||
if (!m_enterPlayAfterServerReady && !XWorldUtil.IsPcMiniGameGatewayReady())
|
||||
{
|
||||
UnityEngine.Debug.Log("PC MiniGame Gateway is not ready. Starting it before entering Play Mode...");
|
||||
EditorApplication.isPlaying = false;
|
||||
m_enterPlayAfterServerReady = true;
|
||||
m_waitServerStartTime = EditorApplication.timeSinceStartup;
|
||||
XWorldUtil.OpenLocalServerAll();
|
||||
EditorApplication.update -= WaitForServerThenEnterPlay;
|
||||
EditorApplication.update += WaitForServerThenEnterPlay;
|
||||
return;
|
||||
}
|
||||
|
||||
m_enterPlayAfterServerReady = false;
|
||||
EditorApplication.update -= WaitForServerThenEnterPlay;
|
||||
XWorldUtil.OpenLocalServerAll();
|
||||
//���lua�Ƿ��б仯������server lua
|
||||
/*if (IsPathChange())
|
||||
{
|
||||
string srcPath = "../Lua/server";
|
||||
string dstPath = "../XDevNode/Data/XWorld/Script";
|
||||
Packager.CopyPath(srcPath, dstPath);
|
||||
//Thread.Sleep(1000);
|
||||
PlayerPrefs.SetString("LastModifiedTime", m_lastModified.ToString());
|
||||
}//*/
|
||||
//Debug.Log("��������ģʽ��ִ���Զ�������");
|
||||
UnityEngine.Debug.Log("PC MiniGame Gateway checked. Legacy XNode auto-start is disabled for this flow.");
|
||||
string processName = "XNode";
|
||||
string executablePath = "../XDevNode/XNode.exe";
|
||||
if (false && !IsProcessRunning(processName))
|
||||
{
|
||||
StartProcess(executablePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.Log("Legacy XNode server startup skipped.");
|
||||
//Console.WriteLine($"{processName} �Ѿ������С�");
|
||||
}
|
||||
|
||||
}
|
||||
else if (state == PlayModeStateChange.ExitingPlayMode)
|
||||
{
|
||||
UnityEngine.Debug.Log("Exist Playing");
|
||||
}
|
||||
}
|
||||
|
||||
private static void WaitForServerThenEnterPlay()
|
||||
{
|
||||
if (XWorldUtil.IsPcMiniGameGatewayReady())
|
||||
{
|
||||
EditorApplication.update -= WaitForServerThenEnterPlay;
|
||||
UnityEngine.Debug.Log("PC MiniGame Gateway is ready. Entering Play Mode.");
|
||||
EditorApplication.EnterPlaymode();
|
||||
return;
|
||||
}
|
||||
|
||||
if (EditorApplication.timeSinceStartup - m_waitServerStartTime > WAIT_SERVER_TIMEOUT_SECONDS)
|
||||
{
|
||||
EditorApplication.update -= WaitForServerThenEnterPlay;
|
||||
m_enterPlayAfterServerReady = false;
|
||||
UnityEngine.Debug.LogError("Timed out waiting for PC MiniGame Gateway. Check XWorld/Server/Open Latest Log.");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsPathChange()
|
||||
{
|
||||
if (m_lastModified == null)
|
||||
{
|
||||
m_lastModified = DateTime.Now;
|
||||
UnityEngine.Debug.Log($"Now Time");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DateTime lastModified = m_lastModified;
|
||||
lastModified = RecursiveLastEditTime("../Lua/server", lastModified);
|
||||
|
||||
if ((lastModified - m_lastModified).TotalSeconds > 1)
|
||||
{
|
||||
m_lastModified = lastModified;
|
||||
UnityEngine.Debug.Log($"LastEditTime Change: {m_lastModified}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static DateTime RecursiveLastEditTime(string path, DateTime lastTime)
|
||||
{
|
||||
string[] names = Directory.GetFiles(path);
|
||||
string[] dirs = Directory.GetDirectories(path);
|
||||
foreach (string filename in names)
|
||||
{
|
||||
DateTime lastModified = File.GetLastWriteTime(filename);
|
||||
if (lastModified > lastTime)
|
||||
lastTime = lastModified;
|
||||
}
|
||||
foreach (string dir in dirs)
|
||||
{
|
||||
if (dir.IndexOf(".svn") >= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//paths.Add(dir.Replace('\\', '/'));
|
||||
lastTime = RecursiveLastEditTime(dir, lastTime);
|
||||
}
|
||||
return lastTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 320e3c8c55bdb1b49a72d97694c543cd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 42e415b5498e64649820a541b7304052
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,478 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Unity.VisualScripting.FullSerializer;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public static class GroundTools
|
||||
{
|
||||
[MenuItem("GroundTools/GroundToolWindow")]
|
||||
public static void OpenGroundToolWindow()
|
||||
{
|
||||
GroundToolWindow window = EditorWindow.GetWindow<GroundToolWindow>("地形工具");
|
||||
window.Show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class GroundToolWindow : EditorWindow
|
||||
{
|
||||
|
||||
private string configPath = "Assets/Editor/GroundToolConfig.asset";
|
||||
private GroundToolConfig groundToolConfig;
|
||||
|
||||
private GameObject selectedGround;
|
||||
|
||||
private bool isConfigChange = false;
|
||||
private float lastChangeTime = 0;// Time.realtimeSinceStartup;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
// 窗口打开时加载配置
|
||||
LoadConfig();
|
||||
}
|
||||
private void LoadConfig()
|
||||
{
|
||||
// 尝试从指定路径加载配置
|
||||
groundToolConfig = AssetDatabase.LoadAssetAtPath<GroundToolConfig>(configPath);
|
||||
if (groundToolConfig == null)
|
||||
{
|
||||
// 如果配置不存在,则创建一个新的
|
||||
groundToolConfig = CreateInstance<GroundToolConfig>();
|
||||
// 确保目录存在
|
||||
string directory = Path.GetDirectoryName(configPath);
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
// 创建资产文件
|
||||
AssetDatabase.CreateAsset(groundToolConfig, configPath);
|
||||
AssetDatabase.SaveAssets();
|
||||
Debug.Log("创建新的地形工具配置文件: " + configPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveConfig()
|
||||
{
|
||||
if (groundToolConfig != null)
|
||||
{
|
||||
EditorUtility.SetDirty(groundToolConfig); // 确保Unity知道资产需要保存
|
||||
AssetDatabase.SaveAssets(); // 保存资产
|
||||
isConfigChange = false;
|
||||
Debug.Log("地形工具配置已保存。");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 绘制编辑器窗口UI
|
||||
/// </summary>
|
||||
private void OnGUI()
|
||||
{
|
||||
GUILayout.Label("地形创建工具", EditorStyles.boldLabel);
|
||||
|
||||
// 创建地形按钮
|
||||
if (GUILayout.Button("创建地形"))
|
||||
{
|
||||
//选择需要存储文件的路径
|
||||
|
||||
|
||||
CreateGround();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(10);
|
||||
|
||||
// 参数设置
|
||||
groundToolConfig.width = EditorGUILayout.IntField("横格", groundToolConfig.width);
|
||||
groundToolConfig.length = EditorGUILayout.IntField("纵格", groundToolConfig.length);
|
||||
groundToolConfig.height = EditorGUILayout.FloatField("高度", groundToolConfig.height);
|
||||
groundToolConfig.perlinScale = EditorGUILayout.Slider("噪声缩放", groundToolConfig.perlinScale, 0.01f, 1f);
|
||||
groundToolConfig.groundIncline = EditorGUILayout.Slider("地面坡度", groundToolConfig.groundIncline, 0f, 1f);
|
||||
EditorGUILayout.Space(10);
|
||||
groundToolConfig.power = EditorGUILayout.Slider("过渡平滑度", groundToolConfig.power, 1f, 5f);
|
||||
groundToolConfig.matSplit1 = EditorGUILayout.Slider("纹理占比分割1", groundToolConfig.matSplit1, 0f, 0.8f);
|
||||
groundToolConfig.matSplit2 = EditorGUILayout.Slider("纹理占比分割2", groundToolConfig.matSplit2, 0.1f, 0.9f);
|
||||
groundToolConfig.matSplit3 = EditorGUILayout.Slider("纹理占比分割3", groundToolConfig.matSplit3, 0.2f, 1f);
|
||||
EditorGUILayout.Space(10);
|
||||
groundToolConfig.texGround1 = EditorGUILayout.ObjectField("纹理1", groundToolConfig.texGround1, typeof(Texture), false) as Texture;
|
||||
groundToolConfig.texGround2 = EditorGUILayout.ObjectField("纹理2", groundToolConfig.texGround2, typeof(Texture), false) as Texture;
|
||||
groundToolConfig.texGround3 = EditorGUILayout.ObjectField("纹理3", groundToolConfig.texGround3, typeof(Texture), false) as Texture;
|
||||
groundToolConfig.texGround4 = EditorGUILayout.ObjectField("纹理4", groundToolConfig.texGround4, typeof(Texture), false) as Texture;
|
||||
EditorGUILayout.Space(10);
|
||||
if (GUILayout.Button("随机参数"))
|
||||
{
|
||||
UnityEngine.Random.InitState((int)DateTime.Now.Ticks);
|
||||
groundToolConfig.randOffset = UnityEngine.Random.Range(0f, 100f);
|
||||
}
|
||||
groundToolConfig.randOffset = EditorGUILayout.FloatField("随机性", groundToolConfig.randOffset);
|
||||
groundToolConfig.randJitter = EditorGUILayout.Slider("纹理扰动", groundToolConfig.randJitter,0, 1);
|
||||
|
||||
EditorGUILayout.Space(10);
|
||||
|
||||
|
||||
EditorGUILayout.Space(10);
|
||||
|
||||
// 选择地形对象
|
||||
selectedGround = EditorGUILayout.ObjectField("选择地形", selectedGround, typeof(GameObject), true) as GameObject;
|
||||
|
||||
GUI.enabled = selectedGround != null;
|
||||
|
||||
// 修改地形按钮
|
||||
if (GUILayout.Button("修改地形"))
|
||||
{
|
||||
ChangeGround();
|
||||
}
|
||||
|
||||
if (GUI.changed)
|
||||
{
|
||||
isConfigChange = true;
|
||||
lastChangeTime = Time.realtimeSinceStartup;
|
||||
}
|
||||
if (isConfigChange && Time.realtimeSinceStartup - lastChangeTime > 5f)
|
||||
{
|
||||
SaveConfig();
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建地形
|
||||
/// </summary>
|
||||
private void CreateGround()
|
||||
{
|
||||
// 创建游戏对象
|
||||
GameObject ground = new GameObject("Ground_" + groundToolConfig.width + "x" + groundToolConfig.length);
|
||||
|
||||
// 添加网格过滤器和网格渲染器
|
||||
MeshFilter meshFilter = ground.AddComponent<MeshFilter>();
|
||||
MeshRenderer meshRenderer = ground.AddComponent<MeshRenderer>();
|
||||
|
||||
// 创建网格
|
||||
Mesh mesh = CreateGroundMesh(groundToolConfig.width, groundToolConfig.length, groundToolConfig.height, groundToolConfig.perlinScale);
|
||||
|
||||
// 应用网格
|
||||
meshFilter.sharedMesh = mesh;
|
||||
|
||||
// 添加碰撞器
|
||||
MeshCollider collider = ground.AddComponent<MeshCollider>();
|
||||
collider.sharedMesh = mesh;
|
||||
|
||||
// 设置材质
|
||||
meshRenderer.material = new Material(Shader.Find("Standard"));
|
||||
|
||||
// 注册撤销操作并选中对象
|
||||
Undo.RegisterCreatedObjectUndo(ground, "Create Ground");
|
||||
Selection.activeGameObject = ground;
|
||||
|
||||
// 更新选中的地形对象
|
||||
selectedGround = ground;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改地形
|
||||
/// </summary>
|
||||
private void ChangeGround()
|
||||
{
|
||||
if (selectedGround == null)
|
||||
{
|
||||
Debug.LogError("请先选择一个地形对象");
|
||||
return;
|
||||
}
|
||||
|
||||
MeshFilter meshFilter = selectedGround.GetComponent<MeshFilter>();
|
||||
if (meshFilter == null) return;
|
||||
|
||||
// 创建新网格
|
||||
Mesh mesh = meshFilter.sharedMesh;//CreateGroundMesh(width, length, height, perlinScale);
|
||||
|
||||
// 记录撤销
|
||||
Undo.RecordObject(meshFilter, "Change Ground");
|
||||
|
||||
// 应用网格
|
||||
meshFilter.sharedMesh = mesh;
|
||||
float[,] heightMap = ModifyVertexHeight(mesh);
|
||||
ModifyMaterial(selectedGround.GetComponent<MeshRenderer>(), heightMap);
|
||||
|
||||
// 更新碰撞器
|
||||
MeshCollider collider = selectedGround.GetComponent<MeshCollider>();
|
||||
if (collider != null)
|
||||
{
|
||||
Undo.RecordObject(collider, "Change Ground Collider");
|
||||
collider.sharedMesh = mesh;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建地形网格
|
||||
/// </summary>
|
||||
private Mesh CreateGroundMesh(int width, int length, float height, float perlinScale)
|
||||
{
|
||||
Mesh mesh = new Mesh();
|
||||
mesh.name = "Ground_" + width + "x" + length + "_Mesh";
|
||||
|
||||
int resolutionX = Mathf.CeilToInt(groundToolConfig.width);
|
||||
int resolutionZ = Mathf.CeilToInt(groundToolConfig.length);
|
||||
|
||||
float halfWidth = width * 0.5f;
|
||||
float halfLength = length * 0.5f;
|
||||
|
||||
// 创建顶点
|
||||
Vector3[] vertices = new Vector3[(resolutionX + 1) * (resolutionZ + 1)];
|
||||
float[,] heightMap = GenerateHeightMap(groundToolConfig.width, groundToolConfig.length, groundToolConfig.height, groundToolConfig.perlinScale);
|
||||
for (int z = 0; z <= resolutionZ; z++)
|
||||
{
|
||||
for (int x = 0; x <= resolutionX; x++)
|
||||
{
|
||||
float xPos = x;// * width / resolutionX - halfWidth;
|
||||
float zPos = z;// * length / resolutionZ - halfLength;
|
||||
|
||||
// 使用Perlin噪声生成高度
|
||||
float y = 0;
|
||||
if (perlinScale > 0)
|
||||
{
|
||||
y = heightMap[x, z];
|
||||
}
|
||||
|
||||
vertices[z * (resolutionX + 1) + x] = new Vector3(xPos, y, zPos);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建三角形
|
||||
int[] triangles = new int[resolutionX * resolutionZ * 6];
|
||||
int triangleIndex = 0;
|
||||
for (int z = 0; z < resolutionZ; z++)
|
||||
{
|
||||
for (int x = 0; x < resolutionX; x++)
|
||||
{
|
||||
int vertexIndex = z * (resolutionX + 1) + x;
|
||||
|
||||
triangles[triangleIndex++] = vertexIndex;
|
||||
triangles[triangleIndex++] = vertexIndex + resolutionX + 1;
|
||||
triangles[triangleIndex++] = vertexIndex + 1;
|
||||
|
||||
triangles[triangleIndex++] = vertexIndex + 1;
|
||||
triangles[triangleIndex++] = vertexIndex + resolutionX + 1;
|
||||
triangles[triangleIndex++] = vertexIndex + resolutionX + 2;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建UV坐标
|
||||
Vector2[] uvs = new Vector2[(resolutionX + 1) * (resolutionZ + 1)];
|
||||
for (int z = 0; z <= resolutionZ; z++)
|
||||
{
|
||||
for (int x = 0; x <= resolutionX; x++)
|
||||
{
|
||||
uvs[z * (resolutionX + 1) + x] = new Vector2((float)x / resolutionX, (float)z / resolutionZ);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置网格数据
|
||||
mesh.vertices = vertices;
|
||||
mesh.triangles = triangles;
|
||||
mesh.uv = uvs;
|
||||
mesh.RecalculateNormals();
|
||||
mesh.RecalculateBounds();
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
//修改模型顶点高度
|
||||
private float[,] ModifyVertexHeight(Mesh mesh)
|
||||
{
|
||||
float[,] heightMap = GenerateHeightMap(groundToolConfig.width, groundToolConfig.length, groundToolConfig.height, groundToolConfig.perlinScale);
|
||||
//for (int i = 0; i < vertices.Length; i++)
|
||||
//{
|
||||
// vertices[i].y = heightMap[i % (width + 1), i / (width + 1)];
|
||||
//}
|
||||
int resolutionX = Mathf.CeilToInt(groundToolConfig.width);
|
||||
int resolutionZ = Mathf.CeilToInt(groundToolConfig.length);
|
||||
Vector3[] vertices = new Vector3[(resolutionX + 1) * (resolutionZ + 1)];
|
||||
for (int z = 0; z <= resolutionZ; z++)
|
||||
{
|
||||
for (int x = 0; x <= resolutionX; x++)
|
||||
{
|
||||
float xPos = x;// * width / resolutionX - halfWidth;
|
||||
float zPos = z;// * length / resolutionZ - halfLength;
|
||||
|
||||
// 使用Perlin噪声生成高度
|
||||
float y = 0;
|
||||
if (groundToolConfig.perlinScale > 0)
|
||||
{
|
||||
y = heightMap[x, z];
|
||||
}
|
||||
|
||||
vertices[z * (resolutionX + 1) + x] = new Vector3(xPos, y, zPos);
|
||||
}
|
||||
}
|
||||
// 创建三角形
|
||||
int[] triangles = new int[resolutionX * resolutionZ * 6];
|
||||
int triangleIndex = 0;
|
||||
for (int z = 0; z < resolutionZ; z++)
|
||||
{
|
||||
for (int x = 0; x < resolutionX; x++)
|
||||
{
|
||||
int vertexIndex = z * (resolutionX + 1) + x;
|
||||
|
||||
triangles[triangleIndex++] = vertexIndex;
|
||||
triangles[triangleIndex++] = vertexIndex + resolutionX + 1;
|
||||
triangles[triangleIndex++] = vertexIndex + 1;
|
||||
|
||||
triangles[triangleIndex++] = vertexIndex + 1;
|
||||
triangles[triangleIndex++] = vertexIndex + resolutionX + 1;
|
||||
triangles[triangleIndex++] = vertexIndex + resolutionX + 2;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建UV坐标
|
||||
Vector2[] uvs = new Vector2[(resolutionX + 1) * (resolutionZ + 1)];
|
||||
for (int z = 0; z <= resolutionZ; z++)
|
||||
{
|
||||
for (int x = 0; x <= resolutionX; x++)
|
||||
{
|
||||
uvs[z * (resolutionX + 1) + x] = new Vector2((float)x / resolutionX, (float)z / resolutionZ);
|
||||
}
|
||||
}
|
||||
mesh.vertices = vertices;
|
||||
mesh.triangles = triangles;
|
||||
mesh.uv = uvs;
|
||||
mesh.RecalculateNormals();
|
||||
mesh.RecalculateBounds();
|
||||
return heightMap;
|
||||
}
|
||||
//填入材质
|
||||
private void ModifyMaterial(MeshRenderer meshRenderer, float[,] heightMap)
|
||||
{
|
||||
// 设置材质
|
||||
Material mtl = new Material(Shader.Find("XWorld/XTerrain"));
|
||||
//设置_LayerTex0 _LayerTex1 _LayerTex2 _LayerTex3 和_Control贴图
|
||||
mtl.SetTexture("_LayerTex3", groundToolConfig.texGround4);
|
||||
mtl.SetTexture("_LayerTex2", groundToolConfig.texGround3);
|
||||
mtl.SetTexture("_LayerTex1", groundToolConfig.texGround2);
|
||||
mtl.SetTexture("_LayerTex0", groundToolConfig.texGround1);
|
||||
|
||||
//生成一个rgba四通道的控制贴图,随机分配四种材质的混合度
|
||||
Texture2D controlTex = new Texture2D(groundToolConfig.width, groundToolConfig.length, TextureFormat.RGBA32, false);
|
||||
for (int z = 0; z <= groundToolConfig.width; z++)
|
||||
{
|
||||
for (int x = 0; x <= groundToolConfig.length; x++)
|
||||
{
|
||||
//float h1 = heightMap[x, z]/height;
|
||||
float h1 = Mathf.PerlinNoise(groundToolConfig.randOffset + z * groundToolConfig.perlinScale, groundToolConfig.randOffset + x * groundToolConfig.perlinScale);
|
||||
float h2 = Mathf.PerlinNoise(groundToolConfig.randOffset + 107 + z * groundToolConfig.perlinScale, groundToolConfig.randOffset + 107 + x * groundToolConfig.perlinScale);
|
||||
Color coefficients = new Color(0, 0, 0, 0);
|
||||
|
||||
float perlinValue = h1 * (1 - groundToolConfig.randJitter) + h2 * groundToolConfig.randJitter;
|
||||
float p;
|
||||
float Split12 = (groundToolConfig.matSplit1 + groundToolConfig.matSplit2)/2.0f;
|
||||
float Split23 = (groundToolConfig.matSplit3 + groundToolConfig.matSplit2) / 2.0f; ;
|
||||
// 确定主导纹理区间
|
||||
if (perlinValue < Split12)//0.33f)//
|
||||
{
|
||||
if (perlinValue < groundToolConfig.matSplit1)
|
||||
{
|
||||
p = 0.5f - Mathf.Pow((groundToolConfig.matSplit1 - perlinValue) / groundToolConfig.matSplit1, groundToolConfig.power)*0.5f;
|
||||
// 纹理0主导:R通道为主,平滑过渡到纹理1
|
||||
coefficients.r = 1.0f - p;
|
||||
coefficients.g = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = 0.5f + Mathf.Pow((perlinValue - groundToolConfig.matSplit1) / (Split12 - groundToolConfig.matSplit1), groundToolConfig.power)*0.5f;
|
||||
|
||||
coefficients.r = 1.0f - p;
|
||||
coefficients.g = p;
|
||||
}
|
||||
//p = Mathf.Pow(perlinValue / groundToolConfig.matSplit1, groundToolConfig.power);
|
||||
//// 纹理1主导:R通道为主,平滑过渡到纹理2
|
||||
//coefficients.r = 1.0f - p;
|
||||
//coefficients.g = p;
|
||||
}
|
||||
else if (perlinValue < Split23)//0.66f)//
|
||||
{
|
||||
if(perlinValue < groundToolConfig.matSplit2)
|
||||
{
|
||||
p = 0.5f - Mathf.Pow(((groundToolConfig.matSplit2 - perlinValue) / (groundToolConfig.matSplit2 - Split12)), groundToolConfig.power)*0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = 0.5f + Mathf.Pow(((perlinValue - groundToolConfig.matSplit2) / (Split23 - groundToolConfig.matSplit2)), groundToolConfig.power)*0.5f;
|
||||
}
|
||||
coefficients.g = 1.0f - p;
|
||||
coefficients.b = p;
|
||||
|
||||
//p = Mathf.Pow(((perlinValue - groundToolConfig.matSplit1) / (groundToolConfig.matSplit2 - groundToolConfig.matSplit1)), groundToolConfig.power);
|
||||
//// 纹理2主导:G通道为主,平滑过渡到相邻纹理
|
||||
//coefficients.g = 1.0f - p;
|
||||
//coefficients.b = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(perlinValue < groundToolConfig.matSplit3)
|
||||
{
|
||||
p = 0.5f - Mathf.Pow(((groundToolConfig.matSplit3 - perlinValue) / (groundToolConfig.matSplit3 - Split23)), groundToolConfig.power)*0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = 0.5f + Mathf.Pow(((perlinValue - groundToolConfig.matSplit3) / (1.0f - groundToolConfig.matSplit3)), groundToolConfig.power)*0.5f;
|
||||
}
|
||||
coefficients.b = 1.0f - p;
|
||||
coefficients.a = p;
|
||||
//p = Mathf.Pow(((perlinValue - groundToolConfig.matSplit2) / (1.0f - groundToolConfig.matSplit2)), groundToolConfig.power);
|
||||
//// 纹理3主导:B通道为主
|
||||
//coefficients.b = 1.0f - p;
|
||||
//coefficients.a = p;
|
||||
}
|
||||
controlTex.SetPixel(z, x, coefficients);
|
||||
}
|
||||
}
|
||||
controlTex.Apply();
|
||||
mtl.SetTexture("_Control", controlTex);
|
||||
meshRenderer.material = mtl;
|
||||
}
|
||||
|
||||
public float[,] GenerateHeightMap(int x, int z, float heightScale = 1f, float PerlinScale = 0.01f)
|
||||
{
|
||||
float[,] heightMap = new float[x + 1, z + 1];
|
||||
//生成一个N分之一宽和高的高度图
|
||||
int N = 16;
|
||||
int quarterX = x / N;
|
||||
int quarterZ = z / N;
|
||||
float[,] quarterHeightMap = new float[quarterX + 1, quarterZ + 1];
|
||||
//for (int i = 0; i <= quarterX; i++)
|
||||
//{
|
||||
// for (int j = 0; j <= quarterZ; j++)
|
||||
// {
|
||||
// quarterHeightMap[i, j] = Mathf.PerlinNoise(randOffset + i * 0.1f, randOffset + j * 0.1f) * heightScale*2;
|
||||
// }
|
||||
//}
|
||||
//将四分之一高度图叠加到总的高度图上
|
||||
int f33 = 0, f66 = 0, f100 = 0;
|
||||
for (int i = 0; i <= x; i++)
|
||||
{
|
||||
for (int j = 0; j <= z; j++)
|
||||
{
|
||||
//heightMap[i, j] = Mathf.PerlinNoise(i * 0.1f, j * 0.1f) * heightScale + quarterHeightMap[i / N, j / N];
|
||||
//heightMap[i, j] = quarterHeightMap[i / N, j / N];
|
||||
float h1 = Mathf.PerlinNoise(groundToolConfig.randOffset + i * PerlinScale, groundToolConfig.randOffset + j * PerlinScale) * heightScale;
|
||||
float h2 = Mathf.PerlinNoise(groundToolConfig.randOffset + i * PerlinScale * groundToolConfig.groundIncline, groundToolConfig.randOffset + j * PerlinScale * groundToolConfig.groundIncline) * heightScale;
|
||||
heightMap[i, j] = h1 > h2? h1 : h2;
|
||||
if (h2 < 0.33f)
|
||||
{
|
||||
f33++;
|
||||
}
|
||||
else if (h2 < 0.66f)
|
||||
{
|
||||
f66++;
|
||||
}
|
||||
else if (h2 <= 1.0f)
|
||||
{
|
||||
f100++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Debug.Log($"TotalCount: {f33}, {f66}, {f100}");
|
||||
return heightMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ece4136e36bcf5048b2dc0cc5b8f5a09
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public static class GroundCreate
|
||||
{
|
||||
//[MenuItem("GroundTools/GroundCreate")]
|
||||
/// <summary>
|
||||
/// 创建一个100x100单位的地表模型
|
||||
/// </summary>
|
||||
public static void CreateGround()
|
||||
{
|
||||
|
||||
// 设置网格参数
|
||||
int width = 128;
|
||||
int length = 128;
|
||||
|
||||
// 创建游戏对象
|
||||
GameObject ground = new GameObject($"Ground");
|
||||
|
||||
// 添加网格过滤器和网格渲染器
|
||||
MeshFilter meshFilter = ground.AddComponent<MeshFilter>();
|
||||
MeshRenderer meshRenderer = ground.AddComponent<MeshRenderer>();
|
||||
|
||||
UnityEngine.Random.InitState((int)DateTime.Now.Ticks);
|
||||
float randOffset = UnityEngine.Random.Range(0f, 100f);
|
||||
|
||||
// 创建网格
|
||||
Mesh mesh = new Mesh();
|
||||
mesh.name = $"Ground_{width}X{length}_Mesh";
|
||||
|
||||
float halfWidth = width * 0.5f;
|
||||
float halfLength = length * 0.5f;
|
||||
|
||||
//创建一个随机高度图,并填入到顶点的y上
|
||||
float[,] heightMap = GenerateHeightMap(width, length);
|
||||
//for (int z = 0; z <= length; z++)
|
||||
//{
|
||||
// for (int x = 0; x <= width; x++)
|
||||
// {
|
||||
// heightMap[x, z] = Mathf.PerlinNoise(x * 0.1f, z * 0.1f) * 2f - 1f;
|
||||
// }
|
||||
//}
|
||||
// 创建顶点
|
||||
Vector3[] vertices = new Vector3[(width + 1) * (length + 1)];
|
||||
for (int z = 0; z <= length; z++)
|
||||
{
|
||||
for (int x = 0; x <= width; x++)
|
||||
{
|
||||
vertices[z * (width + 1) + x] = new Vector3(x - halfWidth, heightMap[x, z], z - halfLength);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建三角形
|
||||
int[] triangles = new int[width * length * 6];
|
||||
int triangleIndex = 0;
|
||||
for (int z = 0; z < length; z++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
int vertexIndex = z * (width + 1) + x;
|
||||
|
||||
triangles[triangleIndex++] = vertexIndex;
|
||||
triangles[triangleIndex++] = vertexIndex + width + 1;
|
||||
triangles[triangleIndex++] = vertexIndex + 1;
|
||||
|
||||
triangles[triangleIndex++] = vertexIndex + 1;
|
||||
triangles[triangleIndex++] = vertexIndex + width + 1;
|
||||
triangles[triangleIndex++] = vertexIndex + width + 2;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建UV坐标
|
||||
Vector2[] uvs = new Vector2[(width + 1) * (length + 1)];
|
||||
for (int z = 0; z <= length; z++)
|
||||
{
|
||||
for (int x = 0; x <= width; x++)
|
||||
{
|
||||
uvs[z * (width + 1) + x] = new Vector2((float)x / width, (float)z / length);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置网格数据
|
||||
mesh.vertices = vertices;
|
||||
mesh.triangles = triangles;
|
||||
mesh.uv = uvs;
|
||||
mesh.RecalculateNormals();
|
||||
mesh.RecalculateBounds();
|
||||
|
||||
// 应用网格
|
||||
meshFilter.sharedMesh = mesh;
|
||||
|
||||
// 添加碰撞器
|
||||
MeshCollider collider = ground.AddComponent<MeshCollider>();
|
||||
collider.sharedMesh = mesh;
|
||||
|
||||
// 设置材质
|
||||
meshRenderer.material = new Material(Shader.Find("XWorld/XTerrain"));
|
||||
//设置_LayerTex0 _LayerTex1 _LayerTex2 _LayerTex3 和_Control贴图
|
||||
meshRenderer.material.SetTexture("_LayerTex0", AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Arts/scene/Terrain/Texture/grass.png"));
|
||||
meshRenderer.material.SetTexture("_LayerTex1", AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Arts/scene/Terrain/Texture/blick.png"));
|
||||
meshRenderer.material.SetTexture("_LayerTex2", AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Arts/scene/Terrain/Texture/mud.png"));
|
||||
meshRenderer.material.SetTexture("_LayerTex3", AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Arts/scene/Terrain/Texture/sand.png"));
|
||||
//生成一个rgba四通道的控制贴图,随机分配四种材质的混合度
|
||||
Texture2D controlTex = new Texture2D(width, length, TextureFormat.RGBA32, false);
|
||||
float PerlinRandom = 0.05f;
|
||||
for (int z = 0; z < length; z++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
//float h = heightMap[x, z];
|
||||
float h1 = Mathf.PerlinNoise(randOffset + z * PerlinRandom, randOffset + x * PerlinRandom);
|
||||
float hLerp;
|
||||
Color color;// = new Color(0, 0, 0, 0);
|
||||
if (h1 < 0.33f)
|
||||
{
|
||||
hLerp = (0.33f - h1)*3;
|
||||
color = new Color(0, 0, hLerp, 1 - hLerp);
|
||||
}
|
||||
else if (h1 < 0.66f)
|
||||
{
|
||||
hLerp = (0.66f - h1) * 3;
|
||||
color = new Color(0, hLerp, 1- hLerp, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
hLerp = (1.0f - h1) * 3;
|
||||
color = new Color(hLerp, 1 - hLerp, 0, 0);
|
||||
}
|
||||
controlTex.SetPixel(x, z, color);
|
||||
}
|
||||
}
|
||||
controlTex.Apply();
|
||||
meshRenderer.material.SetTexture("_Control", controlTex);
|
||||
|
||||
|
||||
// 注册撤销操作并选中对象
|
||||
Undo.RegisterCreatedObjectUndo(ground, "Create 100x100 Ground");
|
||||
Selection.activeGameObject = ground;
|
||||
}
|
||||
|
||||
//生成x * z的高度图,增加一个浮动变化的高度和一个不均匀的高度变化
|
||||
//heightScale 高度缩放因子
|
||||
//heightOffset 高度偏移量
|
||||
public static float[,] GenerateHeightMap(int x, int z, float heightScale = 20f, float PerlinRandom = 0.01f)
|
||||
{
|
||||
float[,] heightMap = new float[x + 1, z + 1];
|
||||
UnityEngine.Random.InitState(Time.frameCount);
|
||||
Debug.Log("Random Seed: " + Time.frameCount);
|
||||
//生成一个N分之一宽和高的高度图
|
||||
int N = 16;
|
||||
int quarterX = x / N;
|
||||
int quarterZ = z / N;
|
||||
float[,] quarterHeightMap = new float[quarterX + 1, quarterZ + 1];
|
||||
for (int i = 0; i <= quarterX; i++)
|
||||
{
|
||||
for (int j = 0; j <= quarterZ; j++)
|
||||
{
|
||||
quarterHeightMap[i, j] = Mathf.PerlinNoise(i * 0.1f, j * 0.1f) * heightScale*2;
|
||||
}
|
||||
}
|
||||
//将四分之一高度图叠加到总的高度图上
|
||||
for (int i = 0; i <= x; i++)
|
||||
{
|
||||
for (int j = 0; j <= z; j++)
|
||||
{
|
||||
//heightMap[i, j] = Mathf.PerlinNoise(i * 0.1f, j * 0.1f) * heightScale + quarterHeightMap[i / N, j / N];
|
||||
//heightMap[i, j] = quarterHeightMap[i / N, j / N];
|
||||
float h1 = Mathf.PerlinNoise(i * PerlinRandom, j * PerlinRandom) * heightScale;
|
||||
float h2 = Mathf.PerlinNoise(i * PerlinRandom*5, j * PerlinRandom*5) * heightScale;
|
||||
heightMap[i, j] = h1 > h2? h1 : h2;
|
||||
}
|
||||
}
|
||||
return heightMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff4bce06a097bd4489beb1dc676d328c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e6914217da6edb34baad8872f8642df3, type: 3}
|
||||
m_Name: GroundToolConfig
|
||||
m_EditorClassIdentifier:
|
||||
randOffset: 24.258888
|
||||
randJitter: 0.382
|
||||
width: 256
|
||||
length: 256
|
||||
height: 30
|
||||
perlinScale: 0.05
|
||||
groundIncline: 0
|
||||
matSplit1: 0.088
|
||||
matSplit2: 0.285
|
||||
matSplit3: 0.593
|
||||
power: 4.12
|
||||
texGround1: {fileID: 2800000, guid: 57d24bd9d5619994fb7856632f627ea5, type: 3}
|
||||
texGround2: {fileID: 2800000, guid: d6d26791584699a4ca75b0c5b9f173f2, type: 3}
|
||||
texGround3: {fileID: 2800000, guid: 741c6de7ade0623478730047979b094b, type: 3}
|
||||
texGround4: {fileID: 2800000, guid: 4d4a4a42f2189504b8bd44c09ace0136, type: 3}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ddbf17bfa8fc8fd4eab0bf98d05492c7
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
// 创建菜单项,方便在项目中创建该资产
|
||||
[CreateAssetMenu(fileName = "GroundToolConfig", menuName = "GroundTools/Ground Tool Configuration")]
|
||||
public class GroundToolConfig : ScriptableObject
|
||||
{
|
||||
// 将所有需要保存的参数定义为public字段或[SerializeField]的私有字段
|
||||
public float randOffset = 0f;
|
||||
public float randJitter = 0.1f;// 随机扰动
|
||||
public int width = 128;
|
||||
public int length = 128;
|
||||
public float height = 30f;
|
||||
public float perlinScale = 0.05f;
|
||||
public float groundIncline = 0.01f;
|
||||
public float matSplit1 = 0.25f;
|
||||
public float matSplit2 = 0.5f;
|
||||
public float matSplit3 = 0.75f;
|
||||
public float power = 2f;
|
||||
// 纹理(Texture)是Unity引擎对象的引用,本身可以被序列化
|
||||
public Texture texGround1;
|
||||
public Texture texGround2;
|
||||
public Texture texGround3;
|
||||
public Texture texGround4;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6914217da6edb34baad8872f8642df3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,253 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace XGameEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// 收集 shader 变体(ShaderVariantCollection)并保存到 Assets/Game/Shader/Game.shadervariants,
|
||||
/// 该文件会被活跃打包流程打进 game_shader.unity3d,运行时由 Game.Init() 加载并 WarmUp。
|
||||
///
|
||||
/// 关键作用:被包含进构建的 SVC 所引用的变体不会被 URP 的 "Strip Unused Variants" 剔除,
|
||||
/// 从而修复"从 AssetBundle 加载的预设(如 Main)在真机上平行光/光照不起效"的问题。
|
||||
///
|
||||
/// 提供两个入口:
|
||||
/// - Tools/Shader/自动收集Art材质变体 :自动遍历 Assets/Game/Art 下所有材质,
|
||||
/// 在临时场景里逐个建 cube 渲染一遍并收集(推荐)。
|
||||
/// - Tools/Shader/收集当前Shader变体到SVC:手动版,收集"当前编辑器会话已渲染过"的变体。
|
||||
///
|
||||
/// 说明:用到的 4 个 ShaderUtil 方法在 2022.3 里是 internal,公开 API 不可见,
|
||||
/// 因此通过反射调用(参见 UnityCsReference/Editor/Mono/ShaderUtil.bindings.cs)。
|
||||
/// 光照相关变体只有在材质被"实际渲染"时才会由 URP 设置并被跟踪,所以必须渲染 cube。
|
||||
/// </summary>
|
||||
public static class ShaderVariantCollector
|
||||
{
|
||||
private const string ArtDir = "Assets/Game/Art";
|
||||
// 放在 Assets/Game/Shader 顶层:活跃打包流程 HybridCLRBuild.BuildHotFix 里
|
||||
// AddBuildMap("game_shader.unity3d","*.*","Assets/Game/Shader") 会(非递归地)把顶层文件打进 game_shader.unity3d。
|
||||
private const string OutputDir = "Assets/Game/Shader";
|
||||
private const string OutputPath = OutputDir + "/Game.shadervariants";
|
||||
private const string TempScenePath = "Assets/Scenes/__temp_shadervariant_collect.unity";
|
||||
|
||||
// ---------------- 反射封装的 internal ShaderUtil 接口 ----------------
|
||||
|
||||
private static MethodInfo GetMethod(string name)
|
||||
{
|
||||
var m = typeof(ShaderUtil).GetMethod(
|
||||
name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
if (m == null)
|
||||
Debug.LogError($"[ShaderVariantCollector] 反射找不到 ShaderUtil.{name}," +
|
||||
"当前 Unity 版本可能改了该内部接口。");
|
||||
return m;
|
||||
}
|
||||
|
||||
private static void ClearCollection()
|
||||
{
|
||||
GetMethod("ClearCurrentShaderVariantCollection")?.Invoke(null, null);
|
||||
}
|
||||
|
||||
private static bool SaveCollection(string path)
|
||||
{
|
||||
var m = GetMethod("SaveCurrentShaderVariantCollection");
|
||||
if (m == null) return false;
|
||||
m.Invoke(null, new object[] { path });
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int GetTrackedShaderCount()
|
||||
{
|
||||
var m = GetMethod("GetCurrentShaderVariantCollectionShaderCount");
|
||||
return m != null ? (int)m.Invoke(null, null) : -1;
|
||||
}
|
||||
|
||||
private static int GetTrackedVariantCount()
|
||||
{
|
||||
var m = GetMethod("GetCurrentShaderVariantCollectionVariantCount");
|
||||
return m != null ? (int)m.Invoke(null, null) : -1;
|
||||
}
|
||||
|
||||
// ---------------- 自动收集 Assets/Game/Art 下所有材质 ----------------
|
||||
|
||||
[MenuItem("Tools/Shader/自动收集Art材质变体")]
|
||||
public static void AutoCollectArtMaterials()
|
||||
{
|
||||
if (!Directory.Exists(ArtDir))
|
||||
{
|
||||
EditorUtility.DisplayDialog("目录不存在", $"找不到目录:\n{ArtDir}", "好");
|
||||
return;
|
||||
}
|
||||
|
||||
// 先让用户保存当前场景,避免丢失未保存内容
|
||||
if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
|
||||
return;
|
||||
|
||||
// 1. 遍历材质
|
||||
string[] guids = AssetDatabase.FindAssets("t:Material", new[] { ArtDir });
|
||||
if (guids.Length == 0)
|
||||
{
|
||||
EditorUtility.DisplayDialog("没有材质", $"{ArtDir} 下没有找到任何材质。", "好");
|
||||
return;
|
||||
}
|
||||
if (guids.Length > 3000 &&
|
||||
!EditorUtility.DisplayDialog("材质较多",
|
||||
$"共找到 {guids.Length} 个材质,将创建同等数量的 cube 渲染,可能较慢且占用内存。是否继续?",
|
||||
"继续", "取消"))
|
||||
return;
|
||||
|
||||
// 2. 新建带默认相机+平行光的临时场景并保存到 Assets/Scenes
|
||||
Scene scene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
|
||||
string sceneDir = Path.GetDirectoryName(TempScenePath);
|
||||
if (!Directory.Exists(sceneDir)) Directory.CreateDirectory(sceneDir);
|
||||
|
||||
Camera cam = Object.FindObjectOfType<Camera>();
|
||||
if (cam == null)
|
||||
cam = new GameObject("Capture Camera", typeof(Camera)).GetComponent<Camera>();
|
||||
Light light = Object.FindObjectOfType<Light>();
|
||||
if (light == null)
|
||||
light = new GameObject("Directional Light", typeof(Light)).GetComponent<Light>();
|
||||
light.type = LightType.Directional;
|
||||
light.intensity = 1f;
|
||||
light.shadows = LightShadows.Soft;
|
||||
light.transform.rotation = Quaternion.Euler(50f, -30f, 0f);
|
||||
|
||||
RenderTexture rt = null;
|
||||
try
|
||||
{
|
||||
// 3. 网格排布,逐个材质创建 cube 并赋上去
|
||||
const float spacing = 2.2f;
|
||||
int cols = Mathf.CeilToInt(Mathf.Sqrt(guids.Length));
|
||||
float half = (cols - 1) * spacing * 0.5f;
|
||||
|
||||
int created = 0;
|
||||
for (int i = 0; i < guids.Length; i++)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
||||
var mat = AssetDatabase.LoadAssetAtPath<Material>(path);
|
||||
if (mat == null || mat.shader == null) continue;
|
||||
|
||||
if (i % 50 == 0)
|
||||
EditorUtility.DisplayProgressBar("收集Shader变体",
|
||||
$"创建 cube ({i + 1}/{guids.Length})", (float)i / guids.Length);
|
||||
|
||||
int col = i % cols;
|
||||
int row = i / cols;
|
||||
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
cube.name = mat.name;
|
||||
var collider = cube.GetComponent<Collider>();
|
||||
if (collider != null) Object.DestroyImmediate(collider);
|
||||
cube.transform.position = new Vector3(col * spacing - half, row * spacing - half, 0f);
|
||||
cube.GetComponent<MeshRenderer>().sharedMaterial = mat;
|
||||
created++;
|
||||
}
|
||||
|
||||
// 4. 正交相机正对网格,渲染到 RT,保证全部进视锥被实际渲染
|
||||
float gridExtent = cols * spacing * 0.5f + spacing;
|
||||
cam.orthographic = true;
|
||||
cam.orthographicSize = gridExtent;
|
||||
cam.aspect = 1f;
|
||||
cam.clearFlags = CameraClearFlags.SolidColor;
|
||||
cam.backgroundColor = Color.gray;
|
||||
cam.transform.position = new Vector3(0f, 0f, -20f);
|
||||
cam.transform.rotation = Quaternion.identity;
|
||||
cam.nearClipPlane = 0.1f;
|
||||
cam.farClipPlane = 100f;
|
||||
|
||||
EditorSceneManager.SaveScene(scene, TempScenePath);
|
||||
|
||||
rt = new RenderTexture(2048, 2048, 24);
|
||||
cam.targetTexture = rt;
|
||||
|
||||
// 采集前清空,确保结果只包含本次渲染的变体
|
||||
ClearCollection();
|
||||
|
||||
EditorUtility.DisplayProgressBar("收集Shader变体", "渲染中...", 0.9f);
|
||||
// 多渲染几帧,确保各变体都被编译并跟踪
|
||||
for (int k = 0; k < 4; k++)
|
||||
cam.Render();
|
||||
|
||||
cam.targetTexture = null;
|
||||
|
||||
int variantCount = GetTrackedVariantCount();
|
||||
int shaderCount = GetTrackedShaderCount();
|
||||
|
||||
// 5. 保存 SVC
|
||||
if (!Directory.Exists(OutputDir)) Directory.CreateDirectory(OutputDir);
|
||||
bool ok = SaveCollection(OutputPath);
|
||||
AssetDatabase.ImportAsset(OutputPath, ImportAssetOptions.ForceUpdate);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
Debug.Log($"[ShaderVariantCollector] 自动收集完成: {OutputPath}\n" +
|
||||
$" 材质: {guids.Length}, 创建cube: {created}, " +
|
||||
$"shader数: {shaderCount}, 变体数: {variantCount}");
|
||||
|
||||
if (!ok || variantCount <= 0)
|
||||
{
|
||||
EditorUtility.DisplayDialog("收集异常",
|
||||
$"变体数={variantCount}。\n若为 0,可能是 URP 下编辑器 Camera.Render 未触发跟踪," +
|
||||
"可改用 Play 模式 + Tools/Shader/收集当前Shader变体到SVC 兜底。", "好");
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.DisplayDialog("收集完成",
|
||||
$"已写入: {OutputPath}\n材质: {guids.Length}\nshader数: {shaderCount}\n变体数: {variantCount}\n\n现在可以重新打包构建。",
|
||||
"好");
|
||||
var asset = AssetDatabase.LoadAssetAtPath<ShaderVariantCollection>(OutputPath);
|
||||
if (asset != null) EditorGUIUtility.PingObject(asset);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
if (rt != null)
|
||||
{
|
||||
if (cam != null) cam.targetTexture = null;
|
||||
rt.Release();
|
||||
Object.DestroyImmediate(rt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- 手动收集(当前会话已渲染过的变体) ----------------
|
||||
|
||||
[MenuItem("Tools/Shader/收集当前Shader变体到SVC")]
|
||||
public static void SaveCurrentVariants()
|
||||
{
|
||||
if (GetMethod("SaveCurrentShaderVariantCollection") == null) return;
|
||||
|
||||
int variantCount = GetTrackedVariantCount();
|
||||
int shaderCount = GetTrackedShaderCount();
|
||||
|
||||
if (variantCount == 0 &&
|
||||
!EditorUtility.DisplayDialog("没有可收集的变体",
|
||||
"当前跟踪到的 shader 变体为 0。\n\n请先进入 Play 模式并显示出问题界面/模型,让相关 shader 实际渲染一次,再执行本命令。",
|
||||
"我知道了", "取消"))
|
||||
return;
|
||||
|
||||
if (!Directory.Exists(OutputDir)) Directory.CreateDirectory(OutputDir);
|
||||
|
||||
if (!SaveCollection(OutputPath)) return;
|
||||
AssetDatabase.ImportAsset(OutputPath, ImportAssetOptions.ForceUpdate);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
Debug.Log($"[ShaderVariantCollector] 已保存变体集合: {OutputPath}\n" +
|
||||
$" shader 数: {shaderCount}, 变体数: {variantCount}");
|
||||
EditorUtility.DisplayDialog("收集完成",
|
||||
$"已写入: {OutputPath}\nshader 数: {shaderCount}\n变体数: {variantCount}\n\n现在可以重新打包构建。", "好");
|
||||
|
||||
var asset = AssetDatabase.LoadAssetAtPath<ShaderVariantCollection>(OutputPath);
|
||||
if (asset != null) EditorGUIUtility.PingObject(asset);
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Shader/清空已跟踪变体")]
|
||||
public static void ClearTrackedVariants()
|
||||
{
|
||||
ClearCollection();
|
||||
Debug.Log("[ShaderVariantCollector] 已清空当前跟踪的 shader 变体,可重新进入 Play 重新采集。");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c39064f03a1c95408249fc79d9fac7d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,43 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: b29e98153ec2fbd44b8f7da1b41194e8, type: 3}
|
||||
m_Name: SpineSettings
|
||||
m_EditorClassIdentifier:
|
||||
defaultScale: 0.01
|
||||
defaultMix: 0.2
|
||||
defaultShader: Spine/Skeleton
|
||||
defaultZSpacing: 0
|
||||
defaultInstantiateLoop: 1
|
||||
defaultPhysicsPositionInheritance: {x: 1, y: 1}
|
||||
defaultPhysicsRotationInheritance: 1
|
||||
showHierarchyIcons: 1
|
||||
reloadAfterPlayMode: 1
|
||||
setTextureImporterSettings: 1
|
||||
textureSettingsReference:
|
||||
fixPrefabOverrideViaMeshFilter: 0
|
||||
removePrefabPreviewMeshes: 0
|
||||
applyAdditiveMaterial: 0
|
||||
blendModeMaterialMultiply: {fileID: 0}
|
||||
blendModeMaterialScreen: {fileID: 0}
|
||||
blendModeMaterialAdditive: {fileID: 0}
|
||||
atlasTxtImportWarning: 1
|
||||
textureImporterWarning: 1
|
||||
componentMaterialWarning: 1
|
||||
skeletonDataAssetNoFileError: 1
|
||||
workflowMismatchDialog: 1
|
||||
skeletonDataAssetMismatchWarning: 1
|
||||
splitComponentChangeWarning: 0
|
||||
autoReloadSceneSkeletons: 1
|
||||
handleScale: 1
|
||||
mecanimEventIncludeFolderName: 1
|
||||
timelineDefaultMixDuration: 0
|
||||
timelineUseBlendDuration: 1
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5936fb33f8b6da542b52eb002552da33
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c2193da1f3f8174eb96bfaea88b8e92
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00114f9cc610c674799c31d48128c48c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making xLua available.
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using XLua;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
|
||||
//配置的详细介绍请看Doc下《XLua的配置.doc》
|
||||
public static class ExampleConfig
|
||||
{
|
||||
/***************如果你全lua编程,可以参考这份自动化配置***************/
|
||||
//--------------begin 纯lua编程配置参考----------------------------
|
||||
//static List<string> exclude = new List<string> {
|
||||
// "HideInInspector", "ExecuteInEditMode",
|
||||
// "AddComponentMenu", "ContextMenu",
|
||||
// "RequireComponent", "DisallowMultipleComponent",
|
||||
// "SerializeField", "AssemblyIsEditorAssembly",
|
||||
// "Attribute", "Types",
|
||||
// "UnitySurrogateSelector", "TrackedReference",
|
||||
// "TypeInferenceRules", "FFTWindow",
|
||||
// "RPC", "Network", "MasterServer",
|
||||
// "BitStream", "HostData",
|
||||
// "ConnectionTesterStatus", "GUI", "EventType",
|
||||
// "EventModifiers", "FontStyle", "TextAlignment",
|
||||
// "TextEditor", "TextEditorDblClickSnapping",
|
||||
// "TextGenerator", "TextClipping", "Gizmos",
|
||||
// "ADBannerView", "ADInterstitialAd",
|
||||
// "Android", "Tizen", "jvalue",
|
||||
// "iPhone", "iOS", "Windows", "CalendarIdentifier",
|
||||
// "CalendarUnit", "CalendarUnit",
|
||||
// "ClusterInput", "FullScreenMovieControlMode",
|
||||
// "FullScreenMovieScalingMode", "Handheld",
|
||||
// "LocalNotification", "NotificationServices",
|
||||
// "RemoteNotificationType", "RemoteNotification",
|
||||
// "SamsungTV", "TextureCompressionQuality",
|
||||
// "TouchScreenKeyboardType", "TouchScreenKeyboard",
|
||||
// "MovieTexture", "UnityEngineInternal",
|
||||
// "Terrain", "Tree", "SplatPrototype",
|
||||
// "DetailPrototype", "DetailRenderMode",
|
||||
// "MeshSubsetCombineUtility", "AOT", "Social", "Enumerator",
|
||||
// "SendMouseEvents", "Cursor", "Flash", "ActionScript",
|
||||
// "OnRequestRebuild", "Ping",
|
||||
// "ShaderVariantCollection", "SimpleJson.Reflection",
|
||||
// "CoroutineTween", "GraphicRebuildTracker",
|
||||
// "Advertisements", "UnityEditor", "WSA",
|
||||
// "EventProvider", "Apple",
|
||||
// "ClusterInput", "Motion",
|
||||
// "UnityEngine.UI.ReflectionMethodsCache", "NativeLeakDetection",
|
||||
// "NativeLeakDetectionMode", "WWWAudioExtensions", "UnityEngine.Experimental",
|
||||
//};
|
||||
|
||||
//static bool isExcluded(Type type)
|
||||
//{
|
||||
// var fullName = type.FullName;
|
||||
// for (int i = 0; i < exclude.Count; i++)
|
||||
// {
|
||||
// if (fullName.Contains(exclude[i]))
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
//}
|
||||
|
||||
//[LuaCallCSharp]
|
||||
//public static IEnumerable<Type> LuaCallCSharp
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// List<string> namespaces = new List<string>() // 在这里添加名字空间
|
||||
// {
|
||||
// "UnityEngine",
|
||||
// "UnityEngine.UI"
|
||||
// };
|
||||
// var unityTypes = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
|
||||
// where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder)
|
||||
// from type in assembly.GetExportedTypes()
|
||||
// where type.Namespace != null && namespaces.Contains(type.Namespace) && !isExcluded(type)
|
||||
// && type.BaseType != typeof(MulticastDelegate) && !type.IsInterface && !type.IsEnum
|
||||
// select type);
|
||||
|
||||
// string[] customAssemblys = new string[] {
|
||||
// "Assembly-CSharp",
|
||||
// };
|
||||
// var customTypes = (from assembly in customAssemblys.Select(s => Assembly.Load(s))
|
||||
// from type in assembly.GetExportedTypes()
|
||||
// where type.Namespace == null || !type.Namespace.StartsWith("XLua")
|
||||
// && type.BaseType != typeof(MulticastDelegate) && !type.IsInterface && !type.IsEnum
|
||||
// select type);
|
||||
// return unityTypes.Concat(customTypes);
|
||||
// }
|
||||
//}
|
||||
|
||||
////自动把LuaCallCSharp涉及到的delegate加到CSharpCallLua列表,后续可以直接用lua函数做callback
|
||||
//[CSharpCallLua]
|
||||
//public static List<Type> CSharpCallLua
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// var lua_call_csharp = LuaCallCSharp;
|
||||
// var delegate_types = new List<Type>();
|
||||
// var flag = BindingFlags.Public | BindingFlags.Instance
|
||||
// | BindingFlags.Static | BindingFlags.IgnoreCase | BindingFlags.DeclaredOnly;
|
||||
// foreach (var field in (from type in lua_call_csharp select type).SelectMany(type => type.GetFields(flag)))
|
||||
// {
|
||||
// if (typeof(Delegate).IsAssignableFrom(field.FieldType))
|
||||
// {
|
||||
// delegate_types.Add(field.FieldType);
|
||||
// }
|
||||
// }
|
||||
|
||||
// foreach (var method in (from type in lua_call_csharp select type).SelectMany(type => type.GetMethods(flag)))
|
||||
// {
|
||||
// if (typeof(Delegate).IsAssignableFrom(method.ReturnType))
|
||||
// {
|
||||
// delegate_types.Add(method.ReturnType);
|
||||
// }
|
||||
// foreach (var param in method.GetParameters())
|
||||
// {
|
||||
// var paramType = param.ParameterType.IsByRef ? param.ParameterType.GetElementType() : param.ParameterType;
|
||||
// if (typeof(Delegate).IsAssignableFrom(paramType))
|
||||
// {
|
||||
// delegate_types.Add(paramType);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return delegate_types.Where(t => t.BaseType == typeof(MulticastDelegate) && !hasGenericParameter(t) && !delegateHasEditorRef(t)).Distinct().ToList();
|
||||
// }
|
||||
//}
|
||||
//--------------end 纯lua编程配置参考----------------------------
|
||||
|
||||
/***************热补丁可以参考这份自动化配置***************/
|
||||
//[Hotfix]
|
||||
//static IEnumerable<Type> HotfixInject
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
|
||||
// where type.Namespace == null || !type.Namespace.StartsWith("XLua")
|
||||
// select type);
|
||||
// }
|
||||
//}
|
||||
//--------------begin 热补丁自动化配置-------------------------
|
||||
//static bool hasGenericParameter(Type type)
|
||||
//{
|
||||
// if (type.IsGenericTypeDefinition) return true;
|
||||
// if (type.IsGenericParameter) return true;
|
||||
// if (type.IsByRef || type.IsArray)
|
||||
// {
|
||||
// return hasGenericParameter(type.GetElementType());
|
||||
// }
|
||||
// if (type.IsGenericType)
|
||||
// {
|
||||
// foreach (var typeArg in type.GetGenericArguments())
|
||||
// {
|
||||
// if (hasGenericParameter(typeArg))
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
//}
|
||||
|
||||
//static bool typeHasEditorRef(Type type)
|
||||
//{
|
||||
// if (type.Namespace != null && (type.Namespace == "UnityEditor" || type.Namespace.StartsWith("UnityEditor.")))
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// if (type.IsNested)
|
||||
// {
|
||||
// return typeHasEditorRef(type.DeclaringType);
|
||||
// }
|
||||
// if (type.IsByRef || type.IsArray)
|
||||
// {
|
||||
// return typeHasEditorRef(type.GetElementType());
|
||||
// }
|
||||
// if (type.IsGenericType)
|
||||
// {
|
||||
// foreach (var typeArg in type.GetGenericArguments())
|
||||
// {
|
||||
// if (typeArg.IsGenericParameter) {
|
||||
// //skip unsigned type parameter
|
||||
// continue;
|
||||
// }
|
||||
// if (typeHasEditorRef(typeArg))
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
//}
|
||||
|
||||
//static bool delegateHasEditorRef(Type delegateType)
|
||||
//{
|
||||
// if (typeHasEditorRef(delegateType)) return true;
|
||||
// var method = delegateType.GetMethod("Invoke");
|
||||
// if (method == null)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// if (typeHasEditorRef(method.ReturnType)) return true;
|
||||
// return method.GetParameters().Any(pinfo => typeHasEditorRef(pinfo.ParameterType));
|
||||
//}
|
||||
|
||||
// 配置某Assembly下所有涉及到的delegate到CSharpCallLua下,Hotfix下拿不准那些delegate需要适配到lua function可以这么配置
|
||||
//[CSharpCallLua]
|
||||
//static IEnumerable<Type> AllDelegate
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// BindingFlags flag = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
|
||||
// List<Type> allTypes = new List<Type>();
|
||||
// var allAssemblys = new Assembly[]
|
||||
// {
|
||||
// Assembly.Load("Assembly-CSharp")
|
||||
// };
|
||||
// foreach (var t in (from assembly in allAssemblys from type in assembly.GetTypes() select type))
|
||||
// {
|
||||
// var p = t;
|
||||
// while (p != null)
|
||||
// {
|
||||
// allTypes.Add(p);
|
||||
// p = p.BaseType;
|
||||
// }
|
||||
// }
|
||||
// allTypes = allTypes.Distinct().ToList();
|
||||
// var allMethods = from type in allTypes
|
||||
// from method in type.GetMethods(flag)
|
||||
// select method;
|
||||
// var returnTypes = from method in allMethods
|
||||
// select method.ReturnType;
|
||||
// var paramTypes = allMethods.SelectMany(m => m.GetParameters()).Select(pinfo => pinfo.ParameterType.IsByRef ? pinfo.ParameterType.GetElementType() : pinfo.ParameterType);
|
||||
// var fieldTypes = from type in allTypes
|
||||
// from field in type.GetFields(flag)
|
||||
// select field.FieldType;
|
||||
// return (returnTypes.Concat(paramTypes).Concat(fieldTypes)).Where(t => t.BaseType == typeof(MulticastDelegate) && !hasGenericParameter(t) && !delegateHasEditorRef(t)).Distinct();
|
||||
// }
|
||||
//}
|
||||
//--------------end 热补丁自动化配置-------------------------
|
||||
|
||||
//黑名单
|
||||
[BlackList]
|
||||
public static List<List<string>> BlackList = new List<List<string>>() {
|
||||
new List<string>(){"System.Xml.XmlNodeList", "ItemOf"},
|
||||
new List<string>(){"UnityEngine.WWW", "movie"},
|
||||
#if UNITY_WEBGL
|
||||
new List<string>(){"UnityEngine.WWW", "threadPriority"},
|
||||
#endif
|
||||
new List<string>(){"UnityEngine.Texture2D", "alphaIsTransparency"},
|
||||
new List<string>(){"UnityEngine.Security", "GetChainOfTrustValue"},
|
||||
new List<string>(){"UnityEngine.CanvasRenderer", "onRequestRebuild"},
|
||||
new List<string>(){"UnityEngine.Light", "areaSize"},
|
||||
new List<string>(){"UnityEngine.Light", "lightmapBakeType"},
|
||||
new List<string>(){"UnityEngine.WWW", "MovieTexture"},
|
||||
new List<string>(){"UnityEngine.WWW", "GetMovieTexture"},
|
||||
new List<string>(){"UnityEngine.AnimatorOverrideController", "PerformOverrideClipListCleanup"},
|
||||
#if !UNITY_WEBPLAYER
|
||||
new List<string>(){"UnityEngine.Application", "ExternalEval"},
|
||||
#endif
|
||||
new List<string>(){"UnityEngine.GameObject", "networkView"}, //4.6.2 not support
|
||||
new List<string>(){"UnityEngine.Component", "networkView"}, //4.6.2 not support
|
||||
new List<string>(){"System.IO.FileInfo", "GetAccessControl", "System.Security.AccessControl.AccessControlSections"},
|
||||
new List<string>(){"System.IO.FileInfo", "SetAccessControl", "System.Security.AccessControl.FileSecurity"},
|
||||
new List<string>(){"System.IO.DirectoryInfo", "GetAccessControl", "System.Security.AccessControl.AccessControlSections"},
|
||||
new List<string>(){"System.IO.DirectoryInfo", "SetAccessControl", "System.Security.AccessControl.DirectorySecurity"},
|
||||
new List<string>(){"System.IO.DirectoryInfo", "CreateSubdirectory", "System.String", "System.Security.AccessControl.DirectorySecurity"},
|
||||
new List<string>(){"System.IO.DirectoryInfo", "Create", "System.Security.AccessControl.DirectorySecurity"},
|
||||
new List<string>(){"UnityEngine.MonoBehaviour", "runInEditMode"},
|
||||
};
|
||||
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
[BlackList]
|
||||
public static List<Type> BlackGenericTypeList = new List<Type>()
|
||||
{
|
||||
typeof(Span<>),
|
||||
typeof(ReadOnlySpan<>)
|
||||
};
|
||||
private static bool IsBlacklistedGenericType(Type type)
|
||||
{
|
||||
if (!type.IsGenericType) return false;
|
||||
return BlackGenericTypeList.Contains(type.GetGenericTypeDefinition());
|
||||
}
|
||||
|
||||
[BlackList]
|
||||
public static Func<MemberInfo, bool> GenericTypeFilter = (memberInfo) =>
|
||||
{
|
||||
switch (memberInfo)
|
||||
{
|
||||
case PropertyInfo propertyInfo:
|
||||
return IsBlacklistedGenericType(propertyInfo.PropertyType);
|
||||
case ConstructorInfo constructorInfo:
|
||||
return constructorInfo.GetParameters().Any(p => IsBlacklistedGenericType(p.ParameterType));
|
||||
case MethodInfo methodInfo:
|
||||
return methodInfo.GetParameters().Any(p => IsBlacklistedGenericType(p.ParameterType));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
[BlackList]
|
||||
public static Func<MemberInfo, bool> MethodFilter = (memberInfo) =>
|
||||
{
|
||||
if (memberInfo.DeclaringType.IsGenericType && memberInfo.DeclaringType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||
{
|
||||
if (memberInfo.MemberType == MemberTypes.Constructor)
|
||||
{
|
||||
ConstructorInfo constructorInfo = memberInfo as ConstructorInfo;
|
||||
var parameterInfos = constructorInfo.GetParameters();
|
||||
if (parameterInfos.Length > 0)
|
||||
{
|
||||
if (typeof(System.Collections.IEnumerable).IsAssignableFrom(parameterInfos[0].ParameterType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (memberInfo.MemberType == MemberTypes.Method)
|
||||
{
|
||||
var methodInfo = memberInfo as MethodInfo;
|
||||
if (methodInfo.Name == "TryAdd" || methodInfo.Name == "Remove" && methodInfo.GetParameters().Length == 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b852d3c62124624888d03e611f7b1fc
|
||||
timeCreated: 1534126175
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e866a5f1000c29940843aece98d0c706
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9f175d9e85601f4da903e391b8b7c77
|
||||
timeCreated: 1482299911
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f94464b9267f9b4cbf2f98681e22880
|
||||
folderAsset: yes
|
||||
timeCreated: 1479105499
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using XLua;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using CSObjectWrapEditor;
|
||||
|
||||
public class LinkXmlGen : ScriptableObject
|
||||
{
|
||||
public TextAsset Template;
|
||||
|
||||
public static IEnumerable<CustomGenTask> GetTasks(LuaEnv lua_env, UserConfig user_cfg)
|
||||
{
|
||||
LuaTable data = lua_env.NewTable();
|
||||
var assembly_infos = (from type in (user_cfg.ReflectionUse.Concat(user_cfg.LuaCallCSharp))
|
||||
group type by type.Assembly.GetName().Name into assembly_info
|
||||
select new { FullName = assembly_info.Key, Types = assembly_info.ToList()}).ToList();
|
||||
data.Set("assembly_infos", assembly_infos);
|
||||
|
||||
yield return new CustomGenTask
|
||||
{
|
||||
Data = data,
|
||||
Output = new StreamWriter(GeneratorConfig.common_path + "/link.xml",
|
||||
false, Encoding.UTF8)
|
||||
};
|
||||
}
|
||||
|
||||
[GenCodeMenu]//加到Generate Code菜单里头
|
||||
public static void GenLinkXml()
|
||||
{
|
||||
Generator.CustomGen(ScriptableObject.CreateInstance<LinkXmlGen>().Template.text, GetTasks);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5fa8c6bd6daed854c98654418f48a830
|
||||
timeCreated: 1482482561
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- Template: {fileID: 4900000, guid: 384feb229d259f549bbbac9e910b782b, type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
<%
|
||||
require "TemplateCommon"
|
||||
%>
|
||||
|
||||
<linker>
|
||||
<%ForEachCsList(assembly_infos, function(assembly_info)%>
|
||||
<assembly fullname="<%=assembly_info.FullName%>">
|
||||
<%ForEachCsList(assembly_info.Types, function(type)
|
||||
%><type fullname="<%=type:ToString()%>" preserve="all"/>
|
||||
<%end)%>
|
||||
</assembly>
|
||||
<%end)%>
|
||||
</linker>
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 384feb229d259f549bbbac9e910b782b
|
||||
timeCreated: 1481621844
|
||||
licenseType: Pro
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,638 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using XLua;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
public static class LuaGen
|
||||
{
|
||||
[LuaCallCSharp]
|
||||
public static List<Type> LuaCallCSharp = new List<Type>()
|
||||
{
|
||||
typeof(UnityEngine.Video.VideoPlayer.EventHandler),
|
||||
typeof(Action<byte[]>),
|
||||
typeof(DateTime),
|
||||
typeof(Dictionary<int, int>),
|
||||
typeof(Dictionary<string, object>),
|
||||
typeof(Dictionary<string,string>),
|
||||
typeof(Dictionary<string,string>),
|
||||
typeof(Dictionary<long,string>),
|
||||
typeof(Dictionary<string,string>.Enumerator),
|
||||
typeof(IEnumerator),
|
||||
typeof(KeyValuePair<string,string>),
|
||||
typeof(List<int>),
|
||||
typeof(List<string>),
|
||||
typeof(List<UnityEngine.Component>),
|
||||
typeof(LuaEnv),
|
||||
typeof(object),
|
||||
typeof(System.Net.Dns),
|
||||
typeof(System.Net.Sockets.AddressFamily),
|
||||
typeof(System.Net.Sockets.SocketError),
|
||||
typeof(System.Runtime.CompilerServices.ExtensionAttribute),
|
||||
typeof(TimeSpan),
|
||||
typeof(Convert),
|
||||
typeof(UnityEngine.NetworkReachability),
|
||||
typeof(UnityEngine.AI.NavMeshAgent),
|
||||
typeof(UnityEngine.AI.NavMeshObstacle),
|
||||
typeof(UnityEngine.AnimationClip),
|
||||
typeof(UnityEngine.AnimationCurve),
|
||||
typeof(UnityEngine.Animator),
|
||||
typeof(UnityEngine.AnimatorStateInfo),
|
||||
typeof(UnityEngine.Application),
|
||||
typeof(UnityEngine.Behaviour),
|
||||
typeof(UnityEngine.Bounds),
|
||||
typeof(UnityEngine.BoxCollider),
|
||||
typeof(UnityEngine.Camera),
|
||||
typeof(UnityEngine.Camera.MonoOrStereoscopicEye),
|
||||
typeof(UnityEngine.Camera.StereoscopicEye),
|
||||
typeof(UnityEngine.Rendering.Universal.CameraExtensions),
|
||||
typeof(UnityEngine.Rendering.Universal.UniversalAdditionalCameraData),
|
||||
//typeof(Cinemachine.CinemachineBrain),
|
||||
//typeof(Cinemachine.CinemachineVirtualCamera),
|
||||
//typeof(Cinemachine.LensSettings),
|
||||
typeof(UnityEngine.Canvas),
|
||||
typeof(UnityEngine.CanvasGroup),
|
||||
typeof(UnityEngine.Collider),
|
||||
typeof(UnityEngine.Color),
|
||||
typeof(UnityEngine.ColorUtility),
|
||||
typeof(UnityEngine.Component),
|
||||
typeof(UnityEngine.Debug),
|
||||
typeof(UnityEngine.Events.UnityEvent),
|
||||
typeof(UnityEngine.EventSystems.BaseEventData),
|
||||
typeof(UnityEngine.EventSystems.PhysicsRaycaster),
|
||||
typeof(UnityEngine.EventSystems.PointerEventData),
|
||||
typeof(UnityEngine.EventSystems.PointerEventData.FramePressState),
|
||||
typeof(UnityEngine.EventSystems.PointerEventData.InputButton),
|
||||
typeof(UnityEngine.EventSystems.UIBehaviour),
|
||||
typeof(UnityEngine.GameObject),
|
||||
typeof(UnityEngine.GUIUtility),
|
||||
typeof(UnityEngine.Input),
|
||||
typeof(UnityEngine.Keyframe),
|
||||
typeof(UnityEngine.LayerMask),
|
||||
typeof(UnityEngine.LineRenderer),
|
||||
typeof(UnityEngine.Material),
|
||||
typeof(UnityEngine.Mathf),
|
||||
typeof(UnityEngine.Matrix4x4),
|
||||
typeof(UnityEngine.MonoBehaviour),
|
||||
typeof(UnityEngine.Networking.DownloadHandler),
|
||||
typeof(UnityEngine.Networking.DownloadHandlerBuffer),
|
||||
typeof(UnityEngine.Networking.DownloadHandlerTexture),
|
||||
typeof(UnityEngine.Networking.UnityWebRequest),
|
||||
typeof(UnityEngine.Networking.UnityWebRequestAsyncOperation),
|
||||
typeof(UnityEngine.Object),
|
||||
typeof(UnityEngine.ParticleSystem),
|
||||
typeof(UnityEngine.ParticleSystem.MainModule),
|
||||
typeof(UnityEngine.Playables.PlayableDirector),
|
||||
typeof(UnityEngine.PlayerPrefs),
|
||||
typeof(UnityEngine.Quaternion),
|
||||
typeof(UnityEngine.Random),
|
||||
typeof(UnityEngine.Ray),
|
||||
typeof(UnityEngine.Ray2D),
|
||||
typeof(UnityEngine.RaycastHit),
|
||||
typeof(UnityEngine.Rect),
|
||||
typeof(UnityEngine.RectTransform),
|
||||
typeof(UnityEngine.RectTransform.Axis),
|
||||
typeof(UnityEngine.RectTransform.Edge),
|
||||
typeof(UnityEngine.RectTransformUtility),
|
||||
typeof(UnityEngine.Renderer),
|
||||
typeof(UnityEngine.RenderTexture),
|
||||
typeof(UnityEngine.Resources),
|
||||
typeof(UnityEngine.Rigidbody),
|
||||
typeof(UnityEngine.RuntimeAnimatorController),
|
||||
typeof(UnityEngine.RuntimePlatform),
|
||||
typeof(UnityEngine.Screen),
|
||||
typeof(UnityEngine.SleepTimeout),
|
||||
typeof(UnityEngine.SkinnedMeshRenderer),
|
||||
typeof(UnityEngine.Sprite),
|
||||
typeof(UnityEngine.SystemInfo),
|
||||
typeof(UnityEngine.TextAsset),
|
||||
typeof(UnityEngine.Texture),
|
||||
typeof(UnityEngine.Texture2D),
|
||||
typeof(UnityEngine.ImageConversion),
|
||||
typeof(UnityEngine.Texture2D.EXRFlags),
|
||||
typeof(UnityEngine.Time),
|
||||
typeof(UnityEngine.TouchPhase),
|
||||
typeof(UnityEngine.Transform),
|
||||
typeof(UnityEngine.GameObject),
|
||||
typeof(UnityEngine.UI.Button),
|
||||
typeof(UnityEngine.UI.Button.ButtonClickedEvent),
|
||||
typeof(UnityEngine.UI.Dropdown),
|
||||
typeof(UnityEngine.UI.GridLayoutGroup),
|
||||
typeof(UnityEngine.UI.GridLayoutGroup.Axis),
|
||||
typeof(UnityEngine.UI.GridLayoutGroup.Constraint),
|
||||
typeof(UnityEngine.UI.GridLayoutGroup.Corner),
|
||||
typeof(UnityEngine.UI.HorizontalLayoutGroup),
|
||||
typeof(UnityEngine.UI.Image),
|
||||
typeof(UnityEngine.UI.Image.FillMethod),
|
||||
typeof(UnityEngine.UI.Image.Origin180),
|
||||
typeof(UnityEngine.UI.Image.Origin360),
|
||||
typeof(UnityEngine.UI.Image.Origin360),
|
||||
typeof(UnityEngine.UI.Image.Origin90),
|
||||
typeof(UnityEngine.UI.Image.OriginHorizontal),
|
||||
typeof(UnityEngine.UI.Image.OriginVertical),
|
||||
typeof(UnityEngine.UI.Image.Type),
|
||||
typeof(UnityEngine.UI.InputField),
|
||||
typeof(UnityEngine.UI.InputField.CharacterValidation),
|
||||
typeof(UnityEngine.UI.InputField.ContentType),
|
||||
typeof(UnityEngine.UI.InputField.InputType),
|
||||
typeof(UnityEngine.UI.InputField.LineType),
|
||||
typeof(UnityEngine.UI.InputField.OnChangeEvent),
|
||||
typeof(UnityEngine.UI.InputField.SubmitEvent),
|
||||
typeof(UnityEngine.UI.InputField.OnValidateInput),
|
||||
typeof(UnityEngine.UI.LayoutGroup),
|
||||
typeof(UnityEngine.UI.LayoutRebuilder),
|
||||
typeof(UnityEngine.UI.MaskableGraphic),
|
||||
typeof(UnityEngine.UI.MaskableGraphic.CullStateChangedEvent),
|
||||
typeof(UnityEngine.UI.RawImage),
|
||||
typeof(UnityEngine.UI.Scrollbar),
|
||||
typeof(UnityEngine.UI.Scrollbar.Direction),
|
||||
typeof(UnityEngine.UI.Scrollbar.ScrollEvent),
|
||||
typeof(UnityEngine.UI.ScrollRect),
|
||||
typeof(UnityEngine.UI.ScrollRect.MovementType),
|
||||
typeof(UnityEngine.UI.ScrollRect.ScrollbarVisibility),
|
||||
typeof(UnityEngine.UI.ScrollRect.ScrollRectEvent),
|
||||
typeof(UnityEngine.UI.Selectable),
|
||||
typeof(UnityEngine.UI.Selectable.Transition),
|
||||
typeof(UnityEngine.UI.Slider),
|
||||
typeof(UnityEngine.UI.Slider.Direction),
|
||||
typeof(UnityEngine.UI.Slider.SliderEvent),
|
||||
typeof(UnityEngine.UI.Text),
|
||||
typeof(UnityEngine.UI.Toggle),
|
||||
typeof(UnityEngine.UI.Toggle.ToggleEvent),
|
||||
typeof(UnityEngine.UI.Toggle.ToggleTransition),
|
||||
typeof(UnityEngine.UI.CanvasScaler),
|
||||
typeof(UnityEngine.Vector2),
|
||||
typeof(UnityEngine.Vector2Int),
|
||||
typeof(UnityEngine.Vector3),
|
||||
typeof(UnityEngine.Vector3Int),
|
||||
typeof(List<UnityEngine.Vector3>),
|
||||
typeof(UnityEngine.Vector4),
|
||||
typeof(UnityEngine.WaitForEndOfFrame),
|
||||
typeof(UnityEngine.TextMesh),
|
||||
typeof(UnityEngine.Profiling.Profiler),
|
||||
typeof(XGame.XWebSocket),
|
||||
typeof(XGame.lsocket),
|
||||
typeof(UnityEngine.Timeline.ActivationTrack),
|
||||
typeof(UnityEngine.Timeline.ControlTrack),
|
||||
typeof(UnityEngine.Timeline.ControlPlayableAsset),
|
||||
typeof(UnityEngine.Video.VideoPlayer),
|
||||
typeof(UnityEngine.LayerMask),
|
||||
typeof(Action<bool>),
|
||||
typeof(Func<string, string>),
|
||||
typeof(Action<int>),
|
||||
typeof(Func<UnityEngine.Networking.DownloadHandler>),
|
||||
typeof(TimeZoneInfo),
|
||||
typeof(DayOfWeek),
|
||||
typeof(DG.Tweening.ShortcutExtensions),
|
||||
typeof(DG.Tweening.TweenExtensions),
|
||||
typeof(DG.Tweening.TweenSettingsExtensions),
|
||||
typeof(DG.Tweening.Ease),
|
||||
typeof(DG.Tweening.RotateMode),
|
||||
//typeof(DG.Tweening.Tween),
|
||||
typeof(DG.Tweening.DOTween),
|
||||
typeof(DG.Tweening.DOTweenModuleUI),
|
||||
|
||||
//typeof(XGame.Utility),
|
||||
|
||||
|
||||
|
||||
#if DEVELOPMENT || RELEASE
|
||||
typeof(GYGame.GMToolViewBuilder),
|
||||
typeof(MobileConsole.UI.GenericNodeView),
|
||||
typeof(MobileConsole.UI.CheckboxNodeView),
|
||||
typeof(MobileConsole.UI.DropdownNodeView),
|
||||
typeof(MobileConsole.UI.InputNodeView),
|
||||
typeof(MobileConsole.UI.SliderNodeView),
|
||||
typeof(MobileConsole.UI.CategoryNodeView),
|
||||
#endif
|
||||
};
|
||||
|
||||
[GCOptimize]
|
||||
public static List<Type> GCOptimizeList = new List<Type>()
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
[CSharpCallLua]
|
||||
public static List<Type> CSharpCallLua = new List<Type>()
|
||||
{
|
||||
typeof(IEnumerator),
|
||||
typeof(UnityEngine.Events.UnityAction),
|
||||
typeof(UnityEngine.Events.UnityAction<UnityEngine.Vector2>),
|
||||
typeof(UnityEngine.Events.UnityAction<int>),
|
||||
typeof(UnityEngine.Events.UnityAction<int,UnityEngine.GameObject>),
|
||||
typeof(UnityEngine.Events.UnityAction<int,bool>),
|
||||
typeof(UnityEngine.Events.UnityAction<int,int>),
|
||||
typeof(UnityEngine.LayerMask),
|
||||
typeof(UnityEngine.EventSystems.PhysicsRaycaster),
|
||||
typeof(Action<string[]>),
|
||||
typeof(Action<UnityEngine.Transform>),
|
||||
typeof(Action<bool, string>),
|
||||
typeof(Action<UnityEngine.Object>),
|
||||
typeof(Action<UnityEngine.EventSystems.PointerEventData>),
|
||||
typeof(Action<UnityEngine.GameObject>),
|
||||
typeof(Action<UnityEngine.EventSystems.BaseEventData>),
|
||||
typeof(Action<UnityEngine.Vector3>),
|
||||
typeof(UnityEngine.Events.UnityAction<bool>),
|
||||
typeof(UnityEngine.Events.UnityAction<int>),
|
||||
typeof(UnityEngine.Events.UnityAction<float>),
|
||||
typeof(UnityEngine.UI.InputField.OnValidateInput),
|
||||
typeof(Action<string, int, char>),
|
||||
typeof(Action<string, string, string, Action, Action>),
|
||||
typeof(Action<string, string, string, object, Action>),
|
||||
typeof(Action<System.Net.Sockets.SocketError>),
|
||||
typeof(Action<XGame.XWebSocket, string>),
|
||||
typeof(Action<byte[]>),
|
||||
typeof(Action<float>),
|
||||
typeof(Action<bool>),
|
||||
typeof(Action<float,float,float,bool>),
|
||||
typeof(Action<uint>),
|
||||
typeof(Action<int>),
|
||||
typeof(Action<string, byte[]>),
|
||||
typeof(Func<int, List<string>>),
|
||||
typeof(Func<LuaTable>),
|
||||
typeof(Func<int, int, int, int>),
|
||||
typeof(Func<int, int, int, bool>),
|
||||
typeof(Func<int, int, LuaTable>),
|
||||
typeof(Func<bool, int, LuaTable>),
|
||||
typeof(Func<bool, bool, int, LuaTable>),
|
||||
typeof(Func<int, int, bool>),
|
||||
typeof(Action<int, Action>),
|
||||
typeof(Action<int, Action, Action, int>),
|
||||
typeof(Action<int, int, Action<bool>>),
|
||||
typeof(Func<int, string>),
|
||||
typeof(Func<int, bool>),
|
||||
typeof(Func<bool>),
|
||||
typeof(Action<int, UnityEngine.EventSystems.PointerEventData>),
|
||||
typeof(Func<int, LuaTable>),
|
||||
typeof(Action<int, Action<int>>),
|
||||
typeof(Action<string>),
|
||||
typeof(Action<string,string>),
|
||||
typeof(UnityEngine.EventSystems.PointerEventData),
|
||||
typeof(Func<UnityEngine.GameObject,int,bool>),
|
||||
typeof(Action<long,string>),
|
||||
|
||||
typeof(Action<UnityEngine.RectTransform, int>),
|
||||
typeof(Action<int, UnityEngine.RectTransform>),
|
||||
typeof(DG.Tweening.Core.DOGetter<UnityEngine.Vector2>),
|
||||
typeof(DG.Tweening.Core.DOGetter<UnityEngine.Vector3>),
|
||||
typeof(DG.Tweening.Core.DOGetter<float>),
|
||||
typeof(DG.Tweening.Core.DOGetter<int>),
|
||||
typeof(DG.Tweening.Core.DOSetter<float>),
|
||||
typeof(DG.Tweening.Core.DOSetter<int>),
|
||||
|
||||
#if DEVELOPMENT || RELEASE
|
||||
typeof(MobileConsole.UI.GenericNodeView.Callback),
|
||||
typeof(MobileConsole.UI.CheckboxNodeView.Callback),
|
||||
typeof(MobileConsole.UI.DropdownNodeView.Callback),
|
||||
typeof(MobileConsole.UI.InputNodeView.Callback),
|
||||
typeof(MobileConsole.UI.SliderNodeView.Callback),
|
||||
#endif
|
||||
};
|
||||
|
||||
private static Type[] Elements =
|
||||
{
|
||||
typeof(bool),
|
||||
typeof(int),
|
||||
typeof(float),
|
||||
typeof(double),
|
||||
typeof(string),
|
||||
typeof(object)
|
||||
};
|
||||
|
||||
private static List<Type[]> GetElementsList()
|
||||
{
|
||||
List<Type[]> list1= new List<Type[]>();
|
||||
//List<Type[]> list1 = XGame.Utility.GetPermutation(Elements, 3);
|
||||
//List<Type[]> list2 = XGame.Utility.GetPermutation(Elements, 2);
|
||||
//list1.AddRange(list2);
|
||||
//for (int i = 0; i < Elements.Length; i++)
|
||||
//{
|
||||
// Type e = Elements[i];
|
||||
// list1.Add(new[]
|
||||
// {
|
||||
// e
|
||||
// });
|
||||
// list1.Add(new[]
|
||||
// {
|
||||
// e,
|
||||
// e
|
||||
// });
|
||||
// list1.Add(new[]
|
||||
// {
|
||||
// e,
|
||||
// e,
|
||||
// e
|
||||
// });
|
||||
//}
|
||||
|
||||
//for (int i = 0; i < list2.Count; ++i)
|
||||
//{
|
||||
// Type[] elements = list2[i];
|
||||
// Type e1 = elements[0];
|
||||
// Type e2 = elements[1];
|
||||
// list1.Add(new[]
|
||||
// {
|
||||
// e1,
|
||||
// e1,
|
||||
// e2
|
||||
// });
|
||||
// list1.Add(new[]
|
||||
// {
|
||||
// e1,
|
||||
// e2,
|
||||
// e1
|
||||
// });
|
||||
// list1.Add(new[]
|
||||
// {
|
||||
// e2,
|
||||
// e1,
|
||||
// e1
|
||||
// });
|
||||
//}
|
||||
|
||||
return list1;
|
||||
}
|
||||
|
||||
private static List<Type> GetCSharpCallLua()
|
||||
{
|
||||
List<Type[]> list = GetElementsList();
|
||||
List<Type> csharpCallLua = new List<Type>();
|
||||
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
Type[] elements = list[i];
|
||||
Type actionGeneric = null;
|
||||
Type funcGeneric = null;
|
||||
|
||||
switch (elements.Length)
|
||||
{
|
||||
case 1:
|
||||
actionGeneric = typeof(Action<>);
|
||||
funcGeneric = typeof(Func<>);
|
||||
break;
|
||||
case 2:
|
||||
actionGeneric = typeof(Action<,>);
|
||||
funcGeneric = typeof(Func<,>);
|
||||
break;
|
||||
case 3:
|
||||
actionGeneric = typeof(Action<,,>);
|
||||
funcGeneric = typeof(Func<,,>);
|
||||
break;
|
||||
}
|
||||
|
||||
if (actionGeneric != null)
|
||||
{
|
||||
csharpCallLua.Add(actionGeneric.MakeGenericType(elements));
|
||||
}
|
||||
|
||||
if (funcGeneric != null)
|
||||
{
|
||||
csharpCallLua.Add(funcGeneric.MakeGenericType(elements));
|
||||
}
|
||||
}
|
||||
|
||||
return csharpCallLua;
|
||||
}
|
||||
|
||||
[CSharpCallLua]
|
||||
public static List<Type> CSharpCallLuaAuto = GetCSharpCallLua();
|
||||
|
||||
[BlackList]
|
||||
public static List<List<string>> BlackList = new List<List<string>>()
|
||||
{
|
||||
new List<string>()
|
||||
{
|
||||
"UnityEngine.Texture2D",
|
||||
"alphaIsTransparency"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"UnityEngine.Security",
|
||||
"GetChainOfTrustValue"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"UnityEngine.CanvasRenderer",
|
||||
"onRequestRebuild"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"UnityEngine.Light",
|
||||
"areaSize"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"UnityEngine.AnimatorOverrideController",
|
||||
"PerformOverrideClipListCleanup"
|
||||
},
|
||||
#if !UNITY_WEBPLAYER
|
||||
new List<string>()
|
||||
{
|
||||
"UnityEngine.Application",
|
||||
"ExternalEval"
|
||||
},
|
||||
#endif
|
||||
new List<string>()
|
||||
{
|
||||
"UnityEngine.GameObject",
|
||||
"networkView"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"UnityEngine.Component",
|
||||
"networkView"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"System.IO.FileInfo",
|
||||
"GetAccessControl",
|
||||
"System.Security.AccessControl.AccessControlSections"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"System.IO.FileInfo",
|
||||
"SetAccessControl",
|
||||
"System.Security.AccessControl.FileSecurity"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"System.IO.DirectoryInfo",
|
||||
"GetAccessControl",
|
||||
"System.Security.AccessControl.AccessControlSections"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"System.IO.DirectoryInfo",
|
||||
"SetAccessControl",
|
||||
"System.Security.AccessControl.DirectorySecurity"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"System.IO.DirectoryInfo",
|
||||
"CreateSubdirectory",
|
||||
"System.String",
|
||||
"System.Security.AccessControl.DirectorySecurity"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"System.IO.DirectoryInfo",
|
||||
"Create",
|
||||
"System.Security.AccessControl.DirectorySecurity"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"UnityEngine.MonoBehaviour",
|
||||
"runInEditMode"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"UnityEngine.Input",
|
||||
"IsJoystickPreconfigured",
|
||||
"System.String"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"UnityEngine.Texture",
|
||||
"imageContentsHash"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"UnityEngine.UI.Text",
|
||||
"OnRebuildRequested"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"XGame.Actor",
|
||||
"RidToActorDict"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"XGame.Actor",
|
||||
"GetInspectedData",
|
||||
"XGame.PropertyInspectorBehaviour"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"XGame.Utility",
|
||||
"GetBuildPlatformName",
|
||||
"UnityEditor.BuildTarget"
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"XGame.FileManager",
|
||||
"OnFileChange",
|
||||
"System.Object",
|
||||
"System.IO.FileSystemEventArgs",
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"XGame.FileManager",
|
||||
"OnFileRename",
|
||||
"System.Object",
|
||||
"System.IO.RenamedEventArgs",
|
||||
},
|
||||
new List<string>()
|
||||
{
|
||||
"XGame.FileManager",
|
||||
"OnFileError",
|
||||
"System.Object",
|
||||
"System.IO.ErrorEventArgs",
|
||||
},
|
||||
|
||||
new List<string>(){ "UnityEngine.Material", "IsChildOf", "UnityEngine.Material"},
|
||||
new List<string>(){ "UnityEngine.Material", "RevertAllPropertyOverrides"},
|
||||
new List<string>(){ "UnityEngine.Material", "IsPropertyOverriden", "System.Int32"},
|
||||
new List<string>(){ "UnityEngine.Material", "IsPropertyOverriden", "System.String"},
|
||||
new List<string>(){ "UnityEngine.Material", "IsPropertyLocked", "System.Int32"},
|
||||
new List<string>(){ "UnityEngine.Material", "IsPropertyLocked", "System.String"},
|
||||
new List<string>(){ "UnityEngine.Material", "IsPropertyLockedByAncestor", "System.Int32"},
|
||||
new List<string>(){ "UnityEngine.Material", "IsPropertyLockedByAncestor", "System.String"},
|
||||
new List<string>(){ "UnityEngine.Material", "SetPropertyLock","System.Int32", "System.Boolean"},
|
||||
new List<string>(){ "UnityEngine.Material", "SetPropertyLock", "System.String", "System.Boolean"},
|
||||
new List<string>(){ "UnityEngine.Material", "ApplyPropertyOverride","UnityEngine.Material", "System.String", "System.Boolean"},
|
||||
new List<string>(){ "UnityEngine.Material", "ApplyPropertyOverride","UnityEngine.Material", "System.Int32", "System.Boolean"},
|
||||
new List<string>(){ "UnityEngine.Material", "RevertPropertyOverride", "System.Int32"},
|
||||
new List<string>(){ "UnityEngine.Material", "RevertPropertyOverride", "System.String"},
|
||||
new List<string>(){ "UnityEngine.Material", "parent"},
|
||||
new List<string>(){ "UnityEngine.Material", "isVariant"},
|
||||
|
||||
new List<string>() { "RenderHeads.Media.AVProVideo.MediaPlayer", "EditorUpdate" },
|
||||
new List<string>() { "RenderHeads.Media.AVProVideo.MediaPlayer", "CheckEditorAudioMute" },
|
||||
new List<string>() { "RenderHeads.Media.AVProVideo.MediaPlayer", "EditorAllPlayersDispose" },
|
||||
new List<string>() { "RenderHeads.Media.AVProVideo.MediaPlayer", "GetPlatformOptions", "RenderHeads.Media.AVProVideo.Platform" },
|
||||
new List<string>() { "RenderHeads.Media.AVProVideo.MediaPlayer", "GetPlatformOptionsVariable", "RenderHeads.Media.AVProVideo.Platform" },
|
||||
new List<string>() { "RenderHeads.Media.AVProVideo.MediaPlayer", "SaveFrameToExr" },
|
||||
new List<string>() { "RenderHeads.Media.AVProVideo.MediaPlayer", "SaveFrameToPng" },
|
||||
new List<string>() { "RenderHeads.Media.AVProVideo.MediaPlayer", "InternalMediaLoadedEvent" },
|
||||
new List<string>() { "UnityEngine.MonoBehaviour", "EnableScriptReloadInCheckConsistency", "System.Boolean"},
|
||||
};
|
||||
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
[BlackList]
|
||||
public static Func<MemberInfo, bool> MethodFilter = (memberInfo) =>
|
||||
{
|
||||
if (memberInfo.DeclaringType.IsGenericType && memberInfo.DeclaringType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||
{
|
||||
if (memberInfo.MemberType == MemberTypes.Constructor)
|
||||
{
|
||||
ConstructorInfo constructorInfo = memberInfo as ConstructorInfo;
|
||||
ParameterInfo[] parameterInfos = constructorInfo.GetParameters();
|
||||
if (parameterInfos.Length > 0)
|
||||
{
|
||||
if (typeof(IEnumerable).IsAssignableFrom(parameterInfos[0].ParameterType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (memberInfo.MemberType == MemberTypes.Method)
|
||||
{
|
||||
MethodInfo methodInfo = memberInfo as MethodInfo;
|
||||
if (methodInfo.Name == "TryAdd" || methodInfo.Name == "Remove" && methodInfo.GetParameters().Length == 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (memberInfo.DeclaringType.IsGenericType && memberInfo.DeclaringType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
|
||||
{
|
||||
if (memberInfo.MemberType == MemberTypes.Method)
|
||||
{
|
||||
MethodInfo methodInfo = memberInfo as MethodInfo;
|
||||
if (methodInfo.Name == "Deconstruct")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (memberInfo.MemberType == MemberTypes.Method)
|
||||
{
|
||||
MethodInfo methodInfo = memberInfo as MethodInfo;
|
||||
ParameterInfo[] parameterInfos = methodInfo.GetParameters();
|
||||
foreach (ParameterInfo param in parameterInfos)
|
||||
{
|
||||
if (typeof(ReadOnlySpan<char>).IsAssignableFrom(param.ParameterType)
|
||||
|| typeof(ReadOnlySpan<byte>).IsAssignableFrom(param.ParameterType)
|
||||
|| typeof(ReadOnlySpan<int>).IsAssignableFrom(param.ParameterType)
|
||||
|| typeof(ReadOnlySpan<Vector3>).IsAssignableFrom(param.ParameterType)
|
||||
|| typeof(Span<char>).IsAssignableFrom(param.ParameterType)
|
||||
|| typeof(Span<byte>).IsAssignableFrom(param.ParameterType)
|
||||
|| typeof(Span<bool>).IsAssignableFrom(param.ParameterType)
|
||||
|| typeof(Span<Vector3>).IsAssignableFrom(param.ParameterType)
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e968a5a3fb13be64ebbc3a8ede2b23a2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c7307955fb71fc4090eb2a906a78a0a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
@@ -0,0 +1,589 @@
|
||||
#if USE_UNI_LUA
|
||||
using LuaAPI = UniLua.Lua;
|
||||
using RealStatePtr = UniLua.ILuaState;
|
||||
using LuaCSFunction = UniLua.CSharpFunctionDelegate;
|
||||
#else
|
||||
using LuaAPI = XLua.LuaDLL.Lua;
|
||||
using RealStatePtr = System.IntPtr;
|
||||
using LuaCSFunction = XLuaBase.lua_CSFunction;
|
||||
#endif
|
||||
|
||||
using XLua;
|
||||
using System.Collections.Generic;
|
||||
<%ForEachCsList(namespaces, function(namespace)%>using <%=namespace%>;<%end)%>
|
||||
<%
|
||||
require "TemplateCommon"
|
||||
|
||||
local OpNameMap = {
|
||||
op_Addition = "__AddMeta",
|
||||
op_Subtraction = "__SubMeta",
|
||||
op_Multiply = "__MulMeta",
|
||||
op_Division = "__DivMeta",
|
||||
op_Equality = "__EqMeta",
|
||||
op_UnaryNegation = "__UnmMeta",
|
||||
op_LessThan = "__LTMeta",
|
||||
op_LessThanOrEqual = "__LEMeta",
|
||||
op_Modulus = "__ModMeta",
|
||||
op_BitwiseAnd = "__BandMeta",
|
||||
op_BitwiseOr = "__BorMeta",
|
||||
op_ExclusiveOr = "__BxorMeta",
|
||||
op_OnesComplement = "__BnotMeta",
|
||||
op_LeftShift = "__ShlMeta",
|
||||
op_RightShift = "__ShrMeta",
|
||||
}
|
||||
|
||||
local OpCallNameMap = {
|
||||
op_Addition = "+",
|
||||
op_Subtraction = "-",
|
||||
op_Multiply = "*",
|
||||
op_Division = "/",
|
||||
op_Equality = "==",
|
||||
op_UnaryNegation = "-",
|
||||
op_LessThan = "<",
|
||||
op_LessThanOrEqual = "<=",
|
||||
op_Modulus = "%",
|
||||
op_BitwiseAnd = "&",
|
||||
op_BitwiseOr = "|",
|
||||
op_ExclusiveOr = "^",
|
||||
op_OnesComplement = "~",
|
||||
op_LeftShift = "<<",
|
||||
op_RightShift = ">>",
|
||||
}
|
||||
|
||||
local obj_method_count = 0
|
||||
local obj_getter_count = 0
|
||||
local obj_setter_count = 0
|
||||
local meta_func_count = operators.Count
|
||||
local cls_field_count = 1
|
||||
local cls_getter_count = 0
|
||||
local cls_setter_count = 0
|
||||
|
||||
ForEachCsList(methods, function(method)
|
||||
if method.IsStatic then
|
||||
cls_field_count = cls_field_count + 1
|
||||
else
|
||||
obj_method_count = obj_method_count + 1
|
||||
end
|
||||
end)
|
||||
|
||||
ForEachCsList(events, function(event)
|
||||
if event.IsStatic then
|
||||
cls_field_count = cls_field_count + 1
|
||||
else
|
||||
obj_method_count = obj_method_count + 1
|
||||
end
|
||||
end)
|
||||
|
||||
ForEachCsList(getters, function(getter)
|
||||
if getter.IsStatic then
|
||||
if getter.ReadOnly then
|
||||
cls_field_count = cls_field_count + 1
|
||||
else
|
||||
cls_getter_count = cls_getter_count + 1
|
||||
end
|
||||
else
|
||||
obj_getter_count = obj_getter_count + 1
|
||||
end
|
||||
end)
|
||||
|
||||
ForEachCsList(setters, function(setter)
|
||||
if setter.IsStatic then
|
||||
cls_setter_count = cls_setter_count + 1
|
||||
else
|
||||
obj_setter_count = obj_setter_count + 1
|
||||
end
|
||||
end)
|
||||
|
||||
ForEachCsList(lazymembers, function(lazymember)
|
||||
if lazymember.IsStatic == 'true' then
|
||||
if 'CLS_IDX' == lazymember.Index then
|
||||
cls_field_count = cls_field_count + 1
|
||||
elseif 'CLS_GETTER_IDX' == lazymember.Index then
|
||||
cls_getter_count = cls_getter_count + 1
|
||||
elseif 'CLS_SETTER_IDX' == lazymember.Index then
|
||||
cls_setter_count = cls_setter_count + 1
|
||||
end
|
||||
else
|
||||
if 'METHOD_IDX' == lazymember.Index then
|
||||
obj_method_count = obj_method_count + 1
|
||||
elseif 'GETTER_IDX' == lazymember.Index then
|
||||
obj_getter_count = obj_getter_count + 1
|
||||
elseif 'SETTER_IDX' == lazymember.Index then
|
||||
obj_setter_count = obj_setter_count + 1
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local generic_arg_list, type_constraints = GenericArgumentList(type)
|
||||
|
||||
%>
|
||||
namespace XLua.CSObjectWrap
|
||||
{
|
||||
using Utils = XLua.Utils;
|
||||
public class <%=CSVariableName(type)%>Wrap<%=generic_arg_list%> <%=type_constraints%>
|
||||
{
|
||||
public static void __Register(RealStatePtr L)
|
||||
{
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
System.Type type = typeof(<%=CsFullTypeName(type)%>);
|
||||
Utils.BeginObjectRegister(type, L, translator, <%=meta_func_count%>, <%=obj_method_count%>, <%=obj_getter_count%>, <%=obj_setter_count%>);
|
||||
<%ForEachCsList(operators, function(operator)%>Utils.RegisterFunc(L, Utils.OBJ_META_IDX, "<%=(OpNameMap[operator.Name]):gsub('Meta', ''):lower()%>", <%=OpNameMap[operator.Name]%>);
|
||||
<%end)%>
|
||||
<%ForEachCsList(methods, function(method) if not method.IsStatic then %>Utils.RegisterFunc(L, Utils.METHOD_IDX, "<%=method.Name%>", _m_<%=method.Name%>);
|
||||
<% end end)%>
|
||||
<%ForEachCsList(events, function(event) if not event.IsStatic then %>Utils.RegisterFunc(L, Utils.METHOD_IDX, "<%=event.Name%>", _e_<%=event.Name%>);
|
||||
<% end end)%>
|
||||
<%ForEachCsList(getters, function(getter) if not getter.IsStatic then %>Utils.RegisterFunc(L, Utils.GETTER_IDX, "<%=getter.Name%>", _g_get_<%=getter.Name%>);
|
||||
<%end end)%>
|
||||
<%ForEachCsList(setters, function(setter) if not setter.IsStatic then %>Utils.RegisterFunc(L, Utils.SETTER_IDX, "<%=setter.Name%>", _s_set_<%=setter.Name%>);
|
||||
<%end end)%>
|
||||
<%ForEachCsList(lazymembers, function(lazymember) if lazymember.IsStatic == 'false' then %>Utils.RegisterLazyFunc(L, Utils.<%=lazymember.Index%>, "<%=lazymember.Name%>", type, <%=lazymember.MemberType%>, <%=lazymember.IsStatic%>);
|
||||
<%end end)%>
|
||||
Utils.EndObjectRegister(type, L, translator, <% if type.IsArray or ((indexers.Count or 0) > 0) then %>__CSIndexer<%else%>null<%end%>, <%if type.IsArray or ((newindexers.Count or 0) > 0) then%>__NewIndexer<%else%>null<%end%>,
|
||||
null, null, null);
|
||||
|
||||
Utils.BeginClassRegister(type, L, __CreateInstance, <%=cls_field_count%>, <%=cls_getter_count%>, <%=cls_setter_count%>);
|
||||
<%ForEachCsList(methods, function(method) if method.IsStatic then %>Utils.RegisterFunc(L, Utils.CLS_IDX, "<%=method.Overloads[0].Name%>", _m_<%=method.Name%>);
|
||||
<% end end)%>
|
||||
<%ForEachCsList(events, function(event) if event.IsStatic then %>Utils.RegisterFunc(L, Utils.CLS_IDX, "<%=event.Name%>", _e_<%=event.Name%>);
|
||||
<% end end)%>
|
||||
<%ForEachCsList(getters, function(getter) if getter.IsStatic and getter.ReadOnly then %>Utils.RegisterObject(L, translator, Utils.CLS_IDX, "<%=getter.Name%>", <%=CsFullTypeName(type).."."..getter.Name%>);
|
||||
<%end end)%>
|
||||
<%ForEachCsList(getters, function(getter) if getter.IsStatic and (not getter.ReadOnly) then %>Utils.RegisterFunc(L, Utils.CLS_GETTER_IDX, "<%=getter.Name%>", _g_get_<%=getter.Name%>);
|
||||
<%end end)%>
|
||||
<%ForEachCsList(setters, function(setter) if setter.IsStatic then %>Utils.RegisterFunc(L, Utils.CLS_SETTER_IDX, "<%=setter.Name%>", _s_set_<%=setter.Name%>);
|
||||
<%end end)%>
|
||||
<%ForEachCsList(lazymembers, function(lazymember) if lazymember.IsStatic == 'true' then %>Utils.RegisterLazyFunc(L, Utils.<%=lazymember.Index%>, "<%=lazymember.Name%>", type, <%=lazymember.MemberType%>, <%=lazymember.IsStatic%>);
|
||||
<%end end)%>
|
||||
Utils.EndClassRegister(type, L, translator);
|
||||
}
|
||||
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
static int __CreateInstance(RealStatePtr L)
|
||||
{
|
||||
<%
|
||||
if constructors.Count == 0 and (not type.IsValueType) then
|
||||
%>return LuaAPI.luaL_error(L, "<%=CsFullTypeName(type)%> does not have a constructor!");<%
|
||||
else %>
|
||||
try {
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
<%
|
||||
local hasZeroParamsCtor = false
|
||||
ForEachCsList(constructors, function(constructor, ci)
|
||||
local parameters = constructor:GetParameters()
|
||||
if parameters.Length == 0 then
|
||||
hasZeroParamsCtor = true
|
||||
end
|
||||
local def_count = constructor_def_vals[ci]
|
||||
local param_count = parameters.Length
|
||||
local in_num = CalcCsList(parameters, function(p) return not (p.IsOut and p.ParameterType.IsByRef) end)
|
||||
local out_num = CalcCsList(parameters, function(p) return p.IsOut or p.ParameterType.IsByRef end)
|
||||
local real_param_count = param_count - def_count
|
||||
local has_v_params = param_count > 0 and IsParams(parameters[param_count - 1])
|
||||
local in_pos = 0
|
||||
%>if(LuaAPI.lua_gettop(L) <%=has_v_params and ">=" or "=="%> <%=in_num + 1 - def_count - (has_v_params and 1 or 0)%><%ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
local parameterType = parameter.ParameterType
|
||||
if has_v_params and pi == param_count - 1 then parameterType = parameterType:GetElementType() end
|
||||
if not (parameter.IsOut and parameter.ParameterType.IsByRef) then in_pos = in_pos + 1
|
||||
%> && <%=GetCheckStatement(parameterType, in_pos+1, has_v_params and pi == param_count - 1)%><%
|
||||
end
|
||||
end)%>)
|
||||
{
|
||||
<%ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
%><%=GetCasterStatement(parameter.ParameterType, pi+2, LocalName(parameter.Name), true, has_v_params and pi == param_count - 1)%>;
|
||||
<%end)%>
|
||||
var gen_ret = new <%=CsFullTypeName(type)%>(<%ForEachCsList(parameters, function(parameter, pi) if pi >= real_param_count then return end; if pi ~=0 then %><%=', '%><% end ;if parameter.IsOut and parameter.ParameterType.IsByRef then %>out <% elseif parameter.ParameterType.IsByRef and not parameter.IsIn then %>ref <% end %><%=LocalName(parameter.Name)%><% end)%>);
|
||||
<%=GetPushStatement(type, "gen_ret")%>;
|
||||
<%local in_pos = 0
|
||||
ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
if not (parameter.IsOut and parameter.ParameterType.IsByRef) then
|
||||
in_pos = in_pos + 1
|
||||
end
|
||||
if parameter.ParameterType.IsByRef then
|
||||
%><%=GetPushStatement(parameter.ParameterType:GetElementType(), LocalName(parameter.Name))%>;
|
||||
<%if not parameter.IsOut and parameter.ParameterType.IsByRef and NeedUpdate(parameter.ParameterType) then
|
||||
%><%=GetUpdateStatement(parameter.ParameterType:GetElementType(), in_pos+1, LocalName(parameter.Name))%>;
|
||||
<%end%>
|
||||
<%
|
||||
end
|
||||
end)
|
||||
%>
|
||||
return <%=out_num + 1%>;
|
||||
}
|
||||
<%end)
|
||||
if (not hasZeroParamsCtor) and type.IsValueType then
|
||||
%>
|
||||
if (LuaAPI.lua_gettop(L) == 1)
|
||||
{
|
||||
<%=GetPushStatement(type, "default(" .. CsFullTypeName(type).. ")")%>;
|
||||
return 1;
|
||||
}
|
||||
<%end%>
|
||||
}
|
||||
catch(System.Exception gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
|
||||
}
|
||||
return LuaAPI.luaL_error(L, "invalid arguments to <%=CsFullTypeName(type)%> constructor!");
|
||||
<% end %>
|
||||
}
|
||||
|
||||
<% if type.IsArray or ((indexers.Count or 0) > 0) then %>
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
public static int __CSIndexer(RealStatePtr L)
|
||||
{
|
||||
<%if type.IsArray then %>
|
||||
try {
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
|
||||
if (<%=GetCheckStatement(type, 1)%> && LuaAPI.lua_isnumber(L, 2))
|
||||
{
|
||||
int index = (int)LuaAPI.lua_tonumber(L, 2);
|
||||
<%=GetSelfStatement(type)%>;
|
||||
LuaAPI.lua_pushboolean(L, true);
|
||||
<%=GetPushStatement(type:GetElementType(), "gen_to_be_invoked[index]")%>;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
catch(System.Exception gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
|
||||
}
|
||||
<%elseif indexers.Count > 0 then
|
||||
%>try {
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
<%
|
||||
ForEachCsList(indexers, function(indexer)
|
||||
local paramter = indexer:GetParameters()[0]
|
||||
%>
|
||||
if (<%=GetCheckStatement(type, 1)%> && <%=GetCheckStatement(paramter.ParameterType, 2)%>)
|
||||
{
|
||||
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%=GetCasterStatement(paramter.ParameterType, 2, "index", true)%>;
|
||||
LuaAPI.lua_pushboolean(L, true);
|
||||
<%=GetPushStatement(indexer.ReturnType, "gen_to_be_invoked[index]")%>;
|
||||
return 2;
|
||||
}
|
||||
<%end)%>
|
||||
}
|
||||
catch(System.Exception gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
|
||||
}
|
||||
<%end%>
|
||||
LuaAPI.lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
<% end %>
|
||||
|
||||
<%if type.IsArray or ((newindexers.Count or 0) > 0) then%>
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
public static int __NewIndexer(RealStatePtr L)
|
||||
{
|
||||
<%if type.IsArray or newindexers.Count > 0 then %>ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);<%end%>
|
||||
<%if type.IsArray then
|
||||
local elementType = type:GetElementType()
|
||||
%>
|
||||
try {
|
||||
if (<%=GetCheckStatement(type, 1)%> && LuaAPI.lua_isnumber(L, 2) && <%=GetCheckStatement(elementType, 3)%>)
|
||||
{
|
||||
int index = (int)LuaAPI.lua_tonumber(L, 2);
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%=GetCasterStatement(elementType, 3, "gen_to_be_invoked[index]")%>;
|
||||
LuaAPI.lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
catch(System.Exception gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
|
||||
}
|
||||
<%elseif newindexers.Count > 0 then%>
|
||||
try {
|
||||
<%ForEachCsList(newindexers, function(newindexer)
|
||||
local keyType = newindexer:GetParameters()[0].ParameterType
|
||||
local valueType = newindexer:GetParameters()[1].ParameterType
|
||||
%>
|
||||
if (<%=GetCheckStatement(type, 1)%> && <%=GetCheckStatement(keyType, 2)%> && <%=GetCheckStatement(valueType, 3)%>)
|
||||
{
|
||||
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%=GetCasterStatement(keyType, 2, "key", true)%>;
|
||||
<%if IsStruct(valueType) then%><%=GetCasterStatement(valueType, 3, "gen_value", true)%>;
|
||||
gen_to_be_invoked[key] = gen_value;<%else
|
||||
%><%=GetCasterStatement(valueType, 3, "gen_to_be_invoked[key]")%>;<%end%>
|
||||
LuaAPI.lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
<%end)%>
|
||||
}
|
||||
catch(System.Exception gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
|
||||
}
|
||||
<%end%>
|
||||
LuaAPI.lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
<% end %>
|
||||
|
||||
<%ForEachCsList(operators, function(operator) %>
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
static int <%=OpNameMap[operator.Name]%>(RealStatePtr L)
|
||||
{
|
||||
<% if operator.Name ~= "op_UnaryNegation" and operator.Name ~= "op_OnesComplement" then %>
|
||||
try {
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
<%ForEachCsList(operator.Overloads, function(overload)
|
||||
local left_param = overload:GetParameters()[0]
|
||||
local right_param = overload:GetParameters()[1]
|
||||
%>
|
||||
|
||||
if (<%=GetCheckStatement(left_param.ParameterType, 1)%> && <%=GetCheckStatement(right_param.ParameterType, 2)%>)
|
||||
{
|
||||
<%=GetCasterStatement(left_param.ParameterType, 1, "leftside", true)%>;
|
||||
<%=GetCasterStatement(right_param.ParameterType, 2, "rightside", true)%>;
|
||||
|
||||
<%=GetPushStatement(overload.ReturnType, "leftside " .. OpCallNameMap[operator.Name] .. " rightside")%>;
|
||||
|
||||
return 1;
|
||||
}
|
||||
<%end)%>
|
||||
}
|
||||
catch(System.Exception gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
|
||||
}
|
||||
return LuaAPI.luaL_error(L, "invalid arguments to right hand of <%=OpCallNameMap[operator.Name]%> operator, need <%=CsFullTypeName(type)%>!");
|
||||
<%else%>
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
try {
|
||||
<%=GetCasterStatement(type, 1, "rightside", true)%>;
|
||||
<%=GetPushStatement(operator.Overloads[0].ReturnType, OpCallNameMap[operator.Name] .. " rightside")%>;
|
||||
} catch(System.Exception gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
|
||||
}
|
||||
return 1;
|
||||
<%end%>
|
||||
}
|
||||
<%end)%>
|
||||
|
||||
<%ForEachCsList(methods, function(method)%>
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
static int _m_<%=method.Name%>(RealStatePtr L)
|
||||
{
|
||||
try {
|
||||
<%
|
||||
local need_obj = not method.IsStatic
|
||||
if MethodCallNeedTranslator(method) then
|
||||
%>
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
<%end%>
|
||||
<%if need_obj then%>
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%end%>
|
||||
<%if method.Overloads.Count > 1 then%>
|
||||
int gen_param_count = LuaAPI.lua_gettop(L);
|
||||
<%end%>
|
||||
<%ForEachCsList(method.Overloads, function(overload, oi)
|
||||
local parameters = MethodParameters(overload)
|
||||
local in_num = CalcCsList(parameters, function(p) return not (p.IsOut and p.ParameterType.IsByRef) end)
|
||||
local param_offset = method.IsStatic and 0 or 1
|
||||
local out_num = CalcCsList(parameters, function(p) return p.IsOut or p.ParameterType.IsByRef end)
|
||||
local in_pos = 0
|
||||
local has_return = (overload.ReturnType.FullName ~= "System.Void")
|
||||
local def_count = method.DefaultValues[oi]
|
||||
local param_count = parameters.Length
|
||||
local real_param_count = param_count - def_count
|
||||
local has_v_params = param_count > 0 and IsParams(parameters[param_count - 1])
|
||||
if method.Overloads.Count > 1 then
|
||||
%>if(gen_param_count <%=has_v_params and ">=" or "=="%> <%=in_num+param_offset-def_count - (has_v_params and 1 or 0)%><%
|
||||
ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
local parameterType = parameter.ParameterType
|
||||
if has_v_params and pi == param_count - 1 then parameterType = parameterType:GetElementType() end
|
||||
if not (parameter.IsOut and parameter.ParameterType.IsByRef) then in_pos = in_pos + 1;
|
||||
%>&& <%=GetCheckStatement(parameterType , in_pos+param_offset, has_v_params and pi == param_count - 1)%><%
|
||||
end
|
||||
end)%>) <%end%>
|
||||
{
|
||||
<%if overload.Name == "get_Item" and overload.IsSpecialName then
|
||||
local keyType = overload:GetParameters()[0].ParameterType%>
|
||||
<%=GetCasterStatement(keyType, 2, "key", true)%>;
|
||||
<%=GetPushStatement(overload.ReturnType, "gen_to_be_invoked[key]")%>;
|
||||
<%elseif overload.Name == "set_Item" and overload.IsSpecialName then
|
||||
local keyType = overload:GetParameters()[0].ParameterType
|
||||
local valueType = overload:GetParameters()[1].ParameterType%>
|
||||
<%=GetCasterStatement(keyType, 2, "key", true)%>;
|
||||
<%=GetCasterStatement(valueType, 3, "gen_value", true)%>;
|
||||
gen_to_be_invoked[key] = gen_value;
|
||||
<% else
|
||||
in_pos = 0;
|
||||
ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
%><%if not (parameter.IsOut and parameter.ParameterType.IsByRef) then
|
||||
in_pos = in_pos + 1
|
||||
%><%=GetCasterStatement(parameter.ParameterType, in_pos+param_offset, LocalName(parameter.Name), true, has_v_params and pi == param_count - 1)%><%
|
||||
else%><%=CsFullTypeName(parameter.ParameterType)%> <%=LocalName(parameter.Name)%><%end%>;
|
||||
<%end)%>
|
||||
<%
|
||||
if has_return then
|
||||
%> var gen_ret = <%
|
||||
end
|
||||
%><%if method.IsStatic then
|
||||
%><%=CsFullTypeName(type).."."..UnK(overload.Name)%><%
|
||||
else
|
||||
%>gen_to_be_invoked.<%=UnK(overload.Name)%><%
|
||||
end%>( <%ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
if pi ~= 0 then %>, <% end; if parameter.IsOut and parameter.ParameterType.IsByRef then %>out <% elseif parameter.ParameterType.IsByRef and not parameter.IsIn then %>ref <% end %><%=LocalName(parameter.Name)%><% end) %> );
|
||||
<%
|
||||
if has_return then
|
||||
%> <%=GetPushStatement(overload.ReturnType, "gen_ret")%>;
|
||||
<%
|
||||
end
|
||||
local in_pos = 0
|
||||
ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
if not (parameter.IsOut and parameter.ParameterType.IsByRef) then
|
||||
in_pos = in_pos + 1
|
||||
end
|
||||
if parameter.ParameterType.IsByRef then
|
||||
%><%=GetPushStatement(parameter.ParameterType:GetElementType(), LocalName(parameter.Name))%>;
|
||||
<%if not parameter.IsOut and parameter.ParameterType.IsByRef and NeedUpdate(parameter.ParameterType) then
|
||||
%><%=GetUpdateStatement(parameter.ParameterType:GetElementType(), in_pos+param_offset, LocalName(parameter.Name))%>;
|
||||
<%end%>
|
||||
<%
|
||||
end
|
||||
end)
|
||||
end
|
||||
%>
|
||||
<%if NeedUpdate(type) and not method.IsStatic then%>
|
||||
<%=GetUpdateStatement(type, 1, "gen_to_be_invoked")%>;
|
||||
<%end%>
|
||||
|
||||
return <%=out_num+(has_return and 1 or 0)%>;
|
||||
}
|
||||
<% end)%>
|
||||
} catch(System.Exception gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
|
||||
}
|
||||
<%if method.Overloads.Count > 1 then%>
|
||||
return LuaAPI.luaL_error(L, "invalid arguments to <%=CsFullTypeName(type)%>.<%=method.Overloads[0].Name%>!");
|
||||
<%end%>
|
||||
}
|
||||
<% end)%>
|
||||
|
||||
|
||||
<%ForEachCsList(getters, function(getter)
|
||||
if getter.IsStatic and getter.ReadOnly then return end --readonly static
|
||||
%>
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
static int _g_get_<%=getter.Name%>(RealStatePtr L)
|
||||
{
|
||||
try {
|
||||
<%if AccessorNeedTranslator(getter) then %> ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);<%end%>
|
||||
<%if not getter.IsStatic then%>
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%=GetPushStatement(getter.Type, "gen_to_be_invoked."..UnK(getter.Name))%>;<% else %> <%=GetPushStatement(getter.Type, CsFullTypeName(type).."."..UnK(getter.Name))%>;<% end%>
|
||||
} catch(System.Exception gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
<%end)%>
|
||||
|
||||
<%ForEachCsList(setters, function(setter)
|
||||
local is_struct = IsStruct(setter.Type)
|
||||
%>
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
static int _s_set_<%=setter.Name%>(RealStatePtr L)
|
||||
{
|
||||
try {
|
||||
<%if AccessorNeedTranslator(setter) then %>ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);<%end%>
|
||||
<%if not setter.IsStatic then %>
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%if is_struct then %><%=GetCasterStatement(setter.Type, 2, "gen_value", true)%>;
|
||||
gen_to_be_invoked.<%=UnK(setter.Name)%> = gen_value;<% else
|
||||
%><%=GetCasterStatement(setter.Type, 2, "gen_to_be_invoked." .. UnK(setter.Name))%>;<%end
|
||||
else
|
||||
if is_struct then %><%=GetCasterStatement(setter.Type, 1, "gen_value", true)%>;
|
||||
<%=CsFullTypeName(type)%>.<%=UnK(setter.Name)%> = gen_value;<%else
|
||||
%> <%=GetCasterStatement(setter.Type, 1, CsFullTypeName(type) .."." .. UnK(setter.Name))%>;<%end
|
||||
end%>
|
||||
<%if NeedUpdate(type) and not setter.IsStatic then%>
|
||||
<%=GetUpdateStatement(type, 1, "gen_to_be_invoked")%>;
|
||||
<%end%>
|
||||
} catch(System.Exception gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
<%end)%>
|
||||
|
||||
<%ForEachCsList(events, function(event) if not event.IsStatic then %>
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
static int _e_<%=event.Name%>(RealStatePtr L)
|
||||
{
|
||||
try {
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
int gen_param_count = LuaAPI.lua_gettop(L);
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%=GetCasterStatement(event.Type, 3, "gen_delegate", true)%>;
|
||||
if (gen_delegate == null) {
|
||||
return LuaAPI.luaL_error(L, "#3 need <%=CsFullTypeName(event.Type)%>!");
|
||||
}
|
||||
|
||||
if (gen_param_count == 3)
|
||||
{
|
||||
<%if event.CanAdd then%>
|
||||
if (LuaAPI.xlua_is_eq_str(L, 2, "+")) {
|
||||
gen_to_be_invoked.<%=UnK(event.Name)%> += gen_delegate;
|
||||
return 0;
|
||||
}
|
||||
<%end%>
|
||||
<%if event.CanRemove then%>
|
||||
if (LuaAPI.xlua_is_eq_str(L, 2, "-")) {
|
||||
gen_to_be_invoked.<%=UnK(event.Name)%> -= gen_delegate;
|
||||
return 0;
|
||||
}
|
||||
<%end%>
|
||||
}
|
||||
} catch(System.Exception gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
|
||||
}
|
||||
LuaAPI.luaL_error(L, "invalid arguments to <%=CsFullTypeName(type)%>.<%=event.Name%>!");
|
||||
return 0;
|
||||
}
|
||||
<%end end)%>
|
||||
|
||||
<%ForEachCsList(events, function(event) if event.IsStatic then %>
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
static int _e_<%=event.Name%>(RealStatePtr L)
|
||||
{
|
||||
try {
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
int gen_param_count = LuaAPI.lua_gettop(L);
|
||||
<%=GetCasterStatement(event.Type, 2, "gen_delegate", true)%>;
|
||||
if (gen_delegate == null) {
|
||||
return LuaAPI.luaL_error(L, "#2 need <%=CsFullTypeName(event.Type)%>!");
|
||||
}
|
||||
|
||||
<%if event.CanAdd then%>
|
||||
if (gen_param_count == 2 && LuaAPI.xlua_is_eq_str(L, 1, "+")) {
|
||||
<%=CsFullTypeName(type)%>.<%=UnK(event.Name)%> += gen_delegate;
|
||||
return 0;
|
||||
}
|
||||
<%end%>
|
||||
<%if event.CanRemove then%>
|
||||
if (gen_param_count == 2 && LuaAPI.xlua_is_eq_str(L, 1, "-")) {
|
||||
<%=CsFullTypeName(type)%>.<%=UnK(event.Name)%> -= gen_delegate;
|
||||
return 0;
|
||||
}
|
||||
<%end%>
|
||||
} catch(System.Exception gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
|
||||
}
|
||||
return LuaAPI.luaL_error(L, "invalid arguments to <%=CsFullTypeName(type)%>.<%=event.Name%>!");
|
||||
}
|
||||
<%end end)%>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8503038eabbabe44dac0f5f749d4411a
|
||||
timeCreated: 1481620508
|
||||
licenseType: Pro
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,517 @@
|
||||
#if USE_UNI_LUA
|
||||
using LuaAPI = UniLua.Lua;
|
||||
using RealStatePtr = UniLua.ILuaState;
|
||||
using LuaCSFunction = UniLua.CSharpFunctionDelegate;
|
||||
#else
|
||||
using LuaAPI = XLua.LuaDLL.Lua;
|
||||
using RealStatePtr = System.IntPtr;
|
||||
using LuaCSFunction = XLuaBase.lua_CSFunction;
|
||||
#endif
|
||||
|
||||
using XLua;
|
||||
using System.Collections.Generic;
|
||||
<%ForEachCsList(namespaces, function(namespace)%>using <%=namespace%>;<%end)%>
|
||||
<%
|
||||
require "TemplateCommon"
|
||||
|
||||
local OpNameMap = {
|
||||
op_Addition = "__AddMeta",
|
||||
op_Subtraction = "__SubMeta",
|
||||
op_Multiply = "__MulMeta",
|
||||
op_Division = "__DivMeta",
|
||||
op_Equality = "__EqMeta",
|
||||
op_UnaryNegation = "__UnmMeta",
|
||||
op_LessThan = "__LTMeta",
|
||||
op_LessThanOrEqual = "__LEMeta",
|
||||
op_Modulus = "__ModMeta",
|
||||
op_BitwiseAnd = "__BandMeta",
|
||||
op_BitwiseOr = "__BorMeta",
|
||||
op_ExclusiveOr = "__BxorMeta",
|
||||
op_OnesComplement = "__BnotMeta",
|
||||
op_LeftShift = "__ShlMeta",
|
||||
op_RightShift = "__ShrMeta",
|
||||
}
|
||||
|
||||
local OpCallNameMap = {
|
||||
op_Addition = "+",
|
||||
op_Subtraction = "-",
|
||||
op_Multiply = "*",
|
||||
op_Division = "/",
|
||||
op_Equality = "==",
|
||||
op_UnaryNegation = "-",
|
||||
op_LessThan = "<",
|
||||
op_LessThanOrEqual = "<=",
|
||||
op_Modulus = "%",
|
||||
op_BitwiseAnd = "&",
|
||||
op_BitwiseOr = "|",
|
||||
op_ExclusiveOr = "^",
|
||||
op_OnesComplement = "~",
|
||||
op_LeftShift = "<<",
|
||||
op_RightShift = ">>",
|
||||
}
|
||||
|
||||
local obj_method_count = 0
|
||||
local obj_getter_count = 0
|
||||
local obj_setter_count = 0
|
||||
local meta_func_count = operators.Count
|
||||
local cls_field_count = 1
|
||||
local cls_getter_count = 0
|
||||
local cls_setter_count = 0
|
||||
|
||||
ForEachCsList(methods, function(method)
|
||||
if method.IsStatic then
|
||||
cls_field_count = cls_field_count + 1
|
||||
else
|
||||
obj_method_count = obj_method_count + 1
|
||||
end
|
||||
end)
|
||||
|
||||
ForEachCsList(events, function(event)
|
||||
if event.IsStatic then
|
||||
cls_field_count = cls_field_count + 1
|
||||
else
|
||||
obj_method_count = obj_method_count + 1
|
||||
end
|
||||
end)
|
||||
|
||||
ForEachCsList(getters, function(getter)
|
||||
if getter.IsStatic then
|
||||
if getter.ReadOnly then
|
||||
cls_field_count = cls_field_count + 1
|
||||
else
|
||||
cls_getter_count = cls_getter_count + 1
|
||||
end
|
||||
else
|
||||
obj_getter_count = obj_getter_count + 1
|
||||
end
|
||||
end)
|
||||
|
||||
ForEachCsList(setters, function(setter)
|
||||
if setter.IsStatic then
|
||||
cls_setter_count = cls_setter_count + 1
|
||||
else
|
||||
obj_setter_count = obj_setter_count + 1
|
||||
end
|
||||
end)
|
||||
|
||||
ForEachCsList(lazymembers, function(lazymember)
|
||||
if lazymember.IsStatic == 'true' then
|
||||
if 'CLS_IDX' == lazymember.Index then
|
||||
cls_field_count = cls_field_count + 1
|
||||
elseif 'CLS_GETTER_IDX' == lazymember.Index then
|
||||
cls_getter_count = cls_getter_count + 1
|
||||
elseif 'CLS_SETTER_IDX' == lazymember.Index then
|
||||
cls_setter_count = cls_setter_count + 1
|
||||
end
|
||||
else
|
||||
if 'METHOD_IDX' == lazymember.Index then
|
||||
obj_method_count = obj_method_count + 1
|
||||
elseif 'GETTER_IDX' == lazymember.Index then
|
||||
obj_getter_count = obj_getter_count + 1
|
||||
elseif 'SETTER_IDX' == lazymember.Index then
|
||||
obj_setter_count = obj_setter_count + 1
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local v_type_name = CSVariableName(type)
|
||||
local generic_arg_list, type_constraints = GenericArgumentList(type)
|
||||
|
||||
%>
|
||||
namespace XLua
|
||||
{
|
||||
public partial class ObjectTranslator
|
||||
{
|
||||
public void __Register<%=v_type_name%><%=generic_arg_list%>(RealStatePtr L) <%=type_constraints%>
|
||||
{
|
||||
System.Type type = typeof(<%=CsFullTypeName(type)%>);
|
||||
Utils.BeginObjectRegister(type, L, this, <%=meta_func_count%>, <%=obj_method_count%>, <%=obj_getter_count%>, <%=obj_setter_count%>);
|
||||
<%ForEachCsList(operators, function(operator)%>Utils.RegisterFunc(L, Utils.OBJ_META_IDX, "<%=(OpNameMap[operator.Name]):gsub('Meta', ''):lower()%>", <%=v_type_name%><%=OpNameMap[operator.Name]%><%=generic_arg_list%>);
|
||||
<%end)%>
|
||||
<%ForEachCsList(methods, function(method) if not method.IsStatic then %>Utils.RegisterFunc(L, Utils.METHOD_IDX, "<%=method.Name%>", <%=v_type_name%>_m_<%=method.Name%><%=generic_arg_list%>);
|
||||
<% end end)%>
|
||||
<%ForEachCsList(events, function(event) if not event.IsStatic then %>Utils.RegisterFunc(L, Utils.METHOD_IDX, "<%=event.Name%>", <%=v_type_name%>_e_<%=event.Name%><%=generic_arg_list%>);
|
||||
<% end end)%>
|
||||
<%ForEachCsList(getters, function(getter) if not getter.IsStatic then %>Utils.RegisterFunc(L, Utils.GETTER_IDX, "<%=getter.Name%>", <%=v_type_name%>_g_get_<%=getter.Name%><%=generic_arg_list%>);
|
||||
<%end end)%>
|
||||
<%ForEachCsList(setters, function(setter) if not setter.IsStatic then %>Utils.RegisterFunc(L, Utils.SETTER_IDX, "<%=setter.Name%>", <%=v_type_name%>_s_set_<%=setter.Name%><%=generic_arg_list%>);
|
||||
<%end end)%>
|
||||
<%ForEachCsList(lazymembers, function(lazymember) if lazymember.IsStatic == 'false' then %>Utils.RegisterLazyFunc(L, Utils.<%=lazymember.Index%>, "<%=lazymember.Name%>", type, <%=lazymember.MemberType%>, <%=lazymember.IsStatic%>);
|
||||
<%end end)%>
|
||||
Utils.EndObjectRegister(type, L, this, <% if type.IsArray or ((indexers.Count or 0) > 0) then %>__CSIndexer<%=v_type_name%><%=generic_arg_list%><%else%>null<%end%>, <%if type.IsArray or ((newindexers.Count or 0) > 0) then%>__NewIndexer<%=v_type_name%><%=generic_arg_list%><%else%>null<%end%>,
|
||||
null, null, null);
|
||||
|
||||
Utils.BeginClassRegister(type, L, __CreateInstance<%=v_type_name%><%=generic_arg_list%>, <%=cls_field_count%>, <%=cls_getter_count%>, <%=cls_setter_count%>);
|
||||
<%ForEachCsList(methods, function(method) if method.IsStatic then %>Utils.RegisterFunc(L, Utils.CLS_IDX, "<%=method.Overloads[0].Name%>", <%=v_type_name%>_m_<%=method.Name%><%=generic_arg_list%>);
|
||||
<% end end)%>
|
||||
<%ForEachCsList(events, function(event) if event.IsStatic then %>Utils.RegisterFunc(L, Utils.CLS_IDX, "<%=event.Name%>", <%=v_type_name%>_e_<%=event.Name%><%=generic_arg_list%>);
|
||||
<% end end)%>
|
||||
<%ForEachCsList(getters, function(getter) if getter.IsStatic and getter.ReadOnly then %>Utils.RegisterObject(L, this, Utils.CLS_IDX, "<%=getter.Name%>", <%=CsFullTypeName(type).."."..getter.Name%>);
|
||||
<%end end)%>
|
||||
<%ForEachCsList(getters, function(getter) if getter.IsStatic and (not getter.ReadOnly) then %>Utils.RegisterFunc(L, Utils.CLS_GETTER_IDX, "<%=getter.Name%>", <%=v_type_name%>_g_get_<%=getter.Name%><%=generic_arg_list%>);
|
||||
<%end end)%>
|
||||
<%ForEachCsList(setters, function(setter) if setter.IsStatic then %>Utils.RegisterFunc(L, Utils.CLS_SETTER_IDX, "<%=setter.Name%>", <%=v_type_name%>_s_set_<%=setter.Name%><%=generic_arg_list%>);
|
||||
<%end end)%>
|
||||
<%ForEachCsList(lazymembers, function(lazymember) if lazymember.IsStatic == 'true' then %>Utils.RegisterLazyFunc(L, Utils.<%=lazymember.Index%>, "<%=lazymember.Name%>", type, <%=lazymember.MemberType%>, <%=lazymember.IsStatic%>);
|
||||
<%end end)%>
|
||||
Utils.EndClassRegister(type, L, this);
|
||||
}
|
||||
|
||||
int __CreateInstance<%=v_type_name%><%=generic_arg_list%>(RealStatePtr L, int gen_param_count) <%=type_constraints%>
|
||||
{
|
||||
<%
|
||||
if constructors.Count == 0 and (not type.IsValueType) then
|
||||
%>return LuaAPI.luaL_error(L, "<%=CsFullTypeName(type)%> does not have a constructor!");<%
|
||||
else %>
|
||||
ObjectTranslator translator = this;
|
||||
<%
|
||||
local hasZeroParamsCtor = false
|
||||
ForEachCsList(constructors, function(constructor, ci)
|
||||
local parameters = constructor:GetParameters()
|
||||
if parameters.Length == 0 then
|
||||
hasZeroParamsCtor = true
|
||||
end
|
||||
local def_count = constructor_def_vals[ci]
|
||||
local param_count = parameters.Length
|
||||
local in_num = CalcCsList(parameters, function(p) return not (p.IsOut and p.ParameterType.IsByRef) end)
|
||||
local out_num = CalcCsList(parameters, function(p) return p.IsOut or p.ParameterType.IsByRef end)
|
||||
local real_param_count = param_count - def_count
|
||||
local has_v_params = param_count > 0 and IsParams(parameters[param_count - 1])
|
||||
local in_pos = 0
|
||||
%>if(gen_param_count <%=has_v_params and ">=" or "=="%> <%=in_num + 1 - def_count - (has_v_params and 1 or 0)%><%ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
local parameterType = parameter.ParameterType
|
||||
if has_v_params and pi == param_count - 1 then parameterType = parameterType:GetElementType() end
|
||||
if not (parameter.IsOut and parameter.ParameterType.IsByRef) then in_pos = in_pos + 1
|
||||
%> && <%=GetCheckStatement(parameterType, in_pos+1, has_v_params and pi == param_count - 1)%><%
|
||||
end
|
||||
end)%>)
|
||||
{
|
||||
<%ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
%><%=GetCasterStatement(parameter.ParameterType, pi+2, LocalName(parameter.Name), true, has_v_params and pi == param_count - 1)%>;
|
||||
<%end)%>
|
||||
var gen_ret = new <%=CsFullTypeName(type)%>(<%ForEachCsList(parameters, function(parameter, pi) if pi >= real_param_count then return end; if pi ~=0 then %><%=', '%><% end ;if parameter.IsOut and parameter.ParameterType.IsByRef then %>out <% elseif parameter.ParameterType.IsByRef and not parameter.IsIn then %>ref <% end %><%=LocalName(parameter.Name)%><% end)%>);
|
||||
<%=GetPushStatement(type, "gen_ret")%>;
|
||||
<%local in_pos = 0
|
||||
ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
if not (parameter.IsOut and parameter.ParameterType.IsByRef) then
|
||||
in_pos = in_pos + 1
|
||||
end
|
||||
if parameter.ParameterType.IsByRef then
|
||||
%><%=GetPushStatement(parameter.ParameterType:GetElementType(), LocalName(parameter.Name))%>;
|
||||
<%if not parameter.IsOut and parameter.ParameterType.IsByRef and NeedUpdate(parameter.ParameterType) then
|
||||
%><%=GetUpdateStatement(parameter.ParameterType:GetElementType(), in_pos+1, LocalName(parameter.Name))%>;
|
||||
<%end%>
|
||||
<%
|
||||
end
|
||||
end)
|
||||
%>
|
||||
return <%=out_num + 1%>;
|
||||
}
|
||||
<%end)
|
||||
if (not hasZeroParamsCtor) and type.IsValueType then
|
||||
%>
|
||||
if (gen_param_count == 1)
|
||||
{
|
||||
<%=GetPushStatement(type, "default(" .. CsFullTypeName(type).. ")")%>;
|
||||
return 1;
|
||||
}
|
||||
<%end%>
|
||||
|
||||
return LuaAPI.luaL_error(L, "invalid arguments to <%=CsFullTypeName(type)%> constructor!");
|
||||
<% end %>
|
||||
}
|
||||
|
||||
<% if type.IsArray or ((indexers.Count or 0) > 0) then %>
|
||||
int __CSIndexer<%=v_type_name%><%=generic_arg_list%>(RealStatePtr L, int gen_param_count) <%=type_constraints%>
|
||||
{
|
||||
<%if type.IsArray then %>
|
||||
ObjectTranslator translator = this;
|
||||
if (<%=GetCheckStatement(type, 1)%> && LuaAPI.lua_isnumber(L, 2))
|
||||
{
|
||||
int index = (int)LuaAPI.lua_tonumber(L, 2);
|
||||
<%=GetSelfStatement(type)%>;
|
||||
LuaAPI.lua_pushboolean(L, true);
|
||||
<%=GetPushStatement(type:GetElementType(), "gen_to_be_invoked[index]")%>;
|
||||
return 2;
|
||||
}
|
||||
<%elseif indexers.Count > 0 then
|
||||
%>ObjectTranslator translator = this;
|
||||
<%
|
||||
ForEachCsList(indexers, function(indexer)
|
||||
local paramter = indexer:GetParameters()[0]
|
||||
%>
|
||||
if (<%=GetCheckStatement(type, 1)%> && <%=GetCheckStatement(paramter.ParameterType, 2)%>)
|
||||
{
|
||||
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%=GetCasterStatement(paramter.ParameterType, 2, "index", true)%>;
|
||||
LuaAPI.lua_pushboolean(L, true);
|
||||
<%=GetPushStatement(indexer.ReturnType, "gen_to_be_invoked[index]")%>;
|
||||
return 2;
|
||||
}
|
||||
<%end)
|
||||
end%>
|
||||
LuaAPI.lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
<% end %>
|
||||
|
||||
<%if type.IsArray or ((newindexers.Count or 0) > 0) then%>
|
||||
int __NewIndexer<%=v_type_name%><%=generic_arg_list%>(RealStatePtr L, int gen_param_count) <%=type_constraints%>
|
||||
{
|
||||
<%if type.IsArray or newindexers.Count > 0 then %>ObjectTranslator translator = this;<%end%>
|
||||
<%if type.IsArray then
|
||||
local elementType = type:GetElementType()
|
||||
%>
|
||||
if (<%=GetCheckStatement(type, 1)%> && LuaAPI.lua_isnumber(L, 2) && <%=GetCheckStatement(elementType, 3)%>)
|
||||
{
|
||||
int index = (int)LuaAPI.lua_tonumber(L, 2);
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%=GetCasterStatement(elementType, 3, "gen_to_be_invoked[index]")%>;
|
||||
LuaAPI.lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
<%elseif newindexers.Count > 0 then%>
|
||||
<%ForEachCsList(newindexers, function(newindexer)
|
||||
local keyType = newindexer:GetParameters()[0].ParameterType
|
||||
local valueType = newindexer:GetParameters()[1].ParameterType
|
||||
%>
|
||||
if (<%=GetCheckStatement(type, 1)%> && <%=GetCheckStatement(keyType, 2)%> && <%=GetCheckStatement(valueType, 3)%>)
|
||||
{
|
||||
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%=GetCasterStatement(keyType, 2, "key", true)%>;
|
||||
<%if IsStruct(valueType) then%><%=GetCasterStatement(valueType, 3, "gen_value", true)%>;
|
||||
gen_to_be_invoked[key] = gen_value;<%else
|
||||
%><%=GetCasterStatement(valueType, 3, "gen_to_be_invoked[key]")%>;<%end%>
|
||||
LuaAPI.lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
<%end)
|
||||
end%>
|
||||
LuaAPI.lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
<% end %>
|
||||
|
||||
<%ForEachCsList(operators, function(operator) %>
|
||||
int <%=v_type_name%><%=OpNameMap[operator.Name]%><%=generic_arg_list%>(RealStatePtr L, int gen_param_count) <%=type_constraints%>
|
||||
{
|
||||
ObjectTranslator translator = this;
|
||||
<% if operator.Name ~= "op_UnaryNegation" and operator.Name ~= "op_OnesComplement" then
|
||||
ForEachCsList(operator.Overloads, function(overload)
|
||||
local left_param = overload:GetParameters()[0]
|
||||
local right_param = overload:GetParameters()[1]
|
||||
%>
|
||||
if (<%=GetCheckStatement(left_param.ParameterType, 1)%> && <%=GetCheckStatement(right_param.ParameterType, 2)%>)
|
||||
{
|
||||
<%=GetCasterStatement(left_param.ParameterType, 1, "leftside", true)%>;
|
||||
<%=GetCasterStatement(right_param.ParameterType, 2, "rightside", true)%>;
|
||||
|
||||
<%=GetPushStatement(overload.ReturnType, "leftside " .. OpCallNameMap[operator.Name] .. " rightside")%>;
|
||||
|
||||
return 1;
|
||||
}
|
||||
<%end)%>
|
||||
return LuaAPI.luaL_error(L, "invalid arguments to right hand of <%=OpCallNameMap[operator.Name]%> operator, need <%=CsFullTypeName(type)%>!");
|
||||
<%else%>
|
||||
<%=GetCasterStatement(type, 1, "rightside", true)%>;
|
||||
<%=GetPushStatement(operator.Overloads[0].ReturnType, OpCallNameMap[operator.Name] .. " rightside")%>;
|
||||
return 1;
|
||||
<%end%>
|
||||
}
|
||||
<%end)%>
|
||||
|
||||
<%ForEachCsList(methods, function(method)%>
|
||||
int <%=v_type_name%>_m_<%=method.Name%><%=generic_arg_list%>(RealStatePtr L, int gen_param_count) <%=type_constraints%>
|
||||
{
|
||||
<%
|
||||
local need_obj = not method.IsStatic
|
||||
if MethodCallNeedTranslator(method) then
|
||||
%>
|
||||
ObjectTranslator translator = this;
|
||||
<%end%>
|
||||
<%if need_obj then%>
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%end%>
|
||||
<%ForEachCsList(method.Overloads, function(overload, oi)
|
||||
local parameters = MethodParameters(overload)
|
||||
local in_num = CalcCsList(parameters, function(p) return not (p.IsOut and p.ParameterType.IsByRef) end)
|
||||
local param_offset = method.IsStatic and 0 or 1
|
||||
local out_num = CalcCsList(parameters, function(p) return p.IsOut or p.ParameterType.IsByRef end)
|
||||
local in_pos = 0
|
||||
local has_return = (overload.ReturnType.FullName ~= "System.Void")
|
||||
local def_count = method.DefaultValues[oi]
|
||||
local param_count = parameters.Length
|
||||
local real_param_count = param_count - def_count
|
||||
local has_v_params = param_count > 0 and IsParams(parameters[param_count - 1])
|
||||
if method.Overloads.Count > 1 then
|
||||
%>if(gen_param_count <%=has_v_params and ">=" or "=="%> <%=in_num+param_offset-def_count - (has_v_params and 1 or 0)%><%
|
||||
ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
local parameterType = parameter.ParameterType
|
||||
if has_v_params and pi == param_count - 1 then parameterType = parameterType:GetElementType() end
|
||||
if not (parameter.IsOut and parameter.ParameterType.IsByRef) then in_pos = in_pos + 1;
|
||||
%>&& <%=GetCheckStatement(parameterType , in_pos+param_offset, has_v_params and pi == param_count - 1)%><%
|
||||
end
|
||||
end)%>) <%end%>
|
||||
{
|
||||
<%if overload.Name == "get_Item" and overload.IsSpecialName then
|
||||
local keyType = overload:GetParameters()[0].ParameterType%>
|
||||
<%=GetCasterStatement(keyType, 2, "key", true)%>;
|
||||
<%=GetPushStatement(overload.ReturnType, "gen_to_be_invoked[key]")%>;
|
||||
<%elseif overload.Name == "set_Item" and overload.IsSpecialName then
|
||||
local keyType = overload:GetParameters()[0].ParameterType
|
||||
local valueType = overload:GetParameters()[1].ParameterType%>
|
||||
<%=GetCasterStatement(keyType, 2, "key", true)%>;
|
||||
<%=GetCasterStatement(valueType, 3, "gen_to_be_invoked[key]")%>;
|
||||
<% else
|
||||
in_pos = 0;
|
||||
ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
%><%if not (parameter.IsOut and parameter.ParameterType.IsByRef) then
|
||||
in_pos = in_pos + 1
|
||||
%><%=GetCasterStatement(parameter.ParameterType, in_pos+param_offset, LocalName(parameter.Name), true, has_v_params and pi == param_count - 1)%><%
|
||||
else%><%=CsFullTypeName(parameter.ParameterType)%> <%=LocalName(parameter.Name)%><%end%>;
|
||||
<%end)%>
|
||||
<%
|
||||
if has_return then
|
||||
%>var gen_ret = <%
|
||||
end
|
||||
%><%if method.IsStatic then
|
||||
%><%=CsFullTypeName(type).."."..UnK(overload.Name)%><%
|
||||
else
|
||||
%>gen_to_be_invoked.<%=UnK(overload.Name)%><%
|
||||
end%>( <%ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
if pi ~= 0 then %>, <% end; if parameter.IsOut and parameter.ParameterType.IsByRef then %>out <% elseif parameter.ParameterType.IsByRef and not parameter.IsIn then %>ref <% end %><%=LocalName(parameter.Name)%><% end) %> );
|
||||
<%
|
||||
if has_return then
|
||||
%><%=GetPushStatement(overload.ReturnType, "gen_ret")%>;
|
||||
<%
|
||||
end
|
||||
local in_pos = 0
|
||||
ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi >= real_param_count then return end
|
||||
if not (parameter.IsOut and parameter.ParameterType.IsByRef) then
|
||||
in_pos = in_pos + 1
|
||||
end
|
||||
if parameter.ParameterType.IsByRef then
|
||||
%><%=GetPushStatement(parameter.ParameterType:GetElementType(), LocalName(parameter.Name))%>;
|
||||
<%if not parameter.IsOut and parameter.ParameterType.IsByRef and NeedUpdate(parameter.ParameterType) then
|
||||
%><%=GetUpdateStatement(parameter.ParameterType:GetElementType(), in_pos+param_offset, LocalName(parameter.Name))%>;
|
||||
<%end%>
|
||||
<%
|
||||
end
|
||||
end)
|
||||
end
|
||||
%>
|
||||
<%if NeedUpdate(type) and not method.IsStatic then%>
|
||||
<%=GetUpdateStatement(type, 1, "gen_to_be_invoked")%>;
|
||||
<%end%>
|
||||
|
||||
return <%=out_num+(has_return and 1 or 0)%>;
|
||||
}
|
||||
<% end)%>
|
||||
<%if method.Overloads.Count > 1 then%>
|
||||
return LuaAPI.luaL_error(L, "invalid arguments to <%=CsFullTypeName(type)%>.<%=method.Overloads[0].Name%>!");
|
||||
<%end%>
|
||||
}
|
||||
<% end)%>
|
||||
|
||||
|
||||
<%ForEachCsList(getters, function(getter)
|
||||
if getter.IsStatic and getter.ReadOnly then return end --readonly static
|
||||
%>
|
||||
int <%=v_type_name%>_g_get_<%=getter.Name%><%=generic_arg_list%>(RealStatePtr L, int gen_param_count) <%=type_constraints%>
|
||||
{
|
||||
<%if AccessorNeedTranslator(getter) then %>ObjectTranslator translator = this;<%end%>
|
||||
<%if not getter.IsStatic then%>
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%=GetPushStatement(getter.Type, "gen_to_be_invoked."..UnK(getter.Name))%>;<% else %> <%=GetPushStatement(getter.Type, CsFullTypeName(type).."."..UnK(getter.Name))%>;<% end%>
|
||||
return 1;
|
||||
}
|
||||
<%end)%>
|
||||
|
||||
<%ForEachCsList(setters, function(setter)
|
||||
local is_struct = IsStruct(setter.Type)
|
||||
%>
|
||||
int <%=v_type_name%>_s_set_<%=setter.Name%><%=generic_arg_list%>(RealStatePtr L, int gen_param_count) <%=type_constraints%>
|
||||
{
|
||||
<%if AccessorNeedTranslator(setter) then %>ObjectTranslator translator = this;<%end%>
|
||||
<%if not setter.IsStatic then %>
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%if is_struct then %><%=GetCasterStatement(setter.Type, 2, "gen_value", true)%>;
|
||||
gen_to_be_invoked.<%=UnK(setter.Name)%> = gen_value;<% else
|
||||
%><%=GetCasterStatement(setter.Type, 2, "gen_to_be_invoked." .. UnK(setter.Name))%>;<%end
|
||||
else
|
||||
if is_struct then %><%=GetCasterStatement(setter.Type, 1, "gen_value", true)%>;
|
||||
<%=CsFullTypeName(type)%>.<%=UnK(setter.Name)%> = gen_value;<%else
|
||||
%><%=GetCasterStatement(setter.Type, 1, CsFullTypeName(type) .."." .. UnK(setter.Name))%>;<%end
|
||||
end%>
|
||||
<%if NeedUpdate(type) and not setter.IsStatic then%>
|
||||
<%=GetUpdateStatement(type, 1, "gen_to_be_invoked")%>;
|
||||
<%end%>
|
||||
return 0;
|
||||
}
|
||||
<%end)%>
|
||||
|
||||
<%ForEachCsList(events, function(event) if not event.IsStatic then %>
|
||||
int <%=v_type_name%>_e_<%=event.Name%><%=generic_arg_list%>(RealStatePtr L, int gen_param_count) <%=type_constraints%>
|
||||
{
|
||||
ObjectTranslator translator = this;
|
||||
<%=GetSelfStatement(type)%>;
|
||||
<%=GetCasterStatement(event.Type, 3, "gen_delegate", true)%>;
|
||||
if (gen_delegate == null) {
|
||||
return LuaAPI.luaL_error(L, "#3 need <%=CsFullTypeName(event.Type)%>!");
|
||||
}
|
||||
|
||||
if (gen_param_count == 3)
|
||||
{
|
||||
<%if event.CanAdd then%>
|
||||
if (LuaAPI.xlua_is_eq_str(L, 2, "+")) {
|
||||
gen_to_be_invoked.<%=UnK(event.Name)%> += gen_delegate;
|
||||
return 0;
|
||||
}
|
||||
<%end%>
|
||||
<%if event.CanRemove then%>
|
||||
if (LuaAPI.xlua_is_eq_str(L, 2, "-")) {
|
||||
gen_to_be_invoked.<%=UnK(event.Name)%> -= gen_delegate;
|
||||
return 0;
|
||||
}
|
||||
<%end%>
|
||||
}
|
||||
LuaAPI.luaL_error(L, "invalid arguments to <%=CsFullTypeName(type)%>.<%=event.Name%>!");
|
||||
return 0;
|
||||
}
|
||||
<%end end)%>
|
||||
|
||||
<%ForEachCsList(events, function(event) if event.IsStatic then %>
|
||||
int <%=v_type_name%>_e_<%=event.Name%><%=generic_arg_list%>(RealStatePtr L, int gen_param_count) <%=type_constraints%>
|
||||
{
|
||||
ObjectTranslator translator = this;
|
||||
<%=GetCasterStatement(event.Type, 2, "gen_delegate", true)%>;
|
||||
if (gen_delegate == null) {
|
||||
return LuaAPI.luaL_error(L, "#2 need <%=CsFullTypeName(event.Type)%>!");
|
||||
}
|
||||
|
||||
<%if event.CanAdd then%>
|
||||
if (gen_param_count == 2 && LuaAPI.xlua_is_eq_str(L, 1, "+")) {
|
||||
<%=CsFullTypeName(type)%>.<%=UnK(event.Name)%> += gen_delegate;
|
||||
return 0;
|
||||
}
|
||||
<%end%>
|
||||
<%if event.CanRemove then%>
|
||||
if (gen_param_count == 2 && LuaAPI.xlua_is_eq_str(L, 1, "-")) {
|
||||
<%=CsFullTypeName(type)%>.<%=UnK(event.Name)%> -= gen_delegate;
|
||||
return 0;
|
||||
}
|
||||
<%end%>
|
||||
return LuaAPI.luaL_error(L, "invalid arguments to <%=CsFullTypeName(type)%>.<%=event.Name%>!");
|
||||
}
|
||||
<%end end)%>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2bd79d95fd859724283926ad8fa4df30
|
||||
timeCreated: 1501232428
|
||||
licenseType: Pro
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,104 @@
|
||||
#if USE_UNI_LUA
|
||||
using LuaAPI = UniLua.Lua;
|
||||
using RealStatePtr = UniLua.ILuaState;
|
||||
using LuaCSFunction = UniLua.CSharpFunctionDelegate;
|
||||
#else
|
||||
using LuaAPI = XLua.LuaDLL.Lua;
|
||||
using RealStatePtr = System.IntPtr;
|
||||
using LuaCSFunction = XLuaBase.lua_CSFunction;
|
||||
#endif
|
||||
|
||||
using System;
|
||||
<%
|
||||
require "TemplateCommon"
|
||||
%>
|
||||
|
||||
namespace XLua
|
||||
{
|
||||
public partial class DelegateBridge : DelegateBridgeBase
|
||||
{
|
||||
<%
|
||||
ForEachCsList(delegates_groups, function(delegates_group, group_idx)
|
||||
local delegate = delegates_group.Key
|
||||
local parameters = delegate:GetParameters()
|
||||
local in_num = CalcCsList(parameters, function(p) return not (p.IsOut and p.ParameterType.IsByRef) end)
|
||||
local out_num = CalcCsList(parameters, function(p) return p.IsOut or p.ParameterType.IsByRef end)
|
||||
local in_pos = 0
|
||||
local has_return = (delegate.ReturnType.FullName ~= "System.Void")
|
||||
local return_type_name = has_return and CsFullTypeName(delegate.ReturnType) or "void"
|
||||
local out_idx = has_return and 2 or 1
|
||||
if has_return then out_num = out_num + 1 end
|
||||
%>
|
||||
public <%=return_type_name%> __Gen_Delegate_Imp<%=group_idx%>(<%ForEachCsList(parameters, function(parameter, pi)
|
||||
if pi ~= 0 then
|
||||
%>, <%
|
||||
end
|
||||
if parameter.IsOut and parameter.ParameterType.IsByRef then
|
||||
%>out <%
|
||||
elseif parameter.ParameterType.IsByRef then
|
||||
%>ref <%
|
||||
end
|
||||
%><%=CsFullTypeName(parameter.ParameterType)%> p<%=pi%><%
|
||||
end) %>)
|
||||
{
|
||||
#if THREAD_SAFE || HOTFIX_ENABLE
|
||||
lock (luaEnv.luaEnvLock)
|
||||
{
|
||||
#endif
|
||||
RealStatePtr L = luaEnv.rawL;
|
||||
int errFunc = LuaAPI.pcall_prepare(L, errorFuncRef, luaReference);
|
||||
<%if CallNeedTranslator(delegate, "") then %>ObjectTranslator translator = luaEnv.translator;<%end%>
|
||||
<%
|
||||
local param_count = parameters.Length
|
||||
local has_v_params = param_count > 0 and parameters[param_count - 1].IsParamArray
|
||||
ForEachCsList(parameters, function(parameter, pi)
|
||||
if not (parameter.IsOut and parameter.ParameterType.IsByRef) then
|
||||
%><%=GetPushStatement(parameter.ParameterType, 'p' .. pi, has_v_params and pi == param_count - 1)%>;
|
||||
<%
|
||||
end
|
||||
end) %>
|
||||
PCall(L, <%=has_v_params and ((in_num - 1) .. " + (p".. (param_count - 1) .. " == null ? 0 : p" .. (param_count - 1) .. ".Length)" ) or in_num%>, <%=out_num%>, errFunc);
|
||||
|
||||
<%ForEachCsList(parameters, function(parameter, pi)
|
||||
if parameter.IsOut or parameter.ParameterType.IsByRef then
|
||||
%><%=GetCasterStatement(parameter.ParameterType, "errFunc" .. (" + "..out_idx), 'p' .. pi)%>;
|
||||
<%
|
||||
out_idx = out_idx + 1
|
||||
end
|
||||
end) %>
|
||||
<%if has_return then %><%=GetCasterStatement(delegate.ReturnType, "errFunc + 1", "__gen_ret", true)%>;<% end%>
|
||||
LuaAPI.lua_settop(L, errFunc - 1);
|
||||
<%if has_return then %>return __gen_ret;<% end%>
|
||||
#if THREAD_SAFE || HOTFIX_ENABLE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
<%end)%>
|
||||
|
||||
static DelegateBridge()
|
||||
{
|
||||
Gen_Flag = true;
|
||||
}
|
||||
|
||||
public override Delegate GetDelegateByType(Type type)
|
||||
{
|
||||
<%
|
||||
ForEachCsList(delegates_groups, function(delegates_group, group_idx)
|
||||
ForEachCsList(delegates_group.Value, function(delegate)
|
||||
if delegate.DeclaringType then
|
||||
local delegate_type_name = CsFullTypeName(delegate.DeclaringType)
|
||||
%>
|
||||
if (type == typeof(<%=delegate_type_name%>))
|
||||
{
|
||||
return new <%=delegate_type_name%>(__Gen_Delegate_Imp<%=group_idx%>);
|
||||
}
|
||||
<%
|
||||
end
|
||||
end)
|
||||
end)
|
||||
%>
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d992756e2469044484be75f78e4e556
|
||||
timeCreated: 1481620508
|
||||
licenseType: Pro
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,128 @@
|
||||
#if USE_UNI_LUA
|
||||
using LuaAPI = UniLua.Lua;
|
||||
using RealStatePtr = UniLua.ILuaState;
|
||||
using LuaCSFunction = UniLua.CSharpFunctionDelegate;
|
||||
#else
|
||||
using LuaAPI = XLua.LuaDLL.Lua;
|
||||
using RealStatePtr = System.IntPtr;
|
||||
using LuaCSFunction = XLuaBase.lua_CSFunction;
|
||||
#endif
|
||||
|
||||
using XLua;
|
||||
using System.Collections.Generic;
|
||||
<%
|
||||
require "TemplateCommon"
|
||||
|
||||
local parameters = delegate:GetParameters()
|
||||
local in_num = CalcCsList(parameters, function(p) return not (p.IsOut and p.ParameterType.IsByRef) end)
|
||||
local out_num = CalcCsList(parameters, function(p) return p.IsOut or p.ParameterType.IsByRef end)
|
||||
local in_pos = 0
|
||||
local has_return = (delegate.ReturnType.Name ~= "Void")
|
||||
%>
|
||||
|
||||
namespace XLua.CSObjectWrap
|
||||
{
|
||||
using Utils = XLua.Utils;
|
||||
public class <%=CSVariableName(type)%>Wrap
|
||||
{
|
||||
public static void __Register(RealStatePtr L)
|
||||
{
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
Utils.BeginObjectRegister(typeof(<%=CsFullTypeName(type)%>), L, translator, 0, 0, 0, 0);
|
||||
Utils.EndObjectRegister(typeof(<%=CsFullTypeName(type)%>), L, translator, null, null, null, null, null);
|
||||
|
||||
Utils.BeginClassRegister(typeof(<%=CsFullTypeName(type)%>), L, null, 1, 0, 0);
|
||||
Utils.EndClassRegister(typeof(<%=CsFullTypeName(type)%>), L, translator);
|
||||
}
|
||||
|
||||
static Dictionary<string, LuaCSFunction> __MetaFucntions_Dic = new Dictionary<string, LuaCSFunction>(){
|
||||
{"__call", __CallMeta},
|
||||
{"__add", __AddMeta},
|
||||
{"__sub", __SubMeta},
|
||||
};
|
||||
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
static int __CallMeta(RealStatePtr L)
|
||||
{
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
try {
|
||||
if(LuaAPI.lua_gettop(L) == <%=in_num+1%> && <%=GetCheckStatement(type, 1)%><%
|
||||
ForEachCsList(parameters, function(parameter)
|
||||
if not (parameter.IsOut and parameter.ParameterType.IsByRef) then in_pos = in_pos + 1;
|
||||
%>&& <%=GetCheckStatement(parameter.ParameterType, in_pos+1)%><%
|
||||
end
|
||||
end)%>)
|
||||
{
|
||||
<%
|
||||
in_pos = 0;
|
||||
ForEachCsList(parameters, function(parameter)
|
||||
%><%
|
||||
if not (parameter.IsOut and parameter.ParameterType.IsByRef) then
|
||||
in_pos = in_pos + 1
|
||||
%><%=GetCasterStatement(parameter.ParameterType, in_pos+1, parameter.Name, true)%><%
|
||||
else%><%=CsFullTypeName(parameter.ParameterType)%> <%=parameter.Name%><%end%>;
|
||||
<%end)%>
|
||||
<%=GetSelfStatement(type)%>;
|
||||
|
||||
<%
|
||||
if has_return then
|
||||
%> var __cl_gen_ret = <%
|
||||
end
|
||||
%> __cl_gen_to_be_invoked( <%ForEachCsList(parameters, function(parameter, pi) if pi ~= 0 then %>, <% end; if parameter.IsOut then %>out <% elseif parameter.ParameterType.IsByRef then %>ref <% end %><%=parameter.Name%><% end) %> );
|
||||
<%
|
||||
if has_return then
|
||||
%> <%=GetPushStatement(delegate.ReturnType, "__cl_gen_ret")%>;
|
||||
<%
|
||||
end
|
||||
local in_pos = 0
|
||||
ForEachCsList(parameters, function(parameter)
|
||||
if not (parameter.IsOut and parameter.ParameterType.IsByRef) then
|
||||
in_pos = in_pos + 1
|
||||
end
|
||||
if parameter.IsOut or parameter.ParameterType.IsByRef then
|
||||
%><%=GetPushStatement(parameter.ParameterType:GetElementType(), parameter.Name)%>;
|
||||
<%if not parameter.IsOut and parameter.ParameterType.IsByRef and NeedUpdate(parameter.ParameterType) then
|
||||
%><%=GetUpdateStatement(parameter.ParameterType:GetElementType(), in_pos+param_offset, parameter.Name)%>;
|
||||
<%end%>
|
||||
<%
|
||||
end
|
||||
end)
|
||||
%>
|
||||
|
||||
return <%=out_num+(has_return and 1 or 0)%>;
|
||||
}
|
||||
} catch(System.Exception __gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + __gen_e);
|
||||
}
|
||||
return LuaAPI.luaL_error(L, "invalid arguments to Delegate <%=CsFullTypeName(type)%>!");
|
||||
}
|
||||
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
static int __AddMeta(RealStatePtr L)
|
||||
{
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
try {
|
||||
<%=GetCasterStatement(type, 1, "leftside", true)%>;
|
||||
<%=GetCasterStatement(type, 2, "rightside", true)%>;
|
||||
<%=GetPushStatement(type, "leftside + rightside")%>;
|
||||
return 1;
|
||||
} catch(System.Exception __gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + __gen_e);
|
||||
}
|
||||
}
|
||||
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
static int __SubMeta(RealStatePtr L)
|
||||
{
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
try {
|
||||
<%=GetCasterStatement(type, 1, "leftside", true)%>;
|
||||
<%=GetCasterStatement(type, 2, "rightside", true)%>;
|
||||
<%=GetPushStatement(type, "leftside - rightside")%>;
|
||||
return 1;
|
||||
} catch(System.Exception __gen_e) {
|
||||
return LuaAPI.luaL_error(L, "c# exception:" + __gen_e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33b33e1cd617f794b8c801a32f3b2539
|
||||
timeCreated: 1481620508
|
||||
licenseType: Pro
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,102 @@
|
||||
#if USE_UNI_LUA
|
||||
using LuaAPI = UniLua.Lua;
|
||||
using RealStatePtr = UniLua.ILuaState;
|
||||
using LuaCSFunction = UniLua.CSharpFunctionDelegate;
|
||||
#else
|
||||
using LuaAPI = XLua.LuaDLL.Lua;
|
||||
using RealStatePtr = System.IntPtr;
|
||||
using LuaCSFunction = XLuaBase.lua_CSFunction;
|
||||
#endif
|
||||
|
||||
using XLua;
|
||||
using System.Collections.Generic;
|
||||
<%
|
||||
require "TemplateCommon"
|
||||
local enum_or_op = debug.getmetatable(CS.System.Reflection.BindingFlags.Public).__bor
|
||||
%>
|
||||
|
||||
namespace XLua.CSObjectWrap
|
||||
{
|
||||
using Utils = XLua.Utils;
|
||||
<%ForEachCsList(types, function(type)
|
||||
local fields = type2fields and type2fields[type] or type:GetFields(enum_or_op(CS.System.Reflection.BindingFlags.Public, CS.System.Reflection.BindingFlags.Static))
|
||||
local fields_to_gen = {}
|
||||
ForEachCsList(fields, function(field)
|
||||
if field.Name ~= "value__" and not IsObsolute(field) then
|
||||
table.insert(fields_to_gen, field)
|
||||
end
|
||||
end)
|
||||
%>
|
||||
public class <%=CSVariableName(type)%>Wrap
|
||||
{
|
||||
public static void __Register(RealStatePtr L)
|
||||
{
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
Utils.BeginObjectRegister(typeof(<%=CsFullTypeName(type)%>), L, translator, 0, 0, 0, 0);
|
||||
Utils.EndObjectRegister(typeof(<%=CsFullTypeName(type)%>), L, translator, null, null, null, null, null);
|
||||
|
||||
Utils.BeginClassRegister(typeof(<%=CsFullTypeName(type)%>), L, null, <%=fields.Length + 1%>, 0, 0);
|
||||
<%if #fields_to_gen <= 20 then%>
|
||||
<% ForEachCsList(fields, function(field)
|
||||
if field.Name == "value__" or IsObsolute(field) then return end
|
||||
%>
|
||||
Utils.RegisterObject(L, translator, Utils.CLS_IDX, "<%=field.Name%>", <%=CsFullTypeName(type)%>.<%=UnK(field.Name)%>);
|
||||
<%end)%>
|
||||
<%else%>
|
||||
Utils.RegisterEnumType(L, typeof(<%=CsFullTypeName(type)%>));
|
||||
<%end%>
|
||||
Utils.RegisterFunc(L, Utils.CLS_IDX, "__CastFrom", __CastFrom);
|
||||
|
||||
Utils.EndClassRegister(typeof(<%=CsFullTypeName(type)%>), L, translator);
|
||||
}
|
||||
|
||||
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
|
||||
static int __CastFrom(RealStatePtr L)
|
||||
{
|
||||
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
|
||||
LuaTypes lua_type = LuaAPI.lua_type(L, 1);
|
||||
if (lua_type == LuaTypes.LUA_TNUMBER)
|
||||
{
|
||||
translator.Push<%=CSVariableName(type)%>(L, (<%=CsFullTypeName(type)%>)LuaAPI.xlua_tointeger(L, 1));
|
||||
}
|
||||
<%if #fields_to_gen > 0 then%>
|
||||
else if(lua_type == LuaTypes.LUA_TSTRING)
|
||||
{
|
||||
<%if #fields_to_gen <= 20 then%>
|
||||
<%
|
||||
local is_first = true
|
||||
ForEachCsList(fields, function(field, i)
|
||||
if field.Name == "value__" or IsObsolute(field) then return end
|
||||
%><%=(is_first and "" or "else ")%>if (LuaAPI.xlua_is_eq_str(L, 1, "<%=field.Name%>"))
|
||||
{
|
||||
translator.Push<%=CSVariableName(type)%>(L, <%=CsFullTypeName(type)%>.<%=UnK(field.Name)%>);
|
||||
}
|
||||
<%
|
||||
is_first = false
|
||||
end)
|
||||
%>else
|
||||
{
|
||||
return LuaAPI.luaL_error(L, "invalid string for <%=CsFullTypeName(type)%>!");
|
||||
}
|
||||
<%else%>
|
||||
try
|
||||
{
|
||||
translator.TranslateToEnumToTop(L, typeof(<%=CsFullTypeName(type)%>), 1);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
return LuaAPI.luaL_error(L, "cast to " + typeof(<%=CsFullTypeName(type)%>) + " exception:" + e);
|
||||
}
|
||||
<%end%>
|
||||
}
|
||||
<%end%>
|
||||
else
|
||||
{
|
||||
return LuaAPI.luaL_error(L, "invalid lua type for <%=CsFullTypeName(type)%>! Expect number or string, got + " + lua_type);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
<%end)%>
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user