Moving to flex, Hoping it would fix platform
This commit is contained in:
8
Assets/ParrelSync.meta
Normal file
8
Assets/ParrelSync.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2739caeae15c82940a97a934ae6f724d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/ParrelSync/Examples.meta
Normal file
8
Assets/ParrelSync/Examples.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 654be33bd44a76a4c8c180d1da6ad066
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
31
Assets/ParrelSync/Examples/CustomArgumentExample.cs
Normal file
31
Assets/ParrelSync/Examples/CustomArgumentExample.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
// This should be editor only
|
||||
#if UNITY_EDITOR
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ParrelSync.Example
|
||||
{
|
||||
public class CustomArgumentExample : MonoBehaviour
|
||||
{
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
// Is this editor instance running a clone project?
|
||||
if (ClonesManager.IsClone())
|
||||
{
|
||||
Debug.Log("This is a clone project.");
|
||||
|
||||
//Argument can be set from the clones manager window.
|
||||
string customArgument = ClonesManager.GetArgument();
|
||||
Debug.Log("The custom argument of this clone project is: " + customArgument);
|
||||
// Do what ever you need with the argument string.
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("This is the original project.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
11
Assets/ParrelSync/Examples/CustomArgumentExample.cs.meta
Normal file
11
Assets/ParrelSync/Examples/CustomArgumentExample.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 346d302ecc25a9a41b48b857ce51d873
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
22
Assets/ParrelSync/LICENSE.md
Normal file
22
Assets/ParrelSync/LICENSE.md
Normal file
@@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Greg M
|
||||
Copyright (c) 2020 Ian and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
7
Assets/ParrelSync/LICENSE.md.meta
Normal file
7
Assets/ParrelSync/LICENSE.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4b327eab8d866e4087e166da8cafc09
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/ParrelSync/ParrelSync.meta
Normal file
8
Assets/ParrelSync/ParrelSync.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f5fec620d3bc9546a41a5b67cb9f8b6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/ParrelSync/ParrelSync/Editor.meta
Normal file
8
Assets/ParrelSync/ParrelSync/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a31ea7d0315594440839cdb0db6bc411
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/ParrelSync/ParrelSync/Editor/AssetModBlock.meta
Normal file
8
Assets/ParrelSync/ParrelSync/Editor/AssetModBlock.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b14e706b1e7cb044b23837e8a70cad9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,22 @@
|
||||
using UnityEditor;
|
||||
namespace ParrelSync
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public class EditorQuit
|
||||
{
|
||||
/// <summary>
|
||||
/// Is editor being closed
|
||||
/// </summary>
|
||||
static public bool IsQuiting { get; private set; }
|
||||
static void Quit()
|
||||
{
|
||||
IsQuiting = true;
|
||||
}
|
||||
|
||||
static EditorQuit()
|
||||
{
|
||||
IsQuiting = false;
|
||||
EditorApplication.quitting += Quit;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf2888ff90706904abc2d851c3e59e00
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
namespace ParrelSync
|
||||
{
|
||||
/// <summary>
|
||||
/// For preventing assets being modified from the clone instance.
|
||||
/// </summary>
|
||||
public class ParrelSyncAssetModificationProcessor : UnityEditor.AssetModificationProcessor
|
||||
{
|
||||
public static string[] OnWillSaveAssets(string[] paths)
|
||||
{
|
||||
if (ClonesManager.IsClone() && Preferences.AssetModPref.Value)
|
||||
{
|
||||
if (paths != null && paths.Length > 0 && !EditorQuit.IsQuiting)
|
||||
{
|
||||
EditorUtility.DisplayDialog(
|
||||
ClonesManager.ProjectName + ": Asset modifications saving detected and blocked",
|
||||
"Asset modifications saving are blocked in the clone instance. \n\n" +
|
||||
"This is a clone of the original project. \n" +
|
||||
"Making changes to asset files via the clone editor is not recommended. \n" +
|
||||
"Please use the original editor window if you want to make changes to the project files.",
|
||||
"ok"
|
||||
);
|
||||
foreach (var path in paths)
|
||||
{
|
||||
Debug.Log("Attempting to save " + path + " are blocked.");
|
||||
}
|
||||
}
|
||||
return new string[0] { };
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 755e570bd21b39440a923056e60f1450
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
664
Assets/ParrelSync/ParrelSync/Editor/ClonesManager.cs
Normal file
664
Assets/ParrelSync/ParrelSync/Editor/ClonesManager.cs
Normal file
@@ -0,0 +1,664 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
namespace ParrelSync
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains all required methods for creating a linked clone of the Unity project.
|
||||
/// </summary>
|
||||
public class ClonesManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Name used for an identifying file created in the clone project directory.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// (!) Do not change this after the clone was created, because then connection will be lost.
|
||||
/// </remarks>
|
||||
public const string CloneFileName = ".clone";
|
||||
|
||||
/// <summary>
|
||||
/// Suffix added to the end of the project clone name when it is created.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// (!) Do not change this after the clone was created, because then connection will be lost.
|
||||
/// </remarks>
|
||||
public const string CloneNameSuffix = "_clone";
|
||||
|
||||
public const string ProjectName = "ParrelSync";
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of clones
|
||||
/// </summary>
|
||||
public const int MaxCloneProjectCount = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the file for storing clone's argument.
|
||||
/// </summary>
|
||||
public const string ArgumentFileName = ".parrelsyncarg";
|
||||
|
||||
/// <summary>
|
||||
/// Default argument of the new clone
|
||||
/// </summary>
|
||||
public const string DefaultArgument = "client";
|
||||
|
||||
#region Managing clones
|
||||
|
||||
/// <summary>
|
||||
/// Creates clone from the project currently open in Unity Editor.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Project CreateCloneFromCurrent()
|
||||
{
|
||||
if (IsClone())
|
||||
{
|
||||
Debug.LogError("This project is already a clone. Cannot clone it.");
|
||||
return null;
|
||||
}
|
||||
|
||||
string currentProjectPath = ClonesManager.GetCurrentProjectPath();
|
||||
return ClonesManager.CreateCloneFromPath(currentProjectPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates clone of the project located at the given path.
|
||||
/// </summary>
|
||||
/// <param name="sourceProjectPath"></param>
|
||||
/// <returns></returns>
|
||||
public static Project CreateCloneFromPath(string sourceProjectPath)
|
||||
{
|
||||
Project sourceProject = new Project(sourceProjectPath);
|
||||
|
||||
string cloneProjectPath = null;
|
||||
|
||||
//Find available clone suffix id
|
||||
for (int i = 0; i < MaxCloneProjectCount; i++)
|
||||
{
|
||||
string originalProjectPath = ClonesManager.GetCurrentProject().projectPath;
|
||||
string possibleCloneProjectPath = originalProjectPath + ClonesManager.CloneNameSuffix + "_" + i;
|
||||
|
||||
if (!Directory.Exists(possibleCloneProjectPath))
|
||||
{
|
||||
cloneProjectPath = possibleCloneProjectPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(cloneProjectPath))
|
||||
{
|
||||
Debug.LogError("The number of cloned projects has reach its limit. Limit: " + MaxCloneProjectCount);
|
||||
return null;
|
||||
}
|
||||
|
||||
Project cloneProject = new Project(cloneProjectPath);
|
||||
|
||||
Debug.Log("Start cloning project, original project: " + sourceProject + ", clone project: " + cloneProject);
|
||||
|
||||
ClonesManager.CreateProjectFolder(cloneProject);
|
||||
|
||||
//Copy Folders
|
||||
Debug.Log("Library copy: " + cloneProject.libraryPath);
|
||||
ClonesManager.CopyDirectoryWithProgressBar(sourceProject.libraryPath, cloneProject.libraryPath,
|
||||
"Cloning Project Library '" + sourceProject.name + "'. ");
|
||||
Debug.Log("Packages copy: " + cloneProject.libraryPath);
|
||||
ClonesManager.CopyDirectoryWithProgressBar(sourceProject.packagesPath, cloneProject.packagesPath,
|
||||
"Cloning Project Packages '" + sourceProject.name + "'. ");
|
||||
|
||||
|
||||
//Link Folders
|
||||
ClonesManager.LinkFolders(sourceProject.assetPath, cloneProject.assetPath);
|
||||
ClonesManager.LinkFolders(sourceProject.projectSettingsPath, cloneProject.projectSettingsPath);
|
||||
ClonesManager.LinkFolders(sourceProject.autoBuildPath, cloneProject.autoBuildPath);
|
||||
ClonesManager.LinkFolders(sourceProject.localPackages, cloneProject.localPackages);
|
||||
|
||||
ClonesManager.RegisterClone(cloneProject);
|
||||
|
||||
return cloneProject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a clone by placing an identifying ".clone" file in its root directory.
|
||||
/// </summary>
|
||||
/// <param name="cloneProject"></param>
|
||||
private static void RegisterClone(Project cloneProject)
|
||||
{
|
||||
/// Add clone identifier file.
|
||||
string identifierFile = Path.Combine(cloneProject.projectPath, ClonesManager.CloneFileName);
|
||||
File.Create(identifierFile).Dispose();
|
||||
|
||||
//Add argument file with default argument
|
||||
string argumentFilePath = Path.Combine(cloneProject.projectPath, ClonesManager.ArgumentFileName);
|
||||
File.WriteAllText(argumentFilePath, DefaultArgument, System.Text.Encoding.UTF8);
|
||||
|
||||
/// Add collabignore.txt to stop the clone from messing with Unity Collaborate if it's enabled. Just in case.
|
||||
string collabignoreFile = Path.Combine(cloneProject.projectPath, "collabignore.txt");
|
||||
File.WriteAllText(collabignoreFile, "*"); /// Make it ignore ALL files in the clone.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a project located at the given path (if one exists).
|
||||
/// </summary>
|
||||
/// <param name="projectPath"></param>
|
||||
public static void OpenProject(string projectPath)
|
||||
{
|
||||
if (!Directory.Exists(projectPath))
|
||||
{
|
||||
Debug.LogError("Cannot open the project - provided folder (" + projectPath + ") does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (projectPath == ClonesManager.GetCurrentProjectPath())
|
||||
{
|
||||
Debug.LogError("Cannot open the project - it is already open.");
|
||||
return;
|
||||
}
|
||||
|
||||
string fileName = GetApplicationPath();
|
||||
string args = "-projectPath \"" + projectPath + "\"";
|
||||
Debug.Log("Opening project \"" + fileName + " " + args + "\"");
|
||||
ClonesManager.StartHiddenConsoleProcess(fileName, args);
|
||||
}
|
||||
|
||||
private static string GetApplicationPath()
|
||||
{
|
||||
switch (Application.platform)
|
||||
{
|
||||
case RuntimePlatform.WindowsEditor:
|
||||
return EditorApplication.applicationPath;
|
||||
case RuntimePlatform.OSXEditor:
|
||||
return EditorApplication.applicationPath + "/Contents/MacOS/Unity";
|
||||
case RuntimePlatform.LinuxEditor:
|
||||
return EditorApplication.applicationPath;
|
||||
default:
|
||||
throw new System.NotImplementedException("Platform has not supported yet ;(");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is this project being opened by an Unity editor?
|
||||
/// </summary>
|
||||
/// <param name="projectPath"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsCloneProjectRunning(string projectPath)
|
||||
{
|
||||
|
||||
//Determine whether it is opened in another instance by checking the UnityLockFile
|
||||
string UnityLockFilePath = new string[] { projectPath, "Temp", "UnityLockfile" }
|
||||
.Aggregate(Path.Combine);
|
||||
|
||||
switch (Application.platform)
|
||||
{
|
||||
case (RuntimePlatform.WindowsEditor):
|
||||
//Windows editor will lock "UnityLockfile" file when project is being opened.
|
||||
//Sometime, for instance: windows editor crash, the "UnityLockfile" will not be deleted even the project
|
||||
//isn't being opened, so a check to the "UnityLockfile" lock status may be necessary.
|
||||
if (Preferences.AlsoCheckUnityLockFileStaPref.Value)
|
||||
return File.Exists(UnityLockFilePath) && FileUtilities.IsFileLocked(UnityLockFilePath);
|
||||
else
|
||||
return File.Exists(UnityLockFilePath);
|
||||
case (RuntimePlatform.OSXEditor):
|
||||
//Mac editor won't lock "UnityLockfile" file when project is being opened
|
||||
return File.Exists(UnityLockFilePath);
|
||||
case (RuntimePlatform.LinuxEditor):
|
||||
return File.Exists(UnityLockFilePath);
|
||||
default:
|
||||
throw new System.NotImplementedException("IsCloneProjectRunning: Unsupport Platfrom: " + Application.platform);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the clone of the currently open project, if such exists.
|
||||
/// </summary>
|
||||
public static void DeleteClone(string cloneProjectPath)
|
||||
{
|
||||
/// Clone won't be able to delete itself.
|
||||
if (ClonesManager.IsClone()) return;
|
||||
|
||||
///Extra precautions.
|
||||
if (cloneProjectPath == string.Empty) return;
|
||||
if (cloneProjectPath == ClonesManager.GetOriginalProjectPath()) return;
|
||||
|
||||
//Check what OS is
|
||||
string identifierFile;
|
||||
string args;
|
||||
switch (Application.platform)
|
||||
{
|
||||
case (RuntimePlatform.WindowsEditor):
|
||||
Debug.Log("Attempting to delete folder \"" + cloneProjectPath + "\"");
|
||||
|
||||
//The argument file will be deleted first at the beginning of the project deletion process
|
||||
//to prevent any further reading and writing to it(There's a File.Exist() check at the (file)editor windows.)
|
||||
//If there's any file in the directory being write/read during the deletion process, the directory can't be fully removed.
|
||||
identifierFile = Path.Combine(cloneProjectPath, ClonesManager.ArgumentFileName);
|
||||
File.Delete(identifierFile);
|
||||
|
||||
args = "/c " + @"rmdir /s/q " + string.Format("\"{0}\"", cloneProjectPath);
|
||||
StartHiddenConsoleProcess("cmd.exe", args);
|
||||
|
||||
break;
|
||||
case (RuntimePlatform.OSXEditor):
|
||||
Debug.Log("Attempting to delete folder \"" + cloneProjectPath + "\"");
|
||||
|
||||
//The argument file will be deleted first at the beginning of the project deletion process
|
||||
//to prevent any further reading and writing to it(There's a File.Exist() check at the (file)editor windows.)
|
||||
//If there's any file in the directory being write/read during the deletion process, the directory can't be fully removed.
|
||||
identifierFile = Path.Combine(cloneProjectPath, ClonesManager.ArgumentFileName);
|
||||
File.Delete(identifierFile);
|
||||
|
||||
FileUtil.DeleteFileOrDirectory(cloneProjectPath);
|
||||
|
||||
break;
|
||||
case (RuntimePlatform.LinuxEditor):
|
||||
Debug.Log("Attempting to delete folder \"" + cloneProjectPath + "\"");
|
||||
identifierFile = Path.Combine(cloneProjectPath, ClonesManager.ArgumentFileName);
|
||||
File.Delete(identifierFile);
|
||||
|
||||
FileUtil.DeleteFileOrDirectory(cloneProjectPath);
|
||||
|
||||
break;
|
||||
default:
|
||||
Debug.LogWarning("Not in a known editor. Where are you!?");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Creating project folders
|
||||
|
||||
/// <summary>
|
||||
/// Creates an empty folder using data in the given Project object
|
||||
/// </summary>
|
||||
/// <param name="project"></param>
|
||||
public static void CreateProjectFolder(Project project)
|
||||
{
|
||||
string path = project.projectPath;
|
||||
Debug.Log("Creating new empty folder at: " + path);
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the full contents of the unity library. We want to do this to avoid the lengthy re-serialization of the whole project when it opens up the clone.
|
||||
/// </summary>
|
||||
/// <param name="sourceProject"></param>
|
||||
/// <param name="destinationProject"></param>
|
||||
[System.Obsolete]
|
||||
public static void CopyLibraryFolder(Project sourceProject, Project destinationProject)
|
||||
{
|
||||
if (Directory.Exists(destinationProject.libraryPath))
|
||||
{
|
||||
Debug.LogWarning("Library copy: destination path already exists! ");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("Library copy: " + destinationProject.libraryPath);
|
||||
ClonesManager.CopyDirectoryWithProgressBar(sourceProject.libraryPath, destinationProject.libraryPath,
|
||||
"Cloning project '" + sourceProject.name + "'. ");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Creating symlinks
|
||||
|
||||
/// <summary>
|
||||
/// Creates a symlink between destinationPath and sourcePath (Mac version).
|
||||
/// </summary>
|
||||
/// <param name="sourcePath"></param>
|
||||
/// <param name="destinationPath"></param>
|
||||
private static void CreateLinkMac(string sourcePath, string destinationPath)
|
||||
{
|
||||
sourcePath = sourcePath.Replace(" ", "\\ ");
|
||||
destinationPath = destinationPath.Replace(" ", "\\ ");
|
||||
var command = string.Format("ln -s {0} {1}", sourcePath, destinationPath);
|
||||
|
||||
Debug.Log("Mac hard link " + command);
|
||||
|
||||
ClonesManager.ExecuteBashCommand(command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a symlink between destinationPath and sourcePath (Linux version).
|
||||
/// </summary>
|
||||
/// <param name="sourcePath"></param>
|
||||
/// <param name="destinationPath"></param>
|
||||
private static void CreateLinkLinux(string sourcePath, string destinationPath)
|
||||
{
|
||||
sourcePath = sourcePath.Replace(" ", "\\ ");
|
||||
destinationPath = destinationPath.Replace(" ", "\\ ");
|
||||
var command = string.Format("ln -s {0} {1}", sourcePath, destinationPath);
|
||||
|
||||
Debug.Log("Linux Symlink " + command);
|
||||
|
||||
ClonesManager.ExecuteBashCommand(command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a symlink between destinationPath and sourcePath (Windows version).
|
||||
/// </summary>
|
||||
/// <param name="sourcePath"></param>
|
||||
/// <param name="destinationPath"></param>
|
||||
private static void CreateLinkWin(string sourcePath, string destinationPath)
|
||||
{
|
||||
string cmd = "/C mklink /J " + string.Format("\"{0}\" \"{1}\"", destinationPath, sourcePath);
|
||||
Debug.Log("Windows junction: " + cmd);
|
||||
ClonesManager.StartHiddenConsoleProcess("cmd.exe", cmd);
|
||||
}
|
||||
|
||||
//TODO(?) avoid terminal calls and use proper api stuff. See below for windows!
|
||||
////https://docs.microsoft.com/en-us/windows/desktop/api/ioapiset/nf-ioapiset-deviceiocontrol
|
||||
//[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
//private static extern bool DeviceIoControl(System.IntPtr hDevice, uint dwIoControlCode,
|
||||
// System.IntPtr InBuffer, int nInBufferSize,
|
||||
// System.IntPtr OutBuffer, int nOutBufferSize,
|
||||
// out int pBytesReturned, System.IntPtr lpOverlapped);
|
||||
|
||||
/// <summary>
|
||||
/// Create a link / junction from the original project to it's clone.
|
||||
/// </summary>
|
||||
/// <param name="sourcePath"></param>
|
||||
/// <param name="destinationPath"></param>
|
||||
public static void LinkFolders(string sourcePath, string destinationPath)
|
||||
{
|
||||
if ((Directory.Exists(destinationPath) == false) && (Directory.Exists(sourcePath) == true))
|
||||
{
|
||||
switch (Application.platform)
|
||||
{
|
||||
case (RuntimePlatform.WindowsEditor):
|
||||
CreateLinkWin(sourcePath, destinationPath);
|
||||
break;
|
||||
case (RuntimePlatform.OSXEditor):
|
||||
CreateLinkMac(sourcePath, destinationPath);
|
||||
break;
|
||||
case (RuntimePlatform.LinuxEditor):
|
||||
CreateLinkLinux(sourcePath, destinationPath);
|
||||
break;
|
||||
default:
|
||||
Debug.LogWarning("Not in a known editor. Application.platform: " + Application.platform);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Skipping Asset link, it already exists: " + destinationPath);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utility methods
|
||||
|
||||
private static bool? isCloneFileExistCache = null;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the project currently open in Unity Editor is a clone.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool IsClone()
|
||||
{
|
||||
if (isCloneFileExistCache == null)
|
||||
{
|
||||
/// The project is a clone if its root directory contains an empty file named ".clone".
|
||||
string cloneFilePath = Path.Combine(ClonesManager.GetCurrentProjectPath(), ClonesManager.CloneFileName);
|
||||
isCloneFileExistCache = File.Exists(cloneFilePath);
|
||||
}
|
||||
|
||||
return (bool)isCloneFileExistCache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the path to the current unityEditor project folder's info
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetCurrentProjectPath()
|
||||
{
|
||||
return Application.dataPath.Replace("/Assets", "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a project object that describes all the paths we need to clone it.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Project GetCurrentProject()
|
||||
{
|
||||
string pathString = ClonesManager.GetCurrentProjectPath();
|
||||
return new Project(pathString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the argument of this clone project.
|
||||
/// If this is the original project, will return an empty string.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetArgument()
|
||||
{
|
||||
string argument = "";
|
||||
if (IsClone())
|
||||
{
|
||||
string argumentFilePath = Path.Combine(GetCurrentProjectPath(), ClonesManager.ArgumentFileName);
|
||||
if (File.Exists(argumentFilePath))
|
||||
{
|
||||
argument = File.ReadAllText(argumentFilePath, System.Text.Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path to the original project.
|
||||
/// If currently open project is the original, returns its own path.
|
||||
/// If the original project folder cannot be found, retuns an empty string.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetOriginalProjectPath()
|
||||
{
|
||||
if (IsClone())
|
||||
{
|
||||
/// If this is a clone...
|
||||
/// Original project path can be deduced by removing the suffix from the clone's path.
|
||||
string cloneProjectPath = ClonesManager.GetCurrentProject().projectPath;
|
||||
|
||||
int index = cloneProjectPath.LastIndexOf(ClonesManager.CloneNameSuffix);
|
||||
if (index > 0)
|
||||
{
|
||||
string originalProjectPath = cloneProjectPath.Substring(0, index);
|
||||
if (Directory.Exists(originalProjectPath)) return originalProjectPath;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// If this is the original, we return its own path.
|
||||
return ClonesManager.GetCurrentProjectPath();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all clone projects path.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<string> GetCloneProjectsPath()
|
||||
{
|
||||
List<string> projectsPath = new List<string>();
|
||||
for (int i = 0; i < MaxCloneProjectCount; i++)
|
||||
{
|
||||
string originalProjectPath = ClonesManager.GetCurrentProject().projectPath;
|
||||
string cloneProjectPath = originalProjectPath + ClonesManager.CloneNameSuffix + "_" + i;
|
||||
|
||||
if (Directory.Exists(cloneProjectPath))
|
||||
projectsPath.Add(cloneProjectPath);
|
||||
}
|
||||
|
||||
return projectsPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies directory located at sourcePath to destinationPath. Displays a progress bar.
|
||||
/// </summary>
|
||||
/// <param name="source">Directory to be copied.</param>
|
||||
/// <param name="destination">Destination directory (created automatically if needed).</param>
|
||||
/// <param name="progressBarPrefix">Optional string added to the beginning of the progress bar window header.</param>
|
||||
public static void CopyDirectoryWithProgressBar(string sourcePath, string destinationPath,
|
||||
string progressBarPrefix = "")
|
||||
{
|
||||
var source = new DirectoryInfo(sourcePath);
|
||||
var destination = new DirectoryInfo(destinationPath);
|
||||
|
||||
long totalBytes = 0;
|
||||
long copiedBytes = 0;
|
||||
|
||||
ClonesManager.CopyDirectoryWithProgressBarRecursive(source, destination, ref totalBytes, ref copiedBytes,
|
||||
progressBarPrefix);
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies directory located at sourcePath to destinationPath. Displays a progress bar.
|
||||
/// Same as the previous method, but uses recursion to copy all nested folders as well.
|
||||
/// </summary>
|
||||
/// <param name="source">Directory to be copied.</param>
|
||||
/// <param name="destination">Destination directory (created automatically if needed).</param>
|
||||
/// <param name="totalBytes">Total bytes to be copied. Calculated automatically, initialize at 0.</param>
|
||||
/// <param name="copiedBytes">To track already copied bytes. Calculated automatically, initialize at 0.</param>
|
||||
/// <param name="progressBarPrefix">Optional string added to the beginning of the progress bar window header.</param>
|
||||
private static void CopyDirectoryWithProgressBarRecursive(DirectoryInfo source, DirectoryInfo destination,
|
||||
ref long totalBytes, ref long copiedBytes, string progressBarPrefix = "")
|
||||
{
|
||||
/// Directory cannot be copied into itself.
|
||||
if (source.FullName.ToLower() == destination.FullName.ToLower())
|
||||
{
|
||||
Debug.LogError("Cannot copy directory into itself.");
|
||||
return;
|
||||
}
|
||||
|
||||
/// Calculate total bytes, if required.
|
||||
if (totalBytes == 0)
|
||||
{
|
||||
totalBytes = ClonesManager.GetDirectorySize(source, true, progressBarPrefix);
|
||||
}
|
||||
|
||||
/// Create destination directory, if required.
|
||||
if (!Directory.Exists(destination.FullName))
|
||||
{
|
||||
Directory.CreateDirectory(destination.FullName);
|
||||
}
|
||||
|
||||
/// Copy all files from the source.
|
||||
foreach (FileInfo file in source.GetFiles())
|
||||
{
|
||||
try
|
||||
{
|
||||
file.CopyTo(Path.Combine(destination.ToString(), file.Name), true);
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
/// Some files may throw IOException if they are currently open in Unity editor.
|
||||
/// Just ignore them in such case.
|
||||
}
|
||||
|
||||
/// Account the copied file size.
|
||||
copiedBytes += file.Length;
|
||||
|
||||
/// Display the progress bar.
|
||||
float progress = (float)copiedBytes / (float)totalBytes;
|
||||
bool cancelCopy = EditorUtility.DisplayCancelableProgressBar(
|
||||
progressBarPrefix + "Copying '" + source.FullName + "' to '" + destination.FullName + "'...",
|
||||
"(" + (progress * 100f).ToString("F2") + "%) Copying file '" + file.Name + "'...",
|
||||
progress);
|
||||
if (cancelCopy) return;
|
||||
}
|
||||
|
||||
/// Copy all nested directories from the source.
|
||||
foreach (DirectoryInfo sourceNestedDir in source.GetDirectories())
|
||||
{
|
||||
DirectoryInfo nextDestingationNestedDir = destination.CreateSubdirectory(sourceNestedDir.Name);
|
||||
ClonesManager.CopyDirectoryWithProgressBarRecursive(sourceNestedDir, nextDestingationNestedDir,
|
||||
ref totalBytes, ref copiedBytes, progressBarPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the size of the given directory. Displays a progress bar.
|
||||
/// </summary>
|
||||
/// <param name="directory">Directory, which size has to be calculated.</param>
|
||||
/// <param name="includeNested">If true, size will include all nested directories.</param>
|
||||
/// <param name="progressBarPrefix">Optional string added to the beginning of the progress bar window header.</param>
|
||||
/// <returns>Size of the directory in bytes.</returns>
|
||||
private static long GetDirectorySize(DirectoryInfo directory, bool includeNested = false,
|
||||
string progressBarPrefix = "")
|
||||
{
|
||||
EditorUtility.DisplayProgressBar(progressBarPrefix + "Calculating size of directories...",
|
||||
"Scanning '" + directory.FullName + "'...", 0f);
|
||||
|
||||
/// Calculate size of all files in directory.
|
||||
long filesSize = directory.GetFiles().Sum((FileInfo file) => file.Length);
|
||||
|
||||
/// Calculate size of all nested directories.
|
||||
long directoriesSize = 0;
|
||||
if (includeNested)
|
||||
{
|
||||
IEnumerable<DirectoryInfo> nestedDirectories = directory.GetDirectories();
|
||||
foreach (DirectoryInfo nestedDir in nestedDirectories)
|
||||
{
|
||||
directoriesSize += ClonesManager.GetDirectorySize(nestedDir, true, progressBarPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
return filesSize + directoriesSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts process in the system console, taking the given fileName and args.
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="args"></param>
|
||||
private static void StartHiddenConsoleProcess(string fileName, string args)
|
||||
{
|
||||
System.Diagnostics.Process.Start(fileName, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Thanks to https://github.com/karl-/unity-symlink-utility/blob/master/SymlinkUtility.cs
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
private static void ExecuteBashCommand(string command)
|
||||
{
|
||||
command = command.Replace("\"", "\"\"");
|
||||
|
||||
var proc = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "/bin/bash",
|
||||
Arguments = "-c \"" + command + "\"",
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
};
|
||||
|
||||
using (proc)
|
||||
{
|
||||
proc.Start();
|
||||
proc.WaitForExit();
|
||||
|
||||
if (!proc.StandardError.EndOfStream)
|
||||
{
|
||||
UnityEngine.Debug.LogError(proc.StandardError.ReadToEnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void OpenProjectInFileExplorer(string path)
|
||||
{
|
||||
System.Diagnostics.Process.Start(@path);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
11
Assets/ParrelSync/ParrelSync/Editor/ClonesManager.cs.meta
Normal file
11
Assets/ParrelSync/ParrelSync/Editor/ClonesManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6148e48ed6b61d748b187d06d3687b83
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
198
Assets/ParrelSync/ParrelSync/Editor/ClonesManagerWindow.cs
Normal file
198
Assets/ParrelSync/ParrelSync/Editor/ClonesManagerWindow.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.IO;
|
||||
|
||||
namespace ParrelSync
|
||||
{
|
||||
/// <summary>
|
||||
///Clones manager Unity editor window
|
||||
/// </summary>
|
||||
public class ClonesManagerWindow : EditorWindow
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns true if project clone exists.
|
||||
/// </summary>
|
||||
public bool isCloneCreated
|
||||
{
|
||||
get { return ClonesManager.GetCloneProjectsPath().Count >= 1; }
|
||||
}
|
||||
|
||||
[MenuItem("ParrelSync/Clones Manager", priority = 0)]
|
||||
private static void InitWindow()
|
||||
{
|
||||
ClonesManagerWindow window = (ClonesManagerWindow)EditorWindow.GetWindow(typeof(ClonesManagerWindow));
|
||||
window.titleContent = new GUIContent("Clones Manager");
|
||||
window.Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For storing the scroll position of clones list
|
||||
/// </summary>
|
||||
Vector2 clonesScrollPos;
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
/// If it is a clone project...
|
||||
if (ClonesManager.IsClone())
|
||||
{
|
||||
//Find out the original project name and show the help box
|
||||
string originalProjectPath = ClonesManager.GetOriginalProjectPath();
|
||||
if (originalProjectPath == string.Empty)
|
||||
{
|
||||
/// If original project cannot be found, display warning message.
|
||||
EditorGUILayout.HelpBox(
|
||||
"This project is a clone, but the link to the original seems lost.\nYou have to manually open the original and create a new clone instead of this one.\n",
|
||||
MessageType.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
/// If original project is present, display some usage info.
|
||||
EditorGUILayout.HelpBox(
|
||||
"This project is a clone of the project '" + Path.GetFileName(originalProjectPath) + "'.\nIf you want to make changes the project files or manage clones, please open the original project through Unity Hub.",
|
||||
MessageType.Info);
|
||||
}
|
||||
|
||||
//Clone project custom argument.
|
||||
GUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Arguments", GUILayout.Width(70));
|
||||
if (GUILayout.Button("?", GUILayout.Width(20)))
|
||||
{
|
||||
Application.OpenURL(ExternalLinks.CustomArgumentHelpLink);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
string argumentFilePath = Path.Combine(ClonesManager.GetCurrentProjectPath(), ClonesManager.ArgumentFileName);
|
||||
//Need to be careful with file reading / writing since it will effect the deletion of
|
||||
// the clone project(The directory won't be fully deleted if there's still file inside being read or write).
|
||||
//The argument file will be deleted first at the beginning of the project deletion process
|
||||
//to prevent any further being read and write.
|
||||
//Will need to take some extra cautious if want to change the design of how file editing is handled.
|
||||
if (File.Exists(argumentFilePath))
|
||||
{
|
||||
string argument = File.ReadAllText(argumentFilePath, System.Text.Encoding.UTF8);
|
||||
string argumentTextAreaInput = EditorGUILayout.TextArea(argument,
|
||||
GUILayout.Height(50),
|
||||
GUILayout.MaxWidth(300)
|
||||
);
|
||||
File.WriteAllText(argumentFilePath, argumentTextAreaInput, System.Text.Encoding.UTF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("No argument file found.");
|
||||
}
|
||||
}
|
||||
else// If it is an original project...
|
||||
{
|
||||
if (isCloneCreated)
|
||||
{
|
||||
GUILayout.BeginVertical("HelpBox");
|
||||
GUILayout.Label("Clones of this Project");
|
||||
|
||||
//List all clones
|
||||
clonesScrollPos =
|
||||
EditorGUILayout.BeginScrollView(clonesScrollPos);
|
||||
var cloneProjectsPath = ClonesManager.GetCloneProjectsPath();
|
||||
for (int i = 0; i < cloneProjectsPath.Count; i++)
|
||||
{
|
||||
|
||||
GUILayout.BeginVertical("GroupBox");
|
||||
string cloneProjectPath = cloneProjectsPath[i];
|
||||
|
||||
bool isOpenInAnotherInstance = ClonesManager.IsCloneProjectRunning(cloneProjectPath);
|
||||
|
||||
if (isOpenInAnotherInstance == true)
|
||||
EditorGUILayout.LabelField("Clone " + i + " (Running)", EditorStyles.boldLabel);
|
||||
else
|
||||
EditorGUILayout.LabelField("Clone " + i);
|
||||
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
EditorGUILayout.TextField("Clone project path", cloneProjectPath, EditorStyles.textField);
|
||||
if (GUILayout.Button("View Folder", GUILayout.Width(80)))
|
||||
{
|
||||
ClonesManager.OpenProjectInFileExplorer(cloneProjectPath);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Arguments", GUILayout.Width(70));
|
||||
if (GUILayout.Button("?", GUILayout.Width(20)))
|
||||
{
|
||||
Application.OpenURL(ExternalLinks.CustomArgumentHelpLink);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
string argumentFilePath = Path.Combine(cloneProjectPath, ClonesManager.ArgumentFileName);
|
||||
//Need to be careful with file reading/writing since it will effect the deletion of
|
||||
//the clone project(The directory won't be fully deleted if there's still file inside being read or write).
|
||||
//The argument file will be deleted first at the beginning of the project deletion process
|
||||
//to prevent any further being read and write.
|
||||
//Will need to take some extra cautious if want to change the design of how file editing is handled.
|
||||
if (File.Exists(argumentFilePath))
|
||||
{
|
||||
string argument = File.ReadAllText(argumentFilePath, System.Text.Encoding.UTF8);
|
||||
string argumentTextAreaInput = EditorGUILayout.TextArea(argument,
|
||||
GUILayout.Height(50),
|
||||
GUILayout.MaxWidth(300)
|
||||
);
|
||||
File.WriteAllText(argumentFilePath, argumentTextAreaInput, System.Text.Encoding.UTF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("No argument file found.");
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
|
||||
EditorGUI.BeginDisabledGroup(isOpenInAnotherInstance);
|
||||
|
||||
if (GUILayout.Button("Open in New Editor"))
|
||||
{
|
||||
ClonesManager.OpenProject(cloneProjectPath);
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Delete"))
|
||||
{
|
||||
bool delete = EditorUtility.DisplayDialog(
|
||||
"Delete the clone?",
|
||||
"Are you sure you want to delete the clone project '" + ClonesManager.GetCurrentProject().name + "_clone'?",
|
||||
"Delete",
|
||||
"Cancel");
|
||||
if (delete)
|
||||
{
|
||||
ClonesManager.DeleteClone(cloneProjectPath);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
EditorGUI.EndDisabledGroup();
|
||||
GUILayout.EndVertical();
|
||||
|
||||
}
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
if (GUILayout.Button("Add new clone"))
|
||||
{
|
||||
ClonesManager.CreateCloneFromCurrent();
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
else
|
||||
{
|
||||
/// If no clone created yet, we must create it.
|
||||
EditorGUILayout.HelpBox("No project clones found. Create a new one!", MessageType.Info);
|
||||
if (GUILayout.Button("Create new clone"))
|
||||
{
|
||||
ClonesManager.CreateCloneFromCurrent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a041d83486c20b84bbf5077ddfbbca37
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
13
Assets/ParrelSync/ParrelSync/Editor/ExternalLinks.cs
Normal file
13
Assets/ParrelSync/ParrelSync/Editor/ExternalLinks.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace ParrelSync
|
||||
{
|
||||
public class ExternalLinks
|
||||
{
|
||||
public const string RemoteVersionURL = "https://raw.githubusercontent.com/VeriorPies/ParrelSync/master/VERSION.txt";
|
||||
public const string Releases = "https://github.com/VeriorPies/ParrelSync/releases";
|
||||
public const string CustomArgumentHelpLink = "https://github.com/VeriorPies/ParrelSync/wiki/Argument";
|
||||
|
||||
public const string GitHubHome = "https://github.com/VeriorPies/ParrelSync/";
|
||||
public const string GitHubIssue = "https://github.com/VeriorPies/ParrelSync/issues";
|
||||
public const string FAQ = "https://github.com/VeriorPies/ParrelSync/wiki/Troubleshooting-&-FAQs";
|
||||
}
|
||||
}
|
||||
11
Assets/ParrelSync/ParrelSync/Editor/ExternalLinks.cs.meta
Normal file
11
Assets/ParrelSync/ParrelSync/Editor/ExternalLinks.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 65daf17fbe5101b41977305639f30c65
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
31
Assets/ParrelSync/ParrelSync/Editor/FileUtilities.cs
Normal file
31
Assets/ParrelSync/ParrelSync/Editor/FileUtilities.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ParrelSync
|
||||
{
|
||||
public class FileUtilities : MonoBehaviour
|
||||
{
|
||||
public static bool IsFileLocked(string path)
|
||||
{
|
||||
FileInfo file = new FileInfo(path);
|
||||
try
|
||||
{
|
||||
using (FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
//the file is unavailable because it is:
|
||||
//still being written to
|
||||
//or being processed by another thread
|
||||
//or does not exist (has already been processed)
|
||||
return true;
|
||||
}
|
||||
|
||||
//file is not locked
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/ParrelSync/ParrelSync/Editor/FileUtilities.cs.meta
Normal file
11
Assets/ParrelSync/ParrelSync/Editor/FileUtilities.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11fdc6f78f8c965499a870ca06dca6bc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/ParrelSync/ParrelSync/Editor/NonCore.meta
Normal file
8
Assets/ParrelSync/ParrelSync/Editor/NonCore.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74a7aa389726f964ab34c52e208c2a43
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,78 @@
|
||||
namespace ParrelSync.NonCore
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// A simple script to display feedback/star dialog after certain time of project being opened/re-compiled.
|
||||
/// Will only pop-up once unless "Remind me next time" are chosen.
|
||||
/// Removing this file from project wont effect any other functions.
|
||||
/// </summary>
|
||||
[InitializeOnLoad]
|
||||
public class AskFeedbackDialog
|
||||
{
|
||||
const string InitializeOnLoadCountKey = "ParrelSync_InitOnLoadCount", StopShowingKey = "ParrelSync_StopShowFeedBack";
|
||||
static AskFeedbackDialog()
|
||||
{
|
||||
if (EditorPrefs.HasKey(StopShowingKey)) { return; }
|
||||
|
||||
int InitializeOnLoadCount = EditorPrefs.GetInt(InitializeOnLoadCountKey, 0);
|
||||
if (InitializeOnLoadCount > 20)
|
||||
{
|
||||
ShowDialog();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorPrefs.SetInt(InitializeOnLoadCountKey, InitializeOnLoadCount + 1);
|
||||
}
|
||||
}
|
||||
|
||||
//[MenuItem("ParrelSync/(Debug)Show AskFeedbackDialog ")]
|
||||
private static void ShowDialog()
|
||||
{
|
||||
int option = EditorUtility.DisplayDialogComplex("Do you like " + ParrelSync.ClonesManager.ProjectName + "?",
|
||||
"Do you like " + ParrelSync.ClonesManager.ProjectName + "?\n" +
|
||||
"If so, please don't hesitate to star it on GitHub and contribute to the project!",
|
||||
"Star on GitHub",
|
||||
"Close",
|
||||
"Remind me next time"
|
||||
);
|
||||
|
||||
switch (option)
|
||||
{
|
||||
// First parameter.
|
||||
case 0:
|
||||
Debug.Log("AskFeedbackDialog: Star on GitHub selected");
|
||||
EditorPrefs.SetBool(StopShowingKey, true);
|
||||
EditorPrefs.DeleteKey(InitializeOnLoadCountKey);
|
||||
Application.OpenURL(ExternalLinks.GitHubHome);
|
||||
break;
|
||||
// Second parameter.
|
||||
case 1:
|
||||
Debug.Log("AskFeedbackDialog: Close and never show again.");
|
||||
EditorPrefs.SetBool(StopShowingKey, true);
|
||||
EditorPrefs.DeleteKey(InitializeOnLoadCountKey);
|
||||
break;
|
||||
// Third parameter.
|
||||
case 2:
|
||||
Debug.Log("AskFeedbackDialog: Remind me next time");
|
||||
EditorPrefs.SetInt(InitializeOnLoadCountKey, 0);
|
||||
break;
|
||||
default:
|
||||
//Debug.Log("Close windows.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// For debug purpose
|
||||
///// </summary>
|
||||
//[MenuItem("ParrelSync/(Debug)Delete AskFeedbackDialog keys")]
|
||||
//private static void DebugDeleteAllKeys()
|
||||
//{
|
||||
// EditorPrefs.DeleteKey(InitializeOnLoadCountKey);
|
||||
// EditorPrefs.DeleteKey(StopShowingKey);
|
||||
// Debug.Log("AskFeedbackDialog keys deleted");
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 894412a5b602e6c4ba2cf2d01f4f92b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
26
Assets/ParrelSync/ParrelSync/Editor/NonCore/OtherMenuItem.cs
Normal file
26
Assets/ParrelSync/ParrelSync/Editor/NonCore/OtherMenuItem.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace ParrelSync.NonCore
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public class OtherMenuItem
|
||||
{
|
||||
[MenuItem("ParrelSync/GitHub/View this project on GitHub", priority = 10)]
|
||||
private static void OpenGitHub()
|
||||
{
|
||||
Application.OpenURL(ExternalLinks.GitHubHome);
|
||||
}
|
||||
|
||||
[MenuItem("ParrelSync/GitHub/View FAQ", priority = 11)]
|
||||
private static void OpenFAQ()
|
||||
{
|
||||
Application.OpenURL(ExternalLinks.FAQ);
|
||||
}
|
||||
|
||||
[MenuItem("ParrelSync/GitHub/View Issues", priority = 12)]
|
||||
private static void OpenGitHubIssues()
|
||||
{
|
||||
Application.OpenURL(ExternalLinks.GitHubIssue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7191fa4bfa12ae749b27f73ed292eaf1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
110
Assets/ParrelSync/ParrelSync/Editor/Preferences.cs
Normal file
110
Assets/ParrelSync/ParrelSync/Editor/Preferences.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace ParrelSync
|
||||
{
|
||||
/// <summary>
|
||||
/// To add value caching for <see cref="EditorPrefs"/> functions
|
||||
/// </summary>
|
||||
public class BoolPreference
|
||||
{
|
||||
public string key { get; private set; }
|
||||
public bool defaultValue { get; private set; }
|
||||
public BoolPreference(string key, bool defaultValue)
|
||||
{
|
||||
this.key = key;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
private bool? valueCache = null;
|
||||
|
||||
public bool Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (valueCache == null)
|
||||
valueCache = EditorPrefs.GetBool(key, defaultValue);
|
||||
|
||||
return (bool)valueCache;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (valueCache == value)
|
||||
return;
|
||||
|
||||
EditorPrefs.SetBool(key, value);
|
||||
valueCache = value;
|
||||
Debug.Log("Editor preference updated. key: " + key + ", value: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearValue()
|
||||
{
|
||||
EditorPrefs.DeleteKey(key);
|
||||
valueCache = null;
|
||||
}
|
||||
}
|
||||
|
||||
public class Preferences : EditorWindow
|
||||
{
|
||||
[MenuItem("ParrelSync/Preferences", priority = 1)]
|
||||
private static void InitWindow()
|
||||
{
|
||||
Preferences window = (Preferences)EditorWindow.GetWindow(typeof(Preferences));
|
||||
window.titleContent = new GUIContent(ClonesManager.ProjectName + " Preferences");
|
||||
window.Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disable asset saving in clone editors?
|
||||
/// </summary>
|
||||
public static BoolPreference AssetModPref = new BoolPreference("ParrelSync_DisableClonesAssetSaving", true);
|
||||
|
||||
/// <summary>
|
||||
/// In addition of checking the existence of UnityLockFile,
|
||||
/// also check is the is the UnityLockFile being opened.
|
||||
/// </summary>
|
||||
public static BoolPreference AlsoCheckUnityLockFileStaPref = new BoolPreference("ParrelSync_CheckUnityLockFileOpenStatus", true);
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (ClonesManager.IsClone())
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
"This is a clone project. Please use the original project editor to change preferences.",
|
||||
MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
GUILayout.BeginVertical("HelpBox");
|
||||
GUILayout.Label("Preferences");
|
||||
GUILayout.BeginVertical("GroupBox");
|
||||
|
||||
AssetModPref.Value = EditorGUILayout.ToggleLeft(
|
||||
new GUIContent(
|
||||
"(recommended) Disable asset saving in clone editors- require re-open clone editors",
|
||||
"Disable asset saving in clone editors so all assets can only be modified from the original project editor"
|
||||
),
|
||||
AssetModPref.Value);
|
||||
|
||||
if (Application.platform == RuntimePlatform.WindowsEditor)
|
||||
{
|
||||
AlsoCheckUnityLockFileStaPref.Value = EditorGUILayout.ToggleLeft(
|
||||
new GUIContent(
|
||||
"Also check UnityLockFile lock status while checking clone projects running status",
|
||||
"Disable this can slightly increase Clones Manager window performance, but will lead to in-correct clone project running status" +
|
||||
"(the Clones Manager window show the clone project is still running even it's not) if the clone editor crashed"
|
||||
),
|
||||
AlsoCheckUnityLockFileStaPref.Value);
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
if (GUILayout.Button("Reset to default"))
|
||||
{
|
||||
AssetModPref.ClearValue();
|
||||
AlsoCheckUnityLockFileStaPref.ClearValue();
|
||||
Debug.Log("Editor preferences cleared");
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/ParrelSync/ParrelSync/Editor/Preferences.cs.meta
Normal file
11
Assets/ParrelSync/ParrelSync/Editor/Preferences.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24641be1c0410a745b529e61b508679f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
112
Assets/ParrelSync/ParrelSync/Editor/Project.cs
Normal file
112
Assets/ParrelSync/ParrelSync/Editor/Project.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ParrelSync
|
||||
{
|
||||
public class Project : System.ICloneable
|
||||
{
|
||||
public string name;
|
||||
public string projectPath;
|
||||
string rootPath;
|
||||
public string assetPath;
|
||||
public string projectSettingsPath;
|
||||
public string libraryPath;
|
||||
public string packagesPath;
|
||||
public string autoBuildPath;
|
||||
public string localPackages;
|
||||
|
||||
char[] separator = new char[1] { '/' };
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Project()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the project object by parsing its full path returned by Unity into a bunch of individual folder names and paths.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
public Project(string path)
|
||||
{
|
||||
ParsePath(path);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new object with the same settings
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public object Clone()
|
||||
{
|
||||
Project newProject = new Project();
|
||||
newProject.rootPath = rootPath;
|
||||
newProject.projectPath = projectPath;
|
||||
newProject.assetPath = assetPath;
|
||||
newProject.projectSettingsPath = projectSettingsPath;
|
||||
newProject.libraryPath = libraryPath;
|
||||
newProject.name = name;
|
||||
newProject.separator = separator;
|
||||
newProject.packagesPath = packagesPath;
|
||||
newProject.autoBuildPath = autoBuildPath;
|
||||
newProject.localPackages = localPackages;
|
||||
|
||||
|
||||
return newProject;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Update the project object by renaming and reparsing it. Pass in the new name of a project, and it'll update the other member variables to match.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
public void updateNewName(string newName)
|
||||
{
|
||||
name = newName;
|
||||
ParsePath(rootPath + "/" + name + "/Assets");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Debug override so we can quickly print out the project info.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
string printString = name + "\n" +
|
||||
rootPath + "\n" +
|
||||
projectPath + "\n" +
|
||||
assetPath + "\n" +
|
||||
projectSettingsPath + "\n" +
|
||||
packagesPath + "\n" +
|
||||
autoBuildPath + "\n" +
|
||||
localPackages + "\n" +
|
||||
libraryPath;
|
||||
return (printString);
|
||||
}
|
||||
|
||||
private void ParsePath(string path)
|
||||
{
|
||||
//Unity's Application functions return the Assets path in the Editor.
|
||||
projectPath = path;
|
||||
|
||||
//pop off the last part of the path for the project name, keep the rest for the root path
|
||||
List<string> pathArray = projectPath.Split(separator).ToList<string>();
|
||||
name = pathArray.Last();
|
||||
|
||||
pathArray.RemoveAt(pathArray.Count() - 1);
|
||||
rootPath = string.Join(separator[0].ToString(), pathArray.ToArray());
|
||||
|
||||
assetPath = projectPath + "/Assets";
|
||||
projectSettingsPath = projectPath + "/ProjectSettings";
|
||||
libraryPath = projectPath + "/Library";
|
||||
packagesPath = projectPath + "/Packages";
|
||||
autoBuildPath = projectPath + "/AutoBuild";
|
||||
localPackages = projectPath + "/LocalPackages";
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/ParrelSync/ParrelSync/Editor/Project.cs.meta
Normal file
11
Assets/ParrelSync/ParrelSync/Editor/Project.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec8d3a1577179ef44815739178cf75b4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
60
Assets/ParrelSync/ParrelSync/Editor/UpdateChecker.cs
Normal file
60
Assets/ParrelSync/ParrelSync/Editor/UpdateChecker.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
namespace ParrelSync.Update
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple update checker
|
||||
/// </summary>
|
||||
public class UpdateChecker
|
||||
{
|
||||
//const string LocalVersionFilePath = "Assets/ParrelSync/VERSION.txt";
|
||||
public const string LocalVersion = "1.5.0";
|
||||
[MenuItem("ParrelSync/Check for update", priority = 20)]
|
||||
static void CheckForUpdate()
|
||||
{
|
||||
using (System.Net.WebClient client = new System.Net.WebClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
//This won't work with UPM packages
|
||||
//string localVersionText = AssetDatabase.LoadAssetAtPath<TextAsset>(LocalVersionFilePath).text;
|
||||
|
||||
string localVersionText = LocalVersion;
|
||||
Debug.Log("Local version text : " + LocalVersion);
|
||||
|
||||
string latesteVersionText = client.DownloadString(ExternalLinks.RemoteVersionURL);
|
||||
Debug.Log("latest version text got: " + latesteVersionText);
|
||||
string messageBody = "Current Version: " + localVersionText +"\n"
|
||||
+"Latest Version: " + latesteVersionText + "\n";
|
||||
var latestVersion = new Version(latesteVersionText);
|
||||
var localVersion = new Version(localVersionText);
|
||||
|
||||
if (latestVersion > localVersion)
|
||||
{
|
||||
Debug.Log("There's a newer version");
|
||||
messageBody += "There's a newer version available";
|
||||
if(EditorUtility.DisplayDialog("Check for update.", messageBody, "Get latest release", "Close"))
|
||||
{
|
||||
Application.OpenURL(ExternalLinks.Releases);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("Current version is up-to-date.");
|
||||
messageBody += "Current version is up-to-date.";
|
||||
EditorUtility.DisplayDialog("Check for update.", messageBody,"OK");
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception exp)
|
||||
{
|
||||
Debug.LogError("Error with checking update. Exception: " + exp);
|
||||
EditorUtility.DisplayDialog("Update Error","Error with checking update. \nSee console for more details.",
|
||||
"OK"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/ParrelSync/ParrelSync/Editor/UpdateChecker.cs.meta
Normal file
11
Assets/ParrelSync/ParrelSync/Editor/UpdateChecker.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d3453b3f1a20ea148b5028f8556a7be5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,73 @@
|
||||
namespace ParrelSync.NonCore
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
[InitializeOnLoad]
|
||||
public class ValidateCopiedFoldersIntegrity
|
||||
{
|
||||
const string SessionStateKey = "ValidateCopiedFoldersIntegrity_Init";
|
||||
/// <summary>
|
||||
/// Called once on editor startup.
|
||||
/// Validate copied folders integrity in clone project
|
||||
/// </summary>
|
||||
static ValidateCopiedFoldersIntegrity()
|
||||
{
|
||||
if (!SessionState.GetBool(SessionStateKey, false))
|
||||
{
|
||||
SessionState.SetBool(SessionStateKey, true);
|
||||
if (!ClonesManager.IsClone()) { return; }
|
||||
|
||||
ValidateFolder("Packages");
|
||||
}
|
||||
}
|
||||
|
||||
static void ValidateFolder(string folderName)
|
||||
{
|
||||
var currentProjectPath = Path.Combine(ClonesManager.GetCurrentProjectPath(), folderName);
|
||||
var currentFolderHash = CreateMd5ForFolder(currentProjectPath);
|
||||
|
||||
var originalProjectPath = Path.Combine(ClonesManager.GetOriginalProjectPath(), folderName);
|
||||
var originalFolderHash = CreateMd5ForFolder(originalProjectPath);
|
||||
|
||||
if (currentFolderHash != originalFolderHash)
|
||||
{
|
||||
Debug.Log("ParrelSync: Detected '" + folderName + "' folder changes in the original project. Updating...");
|
||||
FileUtil.ReplaceDirectory(originalProjectPath, currentProjectPath);
|
||||
}
|
||||
}
|
||||
|
||||
static string CreateMd5ForFolder(string path)
|
||||
{
|
||||
// assuming you want to include nested folders
|
||||
var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
|
||||
.OrderBy(p => p).ToList();
|
||||
|
||||
MD5 md5 = MD5.Create();
|
||||
|
||||
for (int i = 0; i < files.Count; i++)
|
||||
{
|
||||
string file = files[i];
|
||||
|
||||
// hash path
|
||||
string relativePath = file.Substring(path.Length + 1);
|
||||
byte[] pathBytes = Encoding.UTF8.GetBytes(relativePath.ToLower());
|
||||
md5.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0);
|
||||
|
||||
// hash contents
|
||||
byte[] contentBytes = File.ReadAllBytes(file);
|
||||
if (i == files.Count - 1)
|
||||
md5.TransformFinalBlock(contentBytes, 0, contentBytes.Length);
|
||||
else
|
||||
md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0);
|
||||
}
|
||||
|
||||
return BitConverter.ToString(md5.Hash).Replace("-", "").ToLower();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8fb344b9abf5274abd744833474b087
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/ParrelSync/ParrelSync/package.json
Normal file
10
Assets/ParrelSync/ParrelSync/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "com.veriorpies.parrelsync",
|
||||
"displayName": "ParrelSync",
|
||||
"version": "1.5.0",
|
||||
"unity": "2018.4",
|
||||
"description": "ParrelSync is a Unity editor extension that allows users to test multiplayer gameplay without building the project by having another Unity editor window opened and mirror the changes from the original project.",
|
||||
"license": "MIT",
|
||||
"keywords": [ "Networking", "Utils", "Editor", "Extensions" ],
|
||||
"dependencies": {}
|
||||
}
|
||||
7
Assets/ParrelSync/ParrelSync/package.json.meta
Normal file
7
Assets/ParrelSync/ParrelSync/package.json.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2a889c264e34b47a7349cbcb2cbedd7
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
15
Assets/ParrelSync/ParrelSync/projectCloner.asmdef
Normal file
15
Assets/ParrelSync/ParrelSync/projectCloner.asmdef
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "ParrelSync",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
Assets/ParrelSync/ParrelSync/projectCloner.asmdef.meta
Normal file
7
Assets/ParrelSync/ParrelSync/projectCloner.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 894a6cc6ed5cd2645bb542978cbed6a9
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
91
Assets/ParrelSync/README.md
Normal file
91
Assets/ParrelSync/README.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# ParrelSync
|
||||
[](https://github.com/VeriorPies/ParrelSync/releases) [](https://github.com/VeriorPies/ParrelSync/wiki) [](https://github.com/VeriorPies/ParrelSync/blob/master/LICENSE.md) [](https://github.com/VeriorPies/ParrelSync/pulls) [](https://discord.gg/TmQk2qG)
|
||||
|
||||
ParrelSync is a Unity editor extension that allows users to test multiplayer gameplay without building the project by having another Unity editor window opened and mirror the changes from the original project.
|
||||
|
||||
<br>
|
||||
|
||||

|
||||
<p align="center">
|
||||
<b>Test project changes on clients and server within seconds - both in editor
|
||||
</b>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
## Features
|
||||
1. Test multiplayer gameplay without building the project
|
||||
2. GUI tools for managing all project clones
|
||||
3. Protected assets from being modified by other clone instances
|
||||
4. Handy APIs to speed up testing workflows
|
||||
## Installation
|
||||
|
||||
1. Backup your project folder or use a version control system such as [Git](https://git-scm.com/) or [SVN](https://subversion.apache.org/)
|
||||
2. Download .unitypackage from the [latest release](https://github.com/VeriorPies/ParrelSync/releases) and import it to your project.
|
||||
3. ParrelSync should appreared in the menu item bar after imported
|
||||

|
||||
|
||||
Check out the [Installation-and-Update](https://github.com/VeriorPies/ParrelSync/wiki/Installation-and-Update) page for more details.
|
||||
|
||||
### UPM Package
|
||||
ParrelSync can also be installed via UPM package.
|
||||
After Unity 2019.3.4f1, Unity 2020.1a21, which support path query parameter of git package. You can install ParrelSync by adding the following to Package Manager.
|
||||
|
||||
```
|
||||
https://github.com/VeriorPies/ParrelSync.git?path=/ParrelSync
|
||||
```
|
||||
|
||||
|
||||
 
|
||||
|
||||
or by adding
|
||||
|
||||
```
|
||||
"com.veriorpies.parrelsync": "https://github.com/VeriorPies/ParrelSync.git?path=/ParrelSync"
|
||||
```
|
||||
|
||||
to the `Packages/manifest.json` file
|
||||
|
||||
|
||||
## Supported Platform
|
||||
Currently, ParrelSync supports Windows, macOS and Linux editors.
|
||||
|
||||
ParrelSync has been tested with the following Unity version. However, it should also work with other versions as well.
|
||||
* *2020.3.1f1*
|
||||
* *2019.3.0f6*
|
||||
* *2018.4.22f1*
|
||||
|
||||
|
||||
## APIs
|
||||
There's some useful APIs for speeding up the multiplayer testing workflow.
|
||||
Here's a basic example:
|
||||
```
|
||||
if (ClonesManager.IsClone()) {
|
||||
// Automatically connect to local host if this is the clone editor
|
||||
}else{
|
||||
// Automatically start server if this is the original editor
|
||||
}
|
||||
```
|
||||
Check out [the doc](https://github.com/VeriorPies/ParrelSync/wiki/List-of-APIs) to view the complete API list.
|
||||
|
||||
## How does it work?
|
||||
For each clone instance, ParrelSync will make a copy of the original project folder and reference the ```Asset```, ```Packages``` and ```ProjectSettings``` folder back to the original project with [symbolic link](https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink). Other folders such as ```Library```, ```Temp```, and ```obj``` will remain independent for each clone project.
|
||||
|
||||
All clones are placed right next to the original project with suffix *```_clone_x```*, which will be something like this in the folder hierarchy.
|
||||
```
|
||||
/ProjectName
|
||||
/ProjectName_clone_0
|
||||
/ProjectName_clone_1
|
||||
...
|
||||
```
|
||||
## Discord Server
|
||||
We have a [Discord server](https://discord.gg/TmQk2qG).
|
||||
|
||||
## Need Help?
|
||||
Some common questions and troubleshooting can be found under the [Troubleshooting & FAQs](https://github.com/VeriorPies/ParrelSync/wiki/Troubleshooting-&-FAQs) page.
|
||||
You can also [create a question post](https://github.com/VeriorPies/ParrelSync/issues/new/choose), or ask on [Discord](https://discord.gg/TmQk2qG) if you prefer to have a real-time conversation.
|
||||
|
||||
## Support this project
|
||||
A star will be appreciated :)
|
||||
|
||||
## Credits
|
||||
This project is originated from hwaet's [UnityProjectCloner](https://github.com/hwaet/UnityProjectCloner)
|
||||
7
Assets/ParrelSync/README.md.meta
Normal file
7
Assets/ParrelSync/README.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa3f2fa6aced9b54b970c8996957df3b
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1
Assets/ParrelSync/VERSION.txt
Normal file
1
Assets/ParrelSync/VERSION.txt
Normal file
@@ -0,0 +1 @@
|
||||
1.5.0
|
||||
7
Assets/ParrelSync/VERSION.txt.meta
Normal file
7
Assets/ParrelSync/VERSION.txt.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9833b240625d4e14995c296b87e34b96
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -17,7 +17,7 @@ GameObject:
|
||||
- component: {fileID: 8584291556063275409}
|
||||
- component: {fileID: 345238637415786487}
|
||||
- component: {fileID: 3855804468415881115}
|
||||
m_Layer: 0
|
||||
m_Layer: 9
|
||||
m_Name: picopark
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
@@ -76,7 +76,7 @@ SpriteRenderer:
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_SortingOrder: 5
|
||||
m_Sprite: {fileID: 21300000, guid: e88c557aba8023277947be6e82d2215f, type: 3}
|
||||
m_Color: {r: 0, g: 1, b: 0.044991016, a: 1}
|
||||
m_FlipX: 1
|
||||
@@ -104,6 +104,11 @@ MonoBehaviour:
|
||||
syncInterval: 0.1
|
||||
LocalComponents:
|
||||
- {fileID: 8584291556063275412}
|
||||
characterSprite: {fileID: 8584291556063275423}
|
||||
insideDoor: 0
|
||||
friendLayer:
|
||||
serializedVersion: 2
|
||||
m_Bits: 1024
|
||||
--- !u!114 &8584291556063275412
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -124,18 +129,20 @@ MonoBehaviour:
|
||||
animator: {fileID: 8584291556063275409}
|
||||
groundLayerMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 256
|
||||
m_Bits: 1280
|
||||
isGrounded: 1
|
||||
isSwimming: 0
|
||||
groundChecker: {fileID: 0}
|
||||
gravity: {x: 0, y: 0}
|
||||
buoyantForce: 0
|
||||
buoyantSpd: 0
|
||||
moveSpeed: 0.05
|
||||
jumpForce: 55
|
||||
moveSpeed: 0.04
|
||||
jumpForce: 70
|
||||
jumpDuration: 0.2
|
||||
jumpSFX: {fileID: 0}
|
||||
listenToInput: 1
|
||||
inDoor: 0
|
||||
insideDoor: 0
|
||||
inWater: 0
|
||||
waterBoost: 0
|
||||
--- !u!61 &8584291556063275411
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2047
Assets/Scenes/level1.unity
Normal file
2047
Assets/Scenes/level1.unity
Normal file
File diff suppressed because it is too large
Load Diff
7
Assets/Scenes/level1.unity.meta
Normal file
7
Assets/Scenes/level1.unity.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a23e274c992dceb98bb635e26225ef6c
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2047
Assets/Scenes/level2.unity
Normal file
2047
Assets/Scenes/level2.unity
Normal file
File diff suppressed because it is too large
Load Diff
7
Assets/Scenes/level2.unity.meta
Normal file
7
Assets/Scenes/level2.unity.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 273f9d92d5b2c2b3db2a4a2f7a3a753f
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
994
Assets/Scenes/login.unity
Normal file
994
Assets/Scenes/login.unity
Normal file
@@ -0,0 +1,994 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!29 &1
|
||||
OcclusionCullingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_OcclusionBakeSettings:
|
||||
smallestOccluder: 5
|
||||
smallestHole: 0.25
|
||||
backfaceThreshold: 100
|
||||
m_SceneGUID: 00000000000000000000000000000000
|
||||
m_OcclusionCullingData: {fileID: 0}
|
||||
--- !u!104 &2
|
||||
RenderSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 9
|
||||
m_Fog: 0
|
||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
m_FogMode: 3
|
||||
m_FogDensity: 0.01
|
||||
m_LinearFogStart: 0
|
||||
m_LinearFogEnd: 300
|
||||
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||
m_AmbientIntensity: 1
|
||||
m_AmbientMode: 3
|
||||
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||
m_SkyboxMaterial: {fileID: 0}
|
||||
m_HaloStrength: 0.5
|
||||
m_FlareStrength: 1
|
||||
m_FlareFadeSpeed: 3
|
||||
m_HaloTexture: {fileID: 0}
|
||||
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_DefaultReflectionMode: 0
|
||||
m_DefaultReflectionResolution: 128
|
||||
m_ReflectionBounces: 1
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 0}
|
||||
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 11
|
||||
m_GIWorkflowMode: 1
|
||||
m_GISettings:
|
||||
serializedVersion: 2
|
||||
m_BounceScale: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_EnvironmentLightingMode: 0
|
||||
m_EnableBakedLightmaps: 0
|
||||
m_EnableRealtimeLightmaps: 0
|
||||
m_LightmapEditorSettings:
|
||||
serializedVersion: 12
|
||||
m_Resolution: 2
|
||||
m_BakeResolution: 40
|
||||
m_AtlasSize: 1024
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAmbientOcclusion: 0
|
||||
m_Padding: 2
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_LightmapsBakeMode: 1
|
||||
m_TextureCompression: 1
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherFiltering: 1
|
||||
m_FinalGatherRayCount: 256
|
||||
m_ReflectionCompression: 2
|
||||
m_MixedBakeMode: 2
|
||||
m_BakeBackend: 1
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 512
|
||||
m_PVRBounces: 2
|
||||
m_PVREnvironmentSampleCount: 256
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_PVRFilteringMode: 1
|
||||
m_PVRDenoiserTypeDirect: 1
|
||||
m_PVRDenoiserTypeIndirect: 1
|
||||
m_PVRDenoiserTypeAO: 1
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVREnvironmentMIS: 1
|
||||
m_PVRCulling: 1
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_LightingDataAsset: {fileID: 0}
|
||||
m_UseShadowmask: 1
|
||||
--- !u!196 &4
|
||||
NavMeshSettings:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_BuildSettings:
|
||||
serializedVersion: 2
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
agentSlope: 45
|
||||
agentClimb: 0.4
|
||||
ledgeDropHeight: 0
|
||||
maxJumpAcrossDistance: 0
|
||||
minRegionArea: 2
|
||||
manualCellSize: 0
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
accuratePlacement: 0
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_NavMeshData: {fileID: 0}
|
||||
--- !u!1 &57747112
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 57747113}
|
||||
- component: {fileID: 57747115}
|
||||
- component: {fileID: 57747114}
|
||||
m_Layer: 5
|
||||
m_Name: Text
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &57747113
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 57747112}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 947167437}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: -0.5}
|
||||
m_SizeDelta: {x: -20, y: -13}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &57747114
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 57747112}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.9716981, g: 0.5916314, b: 0.08250269, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 12800000, guid: aa5beb46a7b830442a612d72f0278ded, type: 3}
|
||||
m_FontSize: 31
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 68
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 0
|
||||
m_HorizontalOverflow: 1
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text:
|
||||
--- !u!222 &57747115
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 57747112}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &224439162
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 224439165}
|
||||
- component: {fileID: 224439164}
|
||||
- component: {fileID: 224439163}
|
||||
m_Layer: 0
|
||||
m_Name: EventSystem
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &224439163
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 224439162}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_HorizontalAxis: Horizontal
|
||||
m_VerticalAxis: Vertical
|
||||
m_SubmitButton: Submit
|
||||
m_CancelButton: Cancel
|
||||
m_InputActionsPerSecond: 10
|
||||
m_RepeatDelay: 0.5
|
||||
m_ForceModuleActive: 0
|
||||
--- !u!114 &224439164
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 224439162}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_FirstSelected: {fileID: 0}
|
||||
m_sendNavigationEvents: 1
|
||||
m_DragThreshold: 10
|
||||
--- !u!4 &224439165
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 224439162}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 3
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &719229600
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 719229601}
|
||||
- component: {fileID: 719229603}
|
||||
- component: {fileID: 719229602}
|
||||
m_Layer: 5
|
||||
m_Name: Placeholder
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &719229601
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 719229600}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 947167437}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: -0.5}
|
||||
m_SizeDelta: {x: -20, y: -13}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &719229602
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 719229600}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 12800000, guid: aa5beb46a7b830442a612d72f0278ded, type: 3}
|
||||
m_FontSize: 31
|
||||
m_FontStyle: 2
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 68
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: 'Ex: sirisena_the_great'
|
||||
--- !u!222 &719229603
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 719229600}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &851051370
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 851051372}
|
||||
- component: {fileID: 851051371}
|
||||
m_Layer: 0
|
||||
m_Name: LoginManager
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &851051371
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 851051370}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: bb602c1a35483c66e97589f39f2fbf49, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
nameInput: {fileID: 947167438}
|
||||
loginBtn: {fileID: 1693299071}
|
||||
--- !u!4 &851051372
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 851051370}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0.6157753, y: -0.9382149, z: -0.72875816}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &947167436
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 947167437}
|
||||
- component: {fileID: 947167440}
|
||||
- component: {fileID: 947167439}
|
||||
- component: {fileID: 947167438}
|
||||
m_Layer: 5
|
||||
m_Name: InputField
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &947167437
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 947167436}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 719229601}
|
||||
- {fileID: 57747113}
|
||||
m_Father: {fileID: 1143938386}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0.000030518, y: 0.0000038147}
|
||||
m_SizeDelta: {x: 586.9, y: 92.7}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &947167438
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 947167436}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 947167439}
|
||||
m_TextComponent: {fileID: 57747114}
|
||||
m_Placeholder: {fileID: 719229602}
|
||||
m_ContentType: 0
|
||||
m_InputType: 0
|
||||
m_AsteriskChar: 42
|
||||
m_KeyboardType: 0
|
||||
m_LineType: 0
|
||||
m_HideMobileInput: 0
|
||||
m_CharacterValidation: 0
|
||||
m_CharacterLimit: 0
|
||||
m_OnEndEdit:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_OnValueChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_CustomCaretColor: 0
|
||||
m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412}
|
||||
m_Text:
|
||||
m_CaretBlinkRate: 0.85
|
||||
m_CaretWidth: 1
|
||||
m_ReadOnly: 0
|
||||
--- !u!114 &947167439
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 947167436}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.8584906, g: 0.8584906, b: 0.8584906, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!222 &947167440
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 947167436}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &1143938382
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1143938386}
|
||||
- component: {fileID: 1143938385}
|
||||
- component: {fileID: 1143938384}
|
||||
- component: {fileID: 1143938383}
|
||||
m_Layer: 5
|
||||
m_Name: Canvas
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &1143938383
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1143938382}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_IgnoreReversedGraphics: 1
|
||||
m_BlockingObjects: 0
|
||||
m_BlockingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
--- !u!114 &1143938384
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1143938382}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_UiScaleMode: 0
|
||||
m_ReferencePixelsPerUnit: 100
|
||||
m_ScaleFactor: 1
|
||||
m_ReferenceResolution: {x: 800, y: 600}
|
||||
m_ScreenMatchMode: 0
|
||||
m_MatchWidthOrHeight: 0
|
||||
m_PhysicalUnit: 3
|
||||
m_FallbackScreenDPI: 96
|
||||
m_DefaultSpriteDPI: 96
|
||||
m_DynamicPixelsPerUnit: 1
|
||||
--- !u!223 &1143938385
|
||||
Canvas:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1143938382}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_RenderMode: 0
|
||||
m_Camera: {fileID: 0}
|
||||
m_PlaneDistance: 100
|
||||
m_PixelPerfect: 0
|
||||
m_ReceivesEvents: 1
|
||||
m_OverrideSorting: 0
|
||||
m_OverridePixelPerfect: 0
|
||||
m_SortingBucketNormalizedSize: 0
|
||||
m_AdditionalShaderChannelsFlag: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
m_TargetDisplay: 0
|
||||
--- !u!224 &1143938386
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1143938382}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||
m_Children:
|
||||
- {fileID: 1227594177}
|
||||
- {fileID: 947167437}
|
||||
- {fileID: 1693299070}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0, y: 0}
|
||||
--- !u!1 &1227594176
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1227594177}
|
||||
- component: {fileID: 1227594179}
|
||||
- component: {fileID: 1227594178}
|
||||
m_Layer: 5
|
||||
m_Name: Text
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1227594177
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1227594176}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1143938386}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -195, y: 131}
|
||||
m_SizeDelta: {x: 461.40002, y: 58.100006}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1227594178
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1227594176}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.9433962, g: 0.4884283, b: 0.0800997, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 12800000, guid: aa5beb46a7b830442a612d72f0278ded, type: 3}
|
||||
m_FontSize: 53
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 62
|
||||
m_Alignment: 0
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: Enter your name
|
||||
--- !u!222 &1227594179
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1227594176}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &1693299069
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1693299070}
|
||||
- component: {fileID: 1693299073}
|
||||
- component: {fileID: 1693299072}
|
||||
- component: {fileID: 1693299071}
|
||||
m_Layer: 5
|
||||
m_Name: Button
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1693299070
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1693299069}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 2132260124}
|
||||
m_Father: {fileID: 1143938386}
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: -99}
|
||||
m_SizeDelta: {x: 302.9, y: 68.7}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1693299071
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1693299069}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 1693299072}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls:
|
||||
- m_Target: {fileID: 851051371}
|
||||
m_MethodName: Login
|
||||
m_Mode: 1
|
||||
m_Arguments:
|
||||
m_ObjectArgument: {fileID: 0}
|
||||
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
|
||||
m_IntArgument: 0
|
||||
m_FloatArgument: 0
|
||||
m_StringArgument:
|
||||
m_BoolArgument: 0
|
||||
m_CallState: 2
|
||||
--- !u!114 &1693299072
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1693299069}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 0.52332425, b: 0, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!222 &1693299073
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1693299069}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &1703577500
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1703577503}
|
||||
- component: {fileID: 1703577502}
|
||||
- component: {fileID: 1703577501}
|
||||
m_Layer: 0
|
||||
m_Name: Main Camera
|
||||
m_TagString: MainCamera
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!81 &1703577501
|
||||
AudioListener:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1703577500}
|
||||
m_Enabled: 1
|
||||
--- !u!20 &1703577502
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1703577500}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 1
|
||||
m_BackGroundColor: {r: 1, g: 1, b: 1, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_FocalLength: 50
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 60
|
||||
orthographic: 1
|
||||
orthographic size: 5
|
||||
m_Depth: -1
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 0}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!4 &1703577503
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1703577500}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: -10}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &2132260123
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2132260124}
|
||||
- component: {fileID: 2132260126}
|
||||
- component: {fileID: 2132260125}
|
||||
m_Layer: 5
|
||||
m_Name: Text
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &2132260124
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2132260123}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1693299070}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &2132260125
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2132260123}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 12800000, guid: aa5beb46a7b830442a612d72f0278ded, type: 3}
|
||||
m_FontSize: 41
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 42
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: continue
|
||||
--- !u!222 &2132260126
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2132260123}
|
||||
m_CullTransparentMesh: 0
|
||||
7
Assets/Scenes/login.unity.meta
Normal file
7
Assets/Scenes/login.unity.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7423273dd26a040fdb50204d3fe23fdc
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
46
Assets/Scripts/Door.cs
Normal file
46
Assets/Scripts/Door.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class Door : MonoBehaviour
|
||||
{
|
||||
public SpriteRenderer openDoorSprite;
|
||||
public bool locked;
|
||||
|
||||
void Start(){
|
||||
if(!locked){
|
||||
openDoorSprite.color = Color.black;
|
||||
}
|
||||
}
|
||||
|
||||
public void unlock(){
|
||||
locked=false;
|
||||
openDoorSprite.color = Color.black;
|
||||
}
|
||||
|
||||
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void OnTriggerEnter2D(Collider2D col){
|
||||
Debug.Log(col.gameObject.name + " Entered");
|
||||
NetPlayer playerObject = col.GetComponent<NetPlayer>();
|
||||
if(!locked&& playerObject!=null){
|
||||
if(playerObject.isLocalPlayer){
|
||||
col.GetComponent<PlayerController>().inDoor = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnTriggerExit2D(Collider2D col){
|
||||
Debug.Log(col.gameObject.name + " Exited");
|
||||
NetPlayer playerObject = col.GetComponent<NetPlayer>();
|
||||
if(!locked&& playerObject!=null){
|
||||
if(playerObject.isLocalPlayer){
|
||||
col.GetComponent<PlayerController>().inDoor = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Door.cs.meta
Normal file
11
Assets/Scripts/Door.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 83130d81d669a3e0cb774960d0a3c596
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -16,6 +16,7 @@ public class InputPresetData{
|
||||
public KeyCode leftInput;
|
||||
public KeyCode rightInput;
|
||||
public KeyCode jumpInput;
|
||||
public KeyCode interactingKey;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +48,7 @@ public static class InputManager{
|
||||
m_data.leftInput = KeyCode.A;
|
||||
m_data.rightInput = KeyCode.D;
|
||||
m_data.jumpInput = KeyCode.Space;
|
||||
m_data.interactingKey=KeyCode.W;
|
||||
|
||||
PlayerPrefs.SetString("inputSettings", JsonUtility.ToJson(m_data));
|
||||
PlayerPrefs.Save();
|
||||
|
||||
85
Assets/Scripts/Lobby.cs
Normal file
85
Assets/Scripts/Lobby.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Mirror;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
public class Lobby : NetworkBehaviour
|
||||
{
|
||||
[SyncVar]
|
||||
public int playerCount;
|
||||
[SyncVar]
|
||||
public string serverName;
|
||||
[SyncVar(hook = nameof(OnMetadataChanged))]
|
||||
public string serverMetadata;
|
||||
public string nextSceneName;
|
||||
void OnMetadataChanged(string oldValue, string newValue){
|
||||
SceneData.metadata = JsonUtility.FromJson<ServerMetadata>(newValue);
|
||||
}
|
||||
|
||||
public Text lobbyNameText;
|
||||
public Text playerCountTxt;
|
||||
void Start()
|
||||
{
|
||||
DontDestroyOnLoad(gameObject);
|
||||
if(isServer){
|
||||
serverName = FindObjectOfType<LightReflectiveMirror.LightReflectiveMirrorTransport>().serverName;
|
||||
serverMetadata = FindObjectOfType<LightReflectiveMirror.LightReflectiveMirrorTransport>().extraServerData;
|
||||
}
|
||||
|
||||
lobbyNameText.text = serverName;
|
||||
SceneData.metadata = JsonUtility.FromJson<ServerMetadata>(serverMetadata);
|
||||
playerCountTxt.text = playerCount+"/" + SceneData.metadata.maxPlayerCount;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
public int[] playlist = new int[2]{1,2};
|
||||
public int curSceneInd=0;
|
||||
void Update()
|
||||
{
|
||||
if(playerCountTxt!=null){
|
||||
playerCountTxt.text = playerCount + "/ " + SceneData.metadata.maxPlayerCount;
|
||||
}
|
||||
if(!isServer){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NetPlayer[] netPlayers = FindObjectsOfType<NetPlayer>();
|
||||
playerCount = netPlayers.Length;
|
||||
if(playerCount < 1){return;}
|
||||
bool allInside =true;
|
||||
foreach(NetPlayer netPlayer in netPlayers){
|
||||
if(!netPlayer.insideDoor){allInside = false;break;}
|
||||
}
|
||||
|
||||
if(allInside){
|
||||
//Move onto next level
|
||||
if(curSceneInd < playlist.Length -1){
|
||||
curSceneInd++;
|
||||
nextSceneName = SceneManager.GetSceneByBuildIndex(playlist[curSceneInd]).name;
|
||||
}else{
|
||||
nextSceneName ="SampleScene";
|
||||
curSceneInd=0;
|
||||
}
|
||||
RpcNextLevel(playlist[curSceneInd]);
|
||||
changeScene(playlist[curSceneInd]);
|
||||
}
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
void RpcNextLevel(int levelName){
|
||||
changeScene(levelName);
|
||||
}
|
||||
|
||||
void changeScene(int levelName){
|
||||
SceneData.localPlayer.GetComponent<PlayerController>().insideDoor=false;
|
||||
SceneData.localPlayer.GetComponent<NetPlayer>().CallChangeInsideDoor(false);
|
||||
|
||||
LoadingScreen.instance.alreadyConnected=true;
|
||||
LoadingScreen.instance.sceneName=null;
|
||||
LoadingScreen.instance.sceneIndex = levelName;
|
||||
LoadingScreen.instance.load();
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Lobby.cs.meta
Normal file
11
Assets/Scripts/Lobby.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e61f23073e4aea54ab53fc45e3c502a9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -16,13 +16,15 @@ public class MainmenuController : MonoBehaviour
|
||||
public LightReflectiveMirrorTransport _LRM;
|
||||
public Toggle isPublic;
|
||||
public InputField serverNameInput;
|
||||
public Slider maxPlayerCount;
|
||||
void Start()
|
||||
{
|
||||
|
||||
_LRM = (LightReflectiveMirrorTransport)Transport.activeTransport;
|
||||
_LRM.serverListUpdated.AddListener(ServerListUpdate);
|
||||
_LRM.connectedToRelay.AddListener(refreshServers);
|
||||
// serverNameInput.text = usernameTxt.text + "'s Server";
|
||||
usernameTxt.text = PlayerPrefs.GetString("username");
|
||||
serverNameInput.text = usernameTxt.text + "'s Server";
|
||||
// refreshServers();
|
||||
}
|
||||
|
||||
@@ -54,7 +56,6 @@ public class MainmenuController : MonoBehaviour
|
||||
//clear all entries
|
||||
Debug.Log("it works");
|
||||
foreach(Transform t in scrollParent) { Destroy(t.gameObject); }
|
||||
bool b1 = false;
|
||||
for (int i =0; i < _LRM.relayServerList.Count; i++)
|
||||
{
|
||||
//int mapId = int.Parse(_LRM.relayServerList[i].serverName.Substring(0, 1));
|
||||
@@ -62,11 +63,7 @@ public class MainmenuController : MonoBehaviour
|
||||
go.transform.GetChild(0).GetComponent<Text>().text = _LRM.relayServerList[i].serverName;
|
||||
go.transform.GetChild(1).GetComponent<Text>().text = _LRM.relayServerList[i].currentPlayers + "/" + _LRM.relayServerList[i].maxPlayers;
|
||||
go.GetComponentInChildren<Button>().onClick.AddListener(() => { joinServer(_LRM.relayServerList[i-1].serverId.ToString()); });
|
||||
if (!b1)
|
||||
{
|
||||
go.GetComponent<Image>().color = Color.grey;
|
||||
b1 = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
scrollParent.GetComponent<RectTransform>().sizeDelta = new Vector2(scrollParent.GetComponent<RectTransform>().sizeDelta.x, heightPerRow *(_LRM.relayServerList.Count+1));
|
||||
@@ -86,28 +83,43 @@ public class MainmenuController : MonoBehaviour
|
||||
|
||||
public void joinServer()
|
||||
{
|
||||
FindObjectOfType<loadingScreen>().serverName = _LRM.relayServerList[curSelected].serverId.ToString();
|
||||
LoadingScreen.instance.serverName = _LRM.relayServerList[curSelected].serverId.ToString();
|
||||
|
||||
FindObjectOfType<loadingScreen>().load();
|
||||
LoadingScreen.instance.load();
|
||||
}
|
||||
public void joinServer(string serverName)
|
||||
{
|
||||
FindObjectOfType<loadingScreen>().serverName = serverName;
|
||||
FindObjectOfType<loadingScreen>().sceneName= "SampleScene";
|
||||
FindObjectOfType<loadingScreen>().isHost=false;
|
||||
LoadingScreen.instance.serverName = serverName;
|
||||
LoadingScreen.instance.sceneName= "SampleScene";
|
||||
LoadingScreen.instance.isHost=false;
|
||||
LoadingScreen.instance.alreadyConnected=false;
|
||||
|
||||
FindObjectOfType<loadingScreen>().load();
|
||||
LoadingScreen.instance.load();
|
||||
}
|
||||
|
||||
public void hostClicked()
|
||||
{
|
||||
if (serverNameInput.text.Length > 3)
|
||||
{
|
||||
FindObjectOfType<loadingScreen>().serverName = serverNameInput.text;
|
||||
FindObjectOfType<loadingScreen>().sceneName= "SampleScene";
|
||||
|
||||
FindObjectOfType<loadingScreen>().isPublic = isPublic.isOn;
|
||||
FindObjectOfType<loadingScreen>().load();
|
||||
LoadingScreen.instance.serverName = serverNameInput.text;
|
||||
LoadingScreen.instance.sceneName= "SampleScene";
|
||||
LoadingScreen.instance.isPublic = isPublic.isOn;
|
||||
LoadingScreen.instance.alreadyConnected=false;
|
||||
LoadingScreen.instance.isHost=true;
|
||||
ServerMetadata metadata = new ServerMetadata();
|
||||
metadata.maxPlayerCount = (int)maxPlayerCount.value;
|
||||
LoadingScreen.instance.serverMetadata = JsonUtility.ToJson(metadata);
|
||||
LoadingScreen.instance.load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
public class ServerMetadata{
|
||||
public int maxPlayerCount;
|
||||
|
||||
public ServerMetadata(){
|
||||
maxPlayerCount = 0;
|
||||
}
|
||||
}
|
||||
@@ -7,19 +7,118 @@ public class NetPlayer : NetworkBehaviour
|
||||
{
|
||||
|
||||
public Behaviour[] LocalComponents;
|
||||
|
||||
public SpriteRenderer characterSprite;
|
||||
[SyncVar]
|
||||
public bool insideDoor;
|
||||
public LayerMask friendLayer;
|
||||
void Start()
|
||||
{
|
||||
DontDestroyOnLoad(gameObject);
|
||||
if(!isLocalPlayer){
|
||||
gameObject.layer = LayerMask.NameToLayer("Friend");
|
||||
//GetComponent<BoxCollider2D>().size = new Vector2(GetComponent<BoxCollider2D>().size.x/2f,GetComponent<BoxCollider2D>().size.y);
|
||||
foreach(Behaviour localComponent in LocalComponents){
|
||||
localComponent.enabled=false;
|
||||
}
|
||||
}
|
||||
if(isLocalPlayer){
|
||||
SceneData.localPlayer = gameObject;
|
||||
if(SceneData.netSceneData==null){Debug.Log("Scene Data is not init yet");}else{
|
||||
transform.position = SceneData.netSceneData.spawnPoint.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
public void ReturnToSpawn(){
|
||||
if(isLocalPlayer){
|
||||
StartCoroutine(returnToSpawn());
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator returnToSpawn(){
|
||||
while(SceneData.netSceneData==null){
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
}
|
||||
while(SceneData.netSceneData.spawnPoint==null){
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
}
|
||||
transform.position = SceneData.netSceneData.spawnPoint.position;
|
||||
|
||||
}
|
||||
public Transform frndTrans;
|
||||
bool oldFlipVal = false;
|
||||
|
||||
Transform oldFriendVal;
|
||||
float oldFriendX;
|
||||
void Update()
|
||||
{
|
||||
|
||||
if(!isLocalPlayer){return;}
|
||||
frndTrans = getOnFriend();
|
||||
// if(oldFriendVal!=frndTrans){//got on someones head, or got off
|
||||
// if(oldFriendVal==null && frndTrans!=null){//got on
|
||||
// oldFriendX = frndTrans.position.x;
|
||||
// oldFriendVal = frndTrans;
|
||||
// }else{//got off
|
||||
// oldFriendX = 0;
|
||||
// oldFriendVal = null;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if(oldFriendVal!=null){
|
||||
// transform.Translate(new Vector2(frndTrans.position.x - oldFriendX,0));
|
||||
// }
|
||||
|
||||
if(oldFlipVal != characterSprite.flipX){
|
||||
if(isServer){
|
||||
RpcFlipX(characterSprite.flipX);
|
||||
}else{
|
||||
CmdFlipX(characterSprite.flipX);
|
||||
}
|
||||
oldFlipVal=characterSprite.flipX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(!isServer){return;}
|
||||
}
|
||||
|
||||
[Command]
|
||||
void CmdFlipX(bool value){
|
||||
FlipX(value);
|
||||
RpcFlipX(value);
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
void RpcFlipX(bool value){
|
||||
if(!isLocalPlayer)FlipX(value);
|
||||
}
|
||||
|
||||
void FlipX(bool value){
|
||||
characterSprite.flipX = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void CallChangeInsideDoor(bool value){
|
||||
if(isServer){
|
||||
insideDoor=value;
|
||||
}else{
|
||||
CmdChangeInsideDoor(value);
|
||||
}
|
||||
}
|
||||
[Command]
|
||||
void CmdChangeInsideDoor(bool value){
|
||||
insideDoor=value;
|
||||
}
|
||||
|
||||
|
||||
public Transform getOnFriend()
|
||||
{
|
||||
Transform friend =null;
|
||||
//return (Physics2D.Linecast(transform.position, groundChecker.position, groundLayerMask));
|
||||
Collider2D col = GetComponentInChildren<Collider2D>();
|
||||
RaycastHit2D hit = Physics2D.BoxCast(col.bounds.center, new Vector2(col.bounds.size.x - (col.bounds.size.x / 5f), col.bounds.size.y), 0, Vector2.down, 0.1f, friendLayer);
|
||||
friend = (hit) ? hit.collider.transform : null;
|
||||
return friend;
|
||||
}
|
||||
}
|
||||
|
||||
21
Assets/Scripts/NetSceneData.cs
Normal file
21
Assets/Scripts/NetSceneData.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class NetSceneData : MonoBehaviour
|
||||
{
|
||||
public Transform spawnPoint;
|
||||
public Transform doorExit;
|
||||
public Door door;
|
||||
void Awake()
|
||||
{
|
||||
SceneData.netSceneData = this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class SceneData{
|
||||
public static NetSceneData netSceneData;
|
||||
public static ServerMetadata metadata;
|
||||
public static GameObject localPlayer;
|
||||
}
|
||||
11
Assets/Scripts/NetSceneData.cs.meta
Normal file
11
Assets/Scripts/NetSceneData.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 176b9539293f58d65a001ed701f1959d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -23,6 +23,9 @@ public class PlayerController : NetworkBehaviour
|
||||
public AudioClip jumpSFX;
|
||||
float jumpT = 0;
|
||||
public bool listenToInput = true;
|
||||
public bool inDoor = false;
|
||||
public bool insideDoor = false;
|
||||
bool enteringDoor = false;
|
||||
|
||||
void Start()
|
||||
{
|
||||
@@ -75,6 +78,18 @@ public class PlayerController : NetworkBehaviour
|
||||
if (Input.GetKey(InputManager.data().leftInput)) { HorizontalAxis = -1; } else if (Input.GetKey(InputManager.data().rightInput)) { HorizontalAxis = 1; }
|
||||
// if (GameManager.isPaused) { HorizontalAxis = 0; }
|
||||
//Move according to input
|
||||
|
||||
//Exit the door
|
||||
if(enteringDoor && !Input.GetKey(InputManager.data().interactingKey)){
|
||||
enteringDoor=false;
|
||||
}
|
||||
if(insideDoor && !enteringDoor && Input.GetKey(InputManager.data().interactingKey)){
|
||||
Debug.Log("Exiting door");
|
||||
transform.position = SceneData.netSceneData.door.transform.position;
|
||||
insideDoor=false;
|
||||
enteringDoor=true;
|
||||
if(GetComponent<NetPlayer>()!=null){GetComponent<NetPlayer>().CallChangeInsideDoor(insideDoor);}
|
||||
}
|
||||
if (listenToInput)
|
||||
{
|
||||
if (isGrounded)
|
||||
@@ -90,7 +105,19 @@ public class PlayerController : NetworkBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
//Enter the door
|
||||
if(inDoor && Input.GetKey(InputManager.data().interactingKey) && !enteringDoor){
|
||||
if(SceneData.netSceneData.doorExit!=null){
|
||||
Debug.Log("Entering door");
|
||||
transform.position = SceneData.netSceneData.doorExit.position;
|
||||
insideDoor = true;
|
||||
enteringDoor=true;
|
||||
if(GetComponent<NetPlayer>()!=null){GetComponent<NetPlayer>().CallChangeInsideDoor(insideDoor);}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isSwimming || inWater) { moveInput = moveInput / 2f; }
|
||||
//Update moving value on Animation
|
||||
animator.SetBool("moving", (moveInput != 0));
|
||||
@@ -109,6 +136,11 @@ public class PlayerController : NetworkBehaviour
|
||||
|
||||
|
||||
//Apply moving input to player
|
||||
if(GetComponent<NetPlayer>()!=null){
|
||||
if(GetComponent<NetPlayer>().frndTrans!=null){
|
||||
rigidbody.velocity = GetComponent<NetPlayer>().frndTrans.GetComponent<Rigidbody2D>().velocity;
|
||||
}
|
||||
}
|
||||
rigidbody.transform.Translate(new Vector2(moveSpeed * moveInput, 0));
|
||||
|
||||
|
||||
@@ -138,6 +170,7 @@ public class PlayerController : NetworkBehaviour
|
||||
_isSwimming = inWater;
|
||||
|
||||
}
|
||||
|
||||
bool b;
|
||||
bool _isSwimming;
|
||||
public bool waterBoost;
|
||||
@@ -183,6 +216,8 @@ public class PlayerController : NetworkBehaviour
|
||||
Collider2D col = GetComponentInChildren<Collider2D>();
|
||||
return (Physics2D.BoxCast(col.bounds.center, new Vector2(col.bounds.size.x - (col.bounds.size.x / 5f), col.bounds.size.y), 0, Vector2.down, 0.1f, groundLayerMask));
|
||||
}
|
||||
|
||||
|
||||
// public bool getInWater(){Collider2D col = GetComponentInChildren<Collider2D>();
|
||||
// return (Physics2D.BoxCast(col.bounds.center, new Vector2(col.bounds.size.x - (col.bounds.size.x / 5f), col.bounds.size.y), 0, Vector2.down, 0.1f, waterLayerMask));
|
||||
// }
|
||||
|
||||
@@ -11,6 +11,7 @@ using UnityEngine.UI;
|
||||
public class loadingScreen : MonoBehaviour
|
||||
{
|
||||
public string sceneName;
|
||||
public int sceneIndex;
|
||||
public RectTransform loadingWheel;
|
||||
public RectTransform loadingProgress;
|
||||
CanvasGroup canvasGroup;
|
||||
@@ -29,6 +30,7 @@ public class loadingScreen : MonoBehaviour
|
||||
|
||||
void Start()
|
||||
{
|
||||
LoadingScreen.instance=this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
canvasGroup = GetComponent<CanvasGroup>();
|
||||
|
||||
@@ -69,26 +71,37 @@ public class loadingScreen : MonoBehaviour
|
||||
loading = true;
|
||||
loadingProgress.sizeDelta = new Vector2(0, loadingProgress.sizeDelta.y);
|
||||
SceneManager.sceneLoaded += SceneManager_sceneLoaded;
|
||||
loadingOperation = SceneManager.LoadSceneAsync(sceneName);
|
||||
if(sceneName != null){
|
||||
loadingOperation = SceneManager.LoadSceneAsync(sceneName);
|
||||
}else{
|
||||
loadingOperation = SceneManager.LoadSceneAsync(sceneIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void SceneManager_sceneLoaded(Scene arg0, LoadSceneMode arg1)
|
||||
{
|
||||
if (loading)
|
||||
hide();
|
||||
if (loading && !alreadyConnected)
|
||||
{
|
||||
// hide();
|
||||
if(isHost){host();}else{join();}
|
||||
|
||||
loading = false;
|
||||
loading = false;
|
||||
}
|
||||
if(alreadyConnected){
|
||||
// Debug.Log()
|
||||
SceneData.netSceneData = FindObjectOfType<NetSceneData>();
|
||||
SceneData.localPlayer.GetComponent<NetPlayer>().ReturnToSpawn();
|
||||
|
||||
}
|
||||
}
|
||||
public bool alreadyConnected= false;
|
||||
public string serverName;
|
||||
public bool isPublic;
|
||||
public string serverMetadata;
|
||||
|
||||
void host()
|
||||
{
|
||||
_LRM.serverName = serverName;
|
||||
_LRM.extraServerData = sceneName;
|
||||
_LRM.extraServerData = serverMetadata;
|
||||
_LRM.isPublicServer = isPublic;
|
||||
|
||||
_LRM.ServerStart();
|
||||
@@ -101,3 +114,8 @@ public class loadingScreen : MonoBehaviour
|
||||
NetworkManager.singleton.StartClient();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class LoadingScreen{
|
||||
public static loadingScreen instance;
|
||||
}
|
||||
|
||||
36
Assets/Scripts/login.cs
Normal file
36
Assets/Scripts/login.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
public class login : MonoBehaviour
|
||||
{
|
||||
public InputField nameInput;
|
||||
public Button loginBtn;
|
||||
void Start()
|
||||
{
|
||||
loginBtn.interactable = false;
|
||||
if (PlayerPrefs.HasKey("username") && PlayerPrefs.GetString("username").Length > 3)
|
||||
{
|
||||
SceneManager.LoadScene("MainMenu");
|
||||
return;
|
||||
}
|
||||
|
||||
nameInput.onValueChanged.AddListener(OnNameinputChange);
|
||||
}
|
||||
|
||||
|
||||
void OnNameinputChange(string value)
|
||||
{
|
||||
loginBtn.interactable = (value.Length > 3);
|
||||
}
|
||||
|
||||
public void Login(){
|
||||
if(nameInput.text.Length <=3){return;}
|
||||
|
||||
PlayerPrefs.SetString("username", nameInput.text);
|
||||
PlayerPrefs.Save();
|
||||
|
||||
SceneManager.LoadScene("MainMenu");
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/login.cs.meta
Normal file
11
Assets/Scripts/login.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb602c1a35483c66e97589f39f2fbf49
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -60,7 +60,19 @@ TextureImporter:
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
maxTextureSize: 512
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 512
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
|
||||
@@ -60,7 +60,19 @@ TextureImporter:
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
maxTextureSize: 512
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 512
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
|
||||
@@ -60,7 +60,19 @@ TextureImporter:
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
maxTextureSize: 128
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 128
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
|
||||
Reference in New Issue
Block a user