Compare commits

...

12 Commits

45 changed files with 3037 additions and 399 deletions

View File

@ -0,0 +1,42 @@
#if UNITY_EDITOR
using System.IO;
using UnityEditor;
using UnityEngine;
public class AxiProjectTools_AssetsAutoSetting : EditorWindow
{
[MenuItem("Axibug移植工具/AssetsAutoSetting/自动设置TextureMaxSize为图片大小1倍")]
public static void AutoSettTextureSize_1x() { SetTextureSite(1f); }
[MenuItem("Axibug移植工具/AssetsAutoSetting/自动设置TextureMaxSize为图片大小2分之1倍")]
public static void AutoSettTextureSize_1_2x() { SetTextureSite(1f / 2f); }
[MenuItem("Axibug移植工具/AssetsAutoSetting/自动设置TextureMaxSize为图片大小4分之1倍")]
public static void AutoSettTextureSize_1_4x() { SetTextureSite(1f / 4f); }
public static void SetTextureSite(float Scale)
{
Texture2D[] textures = Selection.GetFiltered<Texture2D>(SelectionMode.DeepAssets);
if (textures.Length == 0)
{
Debug.LogWarning("请先选择目录或者Texture资源");
return;
}
AssetDatabase.StartAssetEditing(); // 开启批量编辑模式
foreach (var texture in textures)
{
string path = AssetDatabase.GetAssetPath(texture);
TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;
if (importer != null)
{
int size = Mathf.Max(texture.width, texture.height);
int maxsize = Mathf.ClosestPowerOfTwo((int)(size * Scale)); // Unity内置方法适配2的幂次方
importer.maxTextureSize = maxsize;
importer.SaveAndReimport();
}
}
AssetDatabase.StopAssetEditing(); // 结束批量编辑
Debug.Log($"Updated {textures.Length} textures.");
}
}
#endif

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: dc0741a79e74f96449a260406f239066

View File

@ -0,0 +1,840 @@
#if UNITY_EDITOR && UNITY_2020_1_OR_NEWER
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;
public class AxiProjectToolsStatistics : EditorWindow
{
static string cachecfgPath = "Assets/AxiStatisticsDatas.asset";
static Dictionary<string, AxiStatisticsDatas> dictTempData = new Dictionary<string, AxiStatisticsDatas>();
static void ClearTempData()
{
dictTempData.Clear();
}
static string GetRootTempKey(int type, string rootName)
{
return type + "_" + rootName;
}
// 添加Hierarchy右键菜单项
[MenuItem("GameObject/AxiStatistics/GetAxiNodeHash", false, 10)]
public static void GetAxiNodeHash()
{
// 获取当前右键选中的Transform
Transform selectedTransform = Selection.activeTransform;
if (selectedTransform != null)
{
Debug.Log("选中的对象"+selectedTransform.name+",Hash=>"+ GetNodeDataHash(selectedTransform,true));
}
}
static int GetNodeDataHash(Transform trans,bool bLog = false)
{
long hashplus = 0;
hashplus += trans.position.GetHashCode();
hashplus += trans.localPosition.GetHashCode();
#if UNITY_2017_1_OR_NEWER
int count = trans.childCount;
#else
int count = trans.GetChildCount();
#endif
hashplus += count;
for (int i = 0; i < count; i++)
{
hashplus += trans.GetChild(i).name.GetHashCode();
}
if (bLog)
{
//Debug.Log("trans.position.GetHashCode()=>" + trans.position.GetHashCode());
//Debug.Log("trans.localPosition.GetHashCode()=>" + trans.localPosition.GetHashCode());
//Debug.Log("childCount =>" + count);
//Debug.Log("hashplus =>" + hashplus);
//Debug.Log("hashplus.GetHashCode() =>" + hashplus.GetHashCode());
}
return hashplus.GetHashCode();
}
static int GetNodeLinkListHash(List<AxiStatistics_Node_Link> nodes)
{
string hashplus = string.Empty;
foreach (var node in nodes)
{
hashplus += node.Name;
hashplus += node.Idx.ToString();
}
return hashplus.GetHashCode();
}
static string GetNodeLinkListStr(List<AxiStatistics_Node_Link> nodes)
{
string linkstr = string.Empty;
foreach (var node in nodes)
{
linkstr += "/";
linkstr += node.Name;
linkstr += "[" + node.Idx + "]";
}
return linkstr;
}
static void AddComponentData(int _type, string _rootPath, AxiStatistics_Node_Component _comdata, string _nodepath, Component lastcom)
{
string rootKey = GetRootTempKey(_type, _rootPath);
if (!dictTempData.ContainsKey(rootKey))
{
dictTempData[rootKey] = new AxiStatisticsDatas() { type = _type, FullPath = _rootPath, nodes = new List<AxiStatistics_Node>() };
}
AxiStatisticsDatas rootData = dictTempData[rootKey];
List<AxiStatistics_Node_Link> link = new List<AxiStatistics_Node_Link>();
if (lastcom.transform.parent != null)
{
Transform currNode = lastcom.transform;
while (currNode != null)
{
//最顶层了
if (currNode.parent == null)
{
link.Insert(0, new AxiStatistics_Node_Link()
{
NodeHash = GetNodeDataHash(currNode),
Idx = 0,
OnlyOne = true,
Name = currNode.gameObject.name
});
break;
}
int thisNameAllCount = 0;
int thisNodeIdx = -1;
#if UNITY_2017_1_OR_NEWER
int count = currNode.parent.childCount;
#else
int count = currNode.parent.GetChildCount();
#endif
bool bFind = false;
for (int i = 0; i < count; i++)
{
GameObject checkGobj = currNode.parent.GetChild(i).gameObject;
if (checkGobj.name == currNode.name)
{
thisNameAllCount++;
if (checkGobj == currNode.gameObject)
{
thisNodeIdx = thisNameAllCount - 1;
bFind = true;
}
}
}
if (bFind)
{
link.Insert(0, new AxiStatistics_Node_Link()
{
NodeHash = GetNodeDataHash(currNode),
Idx = thisNodeIdx,
OnlyOne = thisNameAllCount == 1,
Name = currNode.gameObject.name
});
currNode = currNode.parent;
}
else
break;
}
}
else
{
link.Insert(0, new AxiStatistics_Node_Link()
{
NodeHash = GetNodeDataHash(lastcom.transform),
Idx = 0,
OnlyOne = true,
Name = lastcom.gameObject.name
});
}
int linkhash = GetNodeLinkListHash(link);
AxiStatistics_Node nodeData = rootData.nodes.Where(w => w.LinkHash == linkhash).FirstOrDefault();
if (nodeData == null)
{
nodeData = new AxiStatistics_Node();
nodeData.Name = Path.GetFileName(_nodepath);
//nodeData.NodeFullPath = _nodepath;
nodeData.components = new List<AxiStatistics_Node_Component>();
//nodeData.NodeIdx = thisNodeIdx;
//nodeData.NodeIdxOnlyOne = bNodeIdxOnlyOne;
nodeData.link = link;
nodeData.LinkHash = linkhash;
nodeData.LinkFullStr = GetNodeLinkListStr(link);
rootData.nodes.Add(nodeData);
}
nodeData.components.Add(_comdata);
}
static bool CheckCom(Component[] allcoms, int comRealIdx, int _type, string _rootPath, Component com, string nodepath)
{
if (com is BoxCollider2D)
{
BoxCollider2D bc = com as BoxCollider2D;
#if UNITY_2017_1_OR_NEWER
Debug.Log(nodepath + "BoxCollider2D->center=>(" + bc.offset.x + "," + bc.offset.y + ") size=>(" + bc.size.x + "," + bc.size.y + "");
#else
Debug.Log(nodepath +"BoxCollider2D->center=>("+ bc.center.x+","+bc.center.y+") size=>("+ bc.size.x+","+bc.size.y+"");
#endif
AxiStatistics_Node_Component _com = new AxiStatistics_Node_Component();
_com.type = typeof(BoxCollider2D).ToString();
#if UNITY_2017_1_OR_NEWER
_com.center = bc.offset;
#else
_com.center = bc.center;
#endif
_com.size = bc.size;
SetCompnentIdxNum<BoxCollider2D>(_com, allcoms, comRealIdx, bc);
AddComponentData(_type, _rootPath, _com, nodepath, com);
}
if (com is Rigidbody2D)
{
Rigidbody2D rig2d = com as Rigidbody2D;
Debug.Log(_rootPath + "Rigidbody2D->simulated=>(" + rig2d.simulated + ")");
Debug.Log(_rootPath + "Rigidbody2D->IsSleeping=>(" + rig2d.isKinematic.ToString() + ")");
AxiStatistics_Node_Component _com = new AxiStatistics_Node_Component();
_com.type = typeof(Rigidbody2D).ToString();
_com.isKinematic = rig2d.isKinematic;
_com.simulated = rig2d.simulated;
_com.gravityScale = rig2d.gravityScale;
SetCompnentIdxNum<Rigidbody2D>(_com, allcoms, comRealIdx, rig2d);
AddComponentData(_type, _rootPath, _com, nodepath, com);
}
return true;
}
/// <summary>
/// 找出同类Idx
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="allcoms"></param>
/// <param name="comRealIdx"></param>
/// <param name="com"></param>
/// <returns></returns>
static void SetCompnentIdxNum<T>(AxiStatistics_Node_Component _comData, Component[] allcoms, int comRealIdx, T com) where T : Component
{
int ComIdxNum;
bool ComTypeIsOnlyOne = false;
int TCount = com.transform.GetComponents<T>().Length;
if (TCount == 1)
{
ComIdxNum = 0;
ComTypeIsOnlyOne = true;
}
else if (TCount < 1)
{
Debug.LogError("找不到,不应该");
ComIdxNum = -1;
}
ComIdxNum = -1;
for (int i = 0; i < allcoms.Length; i++)
{
//他自己自然是了
if (i == comRealIdx)
{
ComIdxNum++;
break;
}
if (allcoms[i] is T)
ComIdxNum++;
}
_comData.ComIdxNum = ComIdxNum;
_comData.ComTypeOnlyOne = ComTypeIsOnlyOne;
}
[MenuItem("Axibug移植工具/Statistics/[1]Collider和RigBody")]
public static void StatisticsCollider()
{
ClearTempData();
StatisticsCollider<BoxCollider2D>();
StatisticsCollider<Rigidbody2D>();
AxiStatisticsCache cache = ScriptableObject.CreateInstance<AxiStatisticsCache>();
foreach (var data in dictTempData)
cache.caches.Add(data.Value);
AssetDatabase.CreateAsset(cache, cachecfgPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
public static void StatisticsCollider<T>() where T : Component
{
AxiProjectTools.GoTAxiProjectToolsSence();
string[] sceneGuids = AssetDatabase.FindAssets("t:scene");
foreach (string guid in sceneGuids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
if (path.Contains(AxiProjectTools.toolSenceName))
continue;
#if UNITY_4_6
EditorApplication.OpenScene(path);
#else
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(path);
#endif
// 创建一个列表来存储根节点
List<GameObject> rootNodes = new List<GameObject>();
// 遍历场景中的所有对象
GameObject[] allObjects = FindObjectsOfType<GameObject>();
foreach (GameObject obj in allObjects)
{
// 检查对象是否有父对象
if (obj.transform.parent == null)
{
// 如果没有父对象,则它是一个根节点
rootNodes.Add(obj);
}
}
foreach (var node in rootNodes)
LoopPrefabNode<T>(0, path, path, node, 0);
}
string[] prefabGuids = AssetDatabase.FindAssets("t:Prefab");
foreach (string guid in prefabGuids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
GetPrefab<T>(path);
}
AxiProjectTools.GoTAxiProjectToolsSence();
Debug.Log("<Color=#FFF333>处理完毕 统计所有预制体和场景下的" + typeof(T).FullName + "</color>");
}
static void GetPrefab<T>(string path) where T : Component
{
#if UNITY_4_6
GameObject prefab = AssetDatabase.LoadAssetAtPath(path,typeof(GameObject)) as GameObject;
#else
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
#endif
LoopPrefabNode<T>(1, path, path, prefab.gameObject, 0);
}
static void LoopPrefabNode<T>(int _type, string _rootPath, string noderootPath, GameObject trans, int depth) where T : Component
{
// #if UNITY_2018_4_OR_NEWER
string nodename = noderootPath + "/" + trans.name;
GameObject prefabRoot = trans.gameObject;
Component[] components = prefabRoot.GetComponents<Component>();
for (int i = 0; i < components.Length; i++)
{
var com = components[i];
if (com == null)
continue;
T comobj = com as T;
if (comobj == null)
continue;
if (CheckCom(components, i, _type, _rootPath, comobj, nodename))
continue;
}
//遍历
foreach (Transform child in trans.transform)
LoopPrefabNode<T>(_type, _rootPath, nodename, child.gameObject, depth + 1);
//#else
// Debug.Log("低版本不要执行本函数");
//#endif
}
#if UNITY_2017_1_OR_NEWER
[MenuItem("Axibug移植工具/Statistics/[2]")]
public static void RepairRigBodyByStatistics()
{
List<string> errLog = new List<string>();
List<string> doneLog = new List<string>();
List<ValueTuple<string, string>> NeedRepair = new List<ValueTuple<string, string>>();
List<ValueTuple<string, string>> FinishRepair = new List<ValueTuple<string, string>>();
string CurrScenePath = string.Empty;
AxiProjectTools.GoTAxiProjectToolsSence();
#if UNITY_4_6
AxiStatisticsCache data = AssetDatabase.LoadAssetAtPath(cachecfgPath,typeof(AxiStatisticsCache)) as AxiStatisticsCache;
#else
AxiStatisticsCache data = AssetDatabase.LoadAssetAtPath<AxiStatisticsCache>(cachecfgPath);
#endif
string[] sceneGuids = AssetDatabase.FindAssets("t:scene");
List<string> ScenePath = new List<string>();
List<string> SceneName = new List<string>();
foreach (string guid in sceneGuids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
if (path.Contains(AxiProjectTools.toolSenceName))
continue;
ScenePath.Add(path);
SceneName.Add(Path.GetFileName(path));
}
string[] prefabGuids = AssetDatabase.FindAssets("t:prefab");
List<string> prefabPath = new List<string>();
List<string> prefabName = new List<string>();
foreach (string guid in prefabGuids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
prefabPath.Add(path);
prefabName.Add(Path.GetFileName(path));
}
foreach (var cache in data.caches.OrderBy(w => w.type))
{
//场景
if (cache.type == 0)
{
#region
string targetName = Path.GetFileName(cache.FullPath);
int Idx = SceneName.IndexOf(targetName);
if (Idx < 0)
{
Debug.LogError(targetName + "[Repair]找不到对应资源");
continue;
}
string targetpath = ScenePath[Idx];
//保证场景切换
if (!string.Equals(CurrScenePath, targetpath))
{
#if UNITY_4_6
EditorApplication.OpenScene(targetpath);
#else
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(targetpath);
#endif
}
CurrScenePath = targetpath;
#endregion
int DirtyCount = 0;
foreach (var node in cache.nodes)
{
GameObject targetNodePathObj = GetNodeByLink(cache.FullPath, node.link, out string errStr);
if (targetNodePathObj == null)
{
errLog.Add(errStr);
continue;
}
/*
string targetNodePath = node.NodeFullPath.Substring(cache.FullPath.Length, node.NodeFullPath.Length - cache.FullPath.Length);
//GameObject targetNodePathObj = GameObject.Find(targetNodePath);
GameObject targetNodePathObj = GetNodeByIdx(node, targetNodePath);
if (targetNodePathObj == null)
{
string err = "[Repair]" + node.NodeFullPath + "找不到对应节点";
errLog.Add(err);
Debug.LogError(err);
continue;
}
*/
foreach (var com in node.components)
{
if (RepairComponent(node.LinkFullStr, targetNodePathObj, com, out var errlog))
{
NeedRepair.Add(new ValueTuple<string, string>($"{cache.FullPath}:{node.LinkFullStr}", $"{com.type}[{com.ComIdxNum}]"));
DirtyCount++;
}
errLog.AddRange(errlog);
}
}
if (DirtyCount > 0)
{
Debug.Log($"[Repair][场景处理]{cache.FullPath}共{DirtyCount}个需要处理");
// 获取当前打开的场景
var activeScene = UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene();
// 保存场景
UnityEditor.SceneManagement.EditorSceneManager.SaveScene(activeScene);
Debug.Log("场景已保存: " + activeScene.path);
string donestr = $"[Repair][场景处理成功]{targetpath},共{DirtyCount}个";
doneLog.Add(donestr);
}
}
else if (cache.type == 1)
{
string targetpath = cache.FullPath;
//来到空场景
if (!string.IsNullOrEmpty(CurrScenePath))
{
AxiProjectTools.GoTAxiProjectToolsSence();
CurrScenePath = string.Empty;
}
GameObject prefabInstance = AssetDatabase.LoadAssetAtPath<GameObject>(targetpath);
if (prefabInstance == null)
{
Debug.LogError($"[Repair]Failed to load prefab at path: {prefabPath}");
return;
}
var obj = GameObject.Instantiate(prefabInstance, null);
int DirtyCount = 0;
foreach (var node in cache.nodes)
{
GameObject targetNodePathObj = GetNodeByLink(cache.FullPath, node.link, out string errStr, obj);
if (targetNodePathObj == null)
{
errLog.Add(errStr);
continue;
}
//if (node.NodeFullPath == targetpath + "/" + Path.GetFileNameWithoutExtension(targetpath))
//{
// //预制体自己就是目标
// targetNodePathObj = obj;
//}
//else
//{
// string targetNodePath = node.NodeFullPath.Substring(cache.FullPath.Length + prefabInstance.name.Length + 2, node.NodeFullPath.Length - cache.FullPath.Length - prefabInstance.name.Length - 2);
// //targetNodePathObj = obj.transform.Find(targetNodePath)?.gameObject;
// targetNodePathObj = GetNodeByIdx(node, targetNodePath, obj);
// if (targetNodePathObj == null)
// {
// Debug.LogError("[Repair]" + targetNodePath + "找不到对应节点");
// continue;
// }
//}
foreach (var com in node.components)
{
if (RepairComponent(node.LinkFullStr, targetNodePathObj, com, out var errlog))
{
NeedRepair.Add(new ValueTuple<string, string>($"{cache.FullPath}:{node.LinkFullStr}", $"{com.type}[{com.ComIdxNum}]"));
DirtyCount++;
}
errLog.AddRange(errlog);
}
}
if (DirtyCount > 0)
{
Debug.Log($"[Repair][预制体处理]{targetpath}共{DirtyCount}个需要处理");
PrefabUtility.SaveAsPrefabAsset(obj, targetpath);
string donestr = $"[Repair][预制体处理成功]{targetpath},共{DirtyCount}个";
doneLog.Add(donestr);
}
GameObject.DestroyImmediate(obj);
}
}
AxiProjectTools.GoTAxiProjectToolsSence();
StringBuilder sb = new StringBuilder();
sb.AppendLine("[Repair][统计]:");
sb.AppendLine("----处理成功----");
foreach (var val in doneLog.OrderBy(w => w))
{
sb.AppendLine(val);
}
sb.AppendLine("----异常统计----");
foreach (var val in errLog.OrderBy(w => w))
{
sb.AppendLine(val);
}
sb.AppendLine("----需要处理----");
foreach (var val in NeedRepair.OrderBy(w => w.Item1))
{
sb.AppendLine($"{val.Item1}=>{val.Item2}");
}
Debug.Log($"{sb}");
File.WriteAllText("Assets/AxiNeedRepair.txt", sb.ToString());
}
// static GameObject GetNodeByIdx(AxiStatistics_Node nodedata, string targetNodePath, GameObject root = null)
// {
// GameObject targetNodePathObj;
// if (root == null)
// targetNodePathObj = GameObject.Find(targetNodePath);
// else
// targetNodePathObj = root.transform.Find(targetNodePath)?.gameObject;
// if (targetNodePathObj == null)
// return null;
// string targetName = targetNodePathObj.name;
// int currIdx = -1;
// if (!nodedata.NodeIdxOnlyOne)
// {
// if (targetNodePathObj.transform.parent != null)
// {
//#if UNITY_2017_1_OR_NEWER
// int count = targetNodePathObj.transform.parent.childCount;
//#else
// int count = targetNodePathObj.transform.parent.GetChildCount();
//#endif
// for (int i = 0; i < count; i++)
// {
// GameObject checkGobj = targetNodePathObj.transform.parent.GetChild(i).gameObject;
// if (checkGobj.name == targetName)
// {
// currIdx++;
// if (nodedata.NodeIdx == currIdx)
// {
// targetNodePathObj = checkGobj;
// break;
// }
// }
// }
// }
// }
// return targetNodePathObj;
// }
static GameObject GetNodeByLink(string rootPath, List<AxiStatistics_Node_Link> linklist, out string errStr, GameObject PrefabRoot = null)
{
List<AxiStatistics_Node_Link> temp_useddlink = new List<AxiStatistics_Node_Link>();
if (linklist.Count < 1)
{
errStr = $"[Repair] Link 为空";
Debug.LogError(errStr);
return null;
}
temp_useddlink.Add(linklist[0]);
GameObject currRoot;
if (PrefabRoot == null)
currRoot = GameObject.Find(linklist[0].Name);
else
{
currRoot = PrefabRoot;
//currRoot = PrefabRoot.transform.Find(linklist[0].Name)?.gameObject;
}
if (currRoot == null)
{
errStr = $"[Repair] 根节点找不到{rootPath}:{GetNodeLinkListStr(linklist)} => null";
Debug.LogError(errStr);
return null;
}
for (int link_i = 1; link_i < linklist.Count; link_i++)
{
AxiStatistics_Node_Link targetLink = linklist[link_i];
temp_useddlink.Add(targetLink);
GameObject findNode = null;
#if UNITY_2017_1_OR_NEWER
int count = currRoot.transform.childCount;
#else
int count = currNode.transform.GetChildCount();
#endif
if (targetLink.OnlyOne)
{
for (int i = 0; i < count; i++)
{
GameObject checkGobj = currRoot.transform.GetChild(i).gameObject;
if (checkGobj.name == targetLink.Name)
{
findNode = checkGobj;
break;
}
}
}
else
{
Dictionary<int, GameObject> tempHash2Node = new Dictionary<int, GameObject>();
List<GameObject> tempGobjList = new List<GameObject>();
bool HashDrity = false;
for (int i = 0; i < count; i++)
{
GameObject checkGobj = currRoot.transform.GetChild(i).gameObject;
if (checkGobj.name == targetLink.Name)
{
int temphash = GetNodeDataHash(checkGobj.transform);
if (!tempHash2Node.ContainsKey(temphash))
{
tempHash2Node.Add(GetNodeDataHash(checkGobj.transform), checkGobj);
}
else
{
HashDrity = true;
}
tempGobjList.Add(checkGobj);
}
}
//Hash严格模式
if (!HashDrity && tempHash2Node.TryGetValue(targetLink.NodeHash, out var val))
{
findNode = val;
}
//下标模式
else
{
if (targetLink.Idx < 0 || tempGobjList.Count == 0 || (tempGobjList.Count != 0 && targetLink.Idx >= tempGobjList.Count))
{
errStr = $"[Repair]link 下标模式 找不到=>{rootPath}:{GetNodeLinkListStr(temp_useddlink)}[{targetLink.Idx}] => 完整链路{rootPath}:{GetNodeLinkListStr(linklist)}";
Debug.LogError(errStr);
return null;
}
else
{
findNode = tempGobjList[targetLink.Idx];
}
}
}
currRoot = findNode;
if (currRoot == null)
break;
}
if (currRoot == null)
{
errStr = $"[Repair]link 找不到[{rootPath}:{GetNodeLinkListStr(temp_useddlink)}] => 完整链路{rootPath}:{GetNodeLinkListStr(linklist)}";
Debug.LogError(errStr);
return null;
}
else
{
errStr = string.Empty;
return currRoot;
}
}
static bool RepairComponent(string NodePath, GameObject targetNodePathObj, AxiStatistics_Node_Component comdata, out List<string> Errlog)
{
Errlog = new List<string>();
string err;
bool Dirty = false;
if (comdata.type == typeof(Rigidbody2D).ToString())
{
Rigidbody2D rg2d = GetCompnentById<Rigidbody2D>(targetNodePathObj, comdata);
if (rg2d == null)
{
err = $"[Repair]{NodePath}=> Rigidbody2D[{comdata.ComIdxNum}] == null";
Debug.LogError(err);
Errlog.Add(err);
Dirty = false;
}
/*
Unity的差异
BodyType选项Unity 4.6.7Rigidbody2D默认等效于新版的Dynamic类型Static或Kinematic
Simulated选项Rigidbody2D组件且Gravity Scale > 0
gravityScale > 0,simulated = true;bodyType = RigidbodyType2D.Dynamic;
*/
if (rg2d.gravityScale != comdata.gravityScale)
{
Debug.Log($"[Repair]{NodePath}=> Rigidbody2D[{comdata.ComIdxNum}] simulated:{rg2d.gravityScale} != :{comdata.gravityScale} rg2d.bodyType => {rg2d.bodyType} ");
rg2d.gravityScale = comdata.gravityScale;
Dirty = true;
}
//if (rg2d.gravityScale > 0 && (!rg2d.simulated || rg2d.bodyType != RigidbodyType2D.Dynamic))
if (!rg2d.simulated || rg2d.bodyType != RigidbodyType2D.Dynamic)
{
Debug.Log($"[Repair]{NodePath}=> Rigidbody2D[{comdata.ComIdxNum}] simulated:{rg2d.simulated} != :{comdata.simulated} rg2d.bodyType => {rg2d.bodyType} ");
rg2d.simulated = true;
rg2d.bodyType = RigidbodyType2D.Dynamic;
Dirty = true;
}
}
else if (comdata.type == typeof(BoxCollider2D).ToString())
{
BoxCollider2D bc = GetCompnentById<BoxCollider2D>(targetNodePathObj, comdata);
if (bc == null)
{
err = $"[Repair]{NodePath}=> BoxCollider2D[{comdata.ComIdxNum}] == null";
Debug.LogError(err);
Errlog.Add(err);
Dirty = false;
}
else
{
if (bc.size != comdata.size)
{
Debug.Log($"[Repair]{NodePath} BoxCollider2D[{comdata.ComIdxNum}] => size:{bc.size} != {comdata.size} ");
bc.size = comdata.size;
Dirty = true;
}
if (bc.offset != comdata.center)
{
Debug.Log($"[Repair]{NodePath} BoxCollider2D[{comdata.ComIdxNum}] => offset:{bc.offset} != center{comdata.center} ");
bc.offset = comdata.center;
Dirty = true;
}
if (Dirty)
{
bc.size = comdata.size;
bc.offset = comdata.center;
}
}
}
return Dirty;
}
static T GetCompnentById<T>(GameObject gobj, AxiStatistics_Node_Component node) where T : Component
{
if (node.ComIdxNum == 0)
return gobj.GetComponent<T>();
else if (node.ComIdxNum > 0)
{
T[] coms = gobj.GetComponents<T>();
if (node.ComIdxNum < coms.Length)
return coms[node.ComIdxNum];
}
return null;
}
#endif
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 32aabdd304d2c4d47b8ef660f672ead1
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -3,19 +3,18 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
public class AxiProjectTools : EditorWindow
{
static string cachecfgPath = "Assets/AxiComToolCache.asset";
static string toolSenceName = "AxiProjectTools";
static string outCsDir = Application.dataPath + "/AxiCom/";
static Dictionary<string, AxiPrefabCache_Com2GUID> ComType2GUID = new Dictionary<string, AxiPrefabCache_Com2GUID>();
static void GoTAxiProjectToolsSence()
public static string toolSenceName = "AxiProjectTools";
public static string outCsDir = Application.dataPath + "/AxiCom/";
public static Dictionary<string, AxiPrefabCache_Com2GUID> ComType2GUID = new Dictionary<string, AxiPrefabCache_Com2GUID>();
public static void GoTAxiProjectToolsSence()
{
string[] sceneGuids = AssetDatabase.FindAssets("t:scene");
foreach (string guid in sceneGuids)
@ -23,12 +22,16 @@ public class AxiProjectTools : EditorWindow
string path = AssetDatabase.GUIDToAssetPath(guid);
if (path.Contains(toolSenceName))
{
EditorSceneManager.OpenScene(path);
#if UNITY_4_6
EditorApplication.OpenScene(path);
#else
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(path);
#endif
return;
}
}
}
[MenuItem("Axibug移植工具/ToLowVersionUnity/[1]UGUI组件")]
public static void Part1()
{
@ -40,12 +43,16 @@ public class AxiProjectTools : EditorWindow
string path = AssetDatabase.GUIDToAssetPath(guid);
if (path.Contains(toolSenceName))
continue;
EditorSceneManager.OpenScene(path);
#if UNITY_4_6
EditorApplication.OpenScene(path);
#else
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(path);
#endif
// 创建一个列表来存储根节点
List<GameObject> rootNodes = new List<GameObject>();
// 遍历场景中的所有对象
GameObject[] allObjects = FindObjectsOfType<GameObject>();
foreach (GameObject obj in allObjects)
@ -57,19 +64,19 @@ public class AxiProjectTools : EditorWindow
rootNodes.Add(obj);
}
}
foreach (var node in rootNodes)
LoopPrefabNode(path, node, 0);
}
string[] prefabGuids = AssetDatabase.FindAssets("t:Prefab");
foreach (string guid in prefabGuids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
GetPrefab(path);
}
AxiPrefabCache cache = ScriptableObject.CreateInstance<AxiPrefabCache>();
foreach (var data in ComType2GUID)
cache.caches.Add(data.Value);
@ -79,66 +86,88 @@ public class AxiProjectTools : EditorWindow
GoTAxiProjectToolsSence();
Debug.Log("<Color=#FFF333>处理完毕 [1]采集所有预制体和场景下的UGUI组件</color>");
}
static void GetPrefab(string path)
{
{
#if UNITY_4_6
GameObject prefab = AssetDatabase.LoadAssetAtPath(path,typeof(GameObject)) as GameObject;
#else
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
#endif
LoopPrefabNode(path, prefab.gameObject, 0);
}
static void LoopPrefabNode(string rootPath, GameObject trans, int depth)
{
string nodename = $"{rootPath}>{trans.name}";
#if UNITY_2018_4_OR_NEWER
GameObject prefabRoot = trans.gameObject;
int comCount = prefabRoot.GetComponentCount();
for (int i = 0; i < comCount; i++)
{
var com = prefabRoot.GetComponentAtIndex(i);
if (com == null)
continue;
MonoBehaviour monoCom = com as MonoBehaviour;
if (monoCom == null)
continue;
Type monoType = monoCom.GetType();
if (!monoType.Assembly.FullName.Contains("UnityEngine.UI"))
continue;
// 获取MonoScript资源
MonoScript monoScript = MonoScript.FromMonoBehaviour(monoCom);
if (monoScript != null)
{
// 获取MonoScript资源的GUID
string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(monoScript));
Debug.Log($"{nodename} | <color=#FFF333>[{monoType.Name}]</color> <color=#FF0000>{guid}</color><color=#00FF00>({monoType.FullName})</color>");
ComType2GUID[monoType.FullName] =
new AxiPrefabCache_Com2GUID()
{
SrcFullName = monoType.FullName,
SrcName = monoType.Name,
GUID = guid,
};
}
else
{
Debug.LogError("!!!! 没得");
}
}
//遍历
foreach (Transform child in trans.transform)
LoopPrefabNode(nodename, child.gameObject, depth + 1);
#else
Debug.Log("低版本不要执行本函数");
#endif
// #if UNITY_2018_4_OR_NEWER
string nodename = rootPath + trans.name;
GameObject prefabRoot = trans.gameObject;
Component[] components = prefabRoot.GetComponents<Component>();
for (int i = 0; i < components.Length; i++)
{
var com = components[i];
if (com == null)
continue;
MonoBehaviour monoCom = com as MonoBehaviour;
if (monoCom == null)
continue;
Type monoType = monoCom.GetType();
if (!monoType.Assembly.FullName.Contains("UnityEngine.UI"))
continue;
// 获取MonoScript资源
MonoScript monoScript = MonoScript.FromMonoBehaviour(monoCom);
if (monoScript != null)
{
// 获取MonoScript资源的GUID
string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(monoScript));
Debug.Log(nodename+" | <color=#FFF333>["+monoType.Name+"]</color> <color=#FF0000>"+guid+"</color><color=#00FF00>("+monoType.FullName+")</color>");
ComType2GUID[monoType.FullName] =
new AxiPrefabCache_Com2GUID()
{
SrcFullName = monoType.FullName,
SrcName = monoType.Name,
GUID = guid,
};
}
else
{
Debug.LogError("!!!! 没得");
}
}
//遍历
foreach (Transform child in trans.transform)
LoopPrefabNode(nodename, child.gameObject, depth + 1);
//#else
// Debug.Log("低版本不要执行本函数");
//#endif
}
[MenuItem("Axibug移植工具/ToLowVersionUnity/[2]")]
public static void Part2()
{
#if UNITY_4_6
if(System.IO.Directory.Exists(outCsDir))
System.IO.Directory.Delete(outCsDir);
#else
if (UnityEngine.Windows.Directory.Exists(outCsDir))
UnityEngine.Windows.Directory.Delete(outCsDir);
#endif
Directory.CreateDirectory(outCsDir);
#if UNITY_4_6
AxiPrefabCache cache = AssetDatabase.LoadAssetAtPath(cachecfgPath,typeof(AxiPrefabCache)) as AxiPrefabCache;
#else
AxiPrefabCache cache = AssetDatabase.LoadAssetAtPath<AxiPrefabCache>(cachecfgPath);
#endif
foreach (var data in cache.caches)
{
string toName = "Axi" + data.SrcName;
@ -160,12 +189,18 @@ public class AxiProjectTools : EditorWindow
AssetDatabase.Refresh();
Debug.Log("<Color=#FFF333>处理完毕 [2]生成中间脚本代码</color>");
}
[MenuItem("Axibug移植工具/ToLowVersionUnity/[3]")]
public static void Part3()
{
#if UNITY_4_6
AxiPrefabCache cache = AssetDatabase.LoadAssetAtPath(cachecfgPath,typeof(AxiPrefabCache)) as AxiPrefabCache;
MonoScript[] allMonoScripts = (MonoScript[])Resources.FindObjectsOfTypeAll(typeof(MonoScript));
#else
AxiPrefabCache cache = AssetDatabase.LoadAssetAtPath<AxiPrefabCache>(cachecfgPath);
List<MonoScript> allMonoScripts = FindAllAssetsOfType<MonoScript>();
#endif
foreach (var data in cache.caches)
{
MonoScript monoScript = allMonoScripts.FirstOrDefault(w => w.name == data.ToName);
@ -183,18 +218,23 @@ public class AxiProjectTools : EditorWindow
AssetDatabase.Refresh();
Debug.Log("<Color=#FFF333>处理完毕 [3]收集生成的脚本</color>");
}
static List<T> FindAllAssetsOfType<T>() where T : UnityEngine.Object
{
List<T> assets = new List<T>();
string[] allGuids = AssetDatabase.FindAssets("");
foreach (string guid in allGuids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
if (path.EndsWith(".cs") || path.EndsWith(".js") || path.EndsWith(".boo")) // Unity支持多种脚本语言但现代Unity主要使用C#
{
#if UNITY_4_6
T asset = AssetDatabase.LoadAssetAtPath(cachecfgPath,typeof(T)) as T;
#else
T asset = AssetDatabase.LoadAssetAtPath<T>(path);
#endif
if (asset != null)
{
assets.Add(asset);
@ -203,12 +243,18 @@ public class AxiProjectTools : EditorWindow
}
return assets;
}
[MenuItem("Axibug移植工具/ToLowVersionUnity/[4]")]
public static void Part4()
{
#if UNITY_4_6
AxiPrefabCache cache = AssetDatabase.LoadAssetAtPath(cachecfgPath,typeof(AxiPrefabCache)) as AxiPrefabCache;
#else
AxiPrefabCache cache = AssetDatabase.LoadAssetAtPath<AxiPrefabCache>(cachecfgPath);
#endif
Dictionary<string, string> tempReplaceDict = new Dictionary<string, string>();
foreach (var data in cache.caches)
{
@ -221,7 +267,7 @@ public class AxiProjectTools : EditorWindow
AssetDatabase.Refresh();
Debug.Log("<Color=#FFF333>处理完毕 [4]替换所有预制体和场景中的组件</color>");
}
static void ProcessAllPrefabs(string form, Dictionary<string, string> tempReplaceDict, bool reverse = false)
{
List<GameObject> prefabs = new List<GameObject>();
@ -240,7 +286,7 @@ public class AxiProjectTools : EditorWindow
}
EditorUtility.ClearProgressBar();
}
/// <summary>
/// 替换值
/// </summary>
@ -257,17 +303,17 @@ public class AxiProjectTools : EditorWindow
File.WriteAllLines(strFilePath, lines);
}
}
[MenuItem("Axibug移植工具/ToLowVersionUnity/[5]UnPack所有嵌套预制体和场景中的预制体")]
public static void UnpackPrefabs()
{
#if UNITY_2018_4_OR_NEWER
GoTAxiProjectToolsSence();
string[] allAssetPaths = AssetDatabase.GetAllAssetPaths();
#if UNITY_2018_4_OR_NEWER
GoTAxiProjectToolsSence();
string[] allAssetPaths = AssetDatabase.GetAllAssetPaths();
int prefabCount = 0;
foreach (string path in allAssetPaths)
{
if (Path.GetExtension(path).Equals(".prefab"))
@ -278,59 +324,59 @@ public class AxiProjectTools : EditorWindow
}
}
Debug.Log($"{prefabCount}个预制体Unpack");
string[] sceneGuids = AssetDatabase.FindAssets("t:scene");
foreach (string guid in sceneGuids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
if (path.Contains(toolSenceName))
continue;
EditorSceneManager.OpenScene(path);
Scene currentScene = SceneManager.GetActiveScene();
GameObject[] rootObjects = currentScene.GetRootGameObjects();
string[] sceneGuids = AssetDatabase.FindAssets("t:scene");
foreach (string guid in sceneGuids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
if (path.Contains(toolSenceName))
continue;
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(path);
UnityEngine.SceneManagement.Scene currentScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
GameObject[] rootObjects = currentScene.GetRootGameObjects();
foreach (GameObject rootObj in rootObjects)
{
// 遍历场景中的所有对象
TraverseHierarchy(rootObj);
}
// Save the scene // 获取当前打开的场景
currentScene = EditorSceneManager.GetActiveScene();
// 保存场景到文件(默认路径和名称)
bool success = EditorSceneManager.SaveScene(currentScene, currentScene.path);
Debug.Log($"{currentScene.name}场景中 所有物体Unpack");
}
GoTAxiProjectToolsSence();
Debug.Log("<Color=#FFF333>处理完毕 [5]UnPack所有预制体</color>");
#else
Debug.Log("低版本不要执行本函数");
#endif
}
static void UnpackPrefab(string prefabPath)
{
// 遍历场景中的所有对象
TraverseHierarchy(rootObj);
}
// Save the scene // 获取当前打开的场景
currentScene = UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene();
// 保存场景到文件(默认路径和名称)
bool success = UnityEditor.SceneManagement.EditorSceneManager.SaveScene(currentScene, currentScene.path);
Debug.Log($"{currentScene.name}场景中 所有物体Unpack");
}
GoTAxiProjectToolsSence();
Debug.Log("<Color=#FFF333>处理完毕 [5]UnPack所有预制体</color>");
#else
Debug.Log("低版本不要执行本函数");
#endif
}
static void UnpackPrefab(string prefabPath)
{
#if UNITY_2018_4_OR_NEWER
#if UNITY_2018_4_OR_NEWER
GameObject prefabInstance = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (prefabInstance == null)
{
Debug.LogError($"Failed to load prefab at path: {prefabPath}");
return;
}
var obj = GameObject.Instantiate(prefabInstance, null);
TraverseHierarchy(obj);
PrefabUtility.SaveAsPrefabAsset(obj, prefabPath);
GameObject.DestroyImmediate(obj);
#else
#else
Debug.Log("低版本不要执行本函数");
#endif
#endif
}
static void TraverseHierarchy(GameObject obj)
{
#if UNITY_2018_4_OR_NEWER
#if UNITY_2018_4_OR_NEWER
// 检查该对象是否是预制体的实例
if (PrefabUtility.IsPartOfPrefabInstance(obj))
{
@ -338,80 +384,123 @@ public class AxiProjectTools : EditorWindow
PrefabUtility.UnpackPrefabInstance(obj, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
Debug.Log("Prefab instance converted to game object: " + obj.name);
}
// 递归遍历子对象
for (int i = 0; i < obj.transform.childCount; i++)
{
TraverseHierarchy(obj.transform.GetChild(i).gameObject);
}
#else
#else
Debug.Log("低版本不要执行本函数");
#endif
#endif
}
[MenuItem("Axibug移植工具/ToLowVersionUnity/[6]Sprite")]
public static void FixMultipleMaterialSprites()
{
string[] guids = AssetDatabase.FindAssets("t:sprite");
List<Sprite> spritesToFix = new List<Sprite>();
[MenuItem("Axibug移植工具/ToLowVersionUnity/[6]Sprite")]
public static void FixMultipleMaterialSprites()
{
string[] guids = AssetDatabase.FindAssets("t:sprite");
List<Sprite> spritesToFix = new List<Sprite>();
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path);
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path);
// 检查是否有多个材质
if (IsUsingMultipleMaterials(sprite))
{
spritesToFix.Add(sprite);
Debug.Log("Found sprite with multiple materials: " + path);
}
}
// 检查是否有多个材质
if (IsUsingMultipleMaterials(sprite))
{
spritesToFix.Add(sprite);
Debug.Log("Found sprite with multiple materials: " + path);
}
}
// 修复每个找到的Sprite
foreach (var sprite in spritesToFix)
{
FixSprite(sprite);
}
// 修复每个找到的Sprite
foreach (var sprite in spritesToFix)
{
FixSprite(sprite);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log("<Color=#FFF333>处理完毕 [6]修复Sprite</color>");
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log("<Color=#FFF333>处理完毕 [6]修复Sprite</color>");
}
private static bool IsUsingMultipleMaterials(Sprite sprite)
{
if (sprite == null) return false;
private static bool IsUsingMultipleMaterials(Sprite sprite)
{
if (sprite == null) return false;
// 获取精灵的材质
var textureImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(sprite)) as TextureImporter;
// 获取精灵的材质
var textureImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(sprite)) as TextureImporter;
return textureImporter != null && textureImporter.spriteImportMode == SpriteImportMode.Multiple;
}
return textureImporter != null && textureImporter.spriteImportMode == SpriteImportMode.Multiple;
}
private static void FixSprite(Sprite sprite)
{
// 获取Sprite的路径
string path = AssetDatabase.GetAssetPath(sprite);
var textureImporter = AssetImporter.GetAtPath(path) as TextureImporter;
private static void FixSprite(Sprite sprite)
{
// 获取Sprite的路径
string path = AssetDatabase.GetAssetPath(sprite);
var textureImporter = AssetImporter.GetAtPath(path) as TextureImporter;
if (textureImporter != null)
{
// 保存当前切割信息
SpriteMetaData[] originalMetaData = textureImporter.spritesheet;
if (textureImporter != null)
{
// 保存当前切割信息
SpriteMetaData[] originalMetaData = textureImporter.spritesheet;
// 临时禁用Sprite导入
textureImporter.spriteImportMode = SpriteImportMode.None;
textureImporter.SaveAndReimport();
// 临时禁用Sprite导入
textureImporter.spriteImportMode = SpriteImportMode.None;
textureImporter.SaveAndReimport();
// 重新启用Sprite导入并保持原样切割参数
textureImporter.spriteImportMode = SpriteImportMode.Multiple;
textureImporter.spritesheet = originalMetaData; // 恢复原来的切割信息
// 重新启用Sprite导入并保持原样切割参数
textureImporter.spriteImportMode = SpriteImportMode.Multiple;
textureImporter.spritesheet = originalMetaData; // 恢复原来的切割信息
// 重新导入以应用更改
textureImporter.SaveAndReimport();
}
}
[MenuItem("Axibug移植工具/ToLowVersionUnity/[7]")]
static void FixPrefabRefs()
{
// 1. 扫描所有预制体
string[] prefabPaths = Directory.GetFiles("Assets", "*.prefab", SearchOption.AllDirectories);
foreach (var path in prefabPaths) FixRefTypeInFile(path);
// 2. 处理场景文件
string[] scenePaths = Directory.GetFiles("Assets", "*.unity", SearchOption.AllDirectories);
foreach (var path in scenePaths) FixRefTypeInFile(path);
AssetDatabase.Refresh();
Debug.Log("<Color=#FFF333>处理完毕 [5]导入低版本后:修复预制体依赖丢失</color>");
Debug.Log("修复完成!已处理" + prefabPaths.Length + "个预制体");
}
public static void FixRefTypeInFile(string filePath)
{
string content = File.ReadAllText(filePath);
// 匹配所有 {fileID: X, guid: Y, type: Z} 结构
string pattern = @"(\{[^}]*guid:\s*(\w+)[^}]*type:\s*)3(\s*[^}]*\})";
string newContent = Regex.Replace(content, pattern, match => {
string guid = match.Groups[2].Value;
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
// 仅当资源类型为 GameObject 时修改 type
if (AssetDatabase.GetMainAssetTypeAtPath(assetPath) == typeof(GameObject))
// if (assetPath.ToLower().EndsWith(".prefab")
////&& assetPath.Contains("/sound/")
//&& assetPath.Contains("/level")
// )
{
Debug.Log("已处理被引用项=>"+assetPath+" ,引用到=>"+ filePath);
Debug.Log("原值=>" + match.Value + " ,处理值=>"+ match.Groups[1].Value + "2" + match.Groups[3].Value);
//return match.Value;
return match.Groups[1].Value + "2" + match.Groups[3].Value; // type:3→2
}
return match.Value;
});
File.WriteAllText(filePath, newContent);
}
// 重新导入以应用更改
textureImporter.SaveAndReimport();
}
}
}
#endif

View File

@ -0,0 +1,73 @@
#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class AxiStatisticsCache : ScriptableObject
{
public List<AxiStatisticsDatas> caches = new List<AxiStatisticsDatas>();
}
[Serializable]
public class AxiStatisticsDatas
{
/// <summary>
/// [0]Sence [1]Prefab
/// </summary>
public int type;
public string FullPath;
public List<AxiStatistics_Node> nodes = new List<AxiStatistics_Node>();
}
[Serializable]
public class AxiStatistics_Node
{
public string Name;
public List<AxiStatistics_Node_Link> link = new List<AxiStatistics_Node_Link>();
public int LinkHash;
public string LinkFullStr;
//public string NodeFullPath;
// /// <summary>
// /// 表示相同路径只有一个
// /// </summary>
// public bool NodeIdxOnlyOne;
/// <summary>
/// 表示相同路径是第几个下标
/// </summary>
//public int NodeIdx;
public List<AxiStatistics_Node_Component> components = new List<AxiStatistics_Node_Component>();
}
[Serializable]
public class AxiStatistics_Node_Link
{
public string Name;
public bool OnlyOne;
public int Idx;
public int NodeHash;
}
[Serializable]
public class AxiStatistics_Node_Component
{
public string type;
/// <summary>
/// 表示相同组件只有一个
/// </summary>
public bool ComTypeOnlyOne;
/// <summary>
/// 表示相同组件是第几个下标
/// </summary>
public int ComIdxNum;
//Rigboody
public bool simulated;
public float gravityScale;
public bool isKinematic;
//BoxCollider2D
public Vector2 center;
public Vector2 size;
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e4cee4feffb506b4c833262e779424f6
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -15,6 +15,11 @@ public class AxiNS
}
}
/// <summary>
/// 延迟提交是否使用多线程
/// </summary>
public static bool usedmultithreading = false;
public AxiNSUser user;
public AxiNSMount mount;
public AxiNSIO io;

View File

@ -7,20 +7,20 @@ using System.Text.RegularExpressions;
public class AxiNSIO
{
string save_name => AxiNS.instance.mount.SaveMountName;
public string save_path => $"{save_name}:/";
string save_name => AxiNS.instance.mount.SaveMountName;
public string save_path => $"{save_name}:/";
#if UNITY_SWITCH
private FileHandle fileHandle = new nn.fs.FileHandle();
#endif
static object commitLock = new object();
static object commitLock = new object();
static bool bDirty = false;
static bool bDirty = false;
bool CommitSave()
{
lock (commitLock)
{
bool CommitSave()
{
lock (commitLock)
{
#if UNITY_SWITCH && !UNITY_EDITOR
// 阻止用户在保存时,退出游戏 Switch 条例 0080
@ -39,41 +39,41 @@ public class AxiNSIO
bDirty = false;
return true;
#else
return false;
return false;
#endif
}
}
}
}
void SetCommitDirty()
{
lock (commitLock)
{
bDirty = true;
}
}
void SetCommitDirty()
{
lock (commitLock)
{
bDirty = true;
}
}
public void ApplyAutoCommit()
{
bool temp;
lock (commitLock)
{
temp = bDirty;
}
public void ApplyAutoCommit()
{
bool temp;
lock (commitLock)
{
temp = bDirty;
}
if (temp)
{
CommitSave();
}
}
if (temp)
{
CommitSave();
}
}
/// <summary>
/// 检查Path是否存在
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public bool CheckPathExists(string filePath)
{
/// <summary>
/// 检查Path是否存在
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public bool CheckPathExists(string filePath)
{
#if !UNITY_SWITCH
return false;
#else
@ -86,14 +86,14 @@ public class AxiNSIO
//return nn.fs.FileSystem.ResultPathAlreadyExists.Includes(result);
return !nn.fs.FileSystem.ResultPathNotFound.Includes(result);
#endif
}
/// <summary>
/// 检查Path是否不存在
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public bool CheckPathNotFound(string filePath)
{
}
/// <summary>
/// 检查Path是否不存在
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public bool CheckPathNotFound(string filePath)
{
#if !UNITY_SWITCH
return false;
#else
@ -102,16 +102,16 @@ public class AxiNSIO
//这个异常捕获。真的别扭
return nn.fs.FileSystem.ResultPathNotFound.Includes(result);
#endif
}
/// <summary>
/// 创建目录目录存在也会返回true
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public bool CreateDir(string filePath)
{
lock (commitLock)
{
}
/// <summary>
/// 创建目录目录存在也会返回true
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public bool CreateDir(string filePath)
{
lock (commitLock)
{
#if !UNITY_SWITCH
return false;
@ -124,43 +124,43 @@ public class AxiNSIO
}
return true;
#endif
}
}
}
}
/// <summary>
/// 保存并创建文件(如果目录不存在回先自动创建目录)
/// </summary>
/// <param name="filePath"></param>
/// <param name="bw"></param>
/// <returns></returns>
public bool FileToSaveWithCreate(string filePath, System.IO.MemoryStream ms)
{
return FileToSaveWithCreate(filePath, ms.ToArray());
}
/// <summary>
/// 保存并创建文件(如果目录不存在回先自动创建目录)
/// </summary>
/// <param name="filePath"></param>
/// <param name="data"></param>
/// <returns></returns>
public AxiNSWait_FileToSaveByMSWithCreate FileToSaveWithCreateAsync(string filePath, System.IO.MemoryStream ms)
{
var wait = new AxiNSWait_FileToSaveByMSWithCreate(filePath, ms);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
/// <summary>
/// 保存并创建文件(如果目录不存在回先自动创建目录)
/// </summary>
/// <param name="filePath"></param>
/// <param name="bw"></param>
/// <returns></returns>
public bool FileToSaveWithCreate(string filePath, System.IO.MemoryStream ms)
{
return FileToSaveWithCreate(filePath, ms.ToArray());
}
/// <summary>
/// 保存并创建文件(如果目录不存在回先自动创建目录)
/// </summary>
/// <param name="filePath"></param>
/// <param name="data"></param>
/// <returns></returns>
public AxiNSWait_FileToSaveByMSWithCreate FileToSaveWithCreateAsync(string filePath, System.IO.MemoryStream ms)
{
var wait = new AxiNSWait_FileToSaveByMSWithCreate(filePath, ms);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
/// <summary>
/// 保存并创建文件(如果目录不存在回先自动创建目录)
/// </summary>
/// <param name="filePath"></param>
/// <param name="data"></param>
/// <param name="immediatelyCommit">是否立即Commit到物理存储</param>
/// <returns></returns>
public bool FileToSaveWithCreate(string filePath, byte[] data, bool immediatelyCommit = true)
{
lock (commitLock)
{
/// <summary>
/// 保存并创建文件(如果目录不存在回先自动创建目录)
/// </summary>
/// <param name="filePath"></param>
/// <param name="data"></param>
/// <param name="immediatelyCommit">是否立即Commit到物理存储</param>
/// <returns></returns>
public bool FileToSaveWithCreate(string filePath, byte[] data, bool immediatelyCommit = true)
{
lock (commitLock)
{
#if !UNITY_SWITCH
return false;
#else
@ -293,42 +293,45 @@ public class AxiNSIO
return true;
}
#endif
}
}
/// <summary>
/// 保存并创建文件(如果目录不存在回先自动创建目录)
/// </summary>
/// <param name="filePath"></param>
/// <param name="data"></param>
/// <returns></returns>
public AxiNSWait_FileToSaveWithCreate FileToSaveWithCreateAsync(string filePath, byte[] data)
{
var wait = new AxiNSWait_FileToSaveWithCreate(filePath, data);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
public byte[] LoadSwitchDataFile(string filename)
{
LoadSwitchDataFile(filename, out byte[] outputData);
return outputData;
}
public bool LoadSwitchDataFile(string filename, ref System.IO.MemoryStream ms)
{
if (LoadSwitchDataFile(filename, out byte[] outputData))
{
using (System.IO.BinaryWriter writer = new System.IO.BinaryWriter(ms))
{
writer.Write(outputData);
}
return true;
}
return false;
}
public bool LoadSwitchDataFile(string filename, out byte[] outputData)
{
}
}
/// <summary>
/// 保存并创建文件(如果目录不存在回先自动创建目录)
/// </summary>
/// <param name="filePath"></param>
/// <param name="data"></param>
/// <returns></returns>
public AxiNSWait_FileToSaveWithCreate FileToSaveWithCreateAsync(string filePath, byte[] data)
{
var wait = new AxiNSWait_FileToSaveWithCreate(filePath, data);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
public byte[] LoadSwitchDataFile(string filename)
{
byte[] outputData;
LoadSwitchDataFile(filename, out outputData);
return outputData;
}
public bool LoadSwitchDataFile(string filename, ref System.IO.MemoryStream ms)
{
byte[] outputData;
if (LoadSwitchDataFile(filename, out outputData))
{
using (System.IO.BinaryWriter writer = new System.IO.BinaryWriter(ms))
{
writer.Write(outputData);
}
return true;
}
return false;
}
public bool LoadSwitchDataFile(string filename, out byte[] outputData)
{
#if !UNITY_SWITCH || UNITY_EDITOR
outputData = null;
return false;
outputData = null;
return false;
#else
outputData = null;
if (!AxiNS.instance.mount.SaveIsMount)
@ -376,32 +379,34 @@ public class AxiNSIO
outputData = loadedData;
return true;
#endif
}
public AxiNSWait_LoadSwitchDataFile LoadSwitchDataFileAsync(string filename)
{
var wait = new AxiNSWait_LoadSwitchDataFile(filename);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
public bool GetDirectoryFiles(string path, out string[] entrys)
{
}
public AxiNSWait_LoadSwitchDataFile LoadSwitchDataFileAsync(string filename)
{
var wait = new AxiNSWait_LoadSwitchDataFile(filename);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
public bool GetDirectoryFiles(string path, out string[] entrys)
{
#if !UNITY_SWITCH || UNITY_EDITOR
entrys = null;
return false;
entrys = null;
return false;
#else
return GetDirectoryEntrys(path,nn.fs.OpenDirectoryMode.File,out entrys);
#endif
}
public bool GetDirectoryDirs(string path, out string[] entrys)
{
}
public bool GetDirectoryDirs(string path, out string[] entrys)
{
#if !UNITY_SWITCH || UNITY_EDITOR
entrys = null;
return false;
entrys = null;
return false;
#else
return GetDirectoryEntrys(path, nn.fs.OpenDirectoryMode.Directory, out entrys);
#endif
}
}
#if UNITY_SWITCH
public bool GetDirectoryEntrys(string path, nn.fs.OpenDirectoryMode type, out string[] entrys)
@ -430,8 +435,9 @@ public class AxiNSIO
}
#endif
public bool GetDirectoryEntrysFullRecursion(string path, out string[] entrys)
{
public bool GetDirectoryEntrysFullRecursion(string path, out string[] entrys)
{
#if UNITY_SWITCH
nn.fs.DirectoryHandle eHandle = new nn.fs.DirectoryHandle();
@ -462,15 +468,15 @@ public class AxiNSIO
entrys = temp.ToArray();
return true;
#else
entrys = default;
entrys = null;
return false;
#endif
}
}
public IEnumerable<string> EnumerateFiles(string path, string searchPattern)
{
public IEnumerable<string> EnumerateFiles(string path, string searchPattern)
{
#if !UNITY_SWITCH || UNITY_EDITOR
yield break;
yield break;
#else
// 将通配符转换为正则表达式(支持*和?
var regexPattern = "^" +
@ -494,10 +500,10 @@ public class AxiNSIO
}
}
#endif
}
}
public bool DeletePathFile(string filename)
{
public bool DeletePathFile(string filename)
{
#if !UNITY_SWITCH
return false;
#else
@ -526,15 +532,15 @@ public class AxiNSIO
return CommitSave();
#endif
}
public AxiNSWait_DeletePathFile DeletePathFileAsync(string filename)
{
var wait = new AxiNSWait_DeletePathFile(filename);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
public bool DeletePathDir(string filename)
{
}
public AxiNSWait_DeletePathFile DeletePathFileAsync(string filename)
{
var wait = new AxiNSWait_DeletePathFile(filename);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
public bool DeletePathDir(string filename)
{
#if !UNITY_SWITCH
return false;
#else
@ -561,15 +567,15 @@ public class AxiNSIO
#endif
return CommitSave();
#endif
}
public AxiNSWait_DeletePathDir DeletePathDirAsync(string filename)
{
var wait = new AxiNSWait_DeletePathDir(filename);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
public bool DeletePathDirRecursively(string filename)
{
}
public AxiNSWait_DeletePathDir DeletePathDirAsync(string filename)
{
var wait = new AxiNSWait_DeletePathDir(filename);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
public bool DeletePathDirRecursively(string filename)
{
#if !UNITY_SWITCH
return false;
#else
@ -596,19 +602,86 @@ public class AxiNSIO
#endif
return CommitSave();
#endif
}
}
public AxiNSWait_DeletePathDirRecursively DeletePathDirRecursivelyAsync(string filename)
{
var wait = new AxiNSWait_DeletePathDirRecursively(filename);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
#if UNITY_SWITCH
public AxiNSWait_DeletePathDirRecursively DeletePathDirRecursivelyAsync(string filename)
{
var wait = new AxiNSWait_DeletePathDirRecursively(filename);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
/// <summary>
/// 递归删除目录
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public bool DeleteRecursivelyPathDir(string filename)
{
#if !UNITY_SWITCH
return false;
#else
#if UNITY_SWITCH && !UNITY_EDITOR
// This next line prevents the user from quitting the game while saving.
// This is required for Nintendo Switch Guideline 0080
UnityEngine.Switch.Notification.EnterExitRequestHandlingSection();
#endif
public bool RenameDir(string oldpath, string newpath)
{
if (CheckPathNotFound(filename))
return false;
nn.Result result;
result = nn.fs.Directory.DeleteRecursively(filename);
if (result.IsSuccess() == false)
{
UnityEngine.Debug.LogError($"nn.fs.File.DeleteRecursively 失败 {filename} : result=>{result.GetErrorInfo()}");
return false;
}
#if UNITY_SWITCH && !UNITY_EDITOR
// End preventing the user from quitting the game while saving.
UnityEngine.Switch.Notification.LeaveExitRequestHandlingSection();
#endif
return CommitSave();
#endif
}
/// <summary>
/// 递归删除情况
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public bool CleanRecursivelyPathDir(string filename)
{
#if !UNITY_SWITCH
return false;
#else
#if UNITY_SWITCH && !UNITY_EDITOR
// This next line prevents the user from quitting the game while saving.
// This is required for Nintendo Switch Guideline 0080
UnityEngine.Switch.Notification.EnterExitRequestHandlingSection();
#endif
if (CheckPathNotFound(filename))
return false;
nn.Result result;
result = nn.fs.Directory.CleanRecursively(filename);
if (result.IsSuccess() == false)
{
UnityEngine.Debug.LogError($"nn.fs.File.DeleteRecursively 失败 {filename} : result=>{result.GetErrorInfo()}");
return false;
}
#if UNITY_SWITCH && !UNITY_EDITOR
// End preventing the user from quitting the game while saving.
UnityEngine.Switch.Notification.LeaveExitRequestHandlingSection();
#endif
return CommitSave();
#endif
}
public bool RenameDir(string oldpath, string newpath)
{
#if !UNITY_SWITCH
return false;
#else
@ -637,9 +710,9 @@ public class AxiNSIO
return CommitSave();
#endif
}
bool EnsureParentDirectory(string filePath, bool bAutoCreateDir = true)
{
}
bool EnsureParentDirectory(string filePath, bool bAutoCreateDir = true)
{
#if !UNITY_SWITCH
return false;
#else
@ -715,14 +788,14 @@ public class AxiNSIO
return true;
#endif
}
/// <summary>
/// 检查指定挂载点是否可访问
/// </summary>
/// <param name="pathPrefix">路径前缀,例如 "save:/" 或 "sd:/"</param>
/// <returns>挂载点是否可访问</returns>
bool IsMountPointAccessible(string pathPrefix)
{
}
/// <summary>
/// 检查指定挂载点是否可访问
/// </summary>
/// <param name="pathPrefix">路径前缀,例如 "save:/" 或 "sd:/"</param>
/// <returns>挂载点是否可访问</returns>
bool IsMountPointAccessible(string pathPrefix)
{
#if !UNITY_SWITCH
return false;
#else
@ -760,5 +833,5 @@ public class AxiNSIO
return true; // 其他挂载点需根据实际需求实现
}
#endif
}
}
}

View File

@ -0,0 +1,41 @@
using System;
using UnityEngine;
public class AxiNSMono : MonoBehaviour
{
Action act;
float waittime;
float lastinvokeTime;
public static void SetInvoke(Action _act, int _waitsec)
{
GameObject gobj = GameObject.Find($"[{nameof(AxiNSMono)}]");
if (gobj == null)
{
gobj = new GameObject();
gobj.name = $"[{nameof(AxiNSMono)}]";
GameObject.DontDestroyOnLoad(gobj);
}
AxiNSMono com = gobj.GetComponent<AxiNSMono>();
if (com == null)
{
com = gobj.AddComponent<AxiNSMono>();
}
com.act = _act;
com.waittime = _waitsec;
}
public void OnEnable()
{
Debug.Log("AxiNSMono Enable");
}
public void Update()
{
if (Time.time - lastinvokeTime < waittime)
return;
lastinvokeTime = Time.time;
if (act != null)
act.Invoke();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 23d5745b8989af04d8a871b5c7b65d50
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -116,4 +116,19 @@ public class AxiNSWait_DeletePathDir : AxiNSWaitBase
{
result = AxiNS.instance.io.DeletePathDir(req.filePath);
}
}
public class AxiNSWait_DeletePathDirRecursively : AxiNSWaitBase
{
S_NSWAIT_Path req;
public bool result;
public AxiNSWait_DeletePathDirRecursively(string filePath)
{
req = new S_NSWAIT_Path() { filePath = filePath };
}
public override void Invoke()
{
result = AxiNS.instance.io.DeletePathDirRecursively(req.filePath);
}
}

View File

@ -4,21 +4,30 @@ using System.Threading;
public class AxiNSWaitHandle
{
static AutoResetEvent autoEvent = new AutoResetEvent(false);
static Thread waitThread = new Thread(Loop);
static bool bSingleInit = false;
static Queue<AxiNSWaitBase> m_QueueReady = new Queue<AxiNSWaitBase>();
static Queue<AxiNSWaitBase> m_QueueWork = new Queue<AxiNSWaitBase>();
public void AddWait(AxiNSWaitBase wait)
{
InitInternalThread();
lock (m_QueueReady)
{
m_QueueReady.Enqueue(wait);
}
autoEvent.Set();
if (AxiNS.usedmultithreading)
{
InitInternalThread();
autoEvent.Set();
}
else
{
InitMonoInit();
}
}
#region 线
static AutoResetEvent autoEvent = new AutoResetEvent(false);
static Thread waitThread = new Thread(Loop);
static bool bSingleInit = false;
static void InitInternalThread()
{
if (bSingleInit) return;
@ -30,27 +39,43 @@ public class AxiNSWaitHandle
{
while (autoEvent.WaitOne())
{
lock (m_QueueReady)
Do();
}
}
#endregion
#region 线
static bool bMonoInit = false;
static void InitMonoInit()
{
if (bMonoInit) return;
AxiNSMono.SetInvoke(Do,15);
bMonoInit = true;
}
#endregion
static void Do()
{
lock (m_QueueReady)
{
while (m_QueueReady.Count > 0)
{
while (m_QueueReady.Count > 0)
{
m_QueueWork.Enqueue(m_QueueReady.Dequeue());
}
m_QueueWork.Enqueue(m_QueueReady.Dequeue());
}
while (m_QueueWork.Count > 0)
}
while (m_QueueWork.Count > 0)
{
AxiNSWaitBase wait = m_QueueWork.Dequeue();
try
{
AxiNSWaitBase wait = m_QueueWork.Dequeue();
try
{
wait.Invoke();
}
catch (Exception ex)
{
wait.errmsg = ex.ToString();
UnityEngine.Debug.Log(ex.ToString());
}
wait.SetDone();
wait.Invoke();
}
catch (Exception ex)
{
wait.errmsg = ex.ToString();
UnityEngine.Debug.Log(ex.ToString());
}
wait.SetDone();
}
}
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 25ea535c006d6544d9b301a2dcde95b9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,5 @@
{
"timestamp": 1648458313,
"signature": "DWppfmRE13R6S+n/9p1BkuJhH8i4OF2aZu3uXd+7pP8L9LaFr+oymbRCxdy+8l1IFlQzQbQL1ewVCMnKQIonn36dYoZpneipJbUa4CBvwiDObtwD1WSasTq8d9smbhOmeBewyLfkHsGmI4z0WvSJFyq11ISeMXe8pCVoq/PNi5gKfxwvOh4Cy49Y65MZOGAI0MOcOyfQjRS7cR5oPEtAQJysVRtcJPcbPSgr5tjbM9dLf7h5/J6AWXCBav4m6h6932umoOv5FsBQhNQquKqbC984E5ku8G45UKX7t7V0pJFBQe0y1++MN8aSVyJ08IV6h206tTOfIyZVRwswMGGyoAvbF5SF0CmL12QbkW7giZJTa23fvOv09sM3nlA2JpyVSvPWgMmv5HGsLvaboXxSVAp6HcN1M83rMPiQaS34YW/f+JgrHumKa/TTwpzml7kG5xdk3dOACLHRlyDag3oHYmC1OpaI1rnlt7r+z3gCYz5dGTavkHHnNRBukliZYft/",
"publicKey": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQm9qQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FZOEFNSUlCaWdLQ0FZRUFzdUhXYUhsZ0I1cVF4ZEJjTlJKSAordHR4SmoxcVY1NTdvMlZaRE1XaXhYRVBkRTBEMVFkT1JIRXNSS1RscmplUXlERU83ZlNQS0ZwZ1A3MU5TTnJCCkFHM2NFSU45aHNQVDhOVmllZmdWem5QTkVMenFkVmdEbFhpb2VpUnV6OERKWFgvblpmU1JWKytwbk9ySTRibG4KS0twelJlNW14OTc1SjhxZ1FvRktKT0NNRlpHdkJMR2MxSzZZaEIzOHJFODZCZzgzbUovWjBEYkVmQjBxZm13cgo2ZDVFUXFsd0E5Y3JZT1YyV1VpWXprSnBLNmJZNzRZNmM1TmpBcEFKeGNiaTFOaDlRVEhUcU44N0ZtMDF0R1ZwCjVNd1pXSWZuYVRUemEvTGZLelR5U0pka0tldEZMVGdkYXpMYlpzUEE2aHBSK0FJRTJhc0tLTi84UUk1N3UzU2cKL2xyMnZKS1IvU2l5eEN1Q20vQWJkYnJMbXk0WjlSdm1jMGdpclA4T0lLQWxBRWZ2TzV5Z2hSKy8vd1RpTFlzUQp1SllDM0V2UE16ZGdKUzdGR2FscnFLZzlPTCsxVzROY05yNWdveVdSUUJ0cktKaWlTZEJVWmVxb0RvSUY5NHpCCndGbzJJT1JFdXFqcU51M3diMWZIM3p1dGdtalFra3IxVjJhd3hmcExLWlROQWdNQkFBRT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg"
}

View File

@ -0,0 +1,49 @@
# Changelog
All notable changes to the input system package will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
Due to package verification, the latest version below is the unpublished version and the date is meaningless.
however, it has to be formatted properly to pass verification tests.
## [0.1.0-preview] - 2019-9-2
First release from develop branch.
## [0.1.1-preview] - 2019-10-29
Updated package dependencies to use latest `com.unity.inputsystem` package version 1.0.0-preview.1
## [0.1.2-preview] - 2021-05-17
Updated package dependencies to `com.unity.inputsystem` package version 1.1.0-preview.2 and Unity 2019.4
Overrides added for aButton, bButton, xButton, yButton functions to map to north, south, east, west buttons correctly for Nintendo layout.
Fixed incorrect shortDisplayName values inherited from Gamepad.cs
Added "Submit" & "Cancel" UI usage tags to A and B buttons.
Added Joy-Con attrbutes to NPad.cs as a bit field, with accessors to get connected and wired states.
Minium Unity versions for checking m_Attributes functions (IsWired/IsConnected)
2021.2.0a10, 2021.1.1f1, 2020.3.4f1, 2019.4.24f1
Added code to parse the Unity application version string and test for NPad attributes support (Assert if attempting to use attributes and Unity version is below minimum required).
## [0.1.3-pre] - 2021-07-06
Updated package dependencies to use `com.unity.inputsystem` package 1.1.0-pre.5
This fixes an issue where earlier 'com.unity.inputsystem' packages (1.1.0-preview.X) were considered more recent than 1.1.0-pre.5 due to the Semantic Versioning spec and that prevented upgrading to 1.1.0-pre.5 or later.
Updated the package name to the use the "Pre-release" label following the new package lifecycle naming convention & patch version increased.
## [0.1.4-pre] - 2021-11-03
Fixed logic error in minimum version check (IsVersionOrHigher) for checking support for m_Attributes.
The Unity version type (alpha, beta, final etc) should be checked ahead of the revision, so 2021.2.0f1 (final 1) is recognised as a later version than 2021.2.0a10 (alpha 10)
## [0.1.5-pre] - 2021-11-15
The package is now signed.
## [0.1.6-pre] - 2022-03-55
Fixed a bug where ResetHaptics and PauseHaptics functions were not specifying a RumblePosition flag (Was None, should be All) and so had no effect when called.
NPadDeviceIOCTLOutputCommand Create function now takes RumblePosition as an argument (defaulting to All)
Fixed a bug in NPadRumbleValues.Reset() where frequencyHigh was not being reset.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2fe913aba0c6c104ca6b05e2a1def256
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3b3482582c1bb9341aacbb0a24c53938
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: aaa7ef903a2a1a041b6888d1a259bda3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9177521509a3da24cb1e37e9eb8d7248
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,27 @@
#if UNITY_EDITOR || UNITY_SWITCH
using UnityEngine.InputSystem.Haptics;
namespace UnityEngine.InputSystem.Switch
{
/// <summary>
/// Extended dual motor gamepad that adds seperate controls for rumble frequency and amplitude.
/// </summary>
public interface INPadRumble : IDualMotorRumble
{
/// <summary>
/// Set rumble for all motors
/// </summary>
void SetMotorSpeeds(float lowAmplitude, float lowFrequency, float highAmplitude, float highFrequency);
/// <summary>
/// Set rumble for left motor
/// </summary>
void SetMotorSpeedLeft(float lowAmplitude, float lowFrequency, float highAmplitude, float highFrequency);
/// <summary>
/// Set rumble for right motor
/// </summary>
void SetMotorSpeedRight(float lowAmplitude, float lowFrequency, float highAmplitude, float highFrequency);
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f7abf5d9c0bddda4cb82a5d0b3525c0b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,746 @@
#if UNITY_EDITOR || UNITY_SWITCH || PACKAGE_DOCS_GENERATION
using System;
using System.Runtime.InteropServices;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.Switch.LowLevel;
using UnityEngine.InputSystem.Utilities;
////REVIEW: The Switch controller can be used to point at things; can we somehow help leverage that?
namespace UnityEngine.InputSystem.Switch.LowLevel
{
/// <summary>
/// Structure of native input reports for Switch NPad controllers.
/// </summary>
/// <seealso href="http://en-americas-support.nintendo.com/app/answers/detail/a_id/22634/~/joy-con-controller-diagram"/>
[StructLayout(LayoutKind.Explicit, Size = 60)]
internal struct NPadInputState : IInputStateTypeInfo
{
public FourCC format
{
get { return new FourCC('N', 'P', 'A', 'D'); }
}
[InputControl(name = "dpad")]
[InputControl(name = "buttonNorth", displayName = "X", shortDisplayName = "X", bit = (uint)Button.North)]
[InputControl(name = "buttonSouth", displayName = "B", shortDisplayName = "B", bit = (uint)Button.South, usages = new[] { "Back", "Cancel" })]
[InputControl(name = "buttonWest", displayName = "Y", shortDisplayName = "Y", bit = (uint)Button.West, usage = "SecondaryAction")]
[InputControl(name = "buttonEast", displayName = "A", shortDisplayName = "A", bit = (uint)Button.East, usages = new[] { "PrimaryAction", "Submit" })]
[InputControl(name = "leftStickPress", displayName = "Left Stick", bit = (uint)Button.StickL)]
[InputControl(name = "rightStickPress", displayName = "Right Stick", bit = (uint)Button.StickR)]
[InputControl(name = "leftShoulder", displayName = "L", shortDisplayName = "L", bit = (uint)Button.L)]
[InputControl(name = "rightShoulder", displayName = "R", shortDisplayName = "R", bit = (uint)Button.R)]
[InputControl(name = "leftTrigger", displayName = "ZL", shortDisplayName = "ZL", format = "BIT", bit = (uint)Button.ZL)]
[InputControl(name = "rightTrigger", displayName = "ZR", shortDisplayName = "ZR", format = "BIT", bit = (uint)Button.ZR)]
[InputControl(name = "start", displayName = "Plus", bit = (uint)Button.Plus, usage = "Menu")]
[InputControl(name = "select", displayName = "Minus", bit = (uint)Button.Minus)]
[InputControl(name = "leftSL", displayName = "SL (Left)", shortDisplayName = "LSL", layout = "Button", bit = (uint)Button.LSL)]
[InputControl(name = "leftSR", displayName = "SR (Left)", shortDisplayName = "LSR", layout = "Button", bit = (uint)Button.LSR)]
[InputControl(name = "rightSL", displayName = "SL (Right)", shortDisplayName = "RSL", layout = "Button", bit = (uint)Button.RSL)]
[InputControl(name = "rightSR", displayName = "SR (Right)", shortDisplayName = "RSR", layout = "Button", bit = (uint)Button.RSR)]
[FieldOffset(0)]
public uint buttons;
[FieldOffset(4)]
public Vector2 leftStick;
[FieldOffset(12)]
public Vector2 rightStick;
[InputControl(name = "acceleration", noisy = true)]
[FieldOffset(20)]
public Vector3 acceleration;
[InputControl(name = "attitude", noisy = true)]
[FieldOffset(32)]
public Quaternion attitude;
[InputControl(name = "angularVelocity", noisy = true)]
[FieldOffset(48)]
public Vector3 angularVelocity;
public float leftTrigger => ((buttons & (1 << (int)Button.ZL)) != 0) ? 1f : 0f;
public float rightTrigger => ((buttons & (1 << (int)Button.ZR)) != 0) ? 1f : 0f;
public enum Button
{
// Dpad buttons. Important to be first in the bitfield as we'll
// point the DpadControl to it.
// IMPORTANT: Order has to match what is expected by DpadControl.
Up,
Down,
Left,
Right,
North,
South,
West,
East,
StickL,
StickR,
L,
R,
ZL,
ZR,
Plus,
Minus,
LSL,
LSR,
RSL,
RSR,
X = North,
B = South,
Y = West,
A = East,
}
public NPadInputState WithButton(Button button, bool value = true)
{
var bit = (uint)1 << (int)button;
if (value)
buttons |= bit;
else
buttons &= ~bit;
return this;
}
}
/// <summary>
/// Switch output report sent as command to the backend.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal struct NPadStatusReport : IInputDeviceCommandInfo
{
public static FourCC Type => new FourCC('N', 'P', 'D', 'S');
internal const int kSize = InputDeviceCommand.BaseCommandSize + 24;
[FieldOffset(0)]
public InputDeviceCommand baseCommand;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 0)]
public NPad.NpadId npadId;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 1)]
public NPad.Orientation orientation;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 2)]
public NPad.Attributes attributes;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 3)]
public char padding0;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 4)]
public NPad.NpadStyles styleMask;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 8)]
public int colorLeftMain;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 12)]
public int colorLeftSub;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 16)]
public int colorRightMain;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 20)]
public int colorRightSub;
public FourCC typeStatic
{
get { return Type; }
}
public static NPadStatusReport Create()
{
return new NPadStatusReport
{
baseCommand = new InputDeviceCommand(Type, kSize),
};
}
}
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal struct NPadControllerSupportCommand : IInputDeviceCommandInfo
{
public static FourCC Type => new FourCC('N', 'P', 'D', 'U');
internal const int kSize = InputDeviceCommand.BaseCommandSize + 8;
[FieldOffset(0)]
public InputDeviceCommand baseCommand;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 0)]
public int command;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 4)]
public int option;
public enum Command : int
{
kShowUI,
kSetHorizontalLayout,
kStartSixAxisSensor,
kStopSixAxisSensor,
}
public FourCC typeStatic
{
get { return Type; }
}
public static NPadControllerSupportCommand Create(NPadControllerSupportCommand.Command command, int option = 0)
{
return new NPadControllerSupportCommand
{
baseCommand = new InputDeviceCommand(Type, kSize),
command = (int)command,
option = option,
};
}
}
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal struct NpadDeviceIOCTLShowUI : IInputDeviceCommandInfo
{
public static FourCC Type => new FourCC("NSUI");
internal const int kSize = InputDeviceCommand.BaseCommandSize;
[FieldOffset(0)]
public InputDeviceCommand baseCommand;
public FourCC typeStatic
{
get { return Type; }
}
public static NpadDeviceIOCTLShowUI Create()
{
return new NpadDeviceIOCTLShowUI
{
baseCommand = new InputDeviceCommand(Type, kSize),
};
}
}
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal struct NpadDeviceIOCTLSetOrientation : IInputDeviceCommandInfo
{
public static FourCC Type => new FourCC("NSOR");
internal const int kSize = InputDeviceCommand.BaseCommandSize + 1;
[FieldOffset(0)]
public InputDeviceCommand baseCommand;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 0)]
public NPad.Orientation orientation;
public FourCC typeStatic
{
get { return Type; }
}
public static NpadDeviceIOCTLSetOrientation Create(NPad.Orientation orientation)
{
return new NpadDeviceIOCTLSetOrientation
{
baseCommand = new InputDeviceCommand(Type, kSize),
orientation = orientation,
};
}
}
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal struct NpadDeviceIOCTLStartSixAxisSensor : IInputDeviceCommandInfo
{
public static FourCC Type => new FourCC("SXST");
internal const int kSize = InputDeviceCommand.BaseCommandSize;
[FieldOffset(0)]
public InputDeviceCommand baseCommand;
public FourCC typeStatic
{
get { return Type; }
}
public static NpadDeviceIOCTLStartSixAxisSensor Create()
{
return new NpadDeviceIOCTLStartSixAxisSensor
{
baseCommand = new InputDeviceCommand(Type, kSize),
};
}
}
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal struct NpadDeviceIOCTLStopSixAxisSensor : IInputDeviceCommandInfo
{
public static FourCC Type => new FourCC("SXSP");
internal const int kSize = InputDeviceCommand.BaseCommandSize;
[FieldOffset(0)]
public InputDeviceCommand baseCommand;
public FourCC typeStatic
{
get { return Type; }
}
public static NpadDeviceIOCTLStopSixAxisSensor Create()
{
return new NpadDeviceIOCTLStopSixAxisSensor
{
baseCommand = new InputDeviceCommand(Type, kSize),
};
}
}
/// <summary>
/// Switch output report sent as command to backend.
/// </summary>
// IMPORTANT: Struct must match the NpadDeviceIOCTLOutputReport in native
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal struct NPadDeviceIOCTLOutputCommand : IInputDeviceCommandInfo
{
public static FourCC Type { get { return new FourCC('N', 'P', 'G', 'O'); } }
internal const int kSize = InputDeviceCommand.BaseCommandSize + 20;
public const float DefaultFrequencyLow = 160.0f;
public const float DefaultFrequencyHigh = 320.0f;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1028:EnumStorageShouldBeInt32", Justification = "Need to match native struct data size")]
public enum NPadRumblePostion : byte
{
Left = 0x02,
Right = 0x04,
All = 0xFF,
None = 0x00,
}
[FieldOffset(0)] public InputDeviceCommand baseCommand;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 0)]
public byte positions;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 4)]
public float amplitudeLow;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 8)]
public float frequencyLow;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 12)]
public float amplitudeHigh;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 16)]
public float frequencyHigh;
public FourCC typeStatic
{
get { return Type; }
}
public static NPadDeviceIOCTLOutputCommand Create(NPadRumblePostion rumblePos = NPadRumblePostion.All)
{
return new NPadDeviceIOCTLOutputCommand()
{
baseCommand = new InputDeviceCommand(Type, kSize),
positions = (byte)rumblePos,
amplitudeLow = 0,
frequencyLow = DefaultFrequencyLow,
amplitudeHigh = 0,
frequencyHigh = DefaultFrequencyHigh
};
}
}
}
namespace UnityEngine.InputSystem.Switch
{
/// <summary>
/// An NPad controller for Switch, which can be a Joy-Con.
/// </summary>
/// <seealso cref="NPadInputState"/>
[InputControlLayout(stateType = typeof(NPadInputState), displayName = "Switch Controller (on Switch)")]
[Scripting.Preserve]
public class NPad : Gamepad, INPadRumble
{
public ButtonControl leftSL { get; private set; }
public ButtonControl leftSR { get; private set; }
public ButtonControl rightSL { get; private set; }
public ButtonControl rightSR { get; private set; }
public Vector3Control acceleration { get; private set; }
public QuaternionControl attitude { get; private set; }
public Vector3Control angularVelocity { get; private set; }
// Override inherited a/b/x/y mappings to match the JoyCon layout
public new ButtonControl bButton => buttonSouth;
public new ButtonControl aButton => buttonEast;
public new ButtonControl yButton => buttonWest;
public new ButtonControl xButton => buttonNorth;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1028:EnumStorageShouldBeInt32", Justification = "Need to match native struct data size")]
public enum Orientation : byte
{
Vertical,
Horizontal,
Default = Vertical,
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1028:EnumStorageShouldBeInt32", Justification = "Need to match native struct data size")]
public enum NpadId : byte
{
No1 = 0x00,
No2 = 0x01,
No3 = 0x02,
No4 = 0x03,
No5 = 0x04,
No6 = 0x05,
No7 = 0x06,
No8 = 0x07,
Handheld = 0x20,
Debug = 0xF0,
Invalid = 0xFF,
}
[Flags]
public enum Attributes
{
IsConnected = 0x01,
IsWired = 0x02,
IsLeftConnected = 0x04,
IsLeftWired = 0x08,
IsRightConnected = 0x10,
IsRightWired = 0x20,
}
//orientation matters for stick axes!!!!
//there's a touchpad and 90% of games don't support it
//each person could play with a different style
[Flags]
public enum NpadStyles
{
FullKey = 1 << 0,//separate;or pro controller;only one accel
Handheld = 1 << 1,//docked to switch
JoyDual = 1 << 2,//separate; one accel per joycon
JoyLeft = 1 << 3,//just one; orientation matters
JoyRight = 1 << 4,//just one; orientation matters
}
public struct JoyConColor
{
public Color32 Main;
public Color32 Sub;
}
public Orientation orientation
{
get
{
RefreshConfigurationIfNeeded();
return m_Orientation;
}
}
public NpadId npadId
{
get
{
RefreshConfigurationIfNeeded();
return m_NpadId;
}
}
public NpadStyles styleMask
{
get
{
RefreshConfigurationIfNeeded();
return m_StyleMask;
}
}
public JoyConColor leftControllerColor
{
get
{
RefreshConfigurationIfNeeded();
return m_LeftControllerColor;
}
}
public JoyConColor rightControllerColor
{
get
{
RefreshConfigurationIfNeeded();
return m_RightControllerColor;
}
}
public bool isConnected
{
get
{
Debug.Assert(SwitchConsoleSupport.NpadAttributesSupported(), k_StringAttributesNotSupported);
RefreshConfigurationIfNeeded();
return (m_Attributes & Attributes.IsConnected) != 0;
}
}
public bool isLeftConnected
{
get
{
Debug.Assert(SwitchConsoleSupport.NpadAttributesSupported(), k_StringAttributesNotSupported);
RefreshConfigurationIfNeeded();
return (m_Attributes & Attributes.IsLeftConnected) != 0;
}
}
public bool isRightConnected
{
get
{
Debug.Assert(SwitchConsoleSupport.NpadAttributesSupported(),k_StringAttributesNotSupported);
RefreshConfigurationIfNeeded();
return (m_Attributes & Attributes.IsRightConnected) != 0;
}
}
public bool isWired
{
get
{
Debug.Assert(SwitchConsoleSupport.NpadAttributesSupported(), k_StringAttributesNotSupported);
RefreshConfigurationIfNeeded();
return (m_Attributes & Attributes.IsWired) != 0;
}
}
public bool isLeftWired
{
get
{
Debug.Assert(SwitchConsoleSupport.NpadAttributesSupported(), k_StringAttributesNotSupported);
RefreshConfigurationIfNeeded();
return (m_Attributes & Attributes.IsLeftWired) != 0;
}
}
public bool isRightWired
{
get
{
Debug.Assert(SwitchConsoleSupport.NpadAttributesSupported(), k_StringAttributesNotSupported);
RefreshConfigurationIfNeeded();
return (m_Attributes & Attributes.IsRightWired) != 0;
}
}
private Orientation m_Orientation;
private NpadId m_NpadId = NpadId.Invalid;
private NpadStyles m_StyleMask;
private JoyConColor m_LeftControllerColor;
private JoyConColor m_RightControllerColor;
private Attributes m_Attributes;
private const string k_StringAttributesNotSupported = "Attributes not supported in this Unity version! Requires 2021.2.0a10, 2021.1.1f1, 2020.3.4f1, 2019.4.24f1 or higher";
private struct NPadRumbleValues
{
public float? amplitudeLow;
public float? frequencyLow;
public float? amplitudeHigh;
public float? frequencyHigh;
public bool HasValues => amplitudeLow.HasValue && frequencyLow.HasValue && amplitudeHigh.HasValue && frequencyHigh.HasValue;
public void SetRumbleValues(float lowAmplitude, float lowFrequency, float highAmplitude, float highFrequency)
{
amplitudeLow = Mathf.Clamp01(lowAmplitude);
frequencyLow = lowFrequency;
amplitudeHigh = Mathf.Clamp01(highAmplitude);
frequencyHigh = highFrequency;
}
public void Reset()
{
amplitudeLow = null;
frequencyLow = null;
amplitudeHigh = null;
frequencyHigh = null;
}
public void ApplyRumbleValues(ref NPadDeviceIOCTLOutputCommand cmd)
{
cmd.amplitudeLow = (float)amplitudeLow;
cmd.frequencyLow = (float)frequencyLow;
cmd.amplitudeHigh = (float)amplitudeHigh;
cmd.frequencyHigh = (float)frequencyHigh;
}
}
private NPadRumbleValues m_leftRumbleValues;
private NPadRumbleValues m_rightRumbleValues;
protected override void RefreshConfiguration()
{
base.RefreshConfiguration();
var command = NPadStatusReport.Create();
if (ExecuteCommand(ref command) > 0)
{
m_NpadId = command.npadId;
m_Orientation = command.orientation;
m_StyleMask = command.styleMask;
m_Attributes = command.attributes;
ReadNNColorIntoJoyConColor(ref m_LeftControllerColor, command.colorLeftMain, command.colorLeftSub);
ReadNNColorIntoJoyConColor(ref m_RightControllerColor, command.colorRightMain, command.colorRightSub);
}
}
// NOTE: This function should be static
public long SetOrientationToSingleJoyCon(Orientation orientation)
{
var supportCommand = NpadDeviceIOCTLSetOrientation.Create(orientation);
return ExecuteCommand(ref supportCommand);
}
public long StartSixAxisSensor()
{
var supportCommand = NpadDeviceIOCTLStartSixAxisSensor.Create();
return ExecuteCommand(ref supportCommand);
}
public long StopSixAxisSensor()
{
var supportCommand = NpadDeviceIOCTLStopSixAxisSensor.Create();
return ExecuteCommand(ref supportCommand);
}
protected override void FinishSetup()
{
base.FinishSetup();
leftSL = GetChildControl<ButtonControl>("leftSL");
leftSR = GetChildControl<ButtonControl>("leftSR");
rightSL = GetChildControl<ButtonControl>("rightSL");
rightSR = GetChildControl<ButtonControl>("rightSR");
acceleration = GetChildControl<Vector3Control>("acceleration");
attitude = GetChildControl<QuaternionControl>("attitude");
angularVelocity = GetChildControl<Vector3Control>("angularVelocity");
}
private static void ReadNNColorIntoJoyConColor(ref JoyConColor controllerColor, int mainColor, int subColor)
{
controllerColor.Main = ConvertNNColorToColor32(mainColor);
controllerColor.Sub = ConvertNNColorToColor32(subColor);
}
private static Color32 ConvertNNColorToColor32(int color)
{
return new Color32((byte)(color & 0xFF), (byte)((color >> 8) & 0xFF), (byte)((color >> 16) & 0xFF), (byte)((color >> 24) & 0xFF));
}
public override void PauseHaptics()
{
var cmd = NPadDeviceIOCTLOutputCommand.Create();
ExecuteCommand(ref cmd);
}
public override void ResetHaptics()
{
var cmd = NPadDeviceIOCTLOutputCommand.Create();
ExecuteCommand(ref cmd);
m_leftRumbleValues.Reset();
m_rightRumbleValues.Reset();
}
public override void ResumeHaptics()
{
if (m_leftRumbleValues.Equals(m_rightRumbleValues) && m_leftRumbleValues.HasValues)
{
var cmd = NPadDeviceIOCTLOutputCommand.Create();
m_leftRumbleValues.ApplyRumbleValues(ref cmd);
ExecuteCommand(ref cmd);
}
else
{
if (m_leftRumbleValues.HasValues)
{
var cmd = NPadDeviceIOCTLOutputCommand.Create(NPadDeviceIOCTLOutputCommand.NPadRumblePostion.Left);
m_leftRumbleValues.ApplyRumbleValues(ref cmd);
ExecuteCommand(ref cmd);
}
if (m_rightRumbleValues.HasValues)
{
var cmd = NPadDeviceIOCTLOutputCommand.Create(NPadDeviceIOCTLOutputCommand.NPadRumblePostion.Right);
m_rightRumbleValues.ApplyRumbleValues(ref cmd);
ExecuteCommand(ref cmd);
}
}
}
/// <summary>
/// Set rummble intensity for all low and high frequency rumble motors
/// </summary>
/// <param name="lowFrequency">Low frequency motor's vibration intensity, 0..1 range</param>
/// <param name="highFrequency">High frequency motor's vibration intensity, 0..1 range</param>
public override void SetMotorSpeeds(float lowFrequency, float highFrequency)
{
SetMotorSpeeds(lowFrequency, NPadDeviceIOCTLOutputCommand.DefaultFrequencyLow, highFrequency, NPadDeviceIOCTLOutputCommand.DefaultFrequencyHigh);
}
/// <summary>
/// Set the intensity and vibration frequency for all low and high frequency rumble motors
/// </summary>
/// <param name="lowAmplitude">Low frequency motor's vibration intensity, 0..1 range</param>
/// <param name="lowFrequency">Low frequency motor's vibration frequency in Hz</param>
/// <param name="highAmplitude">High frequency motor's vibration intensity, 0..1 range</param>
/// <param name="highFrequency">High frequency motor's vibration frequency in Hz</param>
public void SetMotorSpeeds(float lowAmplitude, float lowFrequency, float highAmplitude, float highFrequency)
{
m_leftRumbleValues.SetRumbleValues(lowAmplitude, lowFrequency, highAmplitude, highFrequency);
m_rightRumbleValues.SetRumbleValues(lowAmplitude, lowFrequency, highAmplitude, highFrequency);
var cmd = NPadDeviceIOCTLOutputCommand.Create();
m_leftRumbleValues.ApplyRumbleValues(ref cmd);
ExecuteCommand(ref cmd);
}
/// <summary>
/// Set the intensity and vibration frequency for the left low and high frequency rumble motors
/// </summary>
/// <param name="lowAmplitude">Low frequency motor's vibration intensity, 0..1 range</param>
/// <param name="lowFrequency">Low frequency motor's vibration frequency in Hz</param>
/// <param name="highAmplitude">High frequency motor's vibration intensity, 0..1 range</param>
/// <param name="highFrequency">High frequency motor's vibration frequency in Hz</param>
public void SetMotorSpeedLeft(float lowAmplitude, float lowFrequency, float highAmplitude, float highFrequency)
{
m_leftRumbleValues.SetRumbleValues(lowAmplitude, lowFrequency, highAmplitude, highFrequency);
var cmd = NPadDeviceIOCTLOutputCommand.Create(NPadDeviceIOCTLOutputCommand.NPadRumblePostion.Left);
m_leftRumbleValues.ApplyRumbleValues(ref cmd);
ExecuteCommand(ref cmd);
}
/// <summary>
/// Set the intensity and vibration frequency for the right low and high frequency rumble motors
/// </summary>
/// <param name="lowAmplitude">Low frequency motor's vibration intensity, 0..1 range</param>
/// <param name="lowFrequency">Low frequency motor's vibration frequency in Hz</param>
/// <param name="highAmplitude">High frequency motor's vibration intensity, 0..1 range</param>
/// <param name="highFrequency">High frequency motor's vibration frequency in Hz</param>
public void SetMotorSpeedRight(float lowAmplitude, float lowFrequency, float highAmplitude, float highFrequency)
{
m_rightRumbleValues.SetRumbleValues(lowAmplitude, lowFrequency, highAmplitude, highFrequency);
var cmd = NPadDeviceIOCTLOutputCommand.Create(NPadDeviceIOCTLOutputCommand.NPadRumblePostion.Right);
m_rightRumbleValues.ApplyRumbleValues(ref cmd);
ExecuteCommand(ref cmd);
}
}
}
#endif // UNITY_EDITOR || UNITY_SWITCH

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 10b79550bec1ec546ac93d5768427df9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,189 @@
#if UNITY_EDITOR || UNITY_SWITCH
using UnityEngine.InputSystem.Layouts;
using UnityEngine.Scripting;
#if UNITY_EDITOR
using UnityEditor;
#endif
[assembly: AlwaysLinkAssembly]
namespace UnityEngine.InputSystem.Switch
{
/// <summary>
/// Adds support for Switch NPad controllers.
/// </summary>
#if UNITY_EDITOR
[InitializeOnLoad]
#endif
#if UNITY_DISABLE_DEFAULT_INPUT_PLUGIN_INITIALIZATION
public
#else
internal
#endif
static class SwitchConsoleSupport
{
static SwitchConsoleSupport()
{
#if UNITY_EDITOR || UNITY_SWITCH
InputSystem.RegisterLayout<NPad>(
matches: new InputDeviceMatcher()
.WithInterface("Switch")
.WithManufacturer("Nintendo")
.WithProduct("Wireless Controller"));
#endif
}
[RuntimeInitializeOnLoadMethod]
private static void InitializeInPlayer()
{
s_UnityVersion.ParseUnityVersion();
}
struct UnityVersion
{
public enum EType
{
Unknown,
Alpha,
Beta,
Final,
Patch,
Experimental
}
// [Version].[Major].[Minor][Type][Revision][Suffix]
// Example 2020.3.1f1
// Type being one of:
// a: alpha
// b: beta
// f: public ("final") release
// p: patch release(after final)
// x: experimental
private int Version { get; set; } // Main version (2018, 2019, 2020, 2021 etc)
private int Major { get; set; } // Tech-stream or LTS, e.g .1, .2, .3, .4
private int Minor { get; set; }
private int Revision { get; set; }
private EType Type{ get; set; }
// Must match main version
public bool IsVersionOrHigher(int versionIn, int majorIn = 0, int minorIn = 0, EType typeIn = EType.Unknown, int revisionIn = 0)
{
return Version == versionIn && Major >= majorIn && Minor >= minorIn && ((Type > typeIn || Type == typeIn && Revision >= revisionIn) || Type == EType.Unknown);
}
public bool IsMainVersionOrLater(int versionIn)
{
return Version >= versionIn;
}
// Package min Unity version compatibility is 2019.4 LTS so we don't expect to parse older version strings
public void ParseUnityVersion()
{
string unityVer = Application.unityVersion;
// Parse up to first '.' to read Unity version (year)
var startIdx = 0;
var endIdx = unityVer.IndexOf('.');
var verStr = unityVer.Substring(startIdx, endIdx - startIdx);
if(int.TryParse(verStr, out var version))
{
Version = version;
}
else
{
Debug.LogWarning("Failed to parse Unity version: " + unityVer);
}
// Parse up to second '.' for major revision
startIdx = endIdx + 1;
endIdx = unityVer.IndexOf('.', startIdx);
var majStr = unityVer.Substring(startIdx, endIdx - startIdx);
if (int.TryParse(majStr, out var major))
{
Major = major;
}
// Break down final part of version string, minor revision, type & suffix ([Minor][Type][Revision][Suffix])
startIdx = endIdx + 1;
// Check for -dots suffix and discard.
var suffixIdx = unityVer.IndexOf('-', startIdx);
string minStr = (suffixIdx != -1) ? unityVer.Substring(startIdx, suffixIdx - startIdx) : unityVer.Substring(startIdx);
// Check for China suffix ('c') and discard.
suffixIdx = minStr.IndexOf('c');
if (suffixIdx != -1)
{
minStr = minStr.Substring(0, suffixIdx);
}
Minor = 0;
Revision = 0;
Type = EType.Unknown;
char[] versionTypes = { 'a', 'b', 'f', 'p', 'x' }; // Known version identifiers
var typeIdx = minStr.IndexOfAny(versionTypes);
if (typeIdx != -1)
{
var type = minStr[typeIdx];
switch (type)
{
case 'a': Type = EType.Alpha; break;
case 'b': Type = EType.Beta; break;
case 'f': Type = EType.Final; break;
case 'p': Type = EType.Patch; break;
case 'x': Type = EType.Experimental; break;
default:
Debug.LogWarningFormat("Unrecognized type identifier ({0}) in Unity version string: {1}", type, unityVer);
break;
}
if (int.TryParse(minStr.Substring(0, typeIdx), out var minor))
{
Minor = minor;
}
else
{
Debug.LogWarning("Failed to parse minor version from Unity version string: " + unityVer);
}
if (int.TryParse(minStr.Substring(typeIdx + 1), out var revision))
{
Revision = revision;
}
else
{
Debug.LogWarning("Failed to parse revision from Unity version string: " + unityVer);
}
}
//Debug.LogFormat("Version: {0} Major: {1} Minor: {2} Type: {3} Revision: {4}\n", Version, Major, Minor, Type, Revision);
}
}
static UnityVersion s_UnityVersion;
// Attributes queries require a fix in the Switch player available in the following versions onwards
// (The attributes field is reusing part of the struct that was padding in older versions)
// 2021.2.0a10, 2021.1.1f1, 2020.3.4f1, 2019.4.24f1, Not supported in 2018 or older
public static bool NpadAttributesSupported()
{
if (s_UnityVersion.IsMainVersionOrLater(2022) // Will be supported in all versions of 2022 onward
|| s_UnityVersion.IsVersionOrHigher(2021, 2, 0, UnityVersion.EType.Alpha, 10)
|| s_UnityVersion.IsVersionOrHigher(2020, 3, 4, UnityVersion.EType.Final, 1)
|| s_UnityVersion.IsVersionOrHigher(2019, 4, 24, UnityVersion.EType.Final, 1))
{
return true;
}
else
{
return false;
}
}
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fc10b23f19793734895f4ef18a67daf7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,17 @@
{
"name": "Unity.InputSystem.Switch",
"references": [
"Unity.InputSystem"
],
"includePlatforms": [
"Editor",
"Switch"
],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": []
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6374799de9bd44442818ee6dd5dbbfc5
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,31 @@
**Unity Companion Package License v1.0 ("_License_")**
Copyright © 2019 Unity Technologies ApS ("**_Unity_**")
Unity hereby grants to you a worldwide, non-exclusive, no-charge, and royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute the software that is made available with this License ("**_Software_**"), subject to the following terms and conditions:
1. *Unity Companion Use Only*. Exercise of the license granted herein is limited to exercise for the creation, use, and/or distribution of applications, software, or other content pursuant to a valid Unity development engine software license ("**_Engine License_**"). That means while use of the Software is not limited to use in the software licensed under the Engine License, the Software may not be used for any purpose other than the creation, use, and/or distribution of Engine License-dependent applications, software, or other content. No other exercise of the license granted herein is permitted.
1. *No Modification of Engine License*. Neither this License nor any exercise of the license granted herein modifies the Engine License in any way.
1. *Ownership & Grant Back to You*.
3.1. You own your content. In this License, "derivative works" means derivatives of the Software itself--works derived only from the Software by you under this License (for example, modifying the code of the Software itself to improve its efficacy); “derivative works” of the Software do not include, for example, games, apps, or content that you create using the Software. You keep all right, title, and interest to your own content.
3.2. Unity owns its content. While you keep all right, title, and interest to your own content per the above, as between Unity and you, Unity will own all right, title, and interest to all intellectual property rights (including patent, trademark, and copyright) in the Software and derivative works of the Software, and you hereby assign and agree to assign all such rights in those derivative works to Unity.
3.3. You have a license to those derivative works. Subject to this License, Unity grants to you the same worldwide, non-exclusive, no-charge, and royalty-free copyright license to derivative works of the Software you create as is granted to you for the Software under this License.
1. *Trademarks*. You are not granted any right or license under this License to use any trademarks, service marks, trade names, products names, or branding of Unity or its affiliates ("**_Trademarks_**"). Descriptive uses of Trademarks are permitted; see, for example, Unitys Branding Usage Guidelines at [https://unity3d.com/public-relations/brand](https://unity3d.com/public-relations/brand).
1. *Notices & Third-Party Rights*. This License, including the copyright notice above, must be provided in all substantial portions of the Software and derivative works thereof (or, if that is impracticable, in any other location where such notices are customarily placed). Further, if the Software is accompanied by a Unity "third-party notices" or similar file, you acknowledge and agree that software identified in that file is governed by those separate license terms.
1. *DISCLAIMER, LIMITATION OF LIABILITY*. THE SOFTWARE AND ANY DERIVATIVE WORKS THEREOF IS PROVIDED ON AN "AS IS" BASIS, AND IS PROVIDED WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR NONINFRINGEMENT. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES (WHETHER DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL, INCLUDING PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF USE, DATA, OR PROFITS, AND BUSINESS INTERRUPTION), OR OTHER LIABILITY WHATSOEVER, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM OR OUT OF, OR IN CONNECTION WITH, THE SOFTWARE OR ANY DERIVATIVE WORKS THEREOF OR THE USE OF OR OTHER DEALINGS IN SAME, EVEN WHERE ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1. *USE IS ACCEPTANCE and License Versions*. Your receipt and use of the Software constitutes your acceptance of this License and its terms and conditions. Software released by Unity under this License may be modified or updated and the License with it; upon any such modification or update, you will comply with the terms of the updated License for any use of any of the Software under the updated License.
1. *Use in Compliance with Law and Termination*. Your exercise of the license granted herein will at all times be in compliance with applicable law and will not infringe any proprietary rights (including intellectual property rights); this License will terminate immediately on any breach by you of this License.
1. *Severability*. If any provision of this License is held to be unenforceable or invalid, that provision will be enforced to the maximum extent possible and the other provisions will remain in full force and effect.
1. *Governing Law and Venue*. This License is governed by and construed in accordance with the laws of Denmark, except for its conflict of laws rules; the United Nations Convention on Contracts for the International Sale of Goods will not apply. If you reside (or your principal place of business is) within the United States, you and Unity agree to submit to the personal and exclusive jurisdiction of and venue in the state and federal courts located in San Francisco County, California concerning any dispute arising out of this License ("**_Dispute_**"). If you reside (or your principal place of business is) outside the United States, you and Unity agree to submit to the personal and exclusive jurisdiction of and venue in the courts located in Copenhagen, Denmark concerning any Dispute.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0fc53242e6c9fbd4c88f90fb1e7eff9e
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1 @@
Switch Devices and extension for new input system.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d07bdabda6639b447b233e47dca4e09f
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,9 @@
{
"SuiteConfig":
{
"Targets":
[
"+Switch"
]
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fe4afccdf24f4148b8719f9a4ba5872a
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,17 @@
{
"name": "com.unity.inputsystem.switch",
"displayName": "Input System Switch",
"version": "0.1.6-pre",
"unity": "2019.4",
"description": "Switch Devices for new Input System",
"keywords": [
"input",
"keyboard",
"mouse",
"gamepad",
"touch"
],
"dependencies": {
"com.unity.inputsystem": "1.1.0-pre.5"
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f5132f131fbc3d14da629fca5b83a5e7
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,130 @@
fileFormatVersion: 2
guid: 562e8ae4167d26b42b4dd08d3f809531
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
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
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 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
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -9,7 +9,8 @@
"Essgee.Unity",
"StoicGooseUnity",
"Unity.InputSystem",
"AxiNSApi"
"AxiNSApi",
"Unity.InputSystem.Switch"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@ -1,12 +1,9 @@
using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Common;
using AxibugEmuOnline.Client.Event;
using AxibugEmuOnline.Client.Settings;
using NUnit.Framework.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using VirtualNes.Core;
namespace AxibugEmuOnline.Client

View File

@ -1,7 +1,5 @@
using Assets.Script.AppMain.Filter;
using System.Drawing.Imaging;
using UnityEngine;
using static Coffee.UIExtensions.UIEffect;
namespace AxibugEmuOnline.Client.Filters
{

View File

@ -0,0 +1,36 @@
using AxibugProtobuf;
using System.Collections;
using UnityEngine;
namespace AxibugEmuOnline.Client.InputDevices
{
public class SwitchJoyCon_D : InputDevice_D
{
public Button_C LeftSL;
public Button_C LeftSR;
public Button_C RightSL;
public Button_C RightSR;
public Button_C B;
public Button_C A;
public Button_C Y;
public Button_C X;
public Button_C Up;
public Button_C Down;
public Button_C Left;
public Button_C Right;
public Button_C Minus;
public Button_C Plus;
public Stick_C LeftStick;
public Stick_C RightStick;
public Button_C LeftStickPress;
public Button_C RightStickPress;
public SwitchJoyCon_D(InputResolver resolver) : base(resolver) { }
public override GamePadType PadType => GamePadType.SwitchJoyCon;
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 28380f06191bd35458b20113fbd2960b

View File

@ -1,9 +1,18 @@
#if ENABLE_INPUT_SYSTEM
#if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_WSA || PACKAGE_DOCS_GENERATION
#define DUALSHOCK_SUPPORT
#endif
#if UNITY_EDITOR || UNITY_SWITCH || PACKAGE_DOCS_GENERATION
#define JOYCON_SUPPORT
#endif
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Android;
using UnityEngine.InputSystem.DualShock;
using UnityEngine.InputSystem.Switch;
using UnityEngine.InputSystem.XInput;
namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
@ -24,18 +33,26 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
{
InputDevice_D newDevice = null;
if (ipdev is Keyboard) newDevice = new Keyboard_D(this);
#if DUALSHOCK_SUPPORT
else if (ipdev is DualShockGamepad)
{
if (ipdev is DualShock3GamepadHID) newDevice = new DualShockController_D(this, ps3: true);
else if (ipdev is DualShock4GamepadHID) newDevice = new DualShockController_D(this, ps4: true);
else if (ipdev is DualSenseGamepadHID) newDevice = new DualShockController_D(this, ps5: true);
else newDevice = new DualShockController_D(this);
}
#endif
else if (ipdev is XInputController)
{
newDevice = new XboxController_D(this);
}
#if JOYCON_SUPPORT
else if (ipdev is NPad)
{
newDevice = new SwitchJoyCon_D(this);
}
#endif
else if (ipdev is Gamepad) newDevice = new GamePad_D(this); //注意Gamepad的优先级,因为任何手柄,Inputsystem中的基类都是GamePad
if (newDevice != null)
@ -98,13 +115,13 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
protected override Vector2 OnGetVector2<CONTROLLER>(CONTROLLER control)
{
var ipControl = GetInputSystemControl(control);
return (ipControl as InputControl<Vector2>).value;
return (ipControl as InputControl<Vector2>).ReadValue();
}
protected override float OnGetFloat<CONTROLLER>(CONTROLLER control)
{
var ipControl = GetInputSystemControl(control);
return (ipControl as InputControl<float>).value;
return (ipControl as InputControl<float>).ReadValue();
}
InputControl GetInputSystemControl(InputControl_C key)
@ -233,6 +250,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
mapper[keyboard_d.Semicolon] = ipKeyboard.semicolonKey;
mapper[keyboard_d.Quote] = ipKeyboard.quoteKey;
}
#if DUALSHOCK_SUPPORT
else if (device_d is DualShockController_D ds_d)
{
var ipDsGamePad = ipdevice as DualShockGamepad;
@ -256,6 +274,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
mapper[ds_d.LeftStick] = ipDsGamePad.leftStick;
mapper[ds_d.RightStick] = ipDsGamePad.rightStick;
}
#endif
else if (device_d is XboxController_D xbox_d)
{
var ipXInputGamePad = ipdevice as XInputController;
@ -277,8 +296,31 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
mapper[xbox_d.RightStickPress] = ipXInputGamePad.rightStickButton;
mapper[xbox_d.LeftStick] = ipXInputGamePad.leftStick;
mapper[xbox_d.RightStick] = ipXInputGamePad.rightStick;
}
#if JOYCON_SUPPORT
else if (device_d is SwitchJoyCon_D joycon_d)
{
var ipdevice_joycon = ipdevice as NPad;
mapper[joycon_d.LeftSL] = ipdevice_joycon.leftSL;
mapper[joycon_d.LeftSR] = ipdevice_joycon.leftSR;
mapper[joycon_d.RightSL] = ipdevice_joycon.rightSL;
mapper[joycon_d.RightSR] = ipdevice_joycon.rightSR;
mapper[joycon_d.B] = ipdevice_joycon.bButton;
mapper[joycon_d.A] = ipdevice_joycon.aButton;
mapper[joycon_d.Y] = ipdevice_joycon.yButton;
mapper[joycon_d.X] = ipdevice_joycon.xButton;
mapper[joycon_d.Up] = ipdevice_joycon.dpad.up;
mapper[joycon_d.Down] = ipdevice_joycon.dpad.down;
mapper[joycon_d.Left] = ipdevice_joycon.dpad.left;
mapper[joycon_d.Right] = ipdevice_joycon.dpad.right;
mapper[joycon_d.Minus] = ipdevice_joycon.selectButton;
mapper[joycon_d.Plus] = ipdevice_joycon.startButton;
mapper[joycon_d.LeftStick] = ipdevice_joycon.leftStick;
mapper[joycon_d.RightStick] = ipdevice_joycon.rightStick;
mapper[joycon_d.RightStickPress] = ipdevice_joycon.rightStickButton;
mapper[joycon_d.LeftStickPress] = ipdevice_joycon.leftStickButton;
}
#endif
else if (device_d is GamePad_D gamepad_d)
{
var ipGamepad = ipdevice as Gamepad;
@ -300,6 +342,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
mapper[gamepad_d.RightStickPress] = ipGamepad.rightStickButton;
mapper[gamepad_d.LeftStick] = ipGamepad.leftStick;
mapper[gamepad_d.RightStick] = ipGamepad.rightStick;
}
else throw new System.NotImplementedException($"初始化设备失败,未实现的物理按键映射 for {device_d.GetType()}");
}
@ -308,6 +351,6 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
m_deviceMapper.Remove(keyboard_d);
}
}
}
#endif

View File

@ -163,7 +163,7 @@ PlayerSettings:
androidMaxAspectRatio: 2.1
androidMinAspectRatio: 1
applicationIdentifier:
Android: com.DefaultCompany.AxibugEmuOnline.Client
Android: com.AlienTechnology.AxibugEmuOnline.Client
Standalone: com.AlienTechnology.AxibugEmuOnline.Client
buildNumber:
Standalone: 0
@ -404,11 +404,13 @@ PlayerSettings:
iPhone: 1
tvOS: 1
m_BuildTargetGroupLightmapEncodingQuality: []
m_BuildTargetGroupHDRCubemapEncodingQuality: []
m_BuildTargetGroupLightmapSettings: []
m_BuildTargetGroupLoadStoreDebugModeSettings: []
m_BuildTargetNormalMapEncoding: []
m_BuildTargetDefaultTextureCompressionFormat: []
m_BuildTargetDefaultTextureCompressionFormat:
- serializedVersion: 3
m_BuildTarget: Android
m_Formats: 01000000
playModeTestRunnerEnabled: 0
runPlayModeTestAsEditModeTest: 0
actionOnDotNetUnhandledException: 1
@ -668,12 +670,12 @@ PlayerSettings:
webGLMemoryLinearGrowthStep: 16
webGLMemoryGeometricGrowthStep: 0.2
webGLMemoryGeometricGrowthCap: 96
webGLEnableWebGPU: 0
webGLPowerPreference: 2
webGLWebAssemblyTable: 0
webGLWebAssemblyBigInt: 0
webGLCloseOnQuit: 0
webWasm2023: 0
webEnableSubmoduleStrippingCompatibility: 0
scriptingDefineSymbols:
Android: DOTWEEN;ODIN_INSPECTOR;ODIN_INSPECTOR_3;ODIN_INSPECTOR_3_1;ODIN_INSPECTOR_EDITOR_ONLY;UNITY_POST_PROCESSING_STACK_V2
EmbeddedLinux: UNITY_POST_PROCESSING_STACK_V2
@ -820,4 +822,3 @@ PlayerSettings:
insecureHttpOption: 2
androidVulkanDenyFilterList: []
androidVulkanAllowFilterList: []
androidVulkanDeviceFilterListAsset: {fileID: 0}