您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

635 行
22 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using UnityEditor;
using COSXML;
using COSXML.Model.Object;
using UnityEngine;
using System.Threading.Tasks;
using System.Net.Http.Headers;
using System.Text;
using COSXML.Auth;
using COSXML.Model.Tag;
using COSXML.Transfer;
using Newtonsoft.Json;
namespace Metacity.Publish.Editor
{
public enum ServerType
{
None, // no need server
Official, // use official server
Customize // use customize server
}
public delegate void FailedCallBack();
public class MetacityBuildWindow : EditorWindow
{
private const string configPath = "config/config.json";
private FailedCallBack _failedCallBack;
private Config _config = new Config();
private string _lastAccessToken = null;
private bool _isTokenValid = false;
private SerializedObject _portObject;
private SerializedProperty _portsProperty;
private SerializedProperty _envVerbsProperty;
private readonly GUIStyle _errorStyle = new GUIStyle();
private readonly GUIStyle _passStyle = new GUIStyle();
public List<GameServerPort> gameServerPorts = new List<GameServerPort>();
public List<EnvironmentVariable> environmentVariables = new List<EnvironmentVariable>();
private float _process = 0.0f;
private string _processNote = "";
private bool _showProcessBar = false;
private bool _isPublishClick = false;
private PutObjectRequest _serverRequest;
private PutObjectRequest _clientRequest;
private COSXMLUploadTask _uploadTask;
private void OnEnable()
{
_failedCallBack = CloseProcessBar;
_portObject = new SerializedObject(this);
_envVerbsProperty = _portObject.FindProperty("environmentVariables");
_portsProperty = _portObject.FindProperty("gameServerPorts");
_errorStyle.normal.textColor = Color.red;
_passStyle.normal.textColor = Color.green;
_isPublishClick = false;
LoadConfig();
}
private void OnDestroy()
{
SaveConfig();
}
private void LoadConfig()
{
string path = Path.Combine(Application.dataPath, configPath);
if (!string.IsNullOrEmpty(path))
{
string dir = Path.GetDirectoryName(path);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
if (!System.IO.File.Exists(path))
{
_config = new Config();
var fs = System.IO.File.Create(path);
var json = JsonConvert.SerializeObject(_config);
byte[] array = Encoding.UTF8.GetBytes(json);
fs.Write(array);
fs.Close();
fs.Dispose();
return;
}
Config localConfig = JsonTools.FromFile<Config>(path);
if (localConfig != null)
{
_config = localConfig;
gameServerPorts = _config.gameServerPorts;
environmentVariables = _config.environmentVariables;
}
else
{
Debug.LogError("failed to deserialize config data");
}
}
}
private void SaveConfig()
{
_config.gameServerPorts = gameServerPorts;
_config.environmentVariables = environmentVariables;
string path = Path.Combine(Application.dataPath, configPath);
if (!string.IsNullOrEmpty(path))
{
string dir = Path.GetDirectoryName(path);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
if (!System.IO.File.Exists(path))
{
var fs = System.IO.File.Create(path);
var json = JsonConvert.SerializeObject(_config);
byte[] array = Encoding.UTF8.GetBytes(json);
fs.Write(array);
fs.Close();
fs.Dispose();
return;
}
JsonTools.ToFile(_config, path);
}
}
#region render UI
private void OnGUI()
{
EditorGUILayout.BeginVertical();
RenderHelper();
EditorGUILayout.Space(10);
RenderPublishInfo();
EditorGUILayout.Space(10);
RenderActions();
EditorGUILayout.EndVertical();
Validate();
}
private async void Validate()
{
if (!string.IsNullOrEmpty(_config.accessToken) && _config.accessToken != _lastAccessToken)
{
MetacityInterface.client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _config.accessToken);
bool isValid = await MetacityInterface.CheckAccessToken();
if (isValid)
{
_isTokenValid = true;
_lastAccessToken = _config.accessToken;
UpdateConfig();
}
else
{
_isTokenValid = false;
MetacityInterface.client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _lastAccessToken);
}
}
}
private void RenderHelper()
{
EditorGUILayout.HelpBox("\n" +
"Publish your cloudrendering build zip to metacity platform.\n" +
"\n"
, MessageType.Info);
}
private void RenderPublishInfo()
{
EditorGUILayout.HelpBox("\n" +
"Get your access token from metacity website.\n" +
"\n"
, MessageType.Warning);
EditorGUILayout.Space(10);
_config.accessToken = EditorGUILayout.TextField(new GUIContent("Access Token"), _config.accessToken);
if (!string.IsNullOrEmpty(_config.accessToken))
{
if (_isTokenValid)
{
EditorGUILayout.LabelField("Valid", _passStyle);
}
else
{
EditorGUILayout.LabelField(new GUIContent("Invalid access token"), _errorStyle);
}
}
else
{
EditorGUILayout.LabelField("Access token can't be null", _errorStyle);
}
_config.templateName = EditorGUILayout.TextField(new GUIContent("Template Name"), _config.templateName);
_config.thumbnail = EditorGUILayout.TextField(new GUIContent("Template Thumbnail"), _config.thumbnail);
_config.memberLimit =
EditorGUILayout.IntSlider(new GUIContent("Template Member Limit"), _config.memberLimit, 5, 8);
EditorGUILayout.Space(10);
EditorGUILayout.LabelField("Template Description");
_config.description =
EditorGUILayout.TextArea(_config.description, EditorStyles.textArea, GUILayout.Height(50));
EditorGUILayout.Space(10);
EditorGUILayout.HelpBox("\n" +
"If you need to add/update build content, please export the build file in advance and compress it into zip.\n" +
"\n"
, MessageType.Warning);
_config.buildNeeded = EditorGUILayout.Toggle(new GUIContent("create/update Build"), _config.buildNeeded);
EditorGUI.indentLevel++;
if (_config.buildNeeded)
{
EditorGUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
_config.clientPath = EditorGUILayout.TextField(new GUIContent("client(zip) path"), _config.clientPath);
if (GUILayout.Button(new GUIContent("Browser"), GUILayout.Width(80)))
{
_config.clientPath =
EditorUtility.OpenFilePanel("select client zip file", Application.dataPath, "zip");
EditorUtility.SetDirty(this);
}
EditorGUILayout.EndHorizontal();
_config.executableClientPath = EditorGUILayout.TextField(new GUIContent("executable path"), _config.executableClientPath);
EditorGUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Server Type");
_config.serverType = (ServerType) EditorGUILayout.EnumPopup(_config.serverType);
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space(10);
EditorGUI.indentLevel++;
if (_config.serverType == ServerType.Customize)
{
EditorGUILayout.BeginHorizontal();
_config.serverPath =
EditorGUILayout.TextField(new GUIContent("server(zip) path"), _config.serverPath);
if (GUILayout.Button(new GUIContent("Browser"), GUILayout.Width(80)))
{
_config.serverPath =
EditorUtility.OpenFilePanel("select server zip file", Application.dataPath, "zip");
EditorUtility.SetDirty(this);
}
EditorGUILayout.EndHorizontal();
_config.executableServerPath = EditorGUILayout.TextField(new GUIContent("executable path"), _config.executableServerPath);
EditorGUILayout.Space(10);
_portObject.Update();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(_portsProperty, new GUIContent("Game Server Ports"), true);
EditorGUILayout.Space(10);
EditorGUILayout.PropertyField(_envVerbsProperty, new GUIContent("Environment Variables"), true);
if (EditorGUI.EndChangeCheck())
{
_portObject.ApplyModifiedProperties();
}
}
EditorGUI.indentLevel--;
EditorGUILayout.Space(10);
EditorGUI.indentLevel--;
}
}
private void RenderActions()
{
if (_isPublishClick)
{
_isPublishClick = false;
_showProcessBar = true;
Publish();
}
if (GUILayout.Button($"Publish"))
{
_isPublishClick = true;
EditorUtility.SetDirty(this);
}
if (_showProcessBar)
{
Repaint();
if (EditorUtility.DisplayCancelableProgressBar("Upload File to COS", _processNote, _process))
{
_clientRequest?.Cancel();
_serverRequest?.Cancel();
_uploadTask?.Cancel();
CloseProcessBar();
Debug.Log("Publish canceled");
}
}
}
private async void Publish()
{
bool firstPublish = false;
string crUrl = "";
string uosUrl = "";
bool isValid = await MetacityInterface.CheckAccessToken();
if (!isValid)
{
_isTokenValid = false;
EditorUtility.SetDirty(this);
CloseProcessBar();
return;
}
if (string.IsNullOrEmpty(_config.templateId))
{
var result = await CreateNewTemplateByConfig(_failedCallBack);
if(!result) return;
firstPublish = true;
}
else
{
var template = await MetacityInterface.GetTemplateById(_config.templateId);
if (template == null)
{
var result = await CreateNewTemplateByConfig(_failedCallBack);
if(!result) return;
firstPublish = true;
}
var templateResponse = await MetacityInterface.UpdateTemplateById(template, _config.templateId, _config.templateName, _config.description,
_config.thumbnail, _config.buildId);
if (templateResponse == null)
{
CloseProcessBar();
}
}
SaveConfig();
Debug.Log("Template message has been updated.");
if (_config.buildNeeded)
{
// BuildByMultipleCatalog.DoBuild();
// var rootPath = Path.GetDirectoryName(Application.dataPath);
// var buildPath = Path.Combine(rootPath, BuildByMultipleCatalog.ProjectCacheFolderName);
// var zipPath = Path.Combine(rootPath, "build.zip");
// ProcessBuildZip(buildPath, zipPath);
//
// this._config.clientPath = zipPath;
// this._config.executableClientPath = Path.Combine(EditorUserBuildSettings.activeBuildTarget.ToString(),
// BuildByMultipleCatalog.ProjectCacheProjectName, BuildByMultipleCatalog.ProjectCacheName);
// this._config.serverType = ServerType.Official;
if (string.IsNullOrEmpty(_config.buildId))
{
var result = await CreateNewCloudrenderingByConfig(_failedCallBack);
if (!result) return;
}
else
{
var cr = await MetacityInterface.GetCloudrenderingById(_config.buildId);
if (cr == null)
{
var result = await CreateNewCloudrenderingByConfig(_failedCallBack);
if (!result) return;
}
}
_processNote = "Start upload ...";
if (!string.IsNullOrEmpty(_config.clientPath))
{
crUrl = await UploadFile(_config.clientPath, _failedCallBack, false);
if (string.IsNullOrEmpty(crUrl))
{
return;
}
}
if (_config.serverType == ServerType.Customize)
{
uosUrl = await UploadFile(_config.serverPath, _failedCallBack, true);
if (string.IsNullOrEmpty(uosUrl))
{
return;
}
}
_processNote = "Upload Finished";
bool isPublish = await MetacityInterface.PublishPrepare(
_config.userId,
_config.templateId,
_config.buildId,
_config.serverType.ToString(),
crUrl,
_config.executableClientPath,
Path.GetFileName(_config.clientPath),
clientSize,
uosUrl,
_config.executableServerPath,
_config.environmentVariables,
_config.gameServerPorts,
firstPublish);
if (isPublish)
{
Debug.Log("Publish successful. Please go to metacity website to continue the follow-up operation");
}
else
{
Debug.LogError("Publish Failed");
}
}
CloseProcessBar();
}
private void CloseProcessBar()
{
EditorUtility.ClearProgressBar();
_showProcessBar = false;
EditorUtility.SetDirty(this);
}
private async Task<bool> CreateNewTemplateByConfig(FailedCallBack callBack)
{
var template = await MetacityInterface.CreateTemplate(_config.templateName, _config.description, _config.thumbnail);
if (template == null)
{
callBack.Invoke();
return false;
}
_config.templateId = template.id;
_config.templateName = template.name;
_config.description = template.description;
_config.thumbnail = template.banner;
return true;
}
private async Task<bool> CreateNewCloudrenderingByConfig(FailedCallBack callBack)
{
var cr = await MetacityInterface.CreateCloudrendering(_config.templateName, _config.description,
_config.templateName);
if (cr == null)
{
callBack.Invoke();
return false;
}
_config.buildId = cr.id;
var template = await MetacityInterface.GetTemplateById(_config.templateId);
if (template == null)
{
callBack.Invoke();
return false;
}
var templateResponse = await MetacityInterface.UpdateTemplateById(template, _config.templateId, _config.templateName, _config.description,
_config.thumbnail, _config.buildId);
if (templateResponse == null)
{
callBack.Invoke();
return false;
}
return true;
}
private async void UpdateConfig()
{
_config.userId = await MetacityInterface.GetUserId();
if(string.IsNullOrEmpty(_config.templateId)) return;
var template = await MetacityInterface.GetTemplateById(_config.templateId);
_config.templateName = template.name;
_config.thumbnail = template.banner;
_config.description = template.description;
}
#endregion
#region process zip
private string ProcessBuildZip(string buildPath, string zipPath)
{
if (File.Exists(zipPath))
{
File.Delete(zipPath);
}
ZipFile.CreateFromDirectory(buildPath, zipPath);
return zipPath;
}
#endregion
#region Upload cos
private long clientSize;
private long serverSize;
private async Task<string> UploadFile(string uploadFile, FailedCallBack onFailed, bool isServer)
{
if (!File.Exists(uploadFile))
{
onFailed.Invoke();
return null;
}
FileInfo fileInfo = new FileInfo(uploadFile);
if (isServer)
{
serverSize = fileInfo.Length;
}
else
{
clientSize = fileInfo.Length;
}
string uploadUrl = await MetacityInterface.GetUploadUrlAsync(fileInfo.Name);
string downloadUrl = await MetacityInterface.GetDownloadUrlAsync(fileInfo.Name);
var result = await Task.Run(() => { return UploadFileCos(uploadFile, uploadUrl, isServer); });
if (!result)
{
onFailed.Invoke();
return null;
}
return downloadUrl;
}
bool UploadFileCos(string uploadFile, string requestSignURL, bool isServer)
{
if (File.Exists(uploadFile))
{
CosXmlConfig config = new CosXmlConfig.Builder()
.SetRegion("ap-shanghai")
.SetDebugLog(true)
.Build();
var cosXml = new CosXmlServer(config, null);
try
{
if (isServer)
{
_serverRequest = new PutObjectRequest(null, null, uploadFile);
_serverRequest.RequestURLWithSign = requestSignURL;
_serverRequest.SetCosProgressCallback(delegate(long completed, long total)
{
_process = (float)completed / total;
_processNote = string.Format("uploaded {0} of {1} bytes. {2:##.##} % complete...",
completed,
serverSize,
completed * 100.0/ serverSize);
});
PutObjectResult result = cosXml.PutObject(_serverRequest);
Debug.LogFormat(result.GetResultInfo());
return result.IsSuccessful();
}
else
{
_clientRequest = new PutObjectRequest(null, null, uploadFile);
_clientRequest.RequestURLWithSign = requestSignURL;
_clientRequest.SetCosProgressCallback(delegate(long completed, long total)
{
_process = (float)completed / total;
_processNote = string.Format("uploaded {0} of {1} bytes. {2:##.##} % complete...",
completed,
clientSize,
completed * 100.0/ clientSize);
});
PutObjectResult result = cosXml.PutObject(_clientRequest);
Debug.LogFormat(result.GetResultInfo());
return result.IsSuccessful();
}
}
catch (COSXML.CosException.CosClientException clientEx)
{
Debug.LogException(clientEx);
}
catch (COSXML.CosException.CosServerException serverEx)
{
Debug.LogException(serverEx);
}
}
return false;
}
#endregion
}
}