using UnityEditor; using UnityEngine; using System; using System.Threading; using System.Collections; using System.Collections.Generic; using Perforce.P4; using System.Linq; using System.Text; using System.IO; namespace P4Connect { /// <summary> /// Small class that encompasses a perforce connection /// Always use it with the 'using' statement, so its /// Dispose() method is called and the connection to /// the server is properly closed. /// </summary> public class PerforceConnection : IDisposable { // Give read-only access to the server we're connected to public Server P4Server { get { return _P4Server; } set { _P4Server = value; } } // Give read-only access to the current depot public Repository P4Depot { get { return _P4Depot; } set { _P4Depot = value; } } // Give read-only access to the current connection public Connection P4Connection { get { return _P4Depot.Connection; } } // Give read-only access to the current client public Client P4Client { get { return _P4Depot.Connection.Client; } } static Server _P4Server; static Repository _P4Depot; static int _ConnectionCount; static DateTime _ConnectedTimestamp; bool bDisposed; // Used if display timings is turned on DateTime _InnerStartTimestamp; DateTime _StartTimestamp; List<string> _GetMetaDataTimingInfo; static PerforceConnection() { _ConnectionCount = 0; } static bool Disconnected { get { return _P4Server == null || _P4Depot == null || _P4Depot.Connection == null || _P4Depot.Connection.Status != ConnectionStatus.Connected; } } static bool Connected { get { return _P4Server != null && _P4Depot != null && _P4Depot.Connection != null && _P4Depot.Connection.Status == ConnectionStatus.Connected; } } static void OpenConnection() { if (Disconnected) { // Fetch the configuration settings from Config _P4Server = new Server(new ServerAddress(Config.ServerURI)); _P4Depot = new Repository(_P4Server); _P4Depot.Connection.UserName = Config.Username; _P4Depot.Connection.Client = new Client(); _P4Depot.Connection.Client.Name = Config.Workspace; if (Config.OverrideCharset) { System.Environment.SetEnvironmentVariable("P4CHARSET", Config.Charset); } if (Config.OverrideHostname) { System.Environment.SetEnvironmentVariable("P4HOST", Config.Hostname); } if (Config.UseIgnore) { System.Environment.SetEnvironmentVariable("P4IGNORE", Config.IgnoreName); } // Open the connection, give its log entries a programname and version Options opts = new Options(); opts.Add("ProgramName", "p4connect"); opts.Add("ProgramVersion", Version.unityVersion + "." + Version.build); opts.Add("cwd", Utils.GetProjectDirectory()); if (_P4Depot.Connection.Connect(opts)) { // And set the credentials so that we can use secure connections _P4Depot.Connection.Trust(new TrustCmdOptions(TrustCmdFlags.AutoAccept), ""); _P4Depot.Connection.Credential = _P4Depot.Connection.Login(Config.Password); _P4Depot.Connection.CommandEcho += CommandEcho; } else { if (EditorUtility.DisplayDialog("Perforce connection Exception", "P4Connect could not connect to the server and will disable itself to prevent further slow downs\n(You'll need to \"Edit->Perforce Settings\" to turn it back on)\n\nP4Connect can attempt to cancel the current operation for you (to prevent your local files and the depot from going out of sync until you can fix the connection issue). Would you like to try?", "Yes", "No")) { Config.NeedToCheckSettings(); throw new Exception("P4Connect - Can't connect to server"); } else { Config.NeedToCheckSettings(); } } } if (_ConnectionCount == 0) { // De-register from update EditorApplication.update -= UpdateConnection; } ++_ConnectionCount; } static void CommandEcho(String data) { if (Config.DisplayP4Commands) { Debug.Log(data); } } static void UpdateConnection() { double deltaTime = (DateTime.Now - _ConnectedTimestamp).TotalSeconds; if (deltaTime > Config.ConnectionTimeOut) { ForceCloseConnection(); } } static void CloseConnection() { --_ConnectionCount; if (_ConnectionCount == 0) { EditorApplication.update += UpdateConnection; _ConnectedTimestamp = DateTime.Now; } } public static void ForceCloseConnection() { // Close the connection if (Connected) { _P4Depot.Connection.CommandEcho -= CommandEcho; _P4Depot.Connection.Disconnect(); _P4Depot = null; _P4Server = null; // No need to be updated anymore EditorApplication.update -= UpdateConnection; } } /// <summary> /// Create the Perforce connection on construction /// </summary> public PerforceConnection() { if (Config.DisplayP4Timings) { _StartTimestamp = DateTime.Now; } OpenConnection(); _P4Depot.Connection.TaggedOutputReceived += TaggedEcho; if (Config.DisplayP4Timings) { _InnerStartTimestamp = DateTime.Now; _GetMetaDataTimingInfo = new List<string>(); } } public event Action<FileSpec> FileEchoReceived; void TaggedEcho(uint cmdId, int ObjId, TaggedObject Obj) { if (FileEchoReceived != null) { FileSpec fs = FileSpec.ClientSpec(Obj["clientFile"]); FileEchoReceived(fs); } } /// <summary> /// Dispose of the connection /// to be safe, use "using" instead of calling this directly /// </summary> public void Dispose() { // Simple call the dispose method Dispose(true); // Since Dispose cleans up everything, no need to call the finalizer on this GC.SuppressFinalize(this); } /// <summary> /// Dispose virtual method /// </summary> protected virtual void Dispose(bool abDisposing) { if (!bDisposed) { if (abDisposing) { _P4Depot.Connection.TaggedOutputReceived -= TaggedEcho; if (Config.DisplayP4Timings) { double deltaInnerTime = (DateTime.Now - _InnerStartTimestamp).TotalMilliseconds; CloseConnection(); double deltaTime = (DateTime.Now - _StartTimestamp).TotalMilliseconds; StringBuilder builder = new StringBuilder(); builder.AppendLine("P4Connect - Timing for the last operation: " + deltaTime + " ms (Actual operation: " + deltaInnerTime + " ms)"); if (_GetMetaDataTimingInfo != null) { foreach (string line in _GetMetaDataTimingInfo) { builder.AppendLine(line); } } Debug.Log(builder.ToString()); } else { CloseConnection(); } System.Environment.SetEnvironmentVariable("P4HOST", ""); } bDisposed = true; } } /// <summary> /// Used to track down timing issues /// </summary> public void AppendTimingInfo(string aLine) { if (_GetMetaDataTimingInfo != null) { _GetMetaDataTimingInfo.Add(aLine); } } /// <summary> /// Finalizer /// </summary> ~PerforceConnection() { Dispose(false); } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#10 | 16210 | Norman Morse | Remove files from old locations | ||
#9 | 15401 | Norman Morse |
Fixed serialization of Config so P4Connect remains connected after a Game Run Cleaned up some menus. |
||
#8 | 15266 | Norman Morse |
Integrated "UpdateVersion" tool to update the VersionInfo and the DLL properties with information from "Version" EC generates the Version file for us in builds. Workshop users need to generate their own Release number with two zeros (like 2015.2.0.0) which will have the last two numbers replaced with change ID. |
||
#7 | 12568 | Norman Morse | Fixed some error handling during Perforce Configuration | ||
#6 | 12553 | Norman Morse |
integrate from internal main Build fixes for EC. Major changes to Configuration and re-initialization code. Bug fixes |
||
#5 | 12512 | Norman Morse | Integrate from Dev branch, preparing for Beta3 release | ||
#4 | 12251 | Norman Morse |
Fixes for Beta 2 release Mostly Configuration dialog bug fixes |
||
#3 | 12135 | Norman Morse |
Integrate dev branch changes into main. This code is the basiis of the 2.7 BETA release which provides Unity 5 compatibility |
||
#2 | 11280 | Norman Morse | Customize API Tags for P4Connect | ||
#1 | 10940 | Norman Morse |
Inital Workshop release of P4Connect. Released under BSD-2 license |