AR骑行人物控制代码重构&build混淆代码

This commit is contained in:
lishuo 2023-02-02 18:41:55 +08:00
parent 7822584cdd
commit 2c9440f656
78 changed files with 562 additions and 8031 deletions

View File

@ -153,7 +153,7 @@ namespace Assets.AR
float num5 = this.VideoSyncSource.AverageVideoSpeed(videoFrameAtDistance1, videoFrameAtDistance2); float num5 = this.VideoSyncSource.AverageVideoSpeed(videoFrameAtDistance1, videoFrameAtDistance2);
var ratio = ((double)num5 != 0.0 ? speed / num5 : 0.0f); var ratio = ((double)num5 != 0.0 ? speed / num5 : 0.0f);
var deltaRatio = (float)(((double)frame - ((double)this.VideoPlayer.CurrentFrame - (double)this.VideoFrameOffset)) / 2.0) / this.VideoPlayer.FrameRate; var deltaRatio = (float)(((double)frame - ((double)this.VideoPlayer.CurrentFrame - (double)this.VideoFrameOffset)) / 2.0) / this.VideoPlayer.FrameRate;
float playbackSpeed = Mathf.Clamp(ratio + deltaRatio, 0.0f, 1.8f); float playbackSpeed = Mathf.Clamp(ratio + deltaRatio, 0.0f, 1.5f);
//Debug.Log(playbackSpeed); //Debug.Log(playbackSpeed);
if ((double)playbackSpeed == (double)this.VideoPlayer.PlaybackSpeed || !this.VideoPlayer.SetPlaybackSpeed(playbackSpeed)) if ((double)playbackSpeed == (double)this.VideoPlayer.PlaybackSpeed || !this.VideoPlayer.SetPlaybackSpeed(playbackSpeed))
return; return;

View File

@ -1,33 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class CEditor : Editor
{
[MenuItem("GameObject/CopyHierarchyPath", false, 11)]
public static void CopyHierarchy()
{
GameObject go = Selection.activeGameObject;
string path = go.GetRPath();
path = path.Replace("Canvas (Environment)/", "");
GUIUtility.systemCopyBuffer = path;
}
}
public static class Ex
{
public static string GetRPath(this GameObject go)
{
GameObject current = go;
string path = current.name;
while (null != current.transform.parent)
{
current = current.transform.parent.gameObject;
path = current.name + "/" + path;
}
return path;
}
}

View File

@ -1,40 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class ExportAssets : Editor
{
[@MenuItem("Juze/Build Asset Bundles")]
static void BuildAssetBundles()
{
BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, BuildAssetBundleOptions.UncompressedAssetBundle, BuildTarget.StandaloneWindows);
}
[MenuItem("GameObject/UI/PFButton", false, 100)]
static void CreatePFButtonCommand()
{
GameObject prefab = Resources.Load<GameObject>("UI/Control/PfUIButton");
GameObject game = Instantiate(prefab, Selection.activeTransform);
}
[MenuItem("GameObject/UI/PFUIInputField", false, 100)]
static void CreatePFUIInputFieldCommand()
{
GameObject prefab = Resources.Load<GameObject>("UI/Control/PFUIInputField");
GameObject game = Instantiate(prefab, Selection.activeTransform);
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

View File

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

View File

@ -1,9 +0,0 @@
/*
InfoPlist.strings
IosToRN
Created by lishuo on 2021/2/24.
*/
"CFBundleName"="PowerFun";
"CFBundleDisplayName"="PowerFun";

View File

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

View File

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

View File

@ -1,9 +0,0 @@
/*
InfoPlist.strings
IosToRN
Created by lishuo on 2021/2/24.
*/
"CFBundleName"="运动地球";
"CFBundleDisplayName"="运动地球";

View File

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

View File

@ -1,27 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;
public class MyBuildPostprocessor
{
[PostProcessBuild]
public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
{
//Debug.Log(pathToBuiltProject);
//System.IO.File.AppendAllText("D:\\test.txt",pathToBuiltProject);
#if !(UNITY_IOS || UNITY_ANDROID)
var dir = Path.GetDirectoryName(pathToBuiltProject);
var managedPath = dir + "\\PowerFun_Data\\Managed";
if (!Directory.Exists(managedPath))
{
Directory.CreateDirectory(managedPath);
}
File.Copy(dir + "\\PowerFun_Data\\Plugins\\x86_64\\ANT_WrappedLib.dll", dir + "\\PowerFun_Data\\Managed\\ANT_WrappedLib.dll");
File.Copy(dir + "\\PowerFun_Data\\Plugins\\x86_64\\DSI_CP210xManufacturing_3_1.dll", dir + "\\PowerFun_Data\\Managed\\DSI_CP210xManufacturing_3_1.dll");
File.Copy(dir + "\\PowerFun_Data\\Plugins\\x86_64\\DSI_SiUSBXp_3_1.dll", dir + "\\PowerFun_Data\\Managed\\DSI_SiUSBXp_3_1.dll");
#endif
}
}

View File

@ -1,77 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using ChillyRoom.UnityEditor.iOS.Xcode;
namespace Assets
{
public class NativeLocale
{
public static void AddLocalizedStringsIOS(string projectPath, string localizedDirectoryPath)
{
DirectoryInfo dir = new DirectoryInfo(localizedDirectoryPath);
if (!dir.Exists)
return;
List<string> locales = new List<string>();
var localeDirs = dir.GetDirectories("*.lproj", SearchOption.TopDirectoryOnly);
foreach (var sub in localeDirs)
locales.Add(Path.GetFileNameWithoutExtension(sub.Name));
AddLocalizedStringsIOS(projectPath, localizedDirectoryPath, locales);
}
public static void AddLocalizedStringsIOS(string projectPath, string localizedDirectoryPath, List<string> validLocales)
{
string projPath = projectPath + "/Unity-iPhone.xcodeproj/project.pbxproj";
PBXProject proj = new PBXProject();
proj.ReadFromFile(projPath);
foreach (var locale in validLocales)
{
// copy contents in the localization directory to project directory
string src = Path.Combine(localizedDirectoryPath, locale + ".lproj");
DirectoryCopy(src, Path.Combine(projectPath, "Unity-iPhone/" + locale + ".lproj"));
string fileRelatvePath = string.Format("Unity-iPhone/{0}.lproj/InfoPlist.strings", locale);
proj.AddLocalization("Localizable.strings", locale, fileRelatvePath);
}
proj.WriteToFile(projPath);
}
private static void DirectoryCopy(string sourceDirName, string destDirName)
{
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
return;
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
// skip unity meta files
if (file.FullName.EndsWith(".meta"))
continue;
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
DirectoryInfo[] dirs = dir.GetDirectories();
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath);
}
}
}
}

View File

@ -1,20 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a403a09e241a0480a957591ea60fb785, type: 3}
m_Name: settings
m_EditorClassIdentifier:
usesCleartextTraffic: 1
writeExternalStorage: 0
accessFineLocation: 0
addsKotlin: 1
addsAndroidBrowser: 1
enableJetifier: 1

View File

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 580a44b4404956543a86c106381eae18
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,141 +0,0 @@

#if UNITY_IOS && UNITY_EDITOR
using UnityEditor;
using System.IO;
using UnityEngine;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using System;
#endif
public static class XCodePostProcessBuild
{
#if UNITY_IOS && UNITY_EDITOR
private static readonly string[] csAddFrameworks = new string[]{
"Security.framework","WebKit.framework", "CoreGraphics.framework"
};
[PostProcessBuild(11)]
public static void OnPostprocessBuild(BuildTarget buildTarget, string pathToBuiltProject)
{
if (BuildTarget.iOS != buildTarget)
{
return;
}
string projectPath = pathToBuiltProject + "/Unity-iPhone.xcodeproj/project.pbxproj";
SetFrameworksAndBuildSettings(projectPath);
AddGooglePlist(pathToBuiltProject,projectPath);
SetInfoList(pathToBuiltProject, "com.ZhiXingPai.PowerFun", "wxe3573a84e7e29902");
SetAssociatedDomains(projectPath, "wx.powerfun.com.cn");
Assets.NativeLocale.AddLocalizedStringsIOS(pathToBuiltProject, Path.Combine(Application.dataPath, "Editor/Locale"));
}
private static void AddGooglePlist(string pathToBuiltProject,string path)
{
PBXProject proj = new PBXProject();
proj.ReadFromString(File.ReadAllText(path));
// This is the Xcode target in the generated project
string target = proj.GetUnityMainTargetGuid();
// Copy plist from the project folder to the build folder
FileUtil.CopyFileOrDirectory("Assets/Plugins/iOS/GoogleService-Info.plist", pathToBuiltProject + "/GoogleService-Info.plist");
proj.AddFileToBuild(target, proj.AddFile("GoogleService-Info.plist", "GoogleService-Info.plist"));
// Write PBXProject object back to the file
proj.WriteToFile(path);
}
private static void SetFrameworksAndBuildSettings(string path)
{
PBXProject proj = new PBXProject();
proj.ReadFromString(File.ReadAllText(path));
string target = proj.GetUnityMainTargetGuid();
Debug.Log("Target Name is " + target);
// 设置 BuildSettings
proj.AddBuildProperty(target, "Other Linker Flags", "-Objc -all_load");
proj.SetBuildProperty(target, "ENABLE_BITCODE", "NO");
//根据微信SDK文档的要求加入相关的Frameworks
for (int i = 0; i < csAddFrameworks.Length; ++i)
{
if (!proj.ContainsFramework(target, csAddFrameworks[i]))
proj.AddFrameworkToProject(target, csAddFrameworks[i], false);
}
//苹果登录配置项
//proj.AddCapability(target, PBXCapabilityType.SignInWithApple);
proj.AddFrameworkToProject(proj.GetUnityFrameworkTargetGuid(), "AuthenticationServices.framework", false);
//移除无用配置项
proj.RemoveFrameworkFromProject(proj.GetUnityFrameworkTargetGuid(), "Chromium Embedded Framework.framework");
proj.SetBuildProperty(proj.ProjectGuid(), "ENABLE_BITCODE", "NO");
proj.SetBuildProperty(proj.ProjectGuid(), "CLANG_ENABLE_MODULES", "YES");
File.WriteAllText(path, proj.WriteToString());
}
public static void SetInfoList(string buildPath, string wxUrlName, string wxScheme)
{
string listPath = buildPath + "/Info.plist";
PlistDocument plist = new PlistDocument();
plist.ReadFromString(File.ReadAllText(listPath));
// 在“info”标签栏的“URL type“添加“URL scheme”,值为你在微信后台注册的应用程序的 AppID
PlistElementArray urlArray = plist.root.CreateArray("CFBundleURLTypes");
PlistElementDict dict = urlArray.AddDict();
dict.SetString("CFBundleTypeRole", "Editor");
dict.SetString("CFBundleURLName", wxUrlName);
PlistElementArray urlSchemes = dict.CreateArray("CFBundleURLSchemes");
urlSchemes.AddString(wxScheme);
PlistElementDict dictMine = urlArray.AddDict();
dictMine.SetString("CFBundleTypeRole", "Editor");
dictMine.SetString("CFBundleURLName", "powerfunx");
PlistElementArray urlSchemesMine = dictMine.CreateArray("CFBundleURLSchemes");
urlSchemesMine.AddString("powerfunx");
PlistElementDict dictGG = urlArray.AddDict();
dictGG.SetString("CFBundleTypeRole", "Editor");
dictGG.SetString("CFBundleURLName", "google");
PlistElementArray urlSchemesGG = dictGG.CreateArray("CFBundleURLSchemes");
urlSchemesGG.AddString("com.googleusercontent.apps.492440200766-spo9287smn7epmlarib2pek9kficsq86");
// 在 “info”标签栏的“LSApplicationQueriesSchemes“添加weixin wechat和weixinULAPI
PlistElementArray wxArray = plist.root.CreateArray("LSApplicationQueriesSchemes");
wxArray.AddString("weixin");
wxArray.AddString("wechat");
wxArray.AddString("weixinULAPI");
wxArray.AddString("powerfun");
// 设置转向
//var orientations = plist.root.CreateArray("UISupportedInterfaceOrientations");
//orientations.AddString("UIInterfaceOrientationLandscapeRight");
//orientations.AddString("UIInterfaceOrientationLandscapeLeft");
PlistElementDict qxLoc = plist.root.CreateDict("NSLocationWhenInUseUsageDescription");
qxLoc.SetBoolean("NSLocationWhenInUseUsageDescription", true);
plist.root.SetString("NSCameraUsageDescription","Use the camera to scan the QR code or take a photo or take a video to upload.");
plist.root.SetString("NSPhotoLibraryUsageDescription", "Need to access your image file to upload.");
plist.root.SetString("NSLocationWhenInUseUsageDescription", "Need to get your geographic location in order to push the route for you.");
plist.root.SetBoolean("ITSAppUsesNonExemptEncryption", false);
File.WriteAllText(listPath, plist.WriteToString());
}
// 设置Associated Domains
public static void SetAssociatedDomains(string pbxProjectPath, string domainUrl)
{
//默认 Target Name, 你自己的可能不一样
string targetName = "Unity-iPhone";
//Set the entitlements file name to what you want but make sure it has this extension
string entitlementsFileName = "my_app.entitlements";
var entitlements = new ProjectCapabilityManager(pbxProjectPath, entitlementsFileName, targetName);
entitlements.AddAssociatedDomains(new string[] { "applinks:" + domainUrl });
//苹果登录
entitlements.AddSignInWithApple();
entitlements.AddPushNotifications(false);
entitlements.WriteToFile();
}
#endif
}

View File

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

View File

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

View File

@ -1,813 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ChillyRoom.UnityEditor.iOS.Xcode
{
internal class DeviceTypeRequirement
{
public static readonly string Key = "idiom";
public static readonly string Any = "universal";
public static readonly string iPhone = "iphone";
public static readonly string iPad = "ipad";
public static readonly string Mac = "mac";
public static readonly string iWatch = "watch";
}
internal class MemoryRequirement
{
public static readonly string Key = "memory";
public static readonly string Any = "";
public static readonly string Mem1GB = "1GB";
public static readonly string Mem2GB = "2GB";
}
internal class GraphicsRequirement
{
public static readonly string Key = "graphics-feature-set";
public static readonly string Any = "";
public static readonly string Metal1v2 = "metal1v2";
public static readonly string Metal2v2 = "metal2v2";
}
// only used for image sets
internal class SizeClassRequirement
{
public static readonly string HeightKey = "height-class";
public static readonly string WidthKey = "width-class";
public static readonly string Any = "";
public static readonly string Compact = "compact";
public static readonly string Regular = "regular";
}
// only used for image sets
internal class ScaleRequirement
{
public static readonly string Key = "scale";
public static readonly string Any = ""; // vector image
public static readonly string X1 = "1x";
public static readonly string X2 = "2x";
public static readonly string X3 = "3x";
}
internal class DeviceRequirement
{
internal Dictionary<string, string> values = new Dictionary<string, string>();
public DeviceRequirement AddDevice(string device)
{
AddCustom(DeviceTypeRequirement.Key, device);
return this;
}
public DeviceRequirement AddMemory(string memory)
{
AddCustom(MemoryRequirement.Key, memory);
return this;
}
public DeviceRequirement AddGraphics(string graphics)
{
AddCustom(GraphicsRequirement.Key, graphics);
return this;
}
public DeviceRequirement AddWidthClass(string sizeClass)
{
AddCustom(SizeClassRequirement.WidthKey, sizeClass);
return this;
}
public DeviceRequirement AddHeightClass(string sizeClass)
{
AddCustom(SizeClassRequirement.HeightKey, sizeClass);
return this;
}
public DeviceRequirement AddScale(string scale)
{
AddCustom(ScaleRequirement.Key, scale);
return this;
}
public DeviceRequirement AddCustom(string key, string value)
{
if (values.ContainsKey(key))
values.Remove(key);
values.Add(key, value);
return this;
}
public DeviceRequirement()
{
values.Add("idiom", DeviceTypeRequirement.Any);
}
}
internal class AssetCatalog
{
AssetFolder m_Root;
public string path { get { return m_Root.path; } }
public AssetFolder root { get { return m_Root; } }
public AssetCatalog(string path, string authorId)
{
if (Path.GetExtension(path) != ".xcassets")
throw new Exception("Asset catalogs must have xcassets extension");
m_Root = new AssetFolder(path, null, authorId);
}
AssetFolder OpenFolderForResource(string relativePath)
{
var pathItems = PBXPath.Split(relativePath).ToList();
// remove path filename
pathItems.RemoveAt(pathItems.Count - 1);
AssetFolder folder = root;
foreach (var pathItem in pathItems)
folder = folder.OpenFolder(pathItem);
return folder;
}
// Checks if a dataset at the given path exists and returns it if it does.
// Otherwise, creates a new dataset. Parent folders are created if needed.
// Note: the path is filesystem path, not logical asset name formed
// only from names of the folders that have "provides namespace" attribute.
// If you want to put certain resources in folders with namespace, first
// manually create the folders and then set the providesNamespace attribute.
// OpenNamespacedFolder may help to do this.
public AssetDataSet OpenDataSet(string relativePath)
{
var folder = OpenFolderForResource(relativePath);
return folder.OpenDataSet(Path.GetFileName(relativePath));
}
public AssetImageSet OpenImageSet(string relativePath)
{
var folder = OpenFolderForResource(relativePath);
return folder.OpenImageSet(Path.GetFileName(relativePath));
}
public AssetImageStack OpenImageStack(string relativePath)
{
var folder = OpenFolderForResource(relativePath);
return folder.OpenImageStack(Path.GetFileName(relativePath));
}
public AssetBrandAssetGroup OpenBrandAssetGroup(string relativePath)
{
var folder = OpenFolderForResource(relativePath);
return folder.OpenBrandAssetGroup(Path.GetFileName(relativePath));
}
// Checks if a folder with given path exists and returns it if it does.
// Otherwise, creates a new folder. Parent folders are created if needed.
public AssetFolder OpenFolder(string relativePath)
{
if (relativePath == null)
return root;
var pathItems = PBXPath.Split(relativePath);
if (pathItems.Length == 0)
return root;
AssetFolder folder = root;
foreach (var pathItem in pathItems)
folder = folder.OpenFolder(pathItem);
return folder;
}
// Creates a directory structure with "provides namespace" attribute.
// First, retrieves or creates the directory at relativeBasePath, creating parent
// directories if needed. Effectively calls OpenFolder(relativeBasePath).
// Then, relative to this directory, creates namespacePath directories with "provides
// namespace" attribute set. Fails if the attribute can't be set.
public AssetFolder OpenNamespacedFolder(string relativeBasePath, string namespacePath)
{
var folder = OpenFolder(relativeBasePath);
var pathItems = PBXPath.Split(namespacePath);
foreach (var pathItem in pathItems)
{
folder = folder.OpenFolder(pathItem);
folder.providesNamespace = true;
}
return folder;
}
public void Write()
{
Write(null);
}
public void Write(List<string> warnings)
{
m_Root.Write(warnings);
}
}
internal abstract class AssetCatalogItem
{
public readonly string name;
public readonly string authorId;
public string path { get { return m_Path; } }
protected Dictionary<string, string> m_Properties = new Dictionary<string, string>();
protected string m_Path;
public AssetCatalogItem(string name, string authorId)
{
if (name != null && name.Contains("/"))
throw new Exception("Asset catalog item must not have slashes in name");
this.name = name;
this.authorId = authorId;
}
protected JsonElementDict WriteInfoToJson(JsonDocument doc)
{
var info = doc.root.CreateDict("info");
info.SetInteger("version", 1);
info.SetString("author", authorId);
return info;
}
public abstract void Write(List<string> warnings);
}
internal class AssetFolder : AssetCatalogItem
{
List<AssetCatalogItem> m_Items = new List<AssetCatalogItem>();
bool m_ProvidesNamespace = false;
public bool providesNamespace
{
get { return m_ProvidesNamespace; }
set {
if (m_Items.Count > 0 && value != m_ProvidesNamespace)
throw new Exception("Asset folder namespace providing status can't be "+
"changed after items have been added");
m_ProvidesNamespace = value;
}
}
internal AssetFolder(string parentPath, string name, string authorId) : base(name, authorId)
{
if (name != null)
m_Path = Path.Combine(parentPath, name);
else
m_Path = parentPath;
}
// Checks if a folder with given name exists and returns it if it does.
// Otherwise, creates a new folder.
public AssetFolder OpenFolder(string name)
{
var item = GetChild(name);
if (item != null)
{
if (item is AssetFolder)
return item as AssetFolder;
throw new Exception("The given path is already occupied with an asset");
}
var folder = new AssetFolder(m_Path, name, authorId);
m_Items.Add(folder);
return folder;
}
T GetExistingItemWithType<T>(string name) where T : class
{
var item = GetChild(name);
if (item != null)
{
if (item is T)
return item as T;
throw new Exception("The given path is already occupied with an asset");
}
return null;
}
// Checks if a dataset with given name exists and returns it if it does.
// Otherwise, creates a new data set.
public AssetDataSet OpenDataSet(string name)
{
var item = GetExistingItemWithType<AssetDataSet>(name);
if (item != null)
return item;
var dataset = new AssetDataSet(m_Path, name, authorId);
m_Items.Add(dataset);
return dataset;
}
// Checks if an imageset with given name exists and returns it if it does.
// Otherwise, creates a new image set.
public AssetImageSet OpenImageSet(string name)
{
var item = GetExistingItemWithType<AssetImageSet>(name);
if (item != null)
return item;
var imageset = new AssetImageSet(m_Path, name, authorId);
m_Items.Add(imageset);
return imageset;
}
// Checks if a image stack with given name exists and returns it if it does.
// Otherwise, creates a new image stack.
public AssetImageStack OpenImageStack(string name)
{
var item = GetExistingItemWithType<AssetImageStack>(name);
if (item != null)
return item;
var imageStack = new AssetImageStack(m_Path, name, authorId);
m_Items.Add(imageStack);
return imageStack;
}
// Checks if a brand asset with given name exists and returns it if it does.
// Otherwise, creates a new brand asset.
public AssetBrandAssetGroup OpenBrandAssetGroup(string name)
{
var item = GetExistingItemWithType<AssetBrandAssetGroup>(name);
if (item != null)
return item;
var brandAsset = new AssetBrandAssetGroup(m_Path, name, authorId);
m_Items.Add(brandAsset);
return brandAsset;
}
// Returns the requested item or null if not found
public AssetCatalogItem GetChild(string name)
{
foreach (var item in m_Items)
{
if (item.name == name)
return item;
}
return null;
}
void WriteJson()
{
if (!providesNamespace)
return; // json is optional when namespace is not provided
var doc = new JsonDocument();
WriteInfoToJson(doc);
var props = doc.root.CreateDict("properties");
props.SetBoolean("provides-namespace", providesNamespace);
doc.WriteToFile(Path.Combine(m_Path, "Contents.json"));
}
public override void Write(List<string> warnings)
{
if (Directory.Exists(m_Path))
Directory.Delete(m_Path, true); // ensure we start from clean state
Directory.CreateDirectory(m_Path);
WriteJson();
foreach (var item in m_Items)
item.Write(warnings);
}
}
abstract class AssetCatalogItemWithVariants : AssetCatalogItem
{
protected List<VariantData> m_Variants = new List<VariantData>();
protected List<string> m_ODRTags = new List<string>();
protected AssetCatalogItemWithVariants(string name, string authorId) :
base(name, authorId)
{
}
protected class VariantData
{
public DeviceRequirement requirement;
public string path;
public VariantData(DeviceRequirement requirement, string path)
{
this.requirement = requirement;
this.path = path;
}
}
public bool HasVariant(DeviceRequirement requirement)
{
foreach (var item in m_Variants)
{
if (item.requirement.values == requirement.values)
return true;
}
return false;
}
public void AddOnDemandResourceTag(string tag)
{
if (!m_ODRTags.Contains(tag))
m_ODRTags.Add(tag);
}
protected void AddVariant(VariantData newItem)
{
foreach (var item in m_Variants)
{
if (item.requirement.values == newItem.requirement.values)
throw new Exception("The given requirement has been already added");
if (Path.GetFileName(item.path) == Path.GetFileName(path))
throw new Exception("Two items within the same set must not have the same file name");
}
if (Path.GetFileName(newItem.path) == "Contents.json")
throw new Exception("The file name must not be equal to Contents.json");
m_Variants.Add(newItem);
}
protected void WriteODRTagsToJson(JsonElementDict info)
{
if (m_ODRTags.Count > 0)
{
var tags = info.CreateArray("on-demand-resource-tags");
foreach (var tag in m_ODRTags)
tags.AddString(tag);
}
}
protected void WriteRequirementsToJson(JsonElementDict item, DeviceRequirement req)
{
foreach (var kv in req.values)
{
if (kv.Value != null && kv.Value != "")
item.SetString(kv.Key, kv.Value);
}
}
}
internal class AssetDataSet : AssetCatalogItemWithVariants
{
class DataSetVariant : VariantData
{
public string id;
public DataSetVariant(DeviceRequirement requirement, string path, string id) : base(requirement, path)
{
this.id = id;
}
}
internal AssetDataSet(string parentPath, string name, string authorId) : base(name, authorId)
{
m_Path = Path.Combine(parentPath, name + ".dataset");
}
// an exception is thrown is two equivalent requirements are added.
// The same asset dataset must not have paths with equivalent filenames.
// The identifier allows to identify which data variant is actually loaded (use
// the typeIdentifer property of the NSDataAsset that was created from the data set)
public void AddVariant(DeviceRequirement requirement, string path, string typeIdentifier)
{
foreach (DataSetVariant item in m_Variants)
{
if (item.id != null && typeIdentifier != null && item.id == typeIdentifier)
throw new Exception("Two items within the same dataset must not have the same id");
}
AddVariant(new DataSetVariant(requirement, path, typeIdentifier));
}
public override void Write(List<string> warnings)
{
Directory.CreateDirectory(m_Path);
var doc = new JsonDocument();
var info = WriteInfoToJson(doc);
WriteODRTagsToJson(info);
var data = doc.root.CreateArray("data");
foreach (DataSetVariant item in m_Variants)
{
var filename = Path.GetFileName(item.path);
if (!File.Exists(item.path))
{
if (warnings != null)
warnings.Add("File not found: " + item.path);
}
else
File.Copy(item.path, Path.Combine(m_Path, filename));
var docItem = data.AddDict();
docItem.SetString("filename", filename);
WriteRequirementsToJson(docItem, item.requirement);
if (item.id != null)
docItem.SetString("universal-type-identifier", item.id);
}
doc.WriteToFile(Path.Combine(m_Path, "Contents.json"));
}
}
internal class ImageAlignment
{
public int left = 0, right = 0, top = 0, bottom = 0;
}
internal class ImageResizing
{
public enum SlicingType
{
Horizontal,
Vertical,
HorizontalAndVertical
}
public enum ResizeMode
{
Stretch,
Tile
}
public SlicingType type = SlicingType.HorizontalAndVertical;
public int left = 0; // only valid for horizontal slicing
public int right = 0; // only valid for horizontal slicing
public int top = 0; // only valid for vertical slicing
public int bottom = 0; // only valid for vertical slicing
public ResizeMode centerResizeMode = ResizeMode.Stretch;
public int centerWidth = 0; // only valid for vertical slicing
public int centerHeight = 0; // only valid for horizontal slicing
}
// TODO: rendering intent property
internal class AssetImageSet : AssetCatalogItemWithVariants
{
internal AssetImageSet(string assetCatalogPath, string name, string authorId) : base(name, authorId)
{
m_Path = Path.Combine(assetCatalogPath, name + ".imageset");
}
class ImageSetVariant : VariantData
{
public ImageAlignment alignment = null;
public ImageResizing resizing = null;
public ImageSetVariant(DeviceRequirement requirement, string path) : base(requirement, path)
{
}
}
public void AddVariant(DeviceRequirement requirement, string path)
{
AddVariant(new ImageSetVariant(requirement, path));
}
public void AddVariant(DeviceRequirement requirement, string path, ImageAlignment alignment, ImageResizing resizing)
{
var imageset = new ImageSetVariant(requirement, path);
imageset.alignment = alignment;
imageset.resizing = resizing;
AddVariant(imageset);
}
void WriteAlignmentToJson(JsonElementDict item, ImageAlignment alignment)
{
var docAlignment = item.CreateDict("alignment-insets");
docAlignment.SetInteger("top", alignment.top);
docAlignment.SetInteger("bottom", alignment.bottom);
docAlignment.SetInteger("left", alignment.left);
docAlignment.SetInteger("right", alignment.right);
}
static string GetSlicingMode(ImageResizing.SlicingType mode)
{
switch (mode)
{
case ImageResizing.SlicingType.Horizontal: return "3-part-horizontal";
case ImageResizing.SlicingType.Vertical: return "3-part-vertical";
case ImageResizing.SlicingType.HorizontalAndVertical: return "9-part";
}
return "";
}
static string GetCenterResizeMode(ImageResizing.ResizeMode mode)
{
switch (mode)
{
case ImageResizing.ResizeMode.Stretch: return "stretch";
case ImageResizing.ResizeMode.Tile: return "tile";
}
return "";
}
void WriteResizingToJson(JsonElementDict item, ImageResizing resizing)
{
var docResizing = item.CreateDict("resizing");
docResizing.SetString("mode", GetSlicingMode(resizing.type));
var docCenter = docResizing.CreateDict("center");
docCenter.SetString("mode", GetCenterResizeMode(resizing.centerResizeMode));
docCenter.SetInteger("width", resizing.centerWidth);
docCenter.SetInteger("height", resizing.centerHeight);
var docInsets = docResizing.CreateDict("cap-insets");
docInsets.SetInteger("top", resizing.top);
docInsets.SetInteger("bottom", resizing.bottom);
docInsets.SetInteger("left", resizing.left);
docInsets.SetInteger("right", resizing.right);
}
public override void Write(List<string> warnings)
{
Directory.CreateDirectory(m_Path);
var doc = new JsonDocument();
var info = WriteInfoToJson(doc);
WriteODRTagsToJson(info);
var images = doc.root.CreateArray("images");
foreach (ImageSetVariant item in m_Variants)
{
var filename = Path.GetFileName(item.path);
if (!File.Exists(item.path))
{
if (warnings != null)
warnings.Add("File not found: " + item.path);
}
else
File.Copy(item.path, Path.Combine(m_Path, filename));
var docItem = images.AddDict();
docItem.SetString("filename", filename);
WriteRequirementsToJson(docItem, item.requirement);
if (item.alignment != null)
WriteAlignmentToJson(docItem, item.alignment);
if (item.resizing != null)
WriteResizingToJson(docItem, item.resizing);
}
doc.WriteToFile(Path.Combine(m_Path, "Contents.json"));
}
}
/* A stack layer may either contain an image set or reference another imageset
*/
class AssetImageStackLayer : AssetCatalogItem
{
internal AssetImageStackLayer(string assetCatalogPath, string name, string authorId) : base(name, authorId)
{
m_Path = Path.Combine(assetCatalogPath, name + ".imagestacklayer");
m_Imageset = new AssetImageSet(m_Path, "Content", authorId);
}
AssetImageSet m_Imageset = null;
string m_ReferencedName = null;
public void SetReference(string name)
{
m_Imageset = null;
m_ReferencedName = name;
}
public string ReferencedName()
{
return m_ReferencedName;
}
public AssetImageSet GetImageSet()
{
return m_Imageset;
}
public override void Write(List<string> warnings)
{
Directory.CreateDirectory(m_Path);
var doc = new JsonDocument();
WriteInfoToJson(doc);
if (m_ReferencedName != null)
{
var props = doc.root.CreateDict("properties");
var reference = props.CreateDict("content-reference");
reference.SetString("type", "image-set");
reference.SetString("name", m_ReferencedName);
reference.SetString("matching-style", "fully-qualified-name");
}
if (m_Imageset != null)
m_Imageset.Write(warnings);
doc.WriteToFile(Path.Combine(m_Path, "Contents.json"));
}
}
class AssetImageStack : AssetCatalogItem
{
List<AssetImageStackLayer> m_Layers = new List<AssetImageStackLayer>();
internal AssetImageStack(string assetCatalogPath, string name, string authorId) : base(name, authorId)
{
m_Path = Path.Combine(assetCatalogPath, name + ".imagestack");
}
public AssetImageStackLayer AddLayer(string name)
{
foreach (var layer in m_Layers)
{
if (layer.name == name)
throw new Exception("A layer with given name already exists");
}
var newLayer = new AssetImageStackLayer(m_Path, name, authorId);
m_Layers.Add(newLayer);
return newLayer;
}
public override void Write(List<string> warnings)
{
Directory.CreateDirectory(m_Path);
var doc = new JsonDocument();
WriteInfoToJson(doc);
var docLayers = doc.root.CreateArray("layers");
foreach (var layer in m_Layers)
{
layer.Write(warnings);
var docLayer = docLayers.AddDict();
docLayer.SetString("filename", Path.GetFileName(layer.path));
}
doc.WriteToFile(Path.Combine(m_Path, "Contents.json"));
}
}
class AssetBrandAssetGroup : AssetCatalogItem
{
class AssetBrandAssetItem
{
internal string idiom = null;
internal string role = null;
internal int width, height;
internal AssetCatalogItem item = null;
}
List<AssetBrandAssetItem> m_Items = new List<AssetBrandAssetItem>();
internal AssetBrandAssetGroup(string assetCatalogPath, string name, string authorId) : base(name, authorId)
{
m_Path = Path.Combine(assetCatalogPath, name + ".brandassets");
}
void AddItem(AssetCatalogItem item, string idiom, string role, int width, int height)
{
foreach (var it in m_Items)
{
if (it.item.name == item.name)
throw new Exception("An item with given name already exists");
}
var newItem = new AssetBrandAssetItem();
newItem.item = item;
newItem.idiom = idiom;
newItem.role = role;
newItem.width = width;
newItem.height = height;
m_Items.Add(newItem);
}
public AssetImageSet OpenImageSet(string name, string idiom, string role, int width, int height)
{
var newItem = new AssetImageSet(m_Path, name, authorId);
AddItem(newItem, idiom, role, width, height);
return newItem;
}
public AssetImageStack OpenImageStack(string name, string idiom, string role, int width, int height)
{
var newItem = new AssetImageStack(m_Path, name, authorId);
AddItem(newItem, idiom, role, width, height);
return newItem;
}
public override void Write(List<string> warnings)
{
Directory.CreateDirectory(m_Path);
var doc = new JsonDocument();
WriteInfoToJson(doc);
var docAssets = doc.root.CreateArray("assets");
foreach (var item in m_Items)
{
var docAsset = docAssets.AddDict();
docAsset.SetString("size", String.Format("{0}x{1}", item.width, item.height));
docAsset.SetString("idiom", item.idiom);
docAsset.SetString("role", item.role);
docAsset.SetString("filename", Path.GetFileName(item.item.path));
item.item.Write(warnings);
}
doc.WriteToFile(Path.Combine(m_Path, "Contents.json"));
}
}
} // namespace UnityEditor.iOS.Xcode

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 46dd33873affe4e5caf86cb784bd831a
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,257 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
namespace ChillyRoom.UnityEditor.iOS.Xcode
{
internal class JsonElement
{
protected JsonElement() {}
// convenience methods
public string AsString() { return ((JsonElementString)this).value; }
public int AsInteger() { return ((JsonElementInteger)this).value; }
public bool AsBoolean() { return ((JsonElementBoolean)this).value; }
public JsonElementArray AsArray() { return (JsonElementArray)this; }
public JsonElementDict AsDict() { return (JsonElementDict)this; }
public JsonElement this[string key]
{
get { return AsDict()[key]; }
set { AsDict()[key] = value; }
}
}
internal class JsonElementString : JsonElement
{
public JsonElementString(string v) { value = v; }
public string value;
}
internal class JsonElementInteger : JsonElement
{
public JsonElementInteger(int v) { value = v; }
public int value;
}
internal class JsonElementBoolean : JsonElement
{
public JsonElementBoolean(bool v) { value = v; }
public bool value;
}
internal class JsonElementDict : JsonElement
{
public JsonElementDict() : base() {}
private SortedDictionary<string, JsonElement> m_PrivateValue = new SortedDictionary<string, JsonElement>();
public IDictionary<string, JsonElement> values { get { return m_PrivateValue; }}
new public JsonElement this[string key]
{
get {
if (values.ContainsKey(key))
return values[key];
return null;
}
set { this.values[key] = value; }
}
public bool Contains(string key)
{
return values.ContainsKey(key);
}
public void Remove(string key)
{
values.Remove(key);
}
// convenience methods
public void SetInteger(string key, int val)
{
values[key] = new JsonElementInteger(val);
}
public void SetString(string key, string val)
{
values[key] = new JsonElementString(val);
}
public void SetBoolean(string key, bool val)
{
values[key] = new JsonElementBoolean(val);
}
public JsonElementArray CreateArray(string key)
{
var v = new JsonElementArray();
values[key] = v;
return v;
}
public JsonElementDict CreateDict(string key)
{
var v = new JsonElementDict();
values[key] = v;
return v;
}
}
internal class JsonElementArray : JsonElement
{
public JsonElementArray() : base() {}
public List<JsonElement> values = new List<JsonElement>();
// convenience methods
public void AddString(string val)
{
values.Add(new JsonElementString(val));
}
public void AddInteger(int val)
{
values.Add(new JsonElementInteger(val));
}
public void AddBoolean(bool val)
{
values.Add(new JsonElementBoolean(val));
}
public JsonElementArray AddArray()
{
var v = new JsonElementArray();
values.Add(v);
return v;
}
public JsonElementDict AddDict()
{
var v = new JsonElementDict();
values.Add(v);
return v;
}
}
internal class JsonDocument
{
public JsonElementDict root;
public string indentString = " ";
public JsonDocument()
{
root = new JsonElementDict();
}
void AppendIndent(StringBuilder sb, int indent)
{
for (int i = 0; i < indent; ++i)
sb.Append(indentString);
}
void WriteString(StringBuilder sb, string str)
{
// TODO: escape
sb.Append('"');
sb.Append(str);
sb.Append('"');
}
void WriteBoolean(StringBuilder sb, bool value)
{
sb.Append(value ? "true" : "false");
}
void WriteInteger(StringBuilder sb, int value)
{
sb.Append(value.ToString());
}
void WriteDictKeyValue(StringBuilder sb, string key, JsonElement value, int indent)
{
sb.Append("\n");
AppendIndent(sb, indent);
WriteString(sb, key);
sb.Append(" : ");
if (value is JsonElementString)
WriteString(sb, value.AsString());
else if (value is JsonElementInteger)
WriteInteger(sb, value.AsInteger());
else if (value is JsonElementBoolean)
WriteBoolean(sb, value.AsBoolean());
else if (value is JsonElementDict)
WriteDict(sb, value.AsDict(), indent);
else if (value is JsonElementArray)
WriteArray(sb, value.AsArray(), indent);
}
void WriteDict(StringBuilder sb, JsonElementDict el, int indent)
{
sb.Append("{");
bool hasElement = false;
foreach (var key in el.values.Keys)
{
if (hasElement)
sb.Append(","); // trailing commas not supported
WriteDictKeyValue(sb, key, el[key], indent+1);
hasElement = true;
}
sb.Append("\n");
AppendIndent(sb, indent);
sb.Append("}");
}
void WriteArray(StringBuilder sb, JsonElementArray el, int indent)
{
sb.Append("[");
bool hasElement = false;
foreach (var value in el.values)
{
if (hasElement)
sb.Append(","); // trailing commas not supported
sb.Append("\n");
AppendIndent(sb, indent+1);
if (value is JsonElementString)
WriteString(sb, value.AsString());
else if (value is JsonElementInteger)
WriteInteger(sb, value.AsInteger());
else if (value is JsonElementBoolean)
WriteBoolean(sb, value.AsBoolean());
else if (value is JsonElementDict)
WriteDict(sb, value.AsDict(), indent+1);
else if (value is JsonElementArray)
WriteArray(sb, value.AsArray(), indent+1);
hasElement = true;
}
sb.Append("\n");
AppendIndent(sb, indent);
sb.Append("]");
}
public void WriteToFile(string path)
{
File.WriteAllText(path, WriteToString());
}
public void WriteToStream(TextWriter tw)
{
tw.Write(WriteToString());
}
public string WriteToString()
{
var sb = new StringBuilder();
WriteDict(sb, root, 0);
return sb.ToString();
}
}
} // namespace UnityEditor.iOS.Xcode

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 052ac8a8c9ae3466f94f7b3b6c5b61af
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,9 +0,0 @@
fileFormatVersion: 2
guid: 7625017be5ff149a6b0f20ee645ce11e
folderAsset: yes
timeCreated: 1496741689
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,106 +0,0 @@
using System.Collections.Generic;
using System.Collections;
using System;
namespace ChillyRoom.UnityEditor.iOS.Xcode.PBX
{
class PBXElement
{
protected PBXElement() {}
// convenience methods
public string AsString() { return ((PBXElementString)this).value; }
public PBXElementArray AsArray() { return (PBXElementArray)this; }
public PBXElementDict AsDict() { return (PBXElementDict)this; }
public PBXElement this[string key]
{
get { return AsDict()[key]; }
set { AsDict()[key] = value; }
}
}
class PBXElementString : PBXElement
{
public PBXElementString(string v) { value = v; }
public string value;
}
class PBXElementDict : PBXElement
{
public PBXElementDict() : base() {}
private Dictionary<string, PBXElement> m_PrivateValue = new Dictionary<string, PBXElement>();
public IDictionary<string, PBXElement> values { get { return m_PrivateValue; }}
new public PBXElement this[string key]
{
get {
if (values.ContainsKey(key))
return values[key];
return null;
}
set { this.values[key] = value; }
}
public bool Contains(string key)
{
return values.ContainsKey(key);
}
public void Remove(string key)
{
values.Remove(key);
}
public void SetString(string key, string val)
{
values[key] = new PBXElementString(val);
}
public PBXElementArray CreateArray(string key)
{
var v = new PBXElementArray();
values[key] = v;
return v;
}
public PBXElementDict CreateDict(string key)
{
var v = new PBXElementDict();
values[key] = v;
return v;
}
}
class PBXElementArray : PBXElement
{
public PBXElementArray() : base() {}
public List<PBXElement> values = new List<PBXElement>();
// convenience methods
public void AddString(string val)
{
values.Add(new PBXElementString(val));
}
public PBXElementArray AddArray()
{
var v = new PBXElementArray();
values.Add(v);
return v;
}
public PBXElementDict AddDict()
{
var v = new PBXElementDict();
values.Add(v);
return v;
}
}
} // namespace UnityEditor.iOS.Xcode

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 83cffec4be0e045258109e9714cdaa5f
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,243 +0,0 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.IO;
using System.Linq;
using System;
namespace ChillyRoom.UnityEditor.iOS.Xcode.PBX
{
enum TokenType
{
EOF,
Invalid,
String,
QuotedString,
Comment,
Semicolon, // ;
Comma, // ,
Eq, // =
LParen, // (
RParen, // )
LBrace, // {
RBrace, // }
}
class Token
{
public TokenType type;
// the line of the input stream the token starts in (0-based)
public int line;
// start and past-the-end positions of the token in the input stream
public int begin, end;
}
class TokenList : List<Token>
{
}
class Lexer
{
string text;
int pos;
int length;
int line;
public static TokenList Tokenize(string text)
{
var lexer = new Lexer();
lexer.SetText(text);
return lexer.ScanAll();
}
public void SetText(string text)
{
this.text = text + " "; // to prevent out-of-bounds access during look ahead
pos = 0;
length = text.Length;
line = 0;
}
public TokenList ScanAll()
{
var tokens = new TokenList();
while (true)
{
var tok = new Token();
ScanOne(tok);
tokens.Add(tok);
if (tok.type == TokenType.EOF)
break;
}
return tokens;
}
void UpdateNewlineStats(char ch)
{
if (ch == '\n')
line++;
}
// tokens list is modified in the case when we add BrokenLine token and need to remove already
// added tokens for the current line
void ScanOne(Token tok)
{
while (true)
{
while (pos < length && Char.IsWhiteSpace(text[pos]))
{
UpdateNewlineStats(text[pos]);
pos++;
}
if (pos >= length)
{
tok.type = TokenType.EOF;
break;
}
char ch = text[pos];
char ch2 = text[pos+1];
if (ch == '\"')
ScanQuotedString(tok);
else if (ch == '/' && ch2 == '*')
ScanMultilineComment(tok);
else if (ch == '/' && ch2 == '/')
ScanComment(tok);
else if (IsOperator(ch))
ScanOperator(tok);
else
ScanString(tok); // be more robust and accept whatever is left
return;
}
}
void ScanString(Token tok)
{
tok.type = TokenType.String;
tok.begin = pos;
while (pos < length)
{
char ch = text[pos];
char ch2 = text[pos+1];
if (Char.IsWhiteSpace(ch))
break;
else if (ch == '\"')
break;
else if (ch == '/' && ch2 == '*')
break;
else if (ch == '/' && ch2 == '/')
break;
else if (IsOperator(ch))
break;
pos++;
}
tok.end = pos;
tok.line = line;
}
void ScanQuotedString(Token tok)
{
tok.type = TokenType.QuotedString;
tok.begin = pos;
pos++;
while (pos < length)
{
// ignore escaped quotes
if (text[pos] == '\\' && text[pos+1] == '\"')
{
pos += 2;
continue;
}
// note that we close unclosed quotes
if (text[pos] == '\"')
break;
UpdateNewlineStats(text[pos]);
pos++;
}
pos++;
tok.end = pos;
tok.line = line;
}
void ScanMultilineComment(Token tok)
{
tok.type = TokenType.Comment;
tok.begin = pos;
pos += 2;
while (pos < length)
{
if (text[pos] == '*' && text[pos+1] == '/')
break;
// we support multiline comments
UpdateNewlineStats(text[pos]);
pos++;
}
pos += 2;
tok.end = pos;
tok.line = line;
}
void ScanComment(Token tok)
{
tok.type = TokenType.Comment;
tok.begin = pos;
pos += 2;
while (pos < length)
{
if (text[pos] == '\n')
break;
pos++;
}
UpdateNewlineStats(text[pos]);
pos++;
tok.end = pos;
tok.line = line;
}
bool IsOperator(char ch)
{
if (ch == ';' || ch == ',' || ch == '=' || ch == '(' || ch == ')' || ch == '{' || ch == '}')
return true;
return false;
}
void ScanOperator(Token tok)
{
switch (text[pos])
{
case ';': ScanOperatorSpecific(tok, TokenType.Semicolon); return;
case ',': ScanOperatorSpecific(tok, TokenType.Comma); return;
case '=': ScanOperatorSpecific(tok, TokenType.Eq); return;
case '(': ScanOperatorSpecific(tok, TokenType.LParen); return;
case ')': ScanOperatorSpecific(tok, TokenType.RParen); return;
case '{': ScanOperatorSpecific(tok, TokenType.LBrace); return;
case '}': ScanOperatorSpecific(tok, TokenType.RBrace); return;
default: return;
}
}
void ScanOperatorSpecific(Token tok, TokenType type)
{
tok.type = type;
tok.begin = pos;
pos++;
tok.end = pos;
tok.line = line;
}
}
} // namespace UnityEditor.iOS.Xcode

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 9766f6c4eb5ef42f99c0d5f86e34ba84
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 67cf10cf994604c719f706525399f867
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,171 +0,0 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.IO;
using System.Linq;
using System;
namespace ChillyRoom.UnityEditor.iOS.Xcode.PBX
{
class ValueAST {}
// IdentifierAST := <quoted string> \ <string>
class IdentifierAST : ValueAST
{
public int value = 0; // token id
}
// TreeAST := '{' KeyValuePairList '}'
// KeyValuePairList := KeyValuePair ',' KeyValuePairList
// KeyValuePair ','
// (empty)
class TreeAST : ValueAST
{
public List<KeyValueAST> values = new List<KeyValueAST>();
}
// ListAST := '(' ValueList ')'
// ValueList := ValueAST ',' ValueList
// ValueAST ','
// (empty)
class ArrayAST : ValueAST
{
public List<ValueAST> values = new List<ValueAST>();
}
// KeyValueAST := IdentifierAST '=' ValueAST ';'
// ValueAST := IdentifierAST | TreeAST | ListAST
class KeyValueAST
{
public IdentifierAST key = null;
public ValueAST value = null; // either IdentifierAST, TreeAST or ListAST
}
class Parser
{
TokenList tokens;
int currPos;
public Parser(TokenList tokens)
{
this.tokens = tokens;
currPos = SkipComments(0);
}
int SkipComments(int pos)
{
while (pos < tokens.Count && tokens[pos].type == TokenType.Comment)
{
pos++;
}
return pos;
}
// returns new position
int IncInternal(int pos)
{
if (pos >= tokens.Count)
return pos;
pos++;
return SkipComments(pos);
}
// Increments current pointer if not past the end, returns previous pos
int Inc()
{
int prev = currPos;
currPos = IncInternal(currPos);
return prev;
}
// Returns the token type of the current token
TokenType Tok()
{
if (currPos >= tokens.Count)
return TokenType.EOF;
return tokens[currPos].type;
}
void SkipIf(TokenType type)
{
if (Tok() == type)
Inc();
}
string GetErrorMsg()
{
return "Invalid PBX project (parsing line " + tokens[currPos].line + ")";
}
public IdentifierAST ParseIdentifier()
{
if (Tok() != TokenType.String && Tok() != TokenType.QuotedString)
throw new Exception(GetErrorMsg());
var ast = new IdentifierAST();
ast.value = Inc();
return ast;
}
public TreeAST ParseTree()
{
if (Tok() != TokenType.LBrace)
throw new Exception(GetErrorMsg());
Inc();
var ast = new TreeAST();
while (Tok() != TokenType.RBrace && Tok() != TokenType.EOF)
{
ast.values.Add(ParseKeyValue());
}
SkipIf(TokenType.RBrace);
return ast;
}
public ArrayAST ParseList()
{
if (Tok() != TokenType.LParen)
throw new Exception(GetErrorMsg());
Inc();
var ast = new ArrayAST();
while (Tok() != TokenType.RParen && Tok() != TokenType.EOF)
{
ast.values.Add(ParseValue());
SkipIf(TokenType.Comma);
}
SkipIf(TokenType.RParen);
return ast;
}
// throws on error
public KeyValueAST ParseKeyValue()
{
var ast = new KeyValueAST();
ast.key = ParseIdentifier();
if (Tok() != TokenType.Eq)
throw new Exception(GetErrorMsg());
Inc(); // skip '='
ast.value = ParseValue();
SkipIf(TokenType.Semicolon);
return ast;
}
// throws on error
public ValueAST ParseValue()
{
if (Tok() == TokenType.String || Tok() == TokenType.QuotedString)
return ParseIdentifier();
else if (Tok() == TokenType.LBrace)
return ParseTree();
else if (Tok() == TokenType.LParen)
return ParseList();
throw new Exception(GetErrorMsg());
}
}
} // namespace UnityEditor.iOS.Xcode

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 5ce5a244bc4e04a668ab097db4456665
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,122 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
// Basr classes for section handling
namespace ChillyRoom.UnityEditor.iOS.Xcode.PBX
{
// common base
internal abstract class SectionBase
{
public abstract void AddObject(string key, PBXElementDict value);
public abstract void WriteSection(StringBuilder sb, GUIDToCommentMap comments);
}
// known section: contains objects that we care about
internal class KnownSectionBase<T> : SectionBase where T : PBXObjectData, new()
{
private Dictionary<string, T> m_Entries = new Dictionary<string, T>();
private string m_Name;
public KnownSectionBase(string sectionName)
{
m_Name = sectionName;
}
public IEnumerable<KeyValuePair<string, T>> GetEntries()
{
return m_Entries;
}
public IEnumerable<string> GetGuids()
{
return m_Entries.Keys;
}
public IEnumerable<T> GetObjects()
{
return m_Entries.Values;
}
public override void AddObject(string key, PBXElementDict value)
{
T obj = new T();
obj.guid = key;
obj.SetPropertiesWhenSerializing(value);
obj.UpdateVars();
m_Entries[obj.guid] = obj;
}
public override void WriteSection(StringBuilder sb, GUIDToCommentMap comments)
{
if (m_Entries.Count == 0)
return; // do not write empty sections
sb.AppendFormat("\n\n/* Begin {0} section */", m_Name);
var keys = new List<string>(m_Entries.Keys);
keys.Sort(StringComparer.Ordinal);
foreach (string key in keys)
{
T obj = m_Entries[key];
obj.UpdateProps();
sb.Append("\n\t\t");
comments.WriteStringBuilder(sb, obj.guid);
sb.Append(" = ");
Serializer.WriteDict(sb, obj.GetPropertiesWhenSerializing(), 2,
obj.shouldCompact, obj.checker, comments);
sb.Append(";");
}
sb.AppendFormat("\n/* End {0} section */", m_Name);
}
// returns null if not found
public T this[string guid]
{
get {
if (m_Entries.ContainsKey(guid))
return m_Entries[guid];
return null;
}
}
public bool HasEntry(string guid)
{
return m_Entries.ContainsKey(guid);
}
public void AddEntry(T obj)
{
m_Entries[obj.guid] = obj;
}
public void RemoveEntry(string guid)
{
if (m_Entries.ContainsKey(guid))
m_Entries.Remove(guid);
}
}
// we assume there is only one PBXProject entry
internal class PBXProjectSection : KnownSectionBase<PBXProjectObjectData>
{
public PBXProjectSection() : base("PBXProject")
{
}
public PBXProjectObjectData project
{
get {
foreach (var kv in GetEntries())
return kv.Value;
return null;
}
}
}
} // UnityEditor.iOS.Xcode

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 60639b138b83f4ce9b2448c38a6ba285
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,259 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Linq;
namespace ChillyRoom.UnityEditor.iOS.Xcode.PBX
{
class PropertyCommentChecker
{
private int m_Level;
private bool m_All;
private List<List<string>> m_Props;
/* The argument is an array of matcher strings each of which determine
whether a property with a certain path needs to be decorated with a
comment.
A path is a number of path elements concatenated by '/'. The last path
element is either:
the key if we're referring to a dict key
the value if we're referring to a value in an array
the value if we're referring to a value in a dict
All other path elements are either:
the key if the container is dict
'*' if the container is array
Path matcher has the same structure as a path, except that any of the
elements may be '*'. Matcher matches a path if both have the same number
of elements and for each pair matcher element is the same as path element
or is '*'.
a/b/c matches a/b/c but not a/b nor a/b/c/d
a/* /c matches a/d/c but not a/b nor a/b/c/d
* /* /* matches any path from three elements
*/
protected PropertyCommentChecker(int level, List<List<string>> props)
{
m_Level = level;
m_All = false;
m_Props = props;
}
public PropertyCommentChecker()
{
m_Level = 0;
m_All = false;
m_Props = new List<List<string>>();
}
public PropertyCommentChecker(IEnumerable<string> props)
{
m_Level = 0;
m_All = false;
m_Props = new List<List<string>>();
foreach (var prop in props)
{
m_Props.Add(new List<string>(prop.Split('/')));
}
}
bool CheckContained(string prop)
{
if (m_All)
return true;
foreach (var list in m_Props)
{
if (list.Count == m_Level+1)
{
if (list[m_Level] == prop)
return true;
if (list[m_Level] == "*")
{
m_All = true; // short-circuit all at this level
return true;
}
}
}
return false;
}
public bool CheckStringValueInArray(string value) { return CheckContained(value); }
public bool CheckKeyInDict(string key) { return CheckContained(key); }
public bool CheckStringValueInDict(string key, string value)
{
foreach (var list in m_Props)
{
if (list.Count == m_Level + 2)
{
if ((list[m_Level] == "*" || list[m_Level] == key) &&
list[m_Level+1] == "*" || list[m_Level+1] == value)
return true;
}
}
return false;
}
public PropertyCommentChecker NextLevel(string prop)
{
var newList = new List<List<string>>();
foreach (var list in m_Props)
{
if (list.Count <= m_Level+1)
continue;
if (list[m_Level] == "*" || list[m_Level] == prop)
newList.Add(list);
}
return new PropertyCommentChecker(m_Level + 1, newList);
}
}
class Serializer
{
public static PBXElementDict ParseTreeAST(TreeAST ast, TokenList tokens, string text)
{
var el = new PBXElementDict();
foreach (var kv in ast.values)
{
PBXElementString key = ParseIdentifierAST(kv.key, tokens, text);
PBXElement value = ParseValueAST(kv.value, tokens, text);
el[key.value] = value;
}
return el;
}
public static PBXElementArray ParseArrayAST(ArrayAST ast, TokenList tokens, string text)
{
var el = new PBXElementArray();
foreach (var v in ast.values)
{
el.values.Add(ParseValueAST(v, tokens, text));
}
return el;
}
public static PBXElement ParseValueAST(ValueAST ast, TokenList tokens, string text)
{
if (ast is TreeAST)
return ParseTreeAST((TreeAST)ast, tokens, text);
if (ast is ArrayAST)
return ParseArrayAST((ArrayAST)ast, tokens, text);
if (ast is IdentifierAST)
return ParseIdentifierAST((IdentifierAST)ast, tokens, text);
return null;
}
public static PBXElementString ParseIdentifierAST(IdentifierAST ast, TokenList tokens, string text)
{
Token tok = tokens[ast.value];
string value;
switch (tok.type)
{
case TokenType.String:
value = text.Substring(tok.begin, tok.end - tok.begin);
return new PBXElementString(value);
case TokenType.QuotedString:
value = text.Substring(tok.begin, tok.end - tok.begin);
value = PBXStream.UnquoteString(value);
return new PBXElementString(value);
default:
throw new Exception("Internal parser error");
}
}
static string k_Indent = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
static string GetIndent(int indent)
{
return k_Indent.Substring(0, indent);
}
static void WriteStringImpl(StringBuilder sb, string s, bool comment, GUIDToCommentMap comments)
{
if (comment)
comments.WriteStringBuilder(sb, s);
else
sb.Append(PBXStream.QuoteStringIfNeeded(s));
}
public static void WriteDictKeyValue(StringBuilder sb, string key, PBXElement value, int indent, bool compact,
PropertyCommentChecker checker, GUIDToCommentMap comments)
{
if (!compact)
{
sb.Append("\n");
sb.Append(GetIndent(indent));
}
WriteStringImpl(sb, key, checker.CheckKeyInDict(key), comments);
sb.Append(" = ");
if (value is PBXElementString)
WriteStringImpl(sb, value.AsString(), checker.CheckStringValueInDict(key, value.AsString()), comments);
else if (value is PBXElementDict)
WriteDict(sb, value.AsDict(), indent, compact, checker.NextLevel(key), comments);
else if (value is PBXElementArray)
WriteArray(sb, value.AsArray(), indent, compact, checker.NextLevel(key), comments);
sb.Append(";");
if (compact)
sb.Append(" ");
}
public static void WriteDict(StringBuilder sb, PBXElementDict el, int indent, bool compact,
PropertyCommentChecker checker, GUIDToCommentMap comments)
{
sb.Append("{");
if (el.Contains("isa"))
WriteDictKeyValue(sb, "isa", el["isa"], indent+1, compact, checker, comments);
var keys = new List<string>(el.values.Keys);
keys.Sort(StringComparer.Ordinal);
foreach (var key in keys)
{
if (key != "isa")
WriteDictKeyValue(sb, key, el[key], indent+1, compact, checker, comments);
}
if (!compact)
{
sb.Append("\n");
sb.Append(GetIndent(indent));
}
sb.Append("}");
}
public static void WriteArray(StringBuilder sb, PBXElementArray el, int indent, bool compact,
PropertyCommentChecker checker, GUIDToCommentMap comments)
{
sb.Append("(");
foreach (var value in el.values)
{
if (!compact)
{
sb.Append("\n");
sb.Append(GetIndent(indent+1));
}
if (value is PBXElementString)
WriteStringImpl(sb, value.AsString(), checker.CheckStringValueInArray(value.AsString()), comments);
else if (value is PBXElementDict)
WriteDict(sb, value.AsDict(), indent+1, compact, checker.NextLevel("*"), comments);
else if (value is PBXElementArray)
WriteArray(sb, value.AsArray(), indent+1, compact, checker.NextLevel("*"), comments);
sb.Append(",");
if (compact)
sb.Append(" ");
}
if (!compact)
{
sb.Append("\n");
sb.Append(GetIndent(indent));
}
sb.Append(")");
}
}
} // namespace UnityEditor.iOS.Xcode

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: afe8316bf614347729fac3466d7c77f2
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,300 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
namespace ChillyRoom.UnityEditor.iOS.Xcode.PBX
{
internal class GUIDToCommentMap
{
private Dictionary<string, string> m_Dict = new Dictionary<string, string>();
public string this[string guid]
{
get {
if (m_Dict.ContainsKey(guid))
return m_Dict[guid];
return null;
}
}
public void Add(string guid, string comment)
{
if (m_Dict.ContainsKey(guid))
return;
m_Dict.Add(guid, comment);
}
public void Remove(string guid)
{
m_Dict.Remove(guid);
}
public string Write(string guid)
{
string comment = this[guid];
if (comment == null)
return guid;
return String.Format("{0} /* {1} */", guid, comment);
}
public void WriteStringBuilder(StringBuilder sb, string guid)
{
string comment = this[guid];
if (comment == null)
sb.Append(guid);
else
{
// {0} /* {1} */
sb.Append(guid).Append(" /* ").Append(comment).Append(" */");
}
}
}
internal class PBXGUID
{
internal delegate string GuidGenerator();
// We allow changing Guid generator to make testing of PBXProject possible
private static GuidGenerator guidGenerator = DefaultGuidGenerator;
internal static string DefaultGuidGenerator()
{
return Guid.NewGuid().ToString("N").Substring(8).ToUpper();
}
internal static void SetGuidGenerator(GuidGenerator generator)
{
guidGenerator = generator;
}
// Generates a GUID.
public static string Generate()
{
return guidGenerator();
}
}
internal class PBXRegex
{
public static string GuidRegexString = "[A-Fa-f0-9]{24}";
}
internal class PBXStream
{
static bool DontNeedQuotes(string src)
{
// using a regex instead of explicit matching slows down common cases by 40%
if (src.Length == 0)
return false;
bool hasSlash = false;
for (int i = 0; i < src.Length; ++i)
{
char c = src[i];
if (Char.IsLetterOrDigit(c) || c == '.' || c == '*' || c == '_')
continue;
if (c == '/')
{
hasSlash = true;
continue;
}
return false;
}
if (hasSlash)
{
if (src.Contains("//") || src.Contains("/*") || src.Contains("*/"))
return false;
}
return true;
}
// Quotes the given string if it contains special characters. Note: if the string already
// contains quotes, then they are escaped and the entire string quoted again
public static string QuoteStringIfNeeded(string src)
{
if (DontNeedQuotes(src))
return src;
return "\"" + src.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n") + "\"";
}
// If the given string is quoted, removes the quotes and unescapes any quotes within the string
public static string UnquoteString(string src)
{
if (!src.StartsWith("\"") || !src.EndsWith("\""))
return src;
return src.Substring(1, src.Length - 2).Replace("\\\\", "\u569f").Replace("\\\"", "\"")
.Replace("\\n", "\n").Replace("\u569f", "\\"); // U+569f is a rarely used Chinese character
}
}
internal enum PBXFileType
{
NotBuildable,
Framework,
Source,
Resource,
CopyFile
}
internal class FileTypeUtils
{
internal class FileTypeDesc
{
public FileTypeDesc(string typeName, PBXFileType type)
{
this.name = typeName;
this.type = type;
this.isExplicit = false;
}
public FileTypeDesc(string typeName, PBXFileType type, bool isExplicit)
{
this.name = typeName;
this.type = type;
this.isExplicit = isExplicit;
}
public string name;
public PBXFileType type;
public bool isExplicit;
}
private static readonly Dictionary<string, FileTypeDesc> types =
new Dictionary<string, FileTypeDesc>
{
{ "a", new FileTypeDesc("archive.ar", PBXFileType.Framework) },
{ "app", new FileTypeDesc("wrapper.application", PBXFileType.NotBuildable, true) },
{ "appex", new FileTypeDesc("wrapper.app-extension", PBXFileType.CopyFile) },
{ "bin", new FileTypeDesc("archive.macbinary", PBXFileType.Resource) },
{ "s", new FileTypeDesc("sourcecode.asm", PBXFileType.Source) },
{ "c", new FileTypeDesc("sourcecode.c.c", PBXFileType.Source) },
{ "cc", new FileTypeDesc("sourcecode.cpp.cpp", PBXFileType.Source) },
{ "cpp", new FileTypeDesc("sourcecode.cpp.cpp", PBXFileType.Source) },
{ "swift", new FileTypeDesc("sourcecode.swift", PBXFileType.Source) },
{ "dll", new FileTypeDesc("file", PBXFileType.NotBuildable) },
{ "framework", new FileTypeDesc("wrapper.framework", PBXFileType.Framework) },
{ "h", new FileTypeDesc("sourcecode.c.h", PBXFileType.NotBuildable) },
{ "pch", new FileTypeDesc("sourcecode.c.h", PBXFileType.NotBuildable) },
{ "icns", new FileTypeDesc("image.icns", PBXFileType.Resource) },
{ "xcassets", new FileTypeDesc("folder.assetcatalog", PBXFileType.Resource) },
{ "inc", new FileTypeDesc("sourcecode.inc", PBXFileType.NotBuildable) },
{ "m", new FileTypeDesc("sourcecode.c.objc", PBXFileType.Source) },
{ "mm", new FileTypeDesc("sourcecode.cpp.objcpp", PBXFileType.Source ) },
{ "nib", new FileTypeDesc("wrapper.nib", PBXFileType.Resource) },
{ "plist", new FileTypeDesc("text.plist.xml", PBXFileType.Resource) },
{ "png", new FileTypeDesc("image.png", PBXFileType.Resource) },
{ "rtf", new FileTypeDesc("text.rtf", PBXFileType.Resource) },
{ "tiff", new FileTypeDesc("image.tiff", PBXFileType.Resource) },
{ "txt", new FileTypeDesc("text", PBXFileType.Resource) },
{ "json", new FileTypeDesc("text.json", PBXFileType.Resource) },
{ "xcodeproj", new FileTypeDesc("wrapper.pb-project", PBXFileType.NotBuildable) },
{ "xib", new FileTypeDesc("file.xib", PBXFileType.Resource) },
{ "strings", new FileTypeDesc("text.plist.strings", PBXFileType.Resource) },
{ "storyboard",new FileTypeDesc("file.storyboard", PBXFileType.Resource) },
{ "bundle", new FileTypeDesc("wrapper.plug-in", PBXFileType.Resource) },
{ "dylib", new FileTypeDesc("compiled.mach-o.dylib", PBXFileType.Framework) },
{ "tbd", new FileTypeDesc("sourcecode.text-based-dylib-definition", PBXFileType.Framework) }
};
public static string TrimExtension(string ext)
{
return ext.TrimStart('.');
}
public static bool IsKnownExtension(string ext)
{
ext = TrimExtension(ext);
return types.ContainsKey(ext);
}
internal static bool IsFileTypeExplicit(string ext)
{
ext = TrimExtension(ext);
if (types.ContainsKey(ext))
return types[ext].isExplicit;
return false;
}
public static PBXFileType GetFileType(string ext, bool isFolderRef)
{
ext = TrimExtension(ext);
if (isFolderRef)
return PBXFileType.Resource;
if (!types.ContainsKey(ext))
return PBXFileType.Resource;
return types[ext].type;
}
public static string GetTypeName(string ext)
{
ext = TrimExtension(ext);
if (types.ContainsKey(ext))
return types[ext].name;
// Xcode actually checks the file contents to determine the file type.
// Text files have "text" type and all other files have "file" type.
// Since we can't reasonably determine whether the file in question is
// a text file, we just take the safe route and return "file" type.
return "file";
}
public static bool IsBuildableFile(string ext)
{
ext = TrimExtension(ext);
if (!types.ContainsKey(ext))
return true;
if (types[ext].type != PBXFileType.NotBuildable)
return true;
return false;
}
public static bool IsBuildable(string ext, bool isFolderReference)
{
ext = TrimExtension(ext);
if (isFolderReference)
return true;
return IsBuildableFile(ext);
}
private static readonly Dictionary<PBXSourceTree, string> sourceTree = new Dictionary<PBXSourceTree, string>
{
{ PBXSourceTree.Absolute, "<absolute>" },
{ PBXSourceTree.Group, "<group>" },
{ PBXSourceTree.Build, "BUILT_PRODUCTS_DIR" },
{ PBXSourceTree.Developer, "DEVELOPER_DIR" },
{ PBXSourceTree.Sdk, "SDKROOT" },
{ PBXSourceTree.Source, "SOURCE_ROOT" },
};
private static readonly Dictionary<string, PBXSourceTree> stringToSourceTreeMap = new Dictionary<string, PBXSourceTree>
{
{ "<absolute>", PBXSourceTree.Absolute },
{ "<group>", PBXSourceTree.Group },
{ "BUILT_PRODUCTS_DIR", PBXSourceTree.Build },
{ "DEVELOPER_DIR", PBXSourceTree.Developer },
{ "SDKROOT", PBXSourceTree.Sdk },
{ "SOURCE_ROOT", PBXSourceTree.Source },
};
internal static string SourceTreeDesc(PBXSourceTree tree)
{
return sourceTree[tree];
}
// returns PBXSourceTree.Source on error
internal static PBXSourceTree ParseSourceTree(string tree)
{
if (stringToSourceTreeMap.ContainsKey(tree))
return stringToSourceTreeMap[tree];
return PBXSourceTree.Source;
}
internal static List<PBXSourceTree> AllAbsoluteSourceTrees()
{
return new List<PBXSourceTree>{PBXSourceTree.Absolute, PBXSourceTree.Build,
PBXSourceTree.Developer, PBXSourceTree.Sdk, PBXSourceTree.Source};
}
}
} // UnityEditor.iOS.Xcode

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 8eafbccf2ded14760af588ffcb1ca0f5
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,125 +0,0 @@
namespace ChillyRoom.UnityEditor.iOS.Xcode
{
/// <summary>
/// List of all the capabilities available.
/// </summary>
public sealed class PBXCapabilityType
{
public static readonly PBXCapabilityType ApplePay = new PBXCapabilityType ("com.apple.ApplePay", true);
public static readonly PBXCapabilityType AppGroups = new PBXCapabilityType ("com.apple.ApplicationGroups.iOS", true);
public static readonly PBXCapabilityType AssociatedDomains = new PBXCapabilityType ("com.apple.SafariKeychain", true);
public static readonly PBXCapabilityType BackgroundModes = new PBXCapabilityType ("com.apple.BackgroundModes", false);
public static readonly PBXCapabilityType DataProtection = new PBXCapabilityType ("com.apple.DataProtection", true);
public static readonly PBXCapabilityType GameCenter = new PBXCapabilityType ("com.apple.GameCenter", false, "GameKit.framework");
public static readonly PBXCapabilityType HealthKit = new PBXCapabilityType ("com.apple.HealthKit", true, "HealthKit.framework");
public static readonly PBXCapabilityType HomeKit = new PBXCapabilityType ("com.apple.HomeKit", true, "HomeKit.framework");
public static readonly PBXCapabilityType iCloud = new PBXCapabilityType("com.apple.iCloud", true, "CloudKit.framework", true);
public static readonly PBXCapabilityType InAppPurchase = new PBXCapabilityType ("com.apple.InAppPurchase", false);
public static readonly PBXCapabilityType InterAppAudio = new PBXCapabilityType ("com.apple.InterAppAudio", true, "AudioToolbox.framework");
public static readonly PBXCapabilityType KeychainSharing = new PBXCapabilityType ("com.apple.KeychainSharing", true);
public static readonly PBXCapabilityType Maps = new PBXCapabilityType("com.apple.Maps.iOS", false, "MapKit.framework");
public static readonly PBXCapabilityType PersonalVPN = new PBXCapabilityType("com.apple.VPNLite", true, "NetworkExtension.framework");
public static readonly PBXCapabilityType PushNotifications = new PBXCapabilityType ("com.apple.Push", true);
public static readonly PBXCapabilityType Siri = new PBXCapabilityType ("com.apple.Siri", true);
public static readonly PBXCapabilityType Wallet = new PBXCapabilityType ("com.apple.Wallet", true, "PassKit.framework");
public static readonly PBXCapabilityType WirelessAccessoryConfiguration = new PBXCapabilityType("com.apple.WAC", true, "ExternalAccessory.framework");
private readonly string m_ID;
private readonly bool m_RequiresEntitlements;
private readonly string m_Framework;
private readonly bool m_OptionalFramework;
public bool optionalFramework
{
get { return m_OptionalFramework; }
}
public string framework
{
get { return m_Framework; }
}
public string id
{
get { return m_ID; }
}
public bool requiresEntitlements
{
get { return m_RequiresEntitlements; }
}
public struct TargetCapabilityPair
{
public string targetGuid;
public PBXCapabilityType capability;
public TargetCapabilityPair(string guid, PBXCapabilityType type)
{
targetGuid = guid;
capability = type;
}
}
/// <summary>
/// This private object represents what a capability changes in the PBXProject file
/// </summary>
/// <param name="id">The string used in the PBXProject file to identify the capability and mark it as enabled.</param>
/// <param name="requiresEntitlements">This capability requires an entitlements file therefore we need to add this entitlements file to the code signing entitlement.</param>
/// <param name="framework">Specify which framework need to be added to the project for this capability, if "" no framework are added.</param>
/// <param name="optionalFramework">Some capability (right now only iCloud) adds a framework, not all the time but just when some option are checked
/// this parameter indicates if one of them is checked.</param>
private PBXCapabilityType(string _id, bool _requiresEntitlements, string _framework = "", bool _optionalFramework = false)
{
m_ID = _id;
m_RequiresEntitlements = _requiresEntitlements;
m_Framework = _framework;
m_OptionalFramework = _optionalFramework;
}
public static PBXCapabilityType StringToPBXCapabilityType(string cap)
{
switch (cap)
{
case "com.apple.ApplePay":
return ApplePay;
case "com.apple.ApplicationGroups.iOS":
return AppGroups;
case "com.apple.SafariKeychain":
return AssociatedDomains;
case "com.apple.BackgroundModes":
return BackgroundModes;
case "com.apple.DataProtection":
return DataProtection;
case "com.apple.GameCenter":
return GameCenter;
case "com.apple.HealthKit":
return HealthKit;
case "com.apple.HomeKit":
return HomeKit;
case "com.apple.iCloud":
return iCloud;
case "com.apple.InAppPurchase":
return InAppPurchase;
case "com.apple.InterAppAudio":
return InterAppAudio;
case "com.apple.KeychainSharing":
return KeychainSharing;
case "com.apple.Maps.iOS":
return Maps;
case "com.apple.VPNLite":
return PersonalVPN;
case "com.apple.Push":
return PushNotifications;
case "com.apple.Siri":
return Siri;
case "com.apple.Wallet":
return Wallet;
case "WAC":
return WirelessAccessoryConfiguration;
default:
return null;
}
}
}
}

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 71f2dd6273cda4741b9b3bac41a9b765
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,106 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
namespace ChillyRoom.UnityEditor.iOS.Xcode
{
internal class PBXPath
{
/// Replaces '\' with '/'. We need to apply this function to all paths that come from the user
/// of the API because we store paths to pbxproj and on windows we may get path with '\' slashes
/// instead of '/' slashes
public static string FixSlashes(string path)
{
if (path == null)
return null;
return path.Replace('\\', '/');
}
public static void Combine(string path1, PBXSourceTree tree1, string path2, PBXSourceTree tree2,
out string resPath, out PBXSourceTree resTree)
{
if (tree2 == PBXSourceTree.Group)
{
resPath = Combine(path1, path2);
resTree = tree1;
return;
}
resPath = path2;
resTree = tree2;
}
// Combines two paths
public static string Combine(string path1, string path2)
{
if (path2.StartsWith("/"))
return path2;
if (path1.EndsWith("/"))
return path1 + path2;
if (path1 == "")
return path2;
if (path2 == "")
return path1;
return path1 + "/" + path2;
}
public static string GetDirectory(string path)
{
path = path.TrimEnd('/');
int pos = path.LastIndexOf('/');
if (pos == -1)
return "";
else
return path.Substring(0, pos);
}
public static string GetCurrentDirectory()
{
if (Environment.OSVersion.Platform != PlatformID.MacOSX &&
Environment.OSVersion.Platform != PlatformID.Unix)
{
throw new Exception("PBX project compatible current directory can only obtained on OSX");
}
string path = Directory.GetCurrentDirectory();
path = FixSlashes(path);
if (!IsPathRooted(path))
return "/" + path;
return path;
}
public static string GetFilename(string path)
{
int pos = path.LastIndexOf('/');
if (pos == -1)
return path;
else
return path.Substring(pos + 1);
}
public static bool IsPathRooted(string path)
{
if (path == null || path.Length == 0)
return false;
return path[0] == '/';
}
public static string GetFullPath(string path)
{
if (IsPathRooted(path))
return path;
else
return Combine(GetCurrentDirectory(), path);
}
public static string[] Split(string path)
{
if (string.IsNullOrEmpty(path))
return new string[]{};
return path.Split(new[]{'/'}, StringSplitOptions.RemoveEmptyEntries);
}
}
} // UnityEditor.iOS.Xcode

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 57be5de7dcd844631b3e835186497c25
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 5923416dbf32e48428afbeee2b4eb48e
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,713 +0,0 @@
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System;
using ChillyRoom.UnityEditor.iOS.Xcode.PBX;
namespace ChillyRoom.UnityEditor.iOS.Xcode
{
using PBXBuildFileSection = KnownSectionBase<PBXBuildFileData>;
using PBXFileReferenceSection = KnownSectionBase<PBXFileReferenceData>;
using PBXGroupSection = KnownSectionBase<PBXGroupData>;
using PBXContainerItemProxySection = KnownSectionBase<PBXContainerItemProxyData>;
using PBXReferenceProxySection = KnownSectionBase<PBXReferenceProxyData>;
using PBXSourcesBuildPhaseSection = KnownSectionBase<PBXSourcesBuildPhaseData>;
using PBXFrameworksBuildPhaseSection= KnownSectionBase<PBXFrameworksBuildPhaseData>;
using PBXResourcesBuildPhaseSection = KnownSectionBase<PBXResourcesBuildPhaseData>;
using PBXCopyFilesBuildPhaseSection = KnownSectionBase<PBXCopyFilesBuildPhaseData>;
using PBXShellScriptBuildPhaseSection = KnownSectionBase<PBXShellScriptBuildPhaseData>;
using PBXVariantGroupSection = KnownSectionBase<PBXVariantGroupData>;
using PBXNativeTargetSection = KnownSectionBase<PBXNativeTargetData>;
using PBXTargetDependencySection = KnownSectionBase<PBXTargetDependencyData>;
using XCBuildConfigurationSection = KnownSectionBase<XCBuildConfigurationData>;
using XCConfigurationListSection = KnownSectionBase<XCConfigurationListData>;
using UnknownSection = KnownSectionBase<PBXObjectData>;
internal class PBXProjectData
{
private Dictionary<string, SectionBase> m_Section = null;
private PBXElementDict m_RootElements = null;
private PBXElementDict m_UnknownObjects = null;
private string m_ObjectVersion = null;
private List<string> m_SectionOrder = null;
private Dictionary<string, UnknownSection> m_UnknownSections;
private PBXBuildFileSection buildFiles = null; // use BuildFiles* methods instead of manipulating directly
private PBXFileReferenceSection fileRefs = null; // use FileRefs* methods instead of manipulating directly
private PBXGroupSection groups = null; // use Groups* methods instead of manipulating directly
public PBXContainerItemProxySection containerItems = null;
public PBXReferenceProxySection references = null;
public PBXSourcesBuildPhaseSection sources = null;
public PBXFrameworksBuildPhaseSection frameworks = null;
public PBXResourcesBuildPhaseSection resources = null;
public PBXCopyFilesBuildPhaseSection copyFiles = null;
public PBXShellScriptBuildPhaseSection shellScripts = null;
public PBXNativeTargetSection nativeTargets = null;
public PBXTargetDependencySection targetDependencies = null;
public PBXVariantGroupSection variantGroups = null;
public XCBuildConfigurationSection buildConfigs = null;
public XCConfigurationListSection buildConfigLists = null;
public PBXProjectSection project = null;
// FIXME: create a separate PBXObject tree to represent these relationships
// A build file can be represented only once in all *BuildPhaseSection sections, thus
// we can simplify the cache by not caring about the file extension
private Dictionary<string, Dictionary<string, PBXBuildFileData>> m_FileGuidToBuildFileMap = null;
private Dictionary<string, PBXFileReferenceData> m_ProjectPathToFileRefMap = null;
private Dictionary<string, string> m_FileRefGuidToProjectPathMap = null;
private Dictionary<PBXSourceTree, Dictionary<string, PBXFileReferenceData>> m_RealPathToFileRefMap = null;
private Dictionary<string, PBXGroupData> m_ProjectPathToGroupMap = null;
private Dictionary<string, string> m_GroupGuidToProjectPathMap = null;
private Dictionary<string, PBXGroupData> m_GuidToParentGroupMap = null;
public PBXBuildFileData BuildFilesGet(string guid)
{
return buildFiles[guid];
}
// targetGuid is the guid of the target that contains the section that contains the buildFile
public void BuildFilesAdd(string targetGuid, PBXBuildFileData buildFile)
{
if (!m_FileGuidToBuildFileMap.ContainsKey(targetGuid))
m_FileGuidToBuildFileMap[targetGuid] = new Dictionary<string, PBXBuildFileData>();
m_FileGuidToBuildFileMap[targetGuid][buildFile.fileRef] = buildFile;
buildFiles.AddEntry(buildFile);
}
public void BuildFilesRemove(string targetGuid, string fileGuid)
{
var buildFile = BuildFilesGetForSourceFile(targetGuid, fileGuid);
if (buildFile != null)
{
m_FileGuidToBuildFileMap[targetGuid].Remove(buildFile.fileRef);
buildFiles.RemoveEntry(buildFile.guid);
}
}
public PBXBuildFileData BuildFilesGetForSourceFile(string targetGuid, string fileGuid)
{
if (!m_FileGuidToBuildFileMap.ContainsKey(targetGuid))
return null;
if (!m_FileGuidToBuildFileMap[targetGuid].ContainsKey(fileGuid))
return null;
return m_FileGuidToBuildFileMap[targetGuid][fileGuid];
}
public IEnumerable<PBXBuildFileData> BuildFilesGetAll()
{
return buildFiles.GetObjects();
}
public void FileRefsAdd(string realPath, string projectPath, PBXGroupData parent, PBXFileReferenceData fileRef)
{
fileRefs.AddEntry(fileRef);
m_ProjectPathToFileRefMap.Add(projectPath, fileRef);
m_FileRefGuidToProjectPathMap.Add(fileRef.guid, projectPath);
//m_RealPathToFileRefMap[fileRef.tree].Add(realPath, fileRef); // FIXME
if (m_RealPathToFileRefMap.ContainsKey (fileRef.tree))
m_RealPathToFileRefMap [fileRef.tree].Add (realPath, fileRef); // FIXME
m_GuidToParentGroupMap.Add(fileRef.guid, parent);
}
public IEnumerable<PBXFileReferenceData> FileRefsGetAll ()
{
return fileRefs.GetObjects();
}
public PBXFileReferenceData FileRefsGet(string guid)
{
return fileRefs[guid];
}
public PBXFileReferenceData FileRefsGetByRealPath(string path, PBXSourceTree sourceTree)
{
if (m_RealPathToFileRefMap[sourceTree].ContainsKey(path))
return m_RealPathToFileRefMap[sourceTree][path];
return null;
}
public PBXFileReferenceData FileRefsGetByProjectPath(string path)
{
if (m_ProjectPathToFileRefMap.ContainsKey(path))
return m_ProjectPathToFileRefMap[path];
return null;
}
public void FileRefsRemove(string guid)
{
PBXFileReferenceData fileRef = fileRefs[guid];
fileRefs.RemoveEntry(guid);
m_ProjectPathToFileRefMap.Remove(m_FileRefGuidToProjectPathMap[guid]);
m_FileRefGuidToProjectPathMap.Remove(guid);
foreach (var tree in FileTypeUtils.AllAbsoluteSourceTrees())
m_RealPathToFileRefMap[tree].Remove(fileRef.path);
m_GuidToParentGroupMap.Remove(guid);
}
public PBXGroupData GroupsGet(string guid)
{
return groups[guid];
}
public PBXGroupData GroupsGetByChild(string childGuid)
{
return m_GuidToParentGroupMap[childGuid];
}
public PBXGroupData GroupsGetMainGroup()
{
return groups[project.project.mainGroup];
}
/// Returns the source group identified by sourceGroup. If sourceGroup is empty or null,
/// root group is returned. If no group is found, null is returned.
public PBXGroupData GroupsGetByProjectPath(string sourceGroup)
{
if (m_ProjectPathToGroupMap.ContainsKey(sourceGroup))
return m_ProjectPathToGroupMap[sourceGroup];
return null;
}
public void GroupsAdd(string projectPath, PBXGroupData parent, PBXGroupData gr)
{
m_ProjectPathToGroupMap.Add(projectPath, gr);
m_GroupGuidToProjectPathMap.Add(gr.guid, projectPath);
m_GuidToParentGroupMap.Add(gr.guid, parent);
groups.AddEntry(gr);
}
public void GroupsAddDuplicate(PBXGroupData gr)
{
groups.AddEntry(gr);
}
public void GroupsRemove(string guid)
{
m_ProjectPathToGroupMap.Remove(m_GroupGuidToProjectPathMap[guid]);
m_GroupGuidToProjectPathMap.Remove(guid);
m_GuidToParentGroupMap.Remove(guid);
groups.RemoveEntry(guid);
}
public FileGUIDListBase BuildSectionAny(PBXNativeTargetData target, string path, bool isFolderRef)
{
string ext = Path.GetExtension(path);
var phase = FileTypeUtils.GetFileType(ext, isFolderRef);
switch (phase) {
case PBXFileType.Framework:
foreach (var guid in target.phases)
if (frameworks.HasEntry(guid))
return frameworks[guid];
break;
case PBXFileType.Resource:
foreach (var guid in target.phases)
if (resources.HasEntry(guid))
return resources[guid];
break;
case PBXFileType.Source:
foreach (var guid in target.phases)
if (sources.HasEntry(guid))
return sources[guid];
break;
case PBXFileType.CopyFile:
foreach (var guid in target.phases)
if (copyFiles.HasEntry(guid))
return copyFiles[guid];
break;
}
return null;
}
public FileGUIDListBase BuildSectionAny(string sectionGuid)
{
if (frameworks.HasEntry(sectionGuid))
return frameworks[sectionGuid];
if (resources.HasEntry(sectionGuid))
return resources[sectionGuid];
if (sources.HasEntry(sectionGuid))
return sources[sectionGuid];
if (copyFiles.HasEntry(sectionGuid))
return copyFiles[sectionGuid];
throw new Exception(String.Format("The given GUID {0} does not refer to a known build section", sectionGuid));
}
void RefreshBuildFilesMapForBuildFileGuidList(Dictionary<string, PBXBuildFileData> mapForTarget,
FileGUIDListBase list)
{
foreach (string guid in list.files)
{
var buildFile = buildFiles[guid];
mapForTarget[buildFile.fileRef] = buildFile;
}
}
void RefreshMapsForGroupChildren(string projectPath, string realPath, PBXSourceTree realPathTree, PBXGroupData parent)
{
var children = new List<string>(parent.children);
foreach (string guid in children)
{
PBXFileReferenceData fileRef = fileRefs[guid];
string pPath;
string rPath;
PBXSourceTree rTree;
if (fileRef != null)
{
pPath = PBXPath.Combine(projectPath, fileRef.name);
PBXPath.Combine(realPath, realPathTree, fileRef.path, fileRef.tree, out rPath, out rTree);
if (!m_ProjectPathToFileRefMap.ContainsKey(pPath))
{
m_ProjectPathToFileRefMap.Add(pPath, fileRef);
}
if (!m_FileRefGuidToProjectPathMap.ContainsKey(fileRef.guid))
{
m_FileRefGuidToProjectPathMap.Add(fileRef.guid, pPath);
}
if (!m_RealPathToFileRefMap[rTree].ContainsKey(rPath))
{
m_RealPathToFileRefMap[rTree].Add(rPath, fileRef);
}
if (!m_GuidToParentGroupMap.ContainsKey(guid))
{
m_GuidToParentGroupMap.Add(guid, parent);
}
continue;
}
PBXGroupData gr = groups[guid];
if (gr != null)
{
pPath = PBXPath.Combine(projectPath, gr.name);
PBXPath.Combine(realPath, realPathTree, gr.path, gr.tree, out rPath, out rTree);
if (!m_ProjectPathToGroupMap.ContainsKey(pPath))
{
m_ProjectPathToGroupMap.Add(pPath, gr);
}
if (!m_GroupGuidToProjectPathMap.ContainsKey(gr.guid))
{
m_GroupGuidToProjectPathMap.Add(gr.guid, pPath);
}
if (!m_GuidToParentGroupMap.ContainsKey(guid))
{
m_GuidToParentGroupMap.Add(guid, parent);
}
RefreshMapsForGroupChildren(pPath, rPath, rTree, gr);
}
}
}
void RefreshAuxMaps()
{
foreach (var targetEntry in nativeTargets.GetEntries())
{
var map = new Dictionary<string, PBXBuildFileData>();
foreach (string phaseGuid in targetEntry.Value.phases)
{
if (frameworks.HasEntry(phaseGuid))
RefreshBuildFilesMapForBuildFileGuidList(map, frameworks[phaseGuid]);
if (resources.HasEntry(phaseGuid))
RefreshBuildFilesMapForBuildFileGuidList(map, resources[phaseGuid]);
if (sources.HasEntry(phaseGuid))
RefreshBuildFilesMapForBuildFileGuidList(map, sources[phaseGuid]);
if (copyFiles.HasEntry(phaseGuid))
RefreshBuildFilesMapForBuildFileGuidList(map, copyFiles[phaseGuid]);
}
m_FileGuidToBuildFileMap[targetEntry.Key] = map;
}
RefreshMapsForGroupChildren("", "", PBXSourceTree.Source, GroupsGetMainGroup());
}
public void Clear()
{
buildFiles = new PBXBuildFileSection("PBXBuildFile");
fileRefs = new PBXFileReferenceSection("PBXFileReference");
groups = new PBXGroupSection("PBXGroup");
containerItems = new PBXContainerItemProxySection("PBXContainerItemProxy");
references = new PBXReferenceProxySection("PBXReferenceProxy");
sources = new PBXSourcesBuildPhaseSection("PBXSourcesBuildPhase");
frameworks = new PBXFrameworksBuildPhaseSection("PBXFrameworksBuildPhase");
resources = new PBXResourcesBuildPhaseSection("PBXResourcesBuildPhase");
copyFiles = new PBXCopyFilesBuildPhaseSection("PBXCopyFilesBuildPhase");
shellScripts = new PBXShellScriptBuildPhaseSection("PBXShellScriptBuildPhase");
nativeTargets = new PBXNativeTargetSection("PBXNativeTarget");
targetDependencies = new PBXTargetDependencySection("PBXTargetDependency");
variantGroups = new PBXVariantGroupSection("PBXVariantGroup");
buildConfigs = new XCBuildConfigurationSection("XCBuildConfiguration");
buildConfigLists = new XCConfigurationListSection("XCConfigurationList");
project = new PBXProjectSection();
m_UnknownSections = new Dictionary<string, UnknownSection>();
m_Section = new Dictionary<string, SectionBase>
{
{ "PBXBuildFile", buildFiles },
{ "PBXFileReference", fileRefs },
{ "PBXGroup", groups },
{ "PBXContainerItemProxy", containerItems },
{ "PBXReferenceProxy", references },
{ "PBXSourcesBuildPhase", sources },
{ "PBXFrameworksBuildPhase", frameworks },
{ "PBXResourcesBuildPhase", resources },
{ "PBXCopyFilesBuildPhase", copyFiles },
{ "PBXShellScriptBuildPhase", shellScripts },
{ "PBXNativeTarget", nativeTargets },
{ "PBXTargetDependency", targetDependencies },
{ "PBXVariantGroup", variantGroups },
{ "XCBuildConfiguration", buildConfigs },
{ "XCConfigurationList", buildConfigLists },
{ "PBXProject", project },
};
m_RootElements = new PBXElementDict();
m_UnknownObjects = new PBXElementDict();
m_ObjectVersion = null;
m_SectionOrder = new List<string>{
"PBXBuildFile", "PBXContainerItemProxy", "PBXCopyFilesBuildPhase", "PBXFileReference",
"PBXFrameworksBuildPhase", "PBXGroup", "PBXNativeTarget", "PBXProject", "PBXReferenceProxy",
"PBXResourcesBuildPhase", "PBXShellScriptBuildPhase", "PBXSourcesBuildPhase", "PBXTargetDependency",
"PBXVariantGroup", "XCBuildConfiguration", "XCConfigurationList"
};
m_FileGuidToBuildFileMap = new Dictionary<string, Dictionary<string, PBXBuildFileData>>();
m_ProjectPathToFileRefMap = new Dictionary<string, PBXFileReferenceData>();
m_FileRefGuidToProjectPathMap = new Dictionary<string, string>();
m_RealPathToFileRefMap = new Dictionary<PBXSourceTree, Dictionary<string, PBXFileReferenceData>>();
foreach (var tree in FileTypeUtils.AllAbsoluteSourceTrees())
m_RealPathToFileRefMap.Add(tree, new Dictionary<string, PBXFileReferenceData>());
m_ProjectPathToGroupMap = new Dictionary<string, PBXGroupData>();
m_GroupGuidToProjectPathMap = new Dictionary<string, string>();
m_GuidToParentGroupMap = new Dictionary<string, PBXGroupData>();
}
private void BuildCommentMapForBuildFiles(GUIDToCommentMap comments, List<string> guids, string sectName)
{
foreach (var guid in guids)
{
var buildFile = BuildFilesGet(guid);
if (buildFile != null)
{
var fileRef = FileRefsGet(buildFile.fileRef);
if (fileRef != null)
comments.Add(guid, String.Format("{0} in {1}", fileRef.name, sectName));
else
{
var reference = references[buildFile.fileRef];
if (reference != null)
comments.Add(guid, String.Format("{0} in {1}", reference.path, sectName));
}
}
}
}
private GUIDToCommentMap BuildCommentMap()
{
GUIDToCommentMap comments = new GUIDToCommentMap();
// buildFiles are handled below
// filerefs are handled below
foreach (var e in groups.GetObjects())
comments.Add(e.guid, e.name);
foreach (var e in containerItems.GetObjects())
comments.Add(e.guid, "PBXContainerItemProxy");
foreach (var e in references.GetObjects())
comments.Add(e.guid, e.path);
foreach (var e in sources.GetObjects())
{
comments.Add(e.guid, "Sources");
BuildCommentMapForBuildFiles(comments, e.files, "Sources");
}
foreach (var e in resources.GetObjects())
{
comments.Add(e.guid, "Resources");
BuildCommentMapForBuildFiles(comments, e.files, "Resources");
}
foreach (var e in frameworks.GetObjects())
{
comments.Add(e.guid, "Frameworks");
BuildCommentMapForBuildFiles(comments, e.files, "Frameworks");
}
foreach (var e in copyFiles.GetObjects())
{
string sectName = e.name;
if (sectName == null)
sectName = "CopyFiles";
comments.Add(e.guid, sectName);
BuildCommentMapForBuildFiles(comments, e.files, sectName);
}
foreach (var e in shellScripts.GetObjects())
comments.Add(e.guid, "ShellScript");
foreach (var e in targetDependencies.GetObjects())
comments.Add(e.guid, "PBXTargetDependency");
foreach (var e in nativeTargets.GetObjects())
{
comments.Add(e.guid, e.name);
comments.Add(e.buildConfigList, String.Format("Build configuration list for PBXNativeTarget \"{0}\"", e.name));
}
foreach (var e in variantGroups.GetObjects())
comments.Add(e.guid, e.name);
foreach (var e in buildConfigs.GetObjects())
comments.Add(e.guid, e.name);
foreach (var e in project.GetObjects())
{
comments.Add(e.guid, "Project object");
comments.Add(e.buildConfigList, "Build configuration list for PBXProject \"Unity-iPhone\""); // FIXME: project name is hardcoded
}
foreach (var e in fileRefs.GetObjects())
comments.Add(e.guid, e.name);
if (m_RootElements.Contains("rootObject") && m_RootElements["rootObject"] is PBXElementString)
comments.Add(m_RootElements["rootObject"].AsString(), "Project object");
return comments;
}
private static PBXElementDict ParseContent(string content)
{
TokenList tokens = Lexer.Tokenize(content);
var parser = new Parser(tokens);
TreeAST ast = parser.ParseTree();
return Serializer.ParseTreeAST(ast, tokens, content);
}
public void ReadFromStream(TextReader sr)
{
Clear();
m_RootElements = ParseContent(sr.ReadToEnd());
if (!m_RootElements.Contains("objects"))
throw new Exception("Invalid PBX project file: no objects element");
var objects = m_RootElements["objects"].AsDict();
m_RootElements.Remove("objects");
m_RootElements.SetString("objects", "OBJMARKER");
if (m_RootElements.Contains("objectVersion"))
{
m_ObjectVersion = m_RootElements["objectVersion"].AsString();
m_RootElements.Remove("objectVersion");
}
var allGuids = new List<string>();
string prevSectionName = null;
foreach (var kv in objects.values)
{
allGuids.Add(kv.Key);
var el = kv.Value;
if (!(el is PBXElementDict) || !el.AsDict().Contains("isa"))
{
m_UnknownObjects.values.Add(kv.Key, el);
continue;
}
var dict = el.AsDict();
var sectionName = dict["isa"].AsString();
if (m_Section.ContainsKey(sectionName))
{
var section = m_Section[sectionName];
section.AddObject(kv.Key, dict);
}
else
{
UnknownSection section;
if (m_UnknownSections.ContainsKey(sectionName))
section = m_UnknownSections[sectionName];
else
{
section = new UnknownSection(sectionName);
m_UnknownSections.Add(sectionName, section);
}
section.AddObject(kv.Key, dict);
// update section order
if (!m_SectionOrder.Contains(sectionName))
{
int pos = 0;
if (prevSectionName != null)
{
// this never fails, because we already added any previous unknown sections
// to m_SectionOrder
pos = m_SectionOrder.FindIndex(x => x == prevSectionName);
pos += 1;
}
m_SectionOrder.Insert(pos, sectionName);
}
}
prevSectionName = sectionName;
}
RepairStructure(allGuids);
RefreshAuxMaps();
}
public string WriteToString()
{
var commentMap = BuildCommentMap();
var emptyChecker = new PropertyCommentChecker();
var emptyCommentMap = new GUIDToCommentMap();
// since we need to add custom comments, the serialization is much more complex
StringBuilder objectsSb = new StringBuilder();
if (m_ObjectVersion != null) // objectVersion comes right before objects
objectsSb.AppendFormat("objectVersion = {0};\n\t", m_ObjectVersion);
objectsSb.Append("objects = {");
foreach (string sectionName in m_SectionOrder)
{
if (m_Section.ContainsKey(sectionName))
m_Section[sectionName].WriteSection(objectsSb, commentMap);
else if (m_UnknownSections.ContainsKey(sectionName))
m_UnknownSections[sectionName].WriteSection(objectsSb, commentMap);
}
foreach (var kv in m_UnknownObjects.values)
Serializer.WriteDictKeyValue(objectsSb, kv.Key, kv.Value, 2, false, emptyChecker, emptyCommentMap);
objectsSb.Append("\n\t};");
StringBuilder contentSb = new StringBuilder();
contentSb.Append("// !$*UTF8*$!\n");
Serializer.WriteDict(contentSb, m_RootElements, 0, false,
new PropertyCommentChecker(new string[]{"rootObject/*"}), commentMap);
contentSb.Append("\n");
string content = contentSb.ToString();
content = content.Replace("objects = OBJMARKER;", objectsSb.ToString());
return content;
}
// This method walks the project structure and removes invalid entries.
void RepairStructure(List<string> allGuids)
{
var guidSet = new Dictionary<string, bool>(); // emulate HashSet on .Net 2.0
foreach (var guid in allGuids)
guidSet.Add(guid, false);
while (RepairStructureImpl(guidSet) == true)
;
}
/* Iterates the given guid list and removes all guids that are not in allGuids dictionary.
*/
static void RemoveMissingGuidsFromGuidList(PBX.GUIDList guidList, Dictionary<string, bool> allGuids)
{
List<string> guidsToRemove = null;
foreach (var guid in guidList)
{
if (!allGuids.ContainsKey(guid))
{
if (guidsToRemove == null)
guidsToRemove = new List<string>();
guidsToRemove.Add(guid);
}
}
if (guidsToRemove != null)
{
foreach (var guid in guidsToRemove)
guidList.RemoveGUID(guid);
}
}
/* Removes objects from the given @a section for which @a checker returns true.
Also removes the guids of the removed elements from allGuids dictionary.
Returns true if any objects were removed.
*/
static bool RemoveObjectsFromSection<T>(KnownSectionBase<T> section,
Dictionary<string, bool> allGuids,
Func<T, bool> checker) where T : PBXObjectData, new()
{
List<string> guidsToRemove = null;
foreach (var kv in section.GetEntries())
{
if (checker(kv.Value))
{
if (guidsToRemove == null)
guidsToRemove = new List<string>();
guidsToRemove.Add(kv.Key);
}
}
if (guidsToRemove != null)
{
foreach (var guid in guidsToRemove)
{
section.RemoveEntry(guid);
allGuids.Remove(guid);
}
return true;
}
return false;
}
// Returns true if changes were done and one should call RepairStructureImpl again
bool RepairStructureImpl(Dictionary<string, bool> allGuids)
{
bool changed = false;
// PBXBuildFile
changed |= RemoveObjectsFromSection(buildFiles, allGuids,
o => (o.fileRef == null || !allGuids.ContainsKey(o.fileRef)));
// PBXFileReference / fileRefs not cleaned
// PBXGroup
changed |= RemoveObjectsFromSection(groups, allGuids, o => o.children == null);
foreach (var o in groups.GetObjects())
RemoveMissingGuidsFromGuidList(o.children, allGuids);
// PBXContainerItem / containerItems not cleaned
// PBXReferenceProxy / references not cleaned
// PBXSourcesBuildPhase
changed |= RemoveObjectsFromSection(sources, allGuids, o => o.files == null);
foreach (var o in sources.GetObjects())
RemoveMissingGuidsFromGuidList(o.files, allGuids);
// PBXFrameworksBuildPhase
changed |= RemoveObjectsFromSection(frameworks, allGuids, o => o.files == null);
foreach (var o in frameworks.GetObjects())
RemoveMissingGuidsFromGuidList(o.files, allGuids);
// PBXResourcesBuildPhase
changed |= RemoveObjectsFromSection(resources, allGuids, o => o.files == null);
foreach (var o in resources.GetObjects())
RemoveMissingGuidsFromGuidList(o.files, allGuids);
// PBXCopyFilesBuildPhase
changed |= RemoveObjectsFromSection(copyFiles, allGuids, o => o.files == null);
foreach (var o in copyFiles.GetObjects())
RemoveMissingGuidsFromGuidList(o.files, allGuids);
// PBXShellScriptsBuildPhase
changed |= RemoveObjectsFromSection(shellScripts, allGuids, o => o.files == null);
foreach (var o in shellScripts.GetObjects())
RemoveMissingGuidsFromGuidList(o.files, allGuids);
// PBXNativeTarget
changed |= RemoveObjectsFromSection(nativeTargets, allGuids, o => o.phases == null);
foreach (var o in nativeTargets.GetObjects())
RemoveMissingGuidsFromGuidList(o.phases, allGuids);
// PBXTargetDependency / targetDependencies not cleaned
// PBXVariantGroup
changed |= RemoveObjectsFromSection(variantGroups, allGuids, o => o.children == null);
foreach (var o in variantGroups.GetObjects())
RemoveMissingGuidsFromGuidList(o.children, allGuids);
// XCBuildConfiguration / buildConfigs not cleaned
// XCConfigurationList
changed |= RemoveObjectsFromSection(buildConfigLists, allGuids, o => o.buildConfigs == null);
foreach (var o in buildConfigLists.GetObjects())
RemoveMissingGuidsFromGuidList(o.buildConfigs, allGuids);
// PBXProject project not cleaned
return changed;
}
public PBXGroupData GroupsGetByName (string name)
{
foreach (var group in groups.GetEntries())
if (group.Value.name == name)
return group.Value;
return null;
}
}
} // namespace UnityEditor.iOS.Xcode

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 54c86bc46b87645c78e5b211a0eeada5
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,296 +0,0 @@
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System;
using ChillyRoom.UnityEditor.iOS.Xcode.PBX;
namespace ChillyRoom.UnityEditor.iOS.Xcode.Extensions
{
/* This class implements a number of static methods for performing common tasks
on xcode projects.
TODO: Make sure enough stuff is exposed so that it's possible to perform the tasks
without using internal APIs
*/
public static class PBXProjectExtensions
{
// Create a wrapper class so that collection initializers work and we can have a
// compact notation. Note that we can't use Dictionary because the keys may be duplicate
internal class FlagList : List<KeyValuePair<string, string>>
{
public void Add(string flag, string value)
{
Add(new KeyValuePair<string, string>(flag, value));
}
}
internal static FlagList appExtensionReleaseBuildFlags = new FlagList
{
// { "INFOPLIST_FILE", <path/to/info.plist> },
{ "LD_RUNPATH_SEARCH_PATHS", "$(inherited)" },
{ "LD_RUNPATH_SEARCH_PATHS", "@executable_path/Frameworks" },
{ "LD_RUNPATH_SEARCH_PATHS", "@executable_path/../../Frameworks" },
// { "PRODUCT_BUNDLE_IDENTIFIER", "<bundle id>" },
{ "PRODUCT_NAME", "$(TARGET_NAME)" },
{ "SKIP_INSTALL", "YES" },
};
internal static FlagList appExtensionDebugBuildFlags = new FlagList
{
// { "INFOPLIST_FILE", <path/to/info.plist> },
{ "LD_RUNPATH_SEARCH_PATHS", "$(inherited)" },
{ "LD_RUNPATH_SEARCH_PATHS", "@executable_path/Frameworks" },
{ "LD_RUNPATH_SEARCH_PATHS", "@executable_path/../../Frameworks" },
// { "PRODUCT_BUNDLE_IDENTIFIER", "<bundle id>" },
{ "PRODUCT_NAME", "$(TARGET_NAME)" },
{ "SKIP_INSTALL", "YES" },
};
internal static FlagList watchExtensionReleaseBuildFlags = new FlagList
{
{ "ASSETCATALOG_COMPILER_COMPLICATION_NAME", "Complication" },
{ "CLANG_ANALYZER_NONNULL", "YES" },
{ "CLANG_WARN_DOCUMENTATION_COMMENTS", "YES" },
{ "CLANG_WARN_INFINITE_RECURSION", "YES" },
{ "CLANG_WARN_SUSPICIOUS_MOVE", "YES" },
{ "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym" },
{ "GCC_NO_COMMON_BLOCKS", "YES" },
//{ "INFOPLIST_FILE", "<path/to/Info.plist>" },
{ "LD_RUNPATH_SEARCH_PATHS", "$(inherited)" },
{ "LD_RUNPATH_SEARCH_PATHS", "@executable_path/Frameworks" },
{ "LD_RUNPATH_SEARCH_PATHS", "@executable_path/../../Frameworks" },
// { "PRODUCT_BUNDLE_IDENTIFIER", "<bundle id>" },
{ "PRODUCT_NAME", "${TARGET_NAME}" },
{ "SDKROOT", "watchos" },
{ "SKIP_INSTALL", "YES" },
{ "TARGETED_DEVICE_FAMILY", "4" },
{ "WATCHOS_DEPLOYMENT_TARGET", "3.1" },
// the following are needed to override project settings in Unity Xcode project
{ "ARCHS", "$(ARCHS_STANDARD)" },
{ "SUPPORTED_PLATFORMS", "watchos" },
{ "SUPPORTED_PLATFORMS", "watchsimulator" },
};
internal static FlagList watchExtensionDebugBuildFlags = new FlagList
{
{ "ASSETCATALOG_COMPILER_COMPLICATION_NAME", "Complication" },
{ "CLANG_ANALYZER_NONNULL", "YES" },
{ "CLANG_WARN_DOCUMENTATION_COMMENTS", "YES" },
{ "CLANG_WARN_INFINITE_RECURSION", "YES" },
{ "CLANG_WARN_SUSPICIOUS_MOVE", "YES" },
{ "DEBUG_INFORMATION_FORMAT", "dwarf" },
{ "ENABLE_TESTABILITY", "YES" },
{ "GCC_NO_COMMON_BLOCKS", "YES" },
// { "INFOPLIST_FILE", "<path/to/Info.plist>" },
{ "LD_RUNPATH_SEARCH_PATHS", "$(inherited)" },
{ "LD_RUNPATH_SEARCH_PATHS", "@executable_path/Frameworks" },
{ "LD_RUNPATH_SEARCH_PATHS", "@executable_path/../../Frameworks" },
// { "PRODUCT_BUNDLE_IDENTIFIER", "<bundle id>" },
{ "PRODUCT_NAME", "${TARGET_NAME}" },
{ "SDKROOT", "watchos" },
{ "SKIP_INSTALL", "YES" },
{ "TARGETED_DEVICE_FAMILY", "4" },
{ "WATCHOS_DEPLOYMENT_TARGET", "3.1" },
// the following are needed to override project settings in Unity Xcode project
{ "ARCHS", "$(ARCHS_STANDARD)" },
{ "SUPPORTED_PLATFORMS", "watchos" },
{ "SUPPORTED_PLATFORMS", "watchsimulator" },
};
internal static FlagList watchAppReleaseBuildFlags = new FlagList
{
{ "ASSETCATALOG_COMPILER_APPICON_NAME", "AppIcon" },
{ "CLANG_ANALYZER_NONNULL", "YES" },
{ "CLANG_WARN_DOCUMENTATION_COMMENTS", "YES" },
{ "CLANG_WARN_INFINITE_RECURSION", "YES" },
{ "CLANG_WARN_SUSPICIOUS_MOVE", "YES" },
{ "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym" },
{ "GCC_NO_COMMON_BLOCKS", "YES" },
//{ "IBSC_MODULE", "the extension target name with ' ' replaced with '_'" },
//{ "INFOPLIST_FILE", "<path/to/Info.plist>" },
//{ "PRODUCT_BUNDLE_IDENTIFIER", "<bundle id>" },
{ "PRODUCT_NAME", "$(TARGET_NAME)" },
{ "SDKROOT", "watchos" },
{ "SKIP_INSTALL", "YES" },
{ "TARGETED_DEVICE_FAMILY", "4" },
{ "WATCHOS_DEPLOYMENT_TARGET", "3.1" },
// the following are needed to override project settings in Unity Xcode project
{ "ARCHS", "$(ARCHS_STANDARD)" },
{ "SUPPORTED_PLATFORMS", "watchos" },
{ "SUPPORTED_PLATFORMS", "watchsimulator" },
};
internal static FlagList watchAppDebugBuildFlags = new FlagList
{
{ "ASSETCATALOG_COMPILER_APPICON_NAME", "AppIcon" },
{ "CLANG_ANALYZER_NONNULL", "YES" },
{ "CLANG_WARN_DOCUMENTATION_COMMENTS", "YES" },
{ "CLANG_WARN_INFINITE_RECURSION", "YES" },
{ "CLANG_WARN_SUSPICIOUS_MOVE", "YES" },
{ "DEBUG_INFORMATION_FORMAT", "dwarf" },
{ "ENABLE_TESTABILITY", "YES" },
{ "GCC_NO_COMMON_BLOCKS", "YES" },
//{ "IBSC_MODULE", "the extension target name with ' ' replaced with '_'" },
//{ "INFOPLIST_FILE", "<path/to/Info.plist>" },
//{ "PRODUCT_BUNDLE_IDENTIFIER", "<bundle id>" },
{ "PRODUCT_NAME", "$(TARGET_NAME)" },
{ "SDKROOT", "watchos" },
{ "SKIP_INSTALL", "YES" },
{ "TARGETED_DEVICE_FAMILY", "4" },
{ "WATCHOS_DEPLOYMENT_TARGET", "3.1" },
// the following are needed to override project settings in Unity Xcode project
{ "ARCHS", "$(ARCHS_STANDARD)" },
{ "SUPPORTED_PLATFORMS", "watchos" },
{ "SUPPORTED_PLATFORMS", "watchsimulator" },
};
static void SetBuildFlagsFromDict(this PBXProject proj, string configGuid, IEnumerable<KeyValuePair<string, string>> data)
{
foreach (var kv in data)
proj.AddBuildPropertyForConfig(configGuid, kv.Key, kv.Value);
}
internal static void SetDefaultAppExtensionReleaseBuildFlags(this PBXProject proj, string configGuid)
{
SetBuildFlagsFromDict(proj, configGuid, appExtensionReleaseBuildFlags);
}
internal static void SetDefaultAppExtensionDebugBuildFlags(this PBXProject proj, string configGuid)
{
SetBuildFlagsFromDict(proj, configGuid, appExtensionDebugBuildFlags);
}
internal static void SetDefaultWatchExtensionReleaseBuildFlags(this PBXProject proj, string configGuid)
{
SetBuildFlagsFromDict(proj, configGuid, watchExtensionReleaseBuildFlags);
}
internal static void SetDefaultWatchExtensionDebugBuildFlags(this PBXProject proj, string configGuid)
{
SetBuildFlagsFromDict(proj, configGuid, watchExtensionDebugBuildFlags);
}
internal static void SetDefaultWatchAppReleaseBuildFlags(this PBXProject proj, string configGuid)
{
SetBuildFlagsFromDict(proj, configGuid, watchAppReleaseBuildFlags);
}
internal static void SetDefaultWatchAppDebugBuildFlags(this PBXProject proj, string configGuid)
{
SetBuildFlagsFromDict(proj, configGuid, watchAppDebugBuildFlags);
}
/// <summary>
/// Creates an app extension.
/// </summary>
/// <returns>The GUID of the new target.</returns>
/// <param name="proj">A project passed as this argument.</param>
/// <param name="mainTargetGuid">The GUID of the main target to link the app to.</param>
/// <param name="name">The name of the app extension.</param>
/// <param name="bundleId">The bundle ID of the app extension. The bundle ID must be
/// prefixed with the parent app bundle ID.</param>
/// <param name="infoPlistPath">Path to the app extension Info.plist document.</param>
public static string AddAppExtension(this PBXProject proj, string mainTargetGuid,
string name, string bundleId, string infoPlistPath)
{
string ext = ".appex";
var newTargetGuid = proj.AddTarget(name, ext, "com.apple.product-type.app-extension");
foreach (var configName in proj.BuildConfigNames())
{
var configGuid = proj.BuildConfigByName(newTargetGuid, configName);
if (configName.Contains("Debug"))
SetDefaultAppExtensionDebugBuildFlags(proj, configGuid);
else
SetDefaultAppExtensionReleaseBuildFlags(proj, configGuid);
proj.SetBuildPropertyForConfig(configGuid, "INFOPLIST_FILE", infoPlistPath);
proj.SetBuildPropertyForConfig(configGuid, "PRODUCT_BUNDLE_IDENTIFIER", bundleId);
}
proj.AddSourcesBuildPhase(newTargetGuid);
proj.AddResourcesBuildPhase(newTargetGuid);
proj.AddFrameworksBuildPhase(newTargetGuid);
string copyFilesPhaseGuid = proj.AddCopyFilesBuildPhase(mainTargetGuid, "Embed App Extensions", "", "13");
proj.AddFileToBuildSection(mainTargetGuid, copyFilesPhaseGuid, proj.GetTargetProductFileRef(newTargetGuid));
proj.AddTargetDependency(mainTargetGuid, newTargetGuid);
return newTargetGuid;
}
/// <summary>
/// Creates a watch application.
/// </summary>
/// <returns>The GUID of the new target.</returns>
/// <param name="proj">A project passed as this argument.</param>
/// <param name="mainTargetGuid">The GUID of the main target to link the watch app to.</param>
/// <param name="watchExtensionTargetGuid">The GUID of watch extension as returned by [[AddWatchExtension()]].</param>
/// <param name="name">The name of the watch app. It must the same as the name of the watch extension.</param>
/// <param name="bundleId">The bundle ID of the watch app.</param>
/// <param name="infoPlistPath">Path to the watch app Info.plist document.</param>
public static string AddWatchApp(this PBXProject proj, string mainTargetGuid, string watchExtensionTargetGuid,
string name, string bundleId, string infoPlistPath)
{
var newTargetGuid = proj.AddTarget(name, ".app", "com.apple.product-type.application.watchapp2");
var isbcModuleName = proj.nativeTargets[watchExtensionTargetGuid].name.Replace(" ", "_");
foreach (var configName in proj.BuildConfigNames())
{
var configGuid = proj.BuildConfigByName(newTargetGuid, configName);
if (configName.Contains("Debug"))
SetDefaultWatchAppDebugBuildFlags(proj, configGuid);
else
SetDefaultWatchAppReleaseBuildFlags(proj, configGuid);
proj.SetBuildPropertyForConfig(configGuid, "PRODUCT_BUNDLE_IDENTIFIER", bundleId);
proj.SetBuildPropertyForConfig(configGuid, "INFOPLIST_FILE", infoPlistPath);
proj.SetBuildPropertyForConfig(configGuid, "IBSC_MODULE", isbcModuleName);
}
proj.AddResourcesBuildPhase(newTargetGuid);
string copyFilesGuid = proj.AddCopyFilesBuildPhase(newTargetGuid, "Embed App Extensions", "", "13");
proj.AddFileToBuildSection(newTargetGuid, copyFilesGuid, proj.GetTargetProductFileRef(watchExtensionTargetGuid));
string copyWatchFilesGuid = proj.AddCopyFilesBuildPhase(mainTargetGuid, "Embed Watch Content", "$(CONTENTS_FOLDER_PATH)/Watch", "16");
proj.AddFileToBuildSection(mainTargetGuid, copyWatchFilesGuid, proj.GetTargetProductFileRef(newTargetGuid));
proj.AddTargetDependency(newTargetGuid, watchExtensionTargetGuid);
proj.AddTargetDependency(mainTargetGuid, newTargetGuid);
return newTargetGuid;
}
/// <summary>
/// Creates a watch extension.
/// </summary>
/// <returns>The GUID of the new target.</returns>
/// <param name="proj">A project passed as this argument.</param>
/// <param name="mainTarget">The GUID of the main target to link the watch extension to.</param>
/// <param name="name">The name of the watch extension.</param>
/// <param name="bundleId">The bundle ID of the watch extension. The bundle ID must be
/// prefixed with the parent watch app bundle ID.</param>
/// <param name="infoPlistPath">Path to the watch extension Info.plist document.</param>
public static string AddWatchExtension(this PBXProject proj, string mainTarget,
string name, string bundleId, string infoPlistPath)
{
var newTargetGuid = proj.AddTarget(name, ".appex", "com.apple.product-type.watchkit2-extension");
foreach (var configName in proj.BuildConfigNames())
{
var configGuid = proj.BuildConfigByName(newTargetGuid, configName);
if (configName.Contains("Debug"))
SetDefaultWatchExtensionDebugBuildFlags(proj, configGuid);
else
SetDefaultWatchExtensionReleaseBuildFlags(proj, configGuid);
proj.SetBuildPropertyForConfig(configGuid, "PRODUCT_BUNDLE_IDENTIFIER", bundleId);
proj.SetBuildPropertyForConfig(configGuid, "INFOPLIST_FILE", infoPlistPath);
}
proj.AddSourcesBuildPhase(newTargetGuid);
proj.AddResourcesBuildPhase(newTargetGuid);
proj.AddFrameworksBuildPhase(newTargetGuid);
return newTargetGuid;
}
}
} // namespace UnityEditor.iOS.Xcode

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: b84f17869f54f4d7a952c9f63e5744d6
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,351 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
namespace ChillyRoom.UnityEditor.iOS.Xcode
{
public class PlistElement
{
protected PlistElement() {}
// convenience methods
public string AsString() { return ((PlistElementString)this).value; }
public int AsInteger() { return ((PlistElementInteger)this).value; }
public bool AsBoolean() { return ((PlistElementBoolean)this).value; }
public PlistElementArray AsArray() { return (PlistElementArray)this; }
public PlistElementDict AsDict() { return (PlistElementDict)this; }
public PlistElement this[string key]
{
get { return AsDict()[key]; }
set { AsDict()[key] = value; }
}
}
public class PlistElementString : PlistElement
{
public PlistElementString(string v) { value = v; }
public string value;
}
public class PlistElementInteger : PlistElement
{
public PlistElementInteger(int v) { value = v; }
public int value;
}
public class PlistElementBoolean : PlistElement
{
public PlistElementBoolean(bool v) { value = v; }
public bool value;
}
public class PlistElementDict : PlistElement
{
public PlistElementDict() : base() {}
private SortedDictionary<string, PlistElement> m_PrivateValue = new SortedDictionary<string, PlistElement>();
public IDictionary<string, PlistElement> values { get { return m_PrivateValue; }}
new public PlistElement this[string key]
{
get {
if (values.ContainsKey(key))
return values[key];
return null;
}
set { this.values[key] = value; }
}
// convenience methods
public void SetInteger(string key, int val)
{
values[key] = new PlistElementInteger(val);
}
public void SetString(string key, string val)
{
values[key] = new PlistElementString(val);
}
public void SetBoolean(string key, bool val)
{
values[key] = new PlistElementBoolean(val);
}
public PlistElementArray CreateArray(string key)
{
var v = new PlistElementArray();
values[key] = v;
return v;
}
public PlistElementDict CreateDict(string key)
{
var v = new PlistElementDict();
values[key] = v;
return v;
}
}
public class PlistElementArray : PlistElement
{
public PlistElementArray() : base() {}
public List<PlistElement> values = new List<PlistElement>();
// convenience methods
public void AddString(string val)
{
values.Add(new PlistElementString(val));
}
public void AddInteger(int val)
{
values.Add(new PlistElementInteger(val));
}
public void AddBoolean(bool val)
{
values.Add(new PlistElementBoolean(val));
}
public PlistElementArray AddArray()
{
var v = new PlistElementArray();
values.Add(v);
return v;
}
public PlistElementDict AddDict()
{
var v = new PlistElementDict();
values.Add(v);
return v;
}
}
public class PlistDocument
{
public PlistElementDict root;
public string version;
public PlistDocument()
{
root = new PlistElementDict();
version = "1.0";
}
// Parses a string that contains a XML file. No validation is done.
internal static XDocument ParseXmlNoDtd(string text)
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.XmlResolver = null; // prevent DTD download
XmlReader xmlReader = XmlReader.Create(new StringReader(text), settings);
return XDocument.Load(xmlReader);
}
// LINQ serializes XML DTD declaration with an explicit empty 'internal subset'
// (a pair of square brackets at the end of Doctype declaration).
// Even though this is valid XML, XCode does not like it, hence this workaround.
internal static string CleanDtdToString(XDocument doc)
{
// LINQ does not support changing the DTD of existing XDocument instances,
// so we create a dummy document for printing of the Doctype declaration.
// A single dummy element is added to force LINQ not to omit the declaration.
// Also, utf-8 encoding is forced since this is the encoding we use when writing to file in UpdateInfoPlist.
if (doc.DocumentType != null)
{
XDocument tmpDoc =
new XDocument(new XDeclaration("1.0", "utf-8", null),
new XDocumentType(doc.DocumentType.Name, doc.DocumentType.PublicId, doc.DocumentType.SystemId, null),
new XElement(doc.Root.Name));
return "" + tmpDoc.Declaration + "\n" + tmpDoc.DocumentType + "\n" + doc.Root;
}
else
{
XDocument tmpDoc = new XDocument(new XDeclaration("1.0", "utf-8", null), new XElement(doc.Root.Name));
return "" + tmpDoc.Declaration + Environment.NewLine + doc.Root;
}
}
private static string GetText(XElement xml)
{
return String.Join("", xml.Nodes().OfType<XText>().Select(x => x.Value).ToArray());
}
private static PlistElement ReadElement(XElement xml)
{
switch (xml.Name.LocalName)
{
case "dict":
{
List<XElement> children = xml.Elements().ToList();
var el = new PlistElementDict();
if (children.Count % 2 == 1)
throw new Exception("Malformed plist file");
for (int i = 0; i < children.Count - 1; i++)
{
if (children[i].Name != "key")
throw new Exception("Malformed plist file");
string key = GetText(children[i]).Trim();
var newChild = ReadElement(children[i+1]);
if (newChild != null)
{
i++;
el[key] = newChild;
}
}
return el;
}
case "array":
{
List<XElement> children = xml.Elements().ToList();
var el = new PlistElementArray();
foreach (var childXml in children)
{
var newChild = ReadElement(childXml);
if (newChild != null)
el.values.Add(newChild);
}
return el;
}
case "string":
return new PlistElementString(GetText(xml));
case "integer":
{
int r;
if (int.TryParse(GetText(xml), out r))
return new PlistElementInteger(r);
return null;
}
case "true":
return new PlistElementBoolean(true);
case "false":
return new PlistElementBoolean(false);
default:
return null;
}
}
public void Create()
{
const string doc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" +
"<plist version=\"1.0\">" +
"<dict>" +
"</dict>" +
"</plist>";
ReadFromString(doc);
}
public void ReadFromFile(string path)
{
ReadFromString(File.ReadAllText(path));
}
public void ReadFromStream(TextReader tr)
{
ReadFromString(tr.ReadToEnd());
}
public void ReadFromString(string text)
{
XDocument doc = ParseXmlNoDtd(text);
version = (string) doc.Root.Attribute("version");
XElement xml = doc.XPathSelectElement("plist/dict");
var dict = ReadElement(xml);
if (dict == null)
throw new Exception("Error parsing plist file");
root = dict as PlistElementDict;
if (root == null)
throw new Exception("Malformed plist file");
}
private static XElement WriteElement(PlistElement el)
{
if (el is PlistElementBoolean)
{
var realEl = el as PlistElementBoolean;
return new XElement(realEl.value ? "true" : "false");
}
if (el is PlistElementInteger)
{
var realEl = el as PlistElementInteger;
return new XElement("integer", realEl.value.ToString());
}
if (el is PlistElementString)
{
var realEl = el as PlistElementString;
return new XElement("string", realEl.value);
}
if (el is PlistElementDict)
{
var realEl = el as PlistElementDict;
var dictXml = new XElement("dict");
foreach (var kv in realEl.values)
{
var keyXml = new XElement("key", kv.Key);
var valueXml = WriteElement(kv.Value);
if (valueXml != null)
{
dictXml.Add(keyXml);
dictXml.Add(valueXml);
}
}
return dictXml;
}
if (el is PlistElementArray)
{
var realEl = el as PlistElementArray;
var arrayXml = new XElement("array");
foreach (var v in realEl.values)
{
var elXml = WriteElement(v);
if (elXml != null)
arrayXml.Add(elXml);
}
return arrayXml;
}
return null;
}
public void WriteToFile(string path)
{
System.Text.Encoding utf8WithoutBom = new System.Text.UTF8Encoding(false);
File.WriteAllText(path, WriteToString(), utf8WithoutBom);
}
public void WriteToStream(TextWriter tw)
{
tw.Write(WriteToString());
}
public string WriteToString()
{
var el = WriteElement(root);
var rootEl = new XElement("plist");
rootEl.Add(new XAttribute("version", version));
rootEl.Add(el);
var doc = new XDocument();
doc.Add(rootEl);
return CleanDtdToString(doc).Replace("\r\n", "\n");
}
}
} // namespace UnityEditor.iOS.XCode

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: c2ed9743fe9634c808ea1dc01c20e01e
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,578 +0,0 @@
using System;
using System.IO;
namespace ChillyRoom.UnityEditor.iOS.Xcode
{
// This class is here to help you add capabilities to your Xcode project.
// Because capabilities modify the PBXProject, the entitlements file and/or the Info.plist and not consistently,
// it can be tedious.
// Therefore this class open the PBXProject that is always modify by capabilities and open Entitlement and info.plist only when needed.
// For optimisation reasons, we write the file only in the close method.
// If you don't call it the file will not be written.
public class ProjectCapabilityManager
{
private readonly string m_BuildPath;
private readonly string m_TargetGuid;
private readonly string m_PBXProjectPath;
private readonly string m_EntitlementFilePath;
private PlistDocument m_Entitlements;
private PlistDocument m_InfoPlist;
protected internal PBXProject project;
// Create the manager with the required parameter to open files and set the properties in the write place.
public ProjectCapabilityManager(string pbxProjectPath, string entitlementFilePath, string targetName)
{
m_BuildPath = Directory.GetParent(Path.GetDirectoryName(pbxProjectPath)).FullName;
m_EntitlementFilePath = entitlementFilePath;
m_PBXProjectPath = pbxProjectPath;
project = new PBXProject();
project.ReadFromString(File.ReadAllText(m_PBXProjectPath));
m_TargetGuid = project.TargetGuidByName(targetName);
}
// Write the actual file to the disk.
// If you don't call this method nothing will change.
public void WriteToFile()
{
File.WriteAllText(m_PBXProjectPath, project.WriteToString());
if (m_Entitlements != null)
m_Entitlements.WriteToFile(PBXPath.Combine(m_BuildPath, m_EntitlementFilePath));
if (m_InfoPlist != null)
m_InfoPlist.WriteToFile(PBXPath.Combine(m_BuildPath, "Info.plist"));
}
// Add the iCloud capability with the desired options.
public void AddiCloud(bool keyValueStorage, bool iCloudDocument, string[] customContainers)
{
var ent = GetOrCreateEntitlementDoc();
var val = (ent.root[ICloudEntitlements.ContainerIdValue] = new PlistElementArray()) as PlistElementArray;
if (iCloudDocument)
{
val.values.Add(new PlistElementString(ICloudEntitlements.ContainerIdValue));
var ser = (ent.root[ICloudEntitlements.ServicesKey] = new PlistElementArray()) as PlistElementArray;
ser.values.Add(new PlistElementString(ICloudEntitlements.ServicesKitValue));
ser.values.Add(new PlistElementString(ICloudEntitlements.ServicesDocValue));
var ubiquity = (ent.root[ICloudEntitlements.UbiquityContainerIdKey] = new PlistElementArray()) as PlistElementArray;
ubiquity.values.Add(new PlistElementString(ICloudEntitlements.UbiquityContainerIdValue));
for (var i = 0; i < customContainers.Length; i++)
{
ser.values.Add(new PlistElementString(customContainers[i]));
}
}
if (keyValueStorage)
{
ent.root[ICloudEntitlements.KeyValueStoreKey] = new PlistElementString(ICloudEntitlements.KeyValueStoreValue);
}
project.AddCapability(m_TargetGuid, PBXCapabilityType.iCloud, m_EntitlementFilePath, iCloudDocument);
}
// Add Push (or remote) Notifications capability to your project
public void AddPushNotifications(bool development)
{
GetOrCreateEntitlementDoc().root[PushNotificationEntitlements.Key] = new PlistElementString(development ? PushNotificationEntitlements.DevelopmentValue : PushNotificationEntitlements.ProductionValue);
project.AddCapability(m_TargetGuid, PBXCapabilityType.PushNotifications, m_EntitlementFilePath);
}
// Add GameCenter capability to the project.
public void AddGameCenter()
{
var arr = (GetOrCreateInfoDoc().root[GameCenterInfo.Key] ?? (GetOrCreateInfoDoc().root[GameCenterInfo.Key] = new PlistElementArray())) as PlistElementArray;
arr.values.Add(new PlistElementString(GameCenterInfo.Value));
project.AddCapability(m_TargetGuid, PBXCapabilityType.GameCenter);
}
// Add Wallet capability to the project.
public void AddWallet(string[] passSubset)
{
var arr = (GetOrCreateEntitlementDoc().root[WalletEntitlements.Key] = new PlistElementArray()) as PlistElementArray;
if ((passSubset == null || passSubset.Length == 0) && arr != null)
{
arr.values.Add(new PlistElementString(WalletEntitlements.BaseValue + WalletEntitlements.BaseValue));
}
else
{
for (var i = 0; i < passSubset.Length; i++)
{
if (arr != null)
arr.values.Add(new PlistElementString(WalletEntitlements.BaseValue + passSubset[i]));
}
}
project.AddCapability(m_TargetGuid, PBXCapabilityType.Wallet, m_EntitlementFilePath);
}
// Add Siri capability to the project.
public void AddSiri()
{
GetOrCreateEntitlementDoc().root[SiriEntitlements.Key] = new PlistElementBoolean(true);
project.AddCapability(m_TargetGuid, PBXCapabilityType.Siri, m_EntitlementFilePath);
}
// Add Apple Pay capability to the project.
public void AddApplePay(string[] merchants)
{
var arr = (GetOrCreateEntitlementDoc().root[ApplePayEntitlements.Key] = new PlistElementArray()) as PlistElementArray;
for (var i = 0; i < merchants.Length; i++)
{
arr.values.Add(new PlistElementString(merchants[i]));
}
project.AddCapability(m_TargetGuid, PBXCapabilityType.ApplePay, m_EntitlementFilePath);
}
// Add In App Purchase capability to the project.
public void AddInAppPurchase()
{
project.AddCapability(m_TargetGuid, PBXCapabilityType.InAppPurchase);
}
// Add Maps capability to the project.
public void AddMaps(MapsOptions options)
{
var bundleArr = (GetOrCreateInfoDoc().root[MapsInfo.BundleKey] ?? (GetOrCreateInfoDoc().root[MapsInfo.BundleKey] = new PlistElementArray())) as PlistElementArray;
bundleArr.values.Add(new PlistElementDict());
PlistElementDict bundleDic = GetOrCreateUniqueDictElementInArray(bundleArr);
bundleDic[MapsInfo.BundleNameKey] = new PlistElementString(MapsInfo.BundleNameValue);
var bundleTypeArr = (bundleDic[MapsInfo.BundleTypeKey] ?? (bundleDic[MapsInfo.BundleTypeKey] = new PlistElementArray())) as PlistElementArray;
GetOrCreateStringElementInArray(bundleTypeArr, MapsInfo.BundleTypeValue);
var optionArr = (GetOrCreateInfoDoc().root[MapsInfo.ModeKey] ??
(GetOrCreateInfoDoc().root[MapsInfo.ModeKey] = new PlistElementArray())) as PlistElementArray;
if ((options & MapsOptions.Airplane) == MapsOptions.Airplane)
{
GetOrCreateStringElementInArray(optionArr, MapsInfo.ModePlaneValue);
}
if ((options & MapsOptions.Bike) == MapsOptions.Bike)
{
GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeBikeValue);
}
if ((options & MapsOptions.Bus) == MapsOptions.Bus)
{
GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeBusValue);
}
if ((options & MapsOptions.Car) == MapsOptions.Car)
{
GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeCarValue);
}
if ((options & MapsOptions.Ferry) == MapsOptions.Ferry)
{
GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeFerryValue);
}
if ((options & MapsOptions.Other) == MapsOptions.Other)
{
GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeOtherValue);
}
if ((options & MapsOptions.Pedestrian) == MapsOptions.Pedestrian)
{
GetOrCreateStringElementInArray(optionArr, MapsInfo.ModePedestrianValue);
}
if ((options & MapsOptions.RideSharing) == MapsOptions.RideSharing)
{
GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeRideShareValue);
}
if ((options & MapsOptions.StreetCar) == MapsOptions.StreetCar)
{
GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeStreetCarValue);
}
if ((options & MapsOptions.Subway) == MapsOptions.Subway)
{
GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeSubwayValue);
}
if ((options & MapsOptions.Taxi) == MapsOptions.Taxi)
{
GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeTaxiValue);
}
if ((options & MapsOptions.Train) == MapsOptions.Train)
{
GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeTrainValue);
}
project.AddCapability(m_TargetGuid, PBXCapabilityType.Maps);
}
// Add Personal VPN capability to the project.
public void AddPersonalVPN()
{
var arr = (GetOrCreateEntitlementDoc().root[VPNEntitlements.Key] = new PlistElementArray()) as PlistElementArray;
arr.values.Add(new PlistElementString(VPNEntitlements.Value));
project.AddCapability(m_TargetGuid, PBXCapabilityType.PersonalVPN, m_EntitlementFilePath);
}
// Add Background capability to the project with the options wanted.
public void AddBackgroundModes(BackgroundModesOptions options)
{
var optionArr = (GetOrCreateInfoDoc().root[BackgroundInfo.Key] ??
(GetOrCreateInfoDoc().root[BackgroundInfo.Key] = new PlistElementArray())) as PlistElementArray;
if ((options & BackgroundModesOptions.ActsAsABluetoothLEAccessory) == BackgroundModesOptions.ActsAsABluetoothLEAccessory)
{
GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeActsBluetoothValue);
}
if ((options & BackgroundModesOptions.AudioAirplayPiP) == BackgroundModesOptions.AudioAirplayPiP)
{
GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeAudioValue);
}
if ((options & BackgroundModesOptions.BackgroundFetch) == BackgroundModesOptions.BackgroundFetch)
{
GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeFetchValue);
}
if ((options & BackgroundModesOptions.ExternalAccessoryCommunication) == BackgroundModesOptions.ExternalAccessoryCommunication)
{
GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeExtAccessoryValue);
}
if ((options & BackgroundModesOptions.LocationUpdates) == BackgroundModesOptions.LocationUpdates)
{
GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeLocationValue);
}
if ((options & BackgroundModesOptions.NewsstandDownloads) == BackgroundModesOptions.NewsstandDownloads)
{
GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeNewsstandValue);
}
if ((options & BackgroundModesOptions.RemoteNotifications) == BackgroundModesOptions.RemoteNotifications)
{
GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModePushValue);
}
if ((options & BackgroundModesOptions.VoiceOverIP) == BackgroundModesOptions.VoiceOverIP)
{
GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeVOIPValue);
}
project.AddCapability(m_TargetGuid, PBXCapabilityType.BackgroundModes);
}
// Add Keychain Sharing capability to the project with a list of groups.
public void AddKeychainSharing(string[] accessGroups)
{
var arr = (GetOrCreateEntitlementDoc().root[KeyChainEntitlements.Key] = new PlistElementArray()) as PlistElementArray;
if (accessGroups != null)
{
for (var i = 0; i < accessGroups.Length; i++)
{
arr.values.Add(new PlistElementString(accessGroups[i]));
}
}
else
{
arr.values.Add(new PlistElementString(KeyChainEntitlements.DefaultValue));
}
project.AddCapability(m_TargetGuid, PBXCapabilityType.KeychainSharing, m_EntitlementFilePath);
}
// Add Inter App Audio capability to the project.
public void AddInterAppAudio()
{
GetOrCreateEntitlementDoc().root[AudioEntitlements.Key] = new PlistElementBoolean(true);
project.AddCapability(m_TargetGuid, PBXCapabilityType.InterAppAudio, m_EntitlementFilePath);
}
// Add Associated Domains capability to the project.
public void AddAssociatedDomains(string[] domains)
{
var arr = (GetOrCreateEntitlementDoc().root[AssociatedDomainsEntitlements.Key] = new PlistElementArray()) as PlistElementArray;
for (var i = 0; i < domains.Length; i++)
{
arr.values.Add(new PlistElementString(domains[i]));
}
project.AddCapability(m_TargetGuid, PBXCapabilityType.AssociatedDomains, m_EntitlementFilePath);
}
// Add App Groups capability to the project.
public void AddAppGroups(string[] groups)
{
var arr = (GetOrCreateEntitlementDoc().root[AppGroupsEntitlements.Key] = new PlistElementArray()) as PlistElementArray;
for (var i = 0; i < groups.Length; i++)
{
arr.values.Add(new PlistElementString(groups[i]));
}
project.AddCapability(m_TargetGuid, PBXCapabilityType.AppGroups, m_EntitlementFilePath);
}
// Add HomeKit capability to the project.
public void AddHomeKit()
{
GetOrCreateEntitlementDoc().root[HomeKitEntitlements.Key] = new PlistElementBoolean(true);
project.AddCapability(m_TargetGuid, PBXCapabilityType.HomeKit, m_EntitlementFilePath);
}
// Add Data Protection capability to the project.
public void AddDataProtection()
{
GetOrCreateEntitlementDoc().root[DataProtectionEntitlements.Key] = new PlistElementString(DataProtectionEntitlements.Value);
project.AddCapability(m_TargetGuid, PBXCapabilityType.DataProtection, m_EntitlementFilePath);
}
// Add HealthKit capability to the project.
public void AddHealthKit()
{
var capabilityArr = (GetOrCreateInfoDoc().root[HealthInfo.Key] ??
(GetOrCreateInfoDoc().root[HealthInfo.Key] = new PlistElementArray())) as PlistElementArray;
GetOrCreateStringElementInArray(capabilityArr, HealthInfo.Value);
GetOrCreateEntitlementDoc().root[HealthKitEntitlements.Key] = new PlistElementBoolean(true);
project.AddCapability(m_TargetGuid, PBXCapabilityType.HealthKit, m_EntitlementFilePath);
}
// Add Wireless Accessory Configuration capability to the project.
public void AddWirelessAccessoryConfiguration()
{
GetOrCreateEntitlementDoc().root[WirelessAccessoryConfigurationEntitlements.Key] = new PlistElementBoolean(true);
project.AddCapability(m_TargetGuid, PBXCapabilityType.WirelessAccessoryConfiguration, m_EntitlementFilePath);
}
private PlistDocument GetOrCreateEntitlementDoc()
{
if (m_Entitlements == null)
{
m_Entitlements = new PlistDocument();
string[] entitlementsFiles = Directory.GetFiles(m_BuildPath, m_EntitlementFilePath);
if (entitlementsFiles.Length > 0)
{
m_Entitlements.ReadFromFile(entitlementsFiles[0]);
}
else
{
m_Entitlements.Create();
}
}
return m_Entitlements;
}
private PlistDocument GetOrCreateInfoDoc()
{
if (m_InfoPlist == null)
{
m_InfoPlist = new PlistDocument();
string[] infoFiles = Directory.GetFiles(m_BuildPath + "/", "Info.plist");
if (infoFiles.Length > 0)
{
m_InfoPlist.ReadFromFile(infoFiles[0]);
}
else
{
m_InfoPlist.Create();
}
}
return m_InfoPlist;
}
private PlistElementString GetOrCreateStringElementInArray(PlistElementArray root, string value)
{
PlistElementString r = null;
var c = root.values.Count;
var exist = false;
for (var i = 0; i < c; i++)
{
if (root.values[i] is PlistElementString && (root.values[i] as PlistElementString).value == value)
{
r = root.values[i] as PlistElementString;
exist = true;
}
}
if (!exist)
{
r = new PlistElementString(value);
root.values.Add(r);
}
return r;
}
private PlistElementDict GetOrCreateUniqueDictElementInArray(PlistElementArray root)
{
PlistElementDict r;
if (root.values.Count == 0)
{
r = root.values[0] as PlistElementDict;
}
else
{
r = new PlistElementDict();
root.values.Add(r);
}
return r;
}
}
// The list of options available for Background Mode.
[Flags]
[Serializable]
public enum BackgroundModesOptions
{
None = 0,
AudioAirplayPiP = 1<<0,
LocationUpdates = 1<<1,
VoiceOverIP = 1<<2,
NewsstandDownloads = 1<<3,
ExternalAccessoryCommunication = 1<<4,
UsesBluetoothLEAccessory = 1<<5,
ActsAsABluetoothLEAccessory = 1<<6,
BackgroundFetch = 1<<7,
RemoteNotifications = 1<<8
}
// The list of options available for Maps.
[Serializable]
[Flags]
public enum MapsOptions
{
None = 0,
Airplane = 1<<0,
Bike = 1<<1,
Bus = 1<<2,
Car = 1<<3,
Ferry = 1<<4,
Pedestrian = 1<<5,
RideSharing = 1<<6,
StreetCar = 1<<7,
Subway = 1<<8,
Taxi = 1<<9,
Train = 1<<10,
Other = 1<<11
}
/* Follows the large quantity of string used as key and value all over the place in the info.plist or entitlements file. */
internal class GameCenterInfo
{
internal static readonly string Key = "UIRequiredDeviceCapabilities";
internal static readonly string Value = "gamekit";
}
internal class MapsInfo
{
internal static readonly string BundleKey = "CFBundleDocumentTypes";
internal static readonly string BundleNameKey = "CFBundleTypeName";
internal static readonly string BundleNameValue = "MKDirectionsRequest";
internal static readonly string BundleTypeKey = "LSItemContentTypes";
internal static readonly string BundleTypeValue = "com.apple.maps.directionsrequest";
internal static readonly string ModeKey = "MKDirectionsApplicationSupportedModes";
internal static readonly string ModePlaneValue = "MKDirectionsModePlane";
internal static readonly string ModeBikeValue = "MKDirectionsModeBike";
internal static readonly string ModeBusValue = "MKDirectionsModeBus";
internal static readonly string ModeCarValue = "MKDirectionsModeCar";
internal static readonly string ModeFerryValue = "MKDirectionsModeFerry";
internal static readonly string ModeOtherValue = "MKDirectionsModeOther";
internal static readonly string ModePedestrianValue = "MKDirectionsModePedestrian";
internal static readonly string ModeRideShareValue = "MKDirectionsModeRideShare";
internal static readonly string ModeStreetCarValue = "MKDirectionsModeStreetCar";
internal static readonly string ModeSubwayValue = "MKDirectionsModeSubway";
internal static readonly string ModeTaxiValue = "MKDirectionsModeTaxi";
internal static readonly string ModeTrainValue = "MKDirectionsModeTrain";
}
internal class BackgroundInfo
{
internal static readonly string Key = "UIBackgroundModes";
internal static readonly string ModeAudioValue = "audio";
internal static readonly string ModeBluetoothValue = "bluetooth-central";
internal static readonly string ModeActsBluetoothValue = "bluetooth-peripheral";
internal static readonly string ModeExtAccessoryValue = "external-accessory";
internal static readonly string ModeFetchValue = "fetch";
internal static readonly string ModeLocationValue = "location";
internal static readonly string ModeNewsstandValue = "newsstand-content";
internal static readonly string ModePushValue = "remote-notification";
internal static readonly string ModeVOIPValue = "voip";
}
internal class HealthInfo
{
internal static readonly string Key = "UIRequiredDeviceCapabilities";
internal static readonly string Value = "healthkit";
}
internal class ICloudEntitlements
{
internal static readonly string ContainerIdKey = "com.apple.developer.icloud-container-identifiers";
internal static readonly string UbiquityContainerIdKey = "com.apple.developer.ubiquity-container-identifiers";
internal static readonly string ContainerIdValue = "iCloud.$(CFBundleIdentifier)";
internal static readonly string UbiquityContainerIdValue = "iCloud.$(CFBundleIdentifier)";
internal static readonly string ServicesKey = "com.apple.developer.icloud-services";
internal static readonly string ServicesDocValue = "CloudDocuments";
internal static readonly string ServicesKitValue = "CloudKit";
internal static readonly string KeyValueStoreKey = "com.apple.developer.ubiquity-kvstore-identifier";
internal static readonly string KeyValueStoreValue = "$(TeamIdentifierPrefix)$(CFBundleIdentifier)";
}
internal class PushNotificationEntitlements
{
internal static readonly string Key = "aps-environment";
internal static readonly string DevelopmentValue = "development";
internal static readonly string ProductionValue = "production";
}
internal class WalletEntitlements
{
internal static readonly string Key = "com.apple.developer.pass-type-identifiers";
internal static readonly string BaseValue = "$(TeamIdentifierPrefix)";
internal static readonly string DefaultValue = "*";
}
internal class SiriEntitlements
{
internal static readonly string Key = "com.apple.developer.siri";
}
internal class ApplePayEntitlements
{
internal static readonly string Key = "com.apple.developer.in-app-payments";
}
internal class VPNEntitlements
{
internal static readonly string Key = "com.apple.developer.networking.vpn.api";
internal static readonly string Value = "allow-vpn";
}
internal class KeyChainEntitlements
{
internal static readonly string Key = "keychain-access-groups";
internal static readonly string DefaultValue = "$(AppIdentifierPrefix)$(CFBundleIdentifier)";
}
internal class AudioEntitlements
{
internal static readonly string Key = "inter-app-audio";
}
internal class AssociatedDomainsEntitlements
{
// value is an array of string of domains
internal static readonly string Key = "com.apple.developer.associated-domains";
}
internal class AppGroupsEntitlements
{
// value is an array of string of groups
internal static readonly string Key = "com.apple.security.application-groups";
}
internal class HomeKitEntitlements
{
// value is bool true.
internal static readonly string Key = "com.apple.developer.homekit";
}
internal class DataProtectionEntitlements
{
internal static readonly string Key = "com.apple.developer.default-data-protection";
internal static readonly string Value = "NSFileProtectionComplete";
}
internal class HealthKitEntitlements
{
// value is bool true.
internal static readonly string Key = "com.apple.developer.healthkit";
}
internal class WirelessAccessoryConfigurationEntitlements
{
// value is bool true.
internal static readonly string Key = "com.apple.external-accessory.wireless-configuration";
}
}

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 2bfeebf480ee141979c8981b78c0a488
timeCreated: 1496741691
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,8 +1,9 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: a5024d7258021714e832782d73a13749 guid: 19b5fde17c327fc47b67f5109de2b5c1
folderAsset: yes folderAsset: yes
timeCreated: 1456430305
licenseType: Store
DefaultImporter: DefaultImporter:
externalObjects: {}
userData: userData:
assetBundleName: assetBundleName:
assetBundleVariant: assetBundleVariant:

View File

@ -1,8 +1,9 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: cbfad999c612c244f9a6c609a97122ca guid: eadea68d080befc40bf4a084b6e50974
folderAsset: yes folderAsset: yes
timeCreated: 1456430305
licenseType: Store
DefaultImporter: DefaultImporter:
externalObjects: {}
userData: userData:
assetBundleName: assetBundleName:
assetBundleVariant: assetBundleVariant:

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2015,2016 Beebyte Limited. All rights reserved.
*/
using System;
namespace Beebyte.Obfuscator
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class DoNotFakeAttribute: System.Attribute
{
public DoNotFakeAttribute()
{
}
}
}

View File

@ -1,7 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: c69c286f97edb5d408caa387050a40c9 guid: 04b72297763b2b248a299450309ef5c3
MonoImporter: MonoImporter:
externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: 0

View File

@ -0,0 +1,7 @@
namespace Beebyte.Obfuscator
{
public enum MessageCode
{
UnityReflectionMethodNotFound
}
}

View File

@ -1,7 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: c50a36b17c46c9b4396813a8b0ec2e88 guid: b489aabd28c6fcd47ba0e3800e63c008
MonoImporter: MonoImporter:
externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: 0

View File

@ -0,0 +1,16 @@

/*
* Copyright (c) 2016 Beebyte Limited. All rights reserved.
*/
using System;
namespace Beebyte.Obfuscator
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class)]
public class ObfuscateLiteralsAttribute : System.Attribute
{
public ObfuscateLiteralsAttribute()
{
}
}
}

View File

@ -1,7 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 04d272fbec5a52a4a8a1bb6b201a3030 guid: eeac2113ec2cb364fa42782c57e2c802
MonoImporter: MonoImporter:
externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: 0

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2015,2016 Beebyte Limited. All rights reserved.
*/
using System;
namespace Beebyte.Obfuscator
{
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Interface|AttributeTargets.Struct|AttributeTargets.Method|AttributeTargets.Enum|AttributeTargets.Field|AttributeTargets.Property|AttributeTargets.Delegate)]
public class RenameAttribute : System.Attribute
{
private readonly string target;
private RenameAttribute()
{
}
public RenameAttribute(string target)
{
this.target = target;
}
public string GetTarget()
{
return target;
}
}
}

View File

@ -1,7 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 9696ca9d085337943844a940a23e41f3 guid: 82b8519c2b68ec346a26608597706bb6
MonoImporter: MonoImporter:
externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: 0

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2016 Beebyte Limited. All rights reserved.
*/
using System;
namespace Beebyte.Obfuscator
{
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Interface|AttributeTargets.Struct|AttributeTargets.Method|AttributeTargets.Enum|AttributeTargets.Field|AttributeTargets.Property|AttributeTargets.Event|AttributeTargets.Delegate)]
public class ReplaceLiteralsWithNameAttribute : System.Attribute
{
public ReplaceLiteralsWithNameAttribute()
{
}
}
}

View File

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

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2015,2016 Beebyte Limited. All rights reserved.
*/
using System;
namespace Beebyte.Obfuscator
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Event | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Delegate)]
public class SkipAttribute : System.Attribute
{
public SkipAttribute()
{
}
}
}

View File

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

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2015,2016 Beebyte Limited. All rights reserved.
*/
using System;
namespace Beebyte.Obfuscator
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Event | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Delegate)]
public class SkipRenameAttribute : System.Attribute
{
public SkipRenameAttribute()
{
}
}
}

View File

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

View File

@ -0,0 +1 @@
// Deprecated - See SuppressLogAttribute.cs

View File

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

View File

@ -0,0 +1,24 @@
using System;
namespace Beebyte.Obfuscator
{
/**
* Suppresses certain messages (usually warnings) that the Obfuscator can output.
*/
[AttributeUsage(AttributeTargets.Method)]
public class SuppressLogAttribute : System.Attribute
{
#pragma warning disable 414
private readonly MessageCode _messageCode;
#pragma warning restore 414
private SuppressLogAttribute()
{
}
public SuppressLogAttribute(MessageCode messageCode)
{
_messageCode = messageCode;
}
}
}

View File

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

View File

@ -50,7 +50,18 @@ public static class PFConstants
{ {
get get
{ {
return Application.streamingAssetsPath+ @"/AVProVideoSamples";
string path = string.Empty;
#if UNITY_EDITOR
path = Application.dataPath + @"/Editor/Video";
#else
path = Application.streamingAssetsPath + @"/Video";
#endif
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
return path;
} }
} }
@ -58,7 +69,17 @@ public static class PFConstants
{ {
get get
{ {
return Application.streamingAssetsPath + @"/AR"; string path = string.Empty;
#if UNITY_EDITOR
path = Application.dataPath + @"/Editor/AR";
#else
path = Application.streamingAssetsPath + @"/AR";
#endif
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
return path;
} }
} }

View File

@ -4,168 +4,165 @@ using UnityEngine;
using System; using System;
using System.Linq; using System.Linq;
namespace Assets.Scenes.Ride.Scripts public class GameEvent { string key { get; set; } }
public class EventQueueSystem : MonoSingleton<EventQueueSystem>
{ {
public class GameEvent { string key { get; set; } } public delegate void EventDelegate<T>(T e) where T : GameEvent;
public class EventQueueSystem : MonoSingleton<EventQueueSystem> private delegate void InternalEventDelegate(GameEvent e);
private Dictionary<Type, InternalEventDelegate> delegates = new Dictionary<Type, InternalEventDelegate>();
private Dictionary<Delegate, InternalEventDelegate> delegateLookup = new Dictionary<Delegate, InternalEventDelegate>();
private Dictionary<InternalEventDelegate, Delegate> delegateLookOnce = new Dictionary<InternalEventDelegate, Delegate>();
private Queue eventQueue = new Queue();
public bool bLimitQueueProcessing = false;
public float limitQueueTime = 1f;
//注册侦听事件(持续)
public static void AddListener<T>(EventDelegate<T> del) where T : GameEvent
{ {
public delegate void EventDelegate<T>(T e) where T : GameEvent; if (!HasListener(del))
private delegate void InternalEventDelegate(GameEvent e);
private Dictionary<Type, InternalEventDelegate> delegates = new Dictionary<Type, InternalEventDelegate>();
private Dictionary<Delegate, InternalEventDelegate> delegateLookup = new Dictionary<Delegate, InternalEventDelegate>();
private Dictionary<InternalEventDelegate, Delegate> delegateLookOnce = new Dictionary<InternalEventDelegate, Delegate>();
private Queue eventQueue = new Queue();
public bool bLimitQueueProcessing = false;
public float limitQueueTime = 1f;
//注册侦听事件(持续)
public static void AddListener<T>(EventDelegate<T> del) where T : GameEvent
{ {
if (!HasListener(del)) Debug.Log(30);
{ Instance.AddDelegate(del);
Debug.Log(30);
Instance.AddDelegate(del);
}
}
//注册侦听事件(一次)
public static void AddListenerOnce<T>(EventDelegate<T> del) where T : GameEvent
{
var result = Instance.AddDelegate(del);
if (result != null)
Instance.delegateLookOnce[result] = del;
}
//判定侦听事件是否存在
public static bool HasListener<T>(EventDelegate<T> del) where T : GameEvent
{
return Instance.delegateLookup.Keys.Where(c => c.GetType() == del.GetType()).Any();
//return Instance.delegateLookup.ContainsKey(del);
}
//移除侦听事件
public static void RemoveListener<T>(EventDelegate<T> del) where T : GameEvent
{
if (Instance == null)
return;
if (Instance.delegateLookup.TryGetValue(del, out InternalEventDelegate eventDelegate))
{
if (Instance.delegates.TryGetValue(typeof(T), out InternalEventDelegate temp))
{
temp -= eventDelegate;
if (temp == null)
Instance.delegates.Remove(typeof(T));
else
Instance.delegates[typeof(T)] = temp;
}
Instance.delegateLookup.Remove(del);
keyList.Clear();
}
}
public static void RemoveAll()
{
if (Instance != null)
{
Instance.delegates.Clear();
Instance.delegateLookup.Clear();
Instance.delegateLookOnce.Clear();
}
}
private InternalEventDelegate AddDelegate<T>(EventDelegate<T> del) where T : GameEvent
{
if (delegateLookup.ContainsKey(del))
return null;
void eventDelegate(GameEvent e) => del((T)e);
delegateLookup[del] = eventDelegate;
if (delegates.TryGetValue(typeof(T), out InternalEventDelegate temp))
delegates[typeof(T)] = temp += eventDelegate;
else
delegates[typeof(T)] = eventDelegate;
return eventDelegate;
}
//单个事件触发
private static void TriggerEvent(GameEvent e)
{
var type = e.GetType();
if (Instance.delegates.TryGetValue(type, out InternalEventDelegate eventDelegate))
{
eventDelegate.Invoke(e);
//移除单一侦听
foreach (InternalEventDelegate item in Instance.delegates[type].GetInvocationList())
{
if (Instance.delegateLookOnce.TryGetValue(item, out Delegate temp))
{
Instance.delegates[type] -= item;
if (Instance.delegates[type] == null)
Instance.delegates.Remove(type);
Instance.delegateLookup.Remove(temp);
Instance.delegateLookOnce.Remove(item);
}
}
}
}
//外部调用的推入事件队列接口
public static void QueueEvent(GameEvent e)
{
if (!Instance.delegates.ContainsKey(e.GetType()))
return;
Instance.eventQueue.Enqueue(e);
}
private static Dictionary<string,GameEvent> keyList = new Dictionary<string, GameEvent>();
public static void QueueEventOnce(GameEvent e,string key)
{
if (!Instance.delegates.ContainsKey(e.GetType()))
return;
if (keyList.ContainsKey(key))
return;
keyList.Add(key,e);
Instance.eventQueue.Enqueue(e);
}
float timer = 0.0f;
//事件队列触发处理
void Update()
{
//float timer = 0.0f;
//while (eventQueue.Count > 0)
//{
// if (bLimitQueueProcessing)
// if (timer > limitQueueTime)
// return;
// var e = eventQueue.Dequeue() as GameEvent;
// TriggerEvent(e);
// if (bLimitQueueProcessing)
// timer += Time.deltaTime;
//}
timer += Time.deltaTime;
while (timer >= 2 && eventQueue.Count > 0)
{
var e = eventQueue.Dequeue() as GameEvent;
TriggerEvent(e);
timer = 0;
}
}
private void OnApplicationQuit()
{
RemoveAll();
eventQueue.Clear();
}
public static void ClearQueue()
{
if (Instance != null)
Instance.eventQueue.Clear();
} }
} }
}
//注册侦听事件(一次)
public static void AddListenerOnce<T>(EventDelegate<T> del) where T : GameEvent
{
var result = Instance.AddDelegate(del);
if (result != null)
Instance.delegateLookOnce[result] = del;
}
//判定侦听事件是否存在
public static bool HasListener<T>(EventDelegate<T> del) where T : GameEvent
{
return Instance.delegateLookup.Keys.Where(c => c.GetType() == del.GetType()).Any();
//return Instance.delegateLookup.ContainsKey(del);
}
//移除侦听事件
public static void RemoveListener<T>(EventDelegate<T> del) where T : GameEvent
{
if (Instance == null)
return;
if (Instance.delegateLookup.TryGetValue(del, out InternalEventDelegate eventDelegate))
{
if (Instance.delegates.TryGetValue(typeof(T), out InternalEventDelegate temp))
{
temp -= eventDelegate;
if (temp == null)
Instance.delegates.Remove(typeof(T));
else
Instance.delegates[typeof(T)] = temp;
}
Instance.delegateLookup.Remove(del);
keyList.Clear();
}
}
public static void RemoveAll()
{
if (Instance != null)
{
Instance.delegates.Clear();
Instance.delegateLookup.Clear();
Instance.delegateLookOnce.Clear();
}
}
private InternalEventDelegate AddDelegate<T>(EventDelegate<T> del) where T : GameEvent
{
if (delegateLookup.ContainsKey(del))
return null;
void eventDelegate(GameEvent e) => del((T)e);
delegateLookup[del] = eventDelegate;
if (delegates.TryGetValue(typeof(T), out InternalEventDelegate temp))
delegates[typeof(T)] = temp += eventDelegate;
else
delegates[typeof(T)] = eventDelegate;
return eventDelegate;
}
//单个事件触发
private static void TriggerEvent(GameEvent e)
{
var type = e.GetType();
if (Instance.delegates.TryGetValue(type, out InternalEventDelegate eventDelegate))
{
eventDelegate.Invoke(e);
//移除单一侦听
foreach (InternalEventDelegate item in Instance.delegates[type].GetInvocationList())
{
if (Instance.delegateLookOnce.TryGetValue(item, out Delegate temp))
{
Instance.delegates[type] -= item;
if (Instance.delegates[type] == null)
Instance.delegates.Remove(type);
Instance.delegateLookup.Remove(temp);
Instance.delegateLookOnce.Remove(item);
}
}
}
}
//外部调用的推入事件队列接口
public static void QueueEvent(GameEvent e)
{
if (!Instance.delegates.ContainsKey(e.GetType()))
return;
Instance.eventQueue.Enqueue(e);
}
private static Dictionary<string, GameEvent> keyList = new Dictionary<string, GameEvent>();
public static void QueueEventOnce(GameEvent e, string key)
{
if (!Instance.delegates.ContainsKey(e.GetType()))
return;
if (keyList.ContainsKey(key))
return;
keyList.Add(key, e);
Instance.eventQueue.Enqueue(e);
}
float timer = 0.0f;
//事件队列触发处理
void Update()
{
//float timer = 0.0f;
//while (eventQueue.Count > 0)
//{
// if (bLimitQueueProcessing)
// if (timer > limitQueueTime)
// return;
// var e = eventQueue.Dequeue() as GameEvent;
// TriggerEvent(e);
// if (bLimitQueueProcessing)
// timer += Time.deltaTime;
//}
timer += Time.deltaTime;
while (timer >= 2 && eventQueue.Count > 0)
{
var e = eventQueue.Dequeue() as GameEvent;
TriggerEvent(e);
timer = 0;
}
}
private void OnApplicationQuit()
{
RemoveAll();
eventQueue.Clear();
}
public static void ClearQueue()
{
if (Instance != null)
Instance.eventQueue.Clear();
}
}

View File

@ -473,5 +473,26 @@ namespace Assets.Scenes.Ride.Scripts
} }
return startTime; return startTime;
} }
//截图
public static void CaptureCamera(Camera camera, Rect rect, string fileName)
{
byte[] bytes = CaptureCameraReturnByte(camera, rect);
System.IO.File.WriteAllBytes(fileName, bytes);
}
private static byte[] CaptureCameraReturnByte(Camera camera, Rect rect)
{
RenderTexture rt = new RenderTexture((int)rect.width, (int)rect.height, 0);
camera.targetTexture = rt;
camera.Render();
RenderTexture.active = rt;
Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false);
screenShot.ReadPixels(rect, 0, 0);
screenShot.Apply();
camera.targetTexture = null;
RenderTexture.active = null;
GameObject.Destroy(rt);
return screenShot.EncodeToJPG();
}
} }
} }

View File

@ -5,62 +5,60 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
namespace Assets.Scenes.Ride.Scripts
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
{ {
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour private static T instance = null;
private static readonly object locker = new object();
private static bool bAppQuitting;
public static T Instance
{ {
private static T instance = null; get
private static readonly object locker = new object();
private static bool bAppQuitting;
public static T Instance
{ {
get if (bAppQuitting)
{ {
if (bAppQuitting) instance = null;
{ return instance;
instance = null; }
return instance;
}
lock (locker) lock (locker)
{
if (instance == null)
{ {
instance = FindObjectOfType<T>();
if (FindObjectsOfType<T>().Length > 1)
{
Debug.LogError("不应该存在多个单例!");
return instance;
}
if (instance == null) if (instance == null)
{ {
instance = FindObjectOfType<T>(); var singleton = new GameObject();
if (FindObjectsOfType<T>().Length > 1) instance = singleton.AddComponent<T>();
{ singleton.name = "(singleton)" + typeof(T);
Debug.LogError("不应该存在多个单例!"); singleton.hideFlags = HideFlags.None;
return instance; DontDestroyOnLoad(singleton);
}
if (instance == null)
{
var singleton = new GameObject();
instance = singleton.AddComponent<T>();
singleton.name = "(singleton)" + typeof(T);
singleton.hideFlags = HideFlags.None;
DontDestroyOnLoad(singleton);
}
else
DontDestroyOnLoad(instance.gameObject);
} }
instance.hideFlags = HideFlags.None; else
return instance; DontDestroyOnLoad(instance.gameObject);
} }
instance.hideFlags = HideFlags.None;
return instance;
} }
} }
}
private void Awake() private void Awake()
{ {
bAppQuitting = false; bAppQuitting = false;
} }
private void OnDestroy() private void OnDestroy()
{ {
bAppQuitting = true; bAppQuitting = true;
}
} }
} }

View File

@ -1,68 +1,63 @@
using Assets.Scenes.Ride.Scripts; using System;
using Assets.Scripts.Apis.Models;
using DG.Tweening;
using Mapbox.Utils;
using System;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using Assets.Core; using Assets.Core;
using Assets.Scripts.Apis.Models;
using DG.Tweening;
using Mapbox.Utils;
using Assets.Scenes.Ride.Scripts;
namespace Assets.Scripts.Scenes.VideoRide namespace Assets.Scripts.Scenes.VideoRide
{ {
public abstract class AbstractVideoPlayer : MonoBehaviour, IRider public abstract class AbstractVideoPlayer : MonoBehaviour, IRider
{ {
public double Diff { get;set; } public double Diff { get;set; }
protected int frames;
protected int currentFrame { get; set; } protected int currentFrame { get; set; }
protected double preTime; protected Animator animator { get; set; }
protected Animator animator;
public GameObject head { get; set; } public GameObject head { get; set; }
protected Image ftpImage { get; set; } protected Image ftpImage { get; set; }
protected Text headName { get; set; } protected Text headName { get; set; }
protected Text headWkg { get; set; } protected Text headWkg { get; set; }
public int userId { get; set; } public int userId { get; set; }
public string userName { get; set; } public string userName { get; set; }
public double weight;//体重 public double weight;//体重
protected double bicycleWeight;//车重 protected double bicycleWeight;//车重
protected double preSpeed; protected double preSpeed;
public double speed; public double speed;
public double power;
protected double elevation;
public double cadance;
public double wkg;
public int? heartRate { get; set; }
public int ticks;
public double totalDistance { get; set; }
public double currentSlope;
protected double nextSlope;
protected double nextSlopeDistance;
public double distance; public double distance;
protected double currentSlopeDistance; public double power;
protected double lastEndDistance; public double elevation { get; set; }
public double totalClimb; public double cadance { get; set; }
public double wkg { get; set; }
public int? heartRate { get; set; }
public double totalDistance { get; set; }
public double currentSlope { get; set; }
protected double nextSlope { get; set; }
protected double nextSlopeDistance { get; set; }
protected double currentSlopeDistance { get; set; }
public double totalClimb { get; set; }
public Vector2d currentlatLon { get; set; } public Vector2d currentlatLon { get; set; }
public int currentIndex; public int currentIndex { get; set; }
public float bearing = 0f;
public int ticks { get; set; }
protected MapDataModel mapData; protected MapDataModel mapData;
private float timer = 0f;
protected bool start = true; protected bool start = true;
protected Sequence sequence;
protected VideoGameManager manager { get; set; } protected VideoGameManager manager { get; set; }
float currenPlayerHeight;
Transform bone_bottle_2 { get; set; } Transform bone_bottle_2 { get; set; }
public double Speed { get; set; } public double Speed { get; set; }
public double StartDistance { get; set; } public double StartDistance { get; set; }
public double PreDistance { get; set; } public double PreDistance { get; set; }
public double EndDistance { get; set; } public double EndDistance { get; set; }
public double OnlineSpeed { get; set; } public double OnlineSpeed { get; set; }
public int UserId => this.userId; public int UserId => this.userId;
public string UserName => this.userName; public string UserName => this.userName;
public bool IsStart = false;
public double mockpower { get; set; } public double mockpower { get; set; }
protected float ratio = 1;
protected virtual void Start() protected virtual void Start()
{ {
@ -74,74 +69,57 @@ namespace Assets.Scripts.Scenes.VideoRide
} }
protected virtual void Update() protected virtual void Update()
{ {
timer -= Time.deltaTime;
CreateHeadImage(); CreateHeadImage();
while (timer <= 0) ComputeAnimator();//控制动画
{ ComputeAnimatorSpeed();//控制动画速度
try
{
ComputeNextSlope();//计算下一个坡度
if (manager.IsStart())
{
ticks++;
ComputePlayer();//计算人物属性
Forward();
ComputeRecord();
ComputeVideo();
}
else
{
power = 0;
OnlineSpeed = 0;
PreDistance = EndDistance;
speed = 0;
distance = 0;
}
ComputeAnimator();//控制动画
timer += 1f;
}
catch (Exception e)
{
power = 0;
speed = 0;
Debug.LogError(e.Message);
}
}
} }
//动画状态机
protected virtual void ComputeAnimator() public void StartAction()
{ {
if (animator != null) try
{ {
if (manager._viewMode == VideoGameManager.ViewMode.FIRST &&manager.CurrentPlayer.UserId == App.CurrentUser.Id) if (manager.IsStart())
{ {
animator.SetFloat("preSpeed", (float)preSpeed); ComputeTimerTick();
animator.SetFloat("speed", (float)Math.Min(speed,25)); ComputeNextSlope();//计算下一个坡度
animator.SetFloat("grade", (float)currentSlope); ComputePlayer();//计算人物属性
animator.SetFloat("power", (float)power); Forward();
ComputeRecord();
} }
else else
{ {
animator.SetFloat("preSpeed", (float)preSpeed); power = 0;
animator.SetFloat("speed", (float)speed); OnlineSpeed = 0;
animator.SetFloat("grade", (float)currentSlope); PreDistance = EndDistance;
animator.SetFloat("power", (float)power); speed = 0;
//播放喝水和回头的动画 distance = 0;
//var headBack = ticks % 60 == 0 && speed > 0;
//var drink = ticks % 125 == 0 && speed > 0;
//animator.SetBool("headBack", headBack);
//animator.SetBool("drinking", drink);
} }
} }
catch (Exception e)
{
power = 0;
speed = 0;
Debug.LogError(e.Message);
}
} }
protected virtual int GetCurrentFrame()
private void ComputeTimerTick()
{ {
return manager.GetCurrentFrame(); ticks++;
}
public virtual void ComputeAnimator()
{
if (animator != null)
{
animator.SetFloat("preSpeed", (float)preSpeed);
animator.SetFloat("speed", (float)speed);
animator.SetFloat("grade", (float)currentSlope);
animator.SetFloat("power", (float)power);
}
} }
protected Vector3 currentRotation;
//计算人物当前属性 //计算人物当前属性
protected virtual void ComputePlayer() public virtual void ComputePlayer()
{ {
if (power > 0) if (power > 0)
{ {
@ -153,17 +131,9 @@ namespace Assets.Scripts.Scenes.VideoRide
speed = 0; speed = 0;
distance = 0; distance = 0;
} }
////一旦有功率就开始骑行、否则暂停
//if (!manager.IsQuit() && manager.CurrentPlayer.UserId == UserId && !manager.IsQuit() && manager.cyclingModel == CyclingModel.Single)
//{
// if (power > 0)
// {
// manager.StartGame();
// }
//}
} }
//计算当前人物的经纬度 //计算当前人物的经纬度
protected virtual void Forward() public virtual void Forward()
{ {
try try
{ {
@ -176,44 +146,28 @@ namespace Assets.Scripts.Scenes.VideoRide
Debug.LogError(e); Debug.LogError(e);
} }
} }
protected float ratio = 1;//视频播放速率 public virtual void ComputeAnimatorSpeed()
protected virtual void ComputeVideo()
{ {
mapData = manager.GetMapData(); if (manager == null)
if (currentIndex + 1 < mapData.List.Count)
{
ratio = (float)(speed / mapData.List[currentIndex + 1].Distance);
}
else
{
ratio = (float)(speed / mapData.List[currentIndex].Distance);
}
if (manager.CurrentPlayer != null && manager.CurrentPlayer.UserId != UserId)
return; return;
mapData = manager.GetMapData();
int safeIndex = currentIndex + 1 < mapData.List.Count ? currentIndex + 1 : currentIndex;
float num = speed == 0 ? 1f : (float)(speed / mapData.List[safeIndex].Distance);
ratio = Mathf.Clamp(num, 0.3f, 1.2f);
if (ratio > 1)
{
ratio = Math.Min(ratio, 1.2f);
}
if (ratio < 1)
{
ratio = Math.Max(ratio, 0.3f);
}
if (speed == 0)
{
ratio = 1;
}
var info = animator.GetCurrentAnimatorClipInfo(0); var info = animator.GetCurrentAnimatorClipInfo(0);
var currentClip = info.FirstOrDefault(); if (info != null)
if (currentClip.clip != null)
{ {
animator.speed = ratio; var currentClip = info.FirstOrDefault();
if (currentClip.clip != null)
{
animator.speed = ratio;
}
} }
} }
protected virtual void ComputeRecord() { } public virtual void ComputeRecord() { }
//计算当前区段属性下一个区段属性 //计算当前区段属性下一个区段属性
void ComputeNextSlope() public void ComputeNextSlope()
{ {
double sumDistance = 0; double sumDistance = 0;
mapData = manager.GetMapData(); mapData = manager.GetMapData();
@ -265,13 +219,12 @@ namespace Assets.Scripts.Scenes.VideoRide
{ {
head?.SetActive(false); head?.SetActive(false);
} }
private void OnEnable() private void OnEnable()
{ {
head?.SetActive(true); head?.SetActive(true);
} }
//显示人物海拔图的头像 //显示人物头顶的名字
protected virtual void CreateHeadImage() public virtual void CreateHeadImage()
{ {
if (head == null) if (head == null)
{ {
@ -281,7 +234,6 @@ namespace Assets.Scripts.Scenes.VideoRide
ftpImage = head.transform.Find("ftp").GetComponent<Image>(); ftpImage = head.transform.Find("ftp").GetComponent<Image>();
headName = head.transform.Find("name").GetComponent<Text>(); headName = head.transform.Find("name").GetComponent<Text>();
headWkg = head.transform.Find("wkg").GetComponent<Text>(); headWkg = head.transform.Find("wkg").GetComponent<Text>();
} }
} }
if (head != null) if (head != null)
@ -293,8 +245,14 @@ namespace Assets.Scripts.Scenes.VideoRide
ftpImage.fillAmount = (float)(wkg / 6); ftpImage.fillAmount = (float)(wkg / 6);
headName.text = UserName; headName.text = UserName;
headWkg.text = $"{wkg}W/KG"; headWkg.text = $"{wkg}W/KG";
head.SetActive(bone_bottle_2.position.z > 0);
} }
} }
public void SetStartDistance(double distance)
{
this.StartDistance = distance *1000;
}
public void Destroy() public void Destroy()
{ {
if (manager.CurrentPlayer != null && manager.CurrentPlayer.UserId == UserId) if (manager.CurrentPlayer != null && manager.CurrentPlayer.UserId == UserId)
@ -306,10 +264,5 @@ namespace Assets.Scripts.Scenes.VideoRide
} }
//设置当前玩家属性 //设置当前玩家属性
public abstract void SetPlayer(string name, double speed, double preDistance, double endDistance, double cadance, double heartRate, double wkg, int userId, double power, double currentPlayerDistance, int frame); public abstract void SetPlayer(string name, double speed, double preDistance, double endDistance, double cadance, double heartRate, double wkg, int userId, double power, double currentPlayerDistance, int frame);
public void SetStartDistance(double distance)
{
this.StartDistance = distance *1000;
}
} }
} }

View File

@ -61,6 +61,7 @@ namespace Assets.Scripts.Scenes.VideoRide
{ {
if (cyclingCotroller.CurrentPlayer != null) if (cyclingCotroller.CurrentPlayer != null)
{ {
uitransform = cyclingCotroller.GetCanvasTransform();
var tr = uitransform.Find("MiniMap/MiniMap/arrow"); var tr = uitransform.Find("MiniMap/MiniMap/arrow");
tr.SetSiblingIndex(9999); tr.SetSiblingIndex(9999);
var pos = _map.GeoToWorldPosition(cyclingCotroller.CurrentPlayer.currentlatLon); var pos = _map.GeoToWorldPosition(cyclingCotroller.CurrentPlayer.currentlatLon);

View File

@ -15,25 +15,16 @@ namespace Assets.Scripts.Scenes.VideoRide
base.Update(); base.Update();
} }
//计算 public override void ComputeAnimator()
protected override void ComputePlayer()
{
}
protected override void ComputeAnimator()
{ {
base.ComputeAnimator(); base.ComputeAnimator();
} }
protected override int GetCurrentFrame()
public override void ComputeAnimatorSpeed()
{ {
return this.currentFrame; base.ComputeAnimatorSpeed();
} }
protected override void ComputeVideo() public override void CreateHeadImage()
{
base.ComputeVideo();
}
protected override void CreateHeadImage()
{ {
base.CreateHeadImage(); base.CreateHeadImage();
if (Diff < 0) if (Diff < 0)
@ -46,8 +37,6 @@ namespace Assets.Scripts.Scenes.VideoRide
{ {
manager = FindObjectOfType<VideoGameManager>(); manager = FindObjectOfType<VideoGameManager>();
} }
var f = totalDistance;
preTime = f;
this.wkg = wkg; this.wkg = wkg;
this.userName = name; this.userName = name;
this.cadance = cadance; this.cadance = cadance;

View File

@ -119,6 +119,7 @@ namespace Assets.Scripts.Scenes.VideoRide
videoLoading.Init();//初始化loading页面 videoLoading.Init();//初始化loading页面
} }
float timer = 0f; float timer = 0f;
int ticks = 0;
protected override void Update() protected override void Update()
{ {
timer -= Time.deltaTime; timer -= Time.deltaTime;
@ -131,6 +132,20 @@ namespace Assets.Scripts.Scenes.VideoRide
try try
{ {
CreateOnlineUser(onlineRiders); CreateOnlineUser(onlineRiders);
if (isStart)
{
var riders = FindObjectsOfType<OnlineVideoPlayer>();
foreach (var rider in riders)
{
rider.StartAction();
}
//解决当前用户setActivefalse时仍能计算数据
if (CurrentPlayer != null && CurrentPlayer is VideoPlayer)
{
CurrentPlayer.StartAction();
}
ticks++;
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -159,18 +174,12 @@ namespace Assets.Scripts.Scenes.VideoRide
private void CreateOnlineUser(List<BaseRider> list) private void CreateOnlineUser(List<BaseRider> list)
{ {
list = list.Where(c => ((OnlineRiderModel)c).IsWatcher == false).ToList(); list = list.Where(c => ((OnlineRiderModel)c).IsWatcher == false).ToList();
//断网移除所有用户
if (list == null || list.Count == 0) if (list == null || list.Count == 0)
{ {
var currentList = FindObjectsOfType<PlayerRenderer>();
foreach (var item in currentList)
{
item.Speed = 0;
item.Paused = true;
}
rideObjs.Clear(); rideObjs.Clear();
visibleRiders.Clear(); visibleRiders.Clear();
//移除退出的选手 var onlineUserList = FindObjectsOfType<AbstractVideoPlayer>();
var onlineUserList = FindObjectsOfType<OnlineVideoPlayer>();
foreach (var item in onlineUserList) foreach (var item in onlineUserList)
{ {
DestroyImmediate(item.gameObject); DestroyImmediate(item.gameObject);
@ -188,7 +197,6 @@ namespace Assets.Scripts.Scenes.VideoRide
{ {
rideObjs.Remove(item); rideObjs.Remove(item);
visibleRiders.Remove(item); visibleRiders.Remove(item);
//trainController.RemoveRider(item.UserId);
} }
} }
var currentPlayerInfo = list.Where(c => c.IsSelf).FirstOrDefault(); var currentPlayerInfo = list.Where(c => c.IsSelf).FirstOrDefault();
@ -200,13 +208,14 @@ namespace Assets.Scripts.Scenes.VideoRide
if(currentPlayerInfo == null) if(currentPlayerInfo == null)
currentPlayerInfo = needUpdateList.FirstOrDefault(); currentPlayerInfo = needUpdateList.FirstOrDefault();
} }
//更新和新增用户
foreach (var item in needUpdateList) foreach (var item in needUpdateList)
{ {
var onlineRider = item as OnlineRiderModel; var onlineRider = item as OnlineRiderModel;
var visibleItem = visibleRiders.Where(c => c.UserId == item.UserId).FirstOrDefault(); var visibleItem = visibleRiders.Where(c => c.UserId == item.UserId).FirstOrDefault();
//更新
if (visibleItem != null) if (visibleItem != null)
{ {
Debug.Log($"count {visibleRiders.Count()}");
visibleItem.SetPlayer(onlineRider.NickName, onlineRider.Speed, onlineRider.PreDistance, onlineRider.EndDistance, item.Cadence, item.HeartRate, onlineRider.WeightKg, item.UserId, onlineRider.Power, currentPlayerInfo.EndDistance, onlineRider.FrameRate.Value); visibleItem.SetPlayer(onlineRider.NickName, onlineRider.Speed, onlineRider.PreDistance, onlineRider.EndDistance, item.Cadence, item.HeartRate, onlineRider.WeightKg, item.UserId, onlineRider.Power, currentPlayerInfo.EndDistance, onlineRider.FrameRate.Value);
if(visibleItem.userId == currentUserId) if(visibleItem.userId == currentUserId)
CurrentPlayer = visibleItem; CurrentPlayer = visibleItem;
@ -293,7 +302,7 @@ namespace Assets.Scripts.Scenes.VideoRide
public GameObject videoPlayer; public GameObject videoPlayer;
public GameObject target; public GameObject target;
private int currentUserId { get; set; } private int currentUserId { get; set; }
//切换人物 TODO:替换写法 //切换人物
public void ChangePlayer(int userId) public void ChangePlayer(int userId)
{ {
currentUserId = userId; currentUserId = userId;
@ -321,7 +330,6 @@ namespace Assets.Scripts.Scenes.VideoRide
//设置骑行模式 //设置骑行模式
public void SetCyclingModel(CyclingModel mode) public void SetCyclingModel(CyclingModel mode)
{ {
//startTime = UIManager.Now.GetDateTime();
this.cyclingModel = mode; this.cyclingModel = mode;
switch (cyclingModel) switch (cyclingModel)
{ {
@ -343,11 +351,6 @@ namespace Assets.Scripts.Scenes.VideoRide
isStart = true; isStart = true;
} }
//骑行是否开始 //骑行是否开始
public bool IsReady()
{
return true;
}
//骑行是否开始
public bool IsStart() public bool IsStart()
{ {
return isStart; return isStart;
@ -390,9 +393,7 @@ namespace Assets.Scripts.Scenes.VideoRide
{ {
return mediaPlayer.Control.GetCurrentTimeFrames(); return mediaPlayer.Control.GetCurrentTimeFrames();
} }
public float ratio = 111.676f;
public float startOffset = 0f;
//获取AR骑行配置信息 //获取AR骑行配置信息
//获取路书gps信息 //获取路书gps信息
public MapDataModel GetMapData() public MapDataModel GetMapData()
@ -418,14 +419,16 @@ namespace Assets.Scripts.Scenes.VideoRide
return mapRoute; return mapRoute;
} }
//保存骑行记录 //保存骑行记录
public void Save(double totalDistance) public void SaveData(double totalDistance)
{ {
if (cyclingController.recorderData == null || cyclingController.recorderData.Saved)
return;
Quit(); Quit();
cyclingController.recorderData.EndTime = UIManager.Now.GetDateTime(); cyclingController.recorderData.EndTime = UIManager.Now.GetDateTime();
var path = PFConstants.MapWorkoutRecordFolder + "/" + recordId; var path = PFConstants.MapWorkoutRecordFolder + "/" + recordId;
Assets.Scenes.Ride.Scripts.Helper.CreateDirectoryIfNotExsit(path); Assets.Scenes.Ride.Scripts.Helper.CreateDirectoryIfNotExsit(path);
string imageFileName = path + "/" + Guid.NewGuid().ToString() + ".png"; string imageFileName = path + "/" + Guid.NewGuid().ToString() + ".png";
CaptureCamera(Camera.main, new Rect(Screen.width * 0f, Screen.height * 0f, Screen.width * 0.5f, Screen.height * 0.5f), imageFileName); Helper.CaptureCamera(Camera.main, new Rect(Screen.width * 0f, Screen.height * 0f, Screen.width * 0.5f, Screen.height * 0.5f), imageFileName);
cyclingController.recorderData.StartTime = startTime; cyclingController.recorderData.StartTime = startTime;
cyclingController.recorderData.IsCompleted = totalDistance >= mapData.TotalDistance; cyclingController.recorderData.IsCompleted = totalDistance >= mapData.TotalDistance;
cyclingController.recorderData.EndDistance = totalDistance; cyclingController.recorderData.EndDistance = totalDistance;
@ -448,27 +451,6 @@ namespace Assets.Scripts.Scenes.VideoRide
{ {
return UIManager.Instance.loginRegOptions.GetCountryImageByName(name); return UIManager.Instance.loginRegOptions.GetCountryImageByName(name);
} }
//截图
protected void CaptureCamera(Camera camera, Rect rect, string fileName)
{
byte[] bytes = CaptureCameraReturnByte(camera, rect);
System.IO.File.WriteAllBytes(fileName, bytes);
}
private byte[] CaptureCameraReturnByte(Camera camera, Rect rect)
{
RenderTexture rt = new RenderTexture((int)rect.width, (int)rect.height, 0);
camera.targetTexture = rt;
camera.Render();
RenderTexture.active = rt;
Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false);
screenShot.ReadPixels(rect, 0, 0);
screenShot.Apply();
camera.targetTexture = null;
RenderTexture.active = null;
GameObject.Destroy(rt);
return screenShot.EncodeToJPG();
}
//根据距离计算下一个点坐标
public Vector2d Along(double endDistance) public Vector2d Along(double endDistance)
{ {
if (mapData != null) if (mapData != null)

View File

@ -16,21 +16,11 @@ namespace Assets.Scripts.Scenes.VideoRide
userName = App.CurrentUser.Nickname; userName = App.CurrentUser.Nickname;
} }
protected bool GetStart()
{
return manager.IsStart();
}
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
} }
public void SetPower(double power)
{
this.power = power;
}
public void SetEndDistance(double distance) public void SetEndDistance(double distance)
{ {
this.totalDistance = distance; this.totalDistance = distance;
@ -48,12 +38,12 @@ namespace Assets.Scripts.Scenes.VideoRide
} }
} }
protected override void ComputeAnimator() public override void ComputeAnimator()
{ {
base.ComputeAnimator(); base.ComputeAnimator();
} }
protected override void ComputePlayer() public override void ComputePlayer()
{ {
heartRate = manager.UpDateHeart(); heartRate = manager.UpDateHeart();
power = manager.UpdatePower(); power = manager.UpdatePower();
@ -93,14 +83,12 @@ namespace Assets.Scripts.Scenes.VideoRide
},true); },true);
} }
} }
//控制视频播放速度
protected override void ComputeVideo()
{
base.ComputeVideo();
//单人骑行到终点自动暂停
}
protected override void ComputeRecord() public override void ComputeAnimatorSpeed()
{
base.ComputeAnimatorSpeed();
}
public override void ComputeRecord()
{ {
var mapData = manager.GetMapData(); var mapData = manager.GetMapData();
//记录骑行数据 //记录骑行数据
@ -134,7 +122,7 @@ namespace Assets.Scripts.Scenes.VideoRide
} }
} }
protected override void Forward() public override void Forward()
{ {
base.Forward(); base.Forward();
distance = Math.Round(speed / 3600, 5, MidpointRounding.AwayFromZero); distance = Math.Round(speed / 3600, 5, MidpointRounding.AwayFromZero);
@ -143,10 +131,7 @@ namespace Assets.Scripts.Scenes.VideoRide
//保存骑行记录 //保存骑行记录
public void Upload() public void Upload()
{ {
if (manager.cyclingController.recorderData != null && !manager.cyclingController.recorderData.Saved)//处理重复上传的问题 manager.SaveData(totalDistance);
{
manager.Save(totalDistance);
}
} }
public override void SetPlayer(string name, double speed, double preDistance, double endDistance, double cadance, double heartRate, double wkg, int userId, double power, double currentPlayerDistance, int frame) public override void SetPlayer(string name, double speed, double preDistance, double endDistance, double cadance, double heartRate, double wkg, int userId, double power, double currentPlayerDistance, int frame)