mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-17 11:35:08 -04:00
Rewrite launcher web tasks to use asyncdownloader
This commit is contained in:
parent
fd5427edb4
commit
2b3fb48f54
@ -127,14 +127,14 @@ namespace ClassicalSharp.Gui.Screens {
|
||||
int lastDownloadStatus = int.MinValue;
|
||||
StringBuffer lastDownload = new StringBuffer(48);
|
||||
void CheckOtherStatuses() {
|
||||
Request item = game.AsyncDownloader.CurrentItem;
|
||||
Request item = game.Downloader.CurrentItem;
|
||||
if (item == null || !(item.Identifier == "terrain" || item.Identifier == "texturePack")) {
|
||||
if (status.Textures[1].IsValid) status.SetText(1, null);
|
||||
lastDownloadStatus = int.MinValue;
|
||||
return;
|
||||
}
|
||||
|
||||
int progress = game.AsyncDownloader.CurrentItemProgress;
|
||||
int progress = game.Downloader.CurrentItemProgress;
|
||||
if (progress == lastDownloadStatus) return;
|
||||
lastDownloadStatus = progress;
|
||||
SetFetchStatus(progress);
|
||||
|
@ -221,7 +221,7 @@ namespace ClassicalSharp.Entities {
|
||||
row[x] = dist < half * half ? inPix : outPix;
|
||||
}
|
||||
}
|
||||
shadowTex = gfx.CreateTexture(fastBmp, true, false);
|
||||
shadowTex = gfx.CreateTexture(fastBmp, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,6 +111,7 @@ namespace ClassicalSharp.Entities {
|
||||
if (List[i] == null) continue;
|
||||
List[i].ContextLost();
|
||||
}
|
||||
game.Graphics.DeleteTexture(ref ShadowComponent.shadowTex);
|
||||
}
|
||||
|
||||
void ContextRecreated() {
|
||||
|
@ -112,7 +112,7 @@ namespace ClassicalSharp.Entities {
|
||||
if (!fetchedSkin && Model.UsesSkin) {
|
||||
Player first = FirstOtherWithSameSkinAndFetchedSkin();
|
||||
if (first == null) {
|
||||
game.AsyncDownloader.DownloadSkin(SkinName, SkinName);
|
||||
game.Downloader.AsyncGetSkin(SkinName, SkinName);
|
||||
} else {
|
||||
ApplySkin(first);
|
||||
}
|
||||
@ -120,7 +120,7 @@ namespace ClassicalSharp.Entities {
|
||||
}
|
||||
|
||||
Request item;
|
||||
if (!game.AsyncDownloader.TryGetItem(SkinName, out item)) return;
|
||||
if (!game.Downloader.TryGetItem(SkinName, out item)) return;
|
||||
if (item == null || item.Data == null) { SetSkinAll(true); return; }
|
||||
|
||||
Bitmap bmp = (Bitmap)item.Data;
|
||||
|
@ -73,7 +73,7 @@ namespace ClassicalSharp {
|
||||
BlockInfo.Init();
|
||||
ModelCache = new ModelCache(this);
|
||||
ModelCache.InitCache();
|
||||
AsyncDownloader = new AsyncDownloader(Drawer2D); Components.Add(AsyncDownloader);
|
||||
Downloader = new AsyncDownloader(Drawer2D); Components.Add(Downloader);
|
||||
Lighting = new BasicLighting(); Components.Add(Lighting);
|
||||
|
||||
Drawer2D.UseBitmappedChat = ClassicMode || !Options.GetBool(OptionsKey.UseChatFont, false);
|
||||
@ -225,7 +225,7 @@ namespace ClassicalSharp {
|
||||
const double defTicks = 1.0 / 20;
|
||||
const double netTicks = 1.0 / 60;
|
||||
|
||||
AddScheduledTask(30, AsyncDownloader.PurgeOldEntriesTask);
|
||||
AddScheduledTask(30, Downloader.PurgeOldEntriesTask);
|
||||
AddScheduledTask(netTicks, Server.Tick);
|
||||
entTask = AddScheduledTask(defTicks, Entities.Tick);
|
||||
|
||||
|
@ -164,7 +164,7 @@ namespace ClassicalSharp {
|
||||
|
||||
public int Vertices;
|
||||
public FrustumCulling Culling;
|
||||
public AsyncDownloader AsyncDownloader;
|
||||
public AsyncDownloader Downloader;
|
||||
|
||||
/// <summary> How sensitive the client is to changes in the player's mouse position. </summary>
|
||||
public int MouseSensitivity = 30;
|
||||
|
@ -65,7 +65,7 @@ namespace ClassicalSharp {
|
||||
protected void WarningScreenTick(Overlay warning) {
|
||||
string identifier = warning.Metadata;
|
||||
Request item;
|
||||
if (!game.AsyncDownloader.TryGetItem(identifier, out item) || item.Data == null) return;
|
||||
if (!game.Downloader.TryGetItem(identifier, out item) || item.Data == null) return;
|
||||
|
||||
long contentLength = (long)item.Data;
|
||||
if (contentLength <= 0) return;
|
||||
@ -78,7 +78,7 @@ namespace ClassicalSharp {
|
||||
|
||||
protected internal void RetrieveTexturePack(string url) {
|
||||
if (!game.AcceptedUrls.HasEntry(url) && !game.DeniedUrls.HasEntry(url)) {
|
||||
game.AsyncDownloader.RetrieveContentLength(url, true, "CL_" + url);
|
||||
game.Downloader.AsyncGetContentLength(url, true, "CL_" + url);
|
||||
string address = url;
|
||||
if (url.StartsWith("https://")) address = url.Substring(8);
|
||||
if (url.StartsWith("http://")) address = url.Substring(7);
|
||||
@ -120,20 +120,18 @@ namespace ClassicalSharp {
|
||||
|
||||
TexturePack.ExtractCurrent(game, url);
|
||||
if (url.Contains(".zip")) {
|
||||
game.AsyncDownloader.DownloadData(url, true, "texturePack",
|
||||
lastModified, etag);
|
||||
game.Downloader.AsyncGetData(url, true, "texturePack", lastModified, etag);
|
||||
} else {
|
||||
game.AsyncDownloader.DownloadImage(url, true, "terrain",
|
||||
lastModified, etag);
|
||||
game.Downloader.AsyncGetImage(url, true, "terrain", lastModified, etag);
|
||||
}
|
||||
}
|
||||
|
||||
protected void CheckAsyncResources() {
|
||||
Request item;
|
||||
if (game.AsyncDownloader.TryGetItem("terrain", out item)) {
|
||||
if (game.Downloader.TryGetItem("terrain", out item)) {
|
||||
TexturePack.ExtractTerrainPng(game, item);
|
||||
}
|
||||
if (game.AsyncDownloader.TryGetItem("texturePack", out item)) {
|
||||
if (game.Downloader.TryGetItem("texturePack", out item)) {
|
||||
TexturePack.ExtractTexturePack(game, item);
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ namespace ClassicalSharp.Network.Protocols {
|
||||
|
||||
public override void Tick() {
|
||||
Request item;
|
||||
game.AsyncDownloader.TryGetItem(womEnvIdentifier, out item);
|
||||
game.Downloader.TryGetItem(womEnvIdentifier, out item);
|
||||
if (item != null && item.Data != null) {
|
||||
ParseWomConfig((string)item.Data);
|
||||
}
|
||||
@ -37,7 +37,7 @@ namespace ClassicalSharp.Network.Protocols {
|
||||
// new world if the async 'get request' didn't complete before the new world was loaded.
|
||||
womCounter++;
|
||||
womEnvIdentifier = "womenv_" + womCounter;
|
||||
game.AsyncDownloader.DownloadPage(url, true, womEnvIdentifier);
|
||||
game.Downloader.AsyncGetString(url, true, womEnvIdentifier);
|
||||
sendWomId = true;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ namespace ClassicalSharp.Network {
|
||||
public int CurrentItemProgress = -3;
|
||||
public IDrawer2D Drawer;
|
||||
public CookieContainer Cookies;
|
||||
public bool KeepAlive;
|
||||
public AsyncDownloader(IDrawer2D drawer) { this.drawer = drawer; }
|
||||
|
||||
#if !LAUNCHER
|
||||
@ -63,59 +64,73 @@ namespace ClassicalSharp.Network {
|
||||
/// <summary> Asynchronously downloads a skin. If 'skinName' points to the url then the skin is
|
||||
/// downloaded from that url, otherwise it is downloaded from the url 'defaultSkinServer'/'skinName'.png </summary>
|
||||
/// <remarks> Identifier is skin_'skinName'.</remarks>
|
||||
public void DownloadSkin(string identifier, string skinName) {
|
||||
string strippedSkinName = Utils.StripColours(skinName);
|
||||
string url = Utils.IsUrlPrefix(skinName, 0) ? skinName :
|
||||
skinServer + strippedSkinName + ".png";
|
||||
public void AsyncGetSkin(string identifier, string skinName) {
|
||||
string url = Utils.IsUrlPrefix(skinName, 0) ? skinName
|
||||
: skinServer + Utils.StripColours(skinName) + ".png";
|
||||
|
||||
AddRequest(url, false, identifier, RequestType.Bitmap,
|
||||
DateTime.MinValue , null);
|
||||
DateTime.MinValue, null, null);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary> Asynchronously downloads a bitmap image from the specified url. </summary>
|
||||
public void DownloadImage(string url, bool priority, string identifier) {
|
||||
public void AsyncGetImage(string url, bool priority, string identifier) {
|
||||
AddRequest(url, priority, identifier, RequestType.Bitmap,
|
||||
DateTime.MinValue, null);
|
||||
DateTime.MinValue, null, null);
|
||||
}
|
||||
|
||||
/// <summary> Asynchronously downloads a string from the specified url. </summary>
|
||||
public void DownloadPage(string url, bool priority, string identifier) {
|
||||
public void AsyncGetString(string url, bool priority, string identifier) {
|
||||
AddRequest(url, priority, identifier, RequestType.String,
|
||||
DateTime.MinValue, null);
|
||||
DateTime.MinValue, null, null);
|
||||
}
|
||||
|
||||
/// <summary> Asynchronously downloads a byte array. </summary>
|
||||
public void DownloadData(string url, bool priority, string identifier) {
|
||||
public void AsyncGetData(string url, bool priority, string identifier) {
|
||||
AddRequest(url, priority, identifier, RequestType.ByteArray,
|
||||
DateTime.MinValue, null);
|
||||
DateTime.MinValue, null, null);
|
||||
}
|
||||
|
||||
/// <summary> Asynchronously downloads a bitmap image. </summary>
|
||||
public void DownloadImage(string url, bool priority, string identifier,
|
||||
public void AsyncGetImage(string url, bool priority, string identifier,
|
||||
DateTime lastModified, string etag) {
|
||||
AddRequest(url, priority, identifier, RequestType.Bitmap,
|
||||
lastModified, etag);
|
||||
lastModified, etag, null);
|
||||
}
|
||||
|
||||
/// <summary> Asynchronously downloads a byte array. </summary>
|
||||
public void DownloadData(string url, bool priority, string identifier,
|
||||
public void AsyncGetData(string url, bool priority, string identifier,
|
||||
DateTime lastModified, string etag) {
|
||||
AddRequest(url, priority, identifier, RequestType.ByteArray,
|
||||
lastModified, etag);
|
||||
lastModified, etag, null);
|
||||
}
|
||||
|
||||
#if !LAUNCHER
|
||||
/// <summary> Asynchronously retrieves the content length of the body response. </summary>
|
||||
public void RetrieveContentLength(string url, bool priority, string identifier) {
|
||||
public void AsyncGetContentLength(string url, bool priority, string identifier) {
|
||||
AddRequest(url, priority, identifier, RequestType.ContentLength,
|
||||
DateTime.MinValue, null);
|
||||
DateTime.MinValue, null, null);
|
||||
}
|
||||
#else
|
||||
/// <summary> Asynchronously retrieves the content length of the body response. </summary>
|
||||
public void AsyncPostString(string url, bool priority, string identifier, string contents) {
|
||||
AddRequest(url, priority, identifier, RequestType.String,
|
||||
DateTime.MinValue, null, contents);
|
||||
}
|
||||
#endif
|
||||
|
||||
void AddRequest(string url, bool priority, string identifier,
|
||||
RequestType type, DateTime lastModified, string etag) {
|
||||
RequestType type, DateTime lastModified, string etag, object data) {
|
||||
lock (pendingLocker) {
|
||||
Request request = new Request(url, identifier, type, lastModified, etag);
|
||||
Request request = new Request();
|
||||
request.Url = url;
|
||||
request.Identifier = identifier;
|
||||
request.Type = type;
|
||||
request.LastModified = lastModified;
|
||||
request.ETag = etag;
|
||||
request.Data = data;
|
||||
|
||||
request.TimeAdded = DateTime.UtcNow;
|
||||
if (priority) {
|
||||
pending.Insert(0, request);
|
||||
} else {
|
||||
@ -208,7 +223,6 @@ namespace ClassicalSharp.Network {
|
||||
string url = request.Url;
|
||||
Utils.LogDebug("Downloading {0} from: {1}", request.Type, url);
|
||||
HttpStatusCode status = HttpStatusCode.OK;
|
||||
request.Data = null;
|
||||
|
||||
try {
|
||||
HttpWebRequest req = MakeRequest(request);
|
||||
@ -228,6 +242,7 @@ namespace ClassicalSharp.Network {
|
||||
status = ((HttpWebResponse)webEx.Response).StatusCode;
|
||||
webEx.Response.Close();
|
||||
}
|
||||
request.WebEx = webEx;
|
||||
}
|
||||
|
||||
if (status != HttpStatusCode.OK) {
|
||||
@ -285,19 +300,31 @@ namespace ClassicalSharp.Network {
|
||||
req.Proxy = null;
|
||||
req.UserAgent = Program.AppName;
|
||||
req.CookieContainer = Cookies;
|
||||
req.KeepAlive = KeepAlive;
|
||||
|
||||
if (request.LastModified != DateTime.MinValue)
|
||||
if (request.LastModified != DateTime.MinValue) {
|
||||
req.IfModifiedSince = request.LastModified;
|
||||
if (request.ETag != null)
|
||||
}
|
||||
if (request.ETag != null) {
|
||||
req.Headers["If-None-Match"] = request.ETag;
|
||||
}
|
||||
|
||||
if (request.Data != null) {
|
||||
req.Method = "POST";
|
||||
req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8;";
|
||||
byte[] encodedData = Encoding.UTF8.GetBytes((string)request.Data);
|
||||
req.ContentLength = encodedData.Length;
|
||||
using (Stream stream = req.GetRequestStream()) {
|
||||
stream.Write(encodedData, 0, encodedData.Length);
|
||||
}
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
static byte[] buffer = new byte[4096 * 8];
|
||||
MemoryStream DownloadBytes(HttpWebResponse response) {
|
||||
int length = (int)response.ContentLength;
|
||||
MemoryStream dst = length > 0 ?
|
||||
new MemoryStream(length) : new MemoryStream();
|
||||
MemoryStream dst = length > 0 ? new MemoryStream(length) : new MemoryStream();
|
||||
CurrentItemProgress = length > 0 ? 0 : -1;
|
||||
|
||||
using (Stream src = response.GetResponseStream()) {
|
||||
@ -335,14 +362,7 @@ namespace ClassicalSharp.Network {
|
||||
/// <summary> ETag of the item most recently cached. (if any) </summary>
|
||||
public string ETag;
|
||||
|
||||
public Request(string url, string identifier, RequestType type, DateTime lastModified, string etag) {
|
||||
Url = url;
|
||||
Identifier = identifier;
|
||||
Type = type;
|
||||
TimeAdded = DateTime.UtcNow;
|
||||
LastModified = lastModified;
|
||||
ETag = etag;
|
||||
}
|
||||
public WebException WebEx;
|
||||
|
||||
public void Dispose() {
|
||||
Bitmap bmp = Data as Bitmap;
|
||||
|
@ -31,8 +31,7 @@ namespace ClassicalSharp.Singleplayer {
|
||||
BlockInfo.CanPlace[i] = true;
|
||||
BlockInfo.CanDelete[i] = true;
|
||||
}
|
||||
game.AsyncDownloader.DownloadSkin(game.LocalPlayer.SkinName,
|
||||
game.LocalPlayer.SkinName);
|
||||
game.Downloader.AsyncGetSkin(game.LocalPlayer.SkinName, game.LocalPlayer.SkinName);
|
||||
|
||||
game.Events.RaiseBlockPermissionsChanged();
|
||||
int seed = new Random().Next();
|
||||
|
@ -6,9 +6,14 @@ using ClassicalSharp;
|
||||
using Launcher.Gui.Widgets;
|
||||
using Launcher.Web;
|
||||
|
||||
namespace Launcher.Gui.Screens {
|
||||
namespace Launcher.Gui.Screens {
|
||||
public sealed partial class MainScreen : InputScreen {
|
||||
|
||||
GetCSRFTokenTask getTask;
|
||||
SignInTask postTask;
|
||||
FetchServersTask fetchTask;
|
||||
bool signingIn = false;
|
||||
|
||||
public override void Tick() {
|
||||
base.Tick();
|
||||
if (game.checkTask != null && game.checkTask.Completed && !updateDone) {
|
||||
@ -17,25 +22,71 @@ namespace Launcher.Gui.Screens {
|
||||
else FailedUpdateCheck(game.checkTask);
|
||||
updateDone = true;
|
||||
}
|
||||
|
||||
if (!signingIn) return;
|
||||
ClassicubeSession session = game.Session;
|
||||
string status = session.Status;
|
||||
if (status != lastStatus)
|
||||
SetStatus(status);
|
||||
|
||||
if (session.Working) return;
|
||||
if (session.Exception != null) {
|
||||
DisplayWebException(session.Exception, session.Status);
|
||||
} else if (HasServers) {
|
||||
game.SetScreen(new ServersScreen(game));
|
||||
return;
|
||||
if (getTask != null) {
|
||||
LoginGetTick();
|
||||
} else if (postTask != null) {
|
||||
LoginPostTick();
|
||||
} else if (fetchTask != null) {
|
||||
FetchTick();
|
||||
}
|
||||
}
|
||||
|
||||
void LoginGetTick() {
|
||||
getTask.Tick();
|
||||
if (!getTask.Completed) return;
|
||||
|
||||
if (getTask.Success) {
|
||||
postTask = new SignInTask();
|
||||
postTask.Username = Get(0);
|
||||
postTask.Password = Get(1);
|
||||
postTask.Token = getTask.Token;
|
||||
postTask.RunAsync(game);
|
||||
} else {
|
||||
DisplayWebException(getTask.WebEx, "sign in");
|
||||
}
|
||||
|
||||
signingIn = false;
|
||||
getTask = null;
|
||||
game.RedrawBackground();
|
||||
Resize();
|
||||
}
|
||||
|
||||
void LoginPostTick() {
|
||||
postTask.Tick();
|
||||
if (!postTask.Completed) return;
|
||||
|
||||
if (postTask.Error != null) {
|
||||
SetStatus("&c" + postTask.Error);
|
||||
} else if (postTask.Success) {
|
||||
game.Username = postTask.Username;
|
||||
fetchTask = new FetchServersTask();
|
||||
fetchTask.RunAsync(game);
|
||||
SetStatus("&eRetrieving servers list..");
|
||||
} else {
|
||||
DisplayWebException(postTask.WebEx, "sign in");
|
||||
}
|
||||
|
||||
postTask = null;
|
||||
game.RedrawBackground();
|
||||
Resize();
|
||||
}
|
||||
|
||||
void FetchTick() {
|
||||
fetchTask.Tick();
|
||||
if (!fetchTask.Completed) return;
|
||||
|
||||
if (fetchTask.Success) {
|
||||
game.Servers = fetchTask.Servers;
|
||||
game.SetScreen(new ServersScreen(game));
|
||||
} else {
|
||||
DisplayWebException(fetchTask.WebEx, "retrieving servers list");
|
||||
game.RedrawBackground();
|
||||
Resize();
|
||||
}
|
||||
|
||||
fetchTask = null;
|
||||
}
|
||||
|
||||
string lastStatus;
|
||||
void SetStatus(string text) {
|
||||
@ -47,12 +98,7 @@ namespace Launcher.Gui.Screens {
|
||||
RedrawWidget(widget);
|
||||
game.Dirty = true;
|
||||
}
|
||||
|
||||
bool HasServers {
|
||||
get { return game.Session.Servers != null && game.Session.Servers.Count != 0; }
|
||||
}
|
||||
|
||||
bool signingIn;
|
||||
|
||||
void LoginAsync(int mouseX, int mouseY) {
|
||||
if (String.IsNullOrEmpty(Get(0))) {
|
||||
SetStatus("&eUsername required"); return;
|
||||
@ -60,7 +106,9 @@ namespace Launcher.Gui.Screens {
|
||||
if (String.IsNullOrEmpty(Get(1))) {
|
||||
SetStatus("&ePassword required"); return;
|
||||
}
|
||||
if (signingIn) return;
|
||||
if (getTask != null) return;
|
||||
|
||||
game.Username = Get(0);
|
||||
UpdateSignInInfo(Get(0), Get(1));
|
||||
|
||||
CheckboxWidget skip = widgets[view.sslIndex] as CheckboxWidget;
|
||||
@ -71,9 +119,11 @@ namespace Launcher.Gui.Screens {
|
||||
ServicePointManager.ServerCertificateValidationCallback = null;
|
||||
}
|
||||
|
||||
game.Session.LoginAsync(Get(0), Get(1));
|
||||
getTask = new GetCSRFTokenTask();
|
||||
getTask.RunAsync(game);
|
||||
game.RedrawBackground();
|
||||
Resize();
|
||||
|
||||
SetStatus("&eSigning in..");
|
||||
signingIn = true;
|
||||
}
|
||||
@ -82,6 +132,8 @@ namespace Launcher.Gui.Screens {
|
||||
ErrorHandler.LogError(action, ex);
|
||||
bool sslCertError = ex.Status == WebExceptionStatus.TrustFailure ||
|
||||
(ex.Status == WebExceptionStatus.SendFailure && OpenTK.Configuration.RunningOnMono);
|
||||
signingIn = false;
|
||||
|
||||
if (ex.Status == WebExceptionStatus.Timeout) {
|
||||
string text = "&cTimed out when connecting to classicube.net.";
|
||||
SetStatus(text);
|
||||
@ -162,8 +214,7 @@ namespace Launcher.Gui.Screens {
|
||||
|
||||
void UpdateSignInInfo(string user, string password) {
|
||||
// If the client has changed some settings in the meantime, make sure we keep the changes
|
||||
if (!Options.Load())
|
||||
return;
|
||||
if (!Options.Load()) return;
|
||||
|
||||
Options.Set("launcher-cc-username", user);
|
||||
Options.Set("launcher-cc-password", Secure.Encode(password, user));
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using ClassicalSharp;
|
||||
using Launcher.Web;
|
||||
using Launcher.Gui.Views;
|
||||
using Launcher.Gui.Widgets;
|
||||
using OpenTK.Input;
|
||||
@ -11,6 +12,7 @@ namespace Launcher.Gui.Screens {
|
||||
|
||||
const int tableX = 10, tableY = 50;
|
||||
ServersView view;
|
||||
FetchServersTask fetchTask;
|
||||
|
||||
public ServersScreen(LauncherWindow game) : base(game) {
|
||||
enterIndex = 3;
|
||||
@ -20,7 +22,7 @@ namespace Launcher.Gui.Screens {
|
||||
|
||||
public override void Tick() {
|
||||
base.Tick();
|
||||
if (fetchingList) CheckFetchStatus();
|
||||
if (fetchTask != null) CheckFetchStatus();
|
||||
|
||||
TableWidget table = (TableWidget)widgets[view.tableIndex];
|
||||
if (!game.Window.Mouse[MouseButton.Left]) {
|
||||
@ -134,12 +136,10 @@ namespace Launcher.Gui.Screens {
|
||||
game.ConnectToServer(table.servers, Get(view.hashIndex));
|
||||
}
|
||||
|
||||
bool fetchingList = false;
|
||||
void RefreshList(int mouseX, int mouseY) {
|
||||
if (fetchingList) return;
|
||||
fetchingList = true;
|
||||
game.Session.FetchServersAsync();
|
||||
|
||||
if (fetchTask != null) return;
|
||||
fetchTask = new FetchServersTask();
|
||||
fetchTask.RunAsync(game);
|
||||
view.RefreshText = "&eWorking..";
|
||||
Resize();
|
||||
}
|
||||
@ -187,10 +187,12 @@ namespace Launcher.Gui.Screens {
|
||||
}
|
||||
|
||||
void CheckFetchStatus() {
|
||||
if (!game.Session.Done) return;
|
||||
fetchingList = false;
|
||||
|
||||
view.RefreshText = game.Session.Exception == null ? "Refresh" : "&cFailed";
|
||||
fetchTask.Tick();
|
||||
if (!fetchTask.Completed) return;
|
||||
if (fetchTask.Success) game.Servers = fetchTask.Servers;
|
||||
|
||||
view.RefreshText = fetchTask.Success ? "Refresh" : "&cFailed";
|
||||
fetchTask = null;
|
||||
Resize();
|
||||
|
||||
// needed to ensure 'highlighted server hash' is over right entry after refresh
|
||||
|
@ -34,7 +34,7 @@ namespace Launcher.Gui.Screens {
|
||||
SuccessfulUpdateCheck(game.checkTask);
|
||||
}
|
||||
checkTask = new UpdateCheckTask();
|
||||
checkTask.Init(game);
|
||||
checkTask.RunAsync(game);
|
||||
}
|
||||
|
||||
Build dev, stable;
|
||||
|
@ -79,7 +79,7 @@ namespace Launcher.Gui.Views {
|
||||
TableWidget widget;
|
||||
if (widgets[tableIndex] != null) {
|
||||
widget = (TableWidget)widgets[tableIndex];
|
||||
if (widget.servers != game.Session.Servers) ResetTable(widget);
|
||||
if (widget.servers != game.Servers) ResetTable(widget);
|
||||
} else {
|
||||
widget = new TableWidget(game);
|
||||
ResetTable(widget);
|
||||
@ -91,7 +91,7 @@ namespace Launcher.Gui.Views {
|
||||
}
|
||||
|
||||
void ResetTable(TableWidget widget) {
|
||||
widget.SetEntries(game.Session.Servers);
|
||||
widget.SetEntries(game.Servers);
|
||||
widget.SetDrawData(drawer, tableFont, textFont,
|
||||
Anchor.LeftOrTop, Anchor.LeftOrTop, tableX, tableY);
|
||||
widget.SortDefault();
|
||||
|
@ -145,15 +145,13 @@
|
||||
<Compile Include="Patcher\ZipWriter.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="WebTasks.cs" />
|
||||
<Compile Include="Updater\Scripts.cs" />
|
||||
<Compile Include="Updater\Applier.cs" />
|
||||
<Compile Include="Utils\Client.cs" />
|
||||
<Compile Include="Utils\JSON.cs" />
|
||||
<Compile Include="Utils\LauncherSkin.cs" />
|
||||
<Compile Include="Utils\Secure.cs" />
|
||||
<Compile Include="WebService\ClassiCubeSession.cs" />
|
||||
<Compile Include="WebService\IWebTask.cs" />
|
||||
<Compile Include="WebService\UpdateCheckTask.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenTK\OpenTK.csproj">
|
||||
@ -173,7 +171,6 @@
|
||||
<Folder Include="Updater" />
|
||||
<Folder Include="Utils" />
|
||||
<Folder Include="Patcher" />
|
||||
<Folder Include="WebService" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
|
||||
</Project>
|
@ -37,7 +37,7 @@ namespace Launcher {
|
||||
public Rectangle DirtyArea;
|
||||
|
||||
/// <summary> Currently active logged in session with classicube.net. </summary>
|
||||
public ClassicubeSession Session = new ClassicubeSession();
|
||||
public string Username;
|
||||
|
||||
/// <summary> Queue used to download resources asynchronously. </summary>
|
||||
public AsyncDownloader Downloader;
|
||||
@ -55,6 +55,8 @@ namespace Launcher {
|
||||
public bool ShouldExit;
|
||||
public bool ShouldUpdate;
|
||||
|
||||
public List<ServerListEntry> Servers = new List<ServerListEntry>();
|
||||
|
||||
public string FontName = "Arial";
|
||||
|
||||
public bool Minimised {
|
||||
@ -136,7 +138,7 @@ namespace Launcher {
|
||||
ServerListEntry entry = publicServers[i];
|
||||
if (entry.Hash != hash) continue;
|
||||
|
||||
data = new ClientStartData(Session.Username, entry.Mppass,
|
||||
data = new ClientStartData(Username, entry.Mppass,
|
||||
entry.IPAddress, entry.Port, entry.Name);
|
||||
Client.Start(data, true, ref ShouldExit);
|
||||
return true;
|
||||
@ -144,7 +146,14 @@ namespace Launcher {
|
||||
|
||||
// Fallback to private server handling
|
||||
try {
|
||||
data = Session.GetConnectInfo(hash);
|
||||
// TODO: Rewrite to be async
|
||||
FetchServerTask task = new FetchServerTask(Username, hash);
|
||||
task.RunAsync(this);
|
||||
|
||||
while (!task.Completed) { task.Tick(); Thread.Sleep(10); }
|
||||
if (task.WebEx != null) throw task.WebEx;
|
||||
|
||||
data = task.Info;
|
||||
} catch (WebException ex) {
|
||||
ErrorHandler.LogError("retrieving server information", ex);
|
||||
return false;
|
||||
@ -165,12 +174,15 @@ namespace Launcher {
|
||||
platformDrawer.info = Window.WindowInfo;
|
||||
platformDrawer.Init();
|
||||
|
||||
fetcher = new ResourceFetcher();
|
||||
fetcher.CheckResourceExistence();
|
||||
Downloader = new AsyncDownloader(Drawer);
|
||||
Downloader.Init("");
|
||||
Downloader.Cookies = new CookieContainer();
|
||||
Downloader.KeepAlive = true;
|
||||
|
||||
fetcher = new ResourceFetcher();
|
||||
fetcher.CheckResourceExistence();
|
||||
checkTask = new UpdateCheckTask();
|
||||
checkTask.Init(this);
|
||||
checkTask.RunAsync(this);
|
||||
|
||||
if (!fetcher.AllResourcesExist) {
|
||||
SetScreen(new ResourcesScreen(this));
|
||||
|
@ -15,7 +15,7 @@ namespace Launcher.Patcher {
|
||||
public List<string> FilesToDownload = new List<string>();
|
||||
|
||||
public void QueueItem(string url, string identifier) {
|
||||
downloader.DownloadData(url, false, identifier);
|
||||
downloader.AsyncGetData(url, false, identifier);
|
||||
FilesToDownload.Add(identifier);
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ namespace Launcher.Patcher {
|
||||
}
|
||||
|
||||
public void AddDownload(string url, string identifier) {
|
||||
downloader.DownloadData(url, false, identifier);
|
||||
downloader.AsyncGetData(url, false, identifier);
|
||||
}
|
||||
|
||||
|
||||
|
@ -4,21 +4,21 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using ClassicalSharp;
|
||||
using ClassicalSharp.Textures;
|
||||
using Launcher.Web;
|
||||
|
||||
namespace Launcher.Updater {
|
||||
|
||||
public static class Applier {
|
||||
|
||||
public static DateTime PatchTime;
|
||||
public const string UpdatesUri = "http://cs.classicube.net/";
|
||||
|
||||
public static void FetchUpdate(string dir) {
|
||||
WebRequest.DefaultWebProxy = null;
|
||||
// TODO: Rewrite to be async
|
||||
using (WebClient client = new WebClient()) {
|
||||
byte[] zipData = client.DownloadData(UpdateCheckTask.UpdatesUri + dir);
|
||||
byte[] zipData = client.DownloadData(UpdatesUri + dir);
|
||||
MakeUpdatesFolder(zipData);
|
||||
}
|
||||
}
|
||||
|
@ -1,161 +0,0 @@
|
||||
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using JsonObject = System.Collections.Generic.Dictionary<string, object>;
|
||||
|
||||
namespace Launcher.Web {
|
||||
|
||||
public class ServerListEntry {
|
||||
public string Hash, Name, Players, MaxPlayers;
|
||||
public string Uptime, IPAddress, Port, Mppass, Software;
|
||||
public bool Featured;
|
||||
}
|
||||
|
||||
public sealed class ClassicubeSession : IWebTask {
|
||||
|
||||
const string classicubeNetUri = "https://www.classicube.net/",
|
||||
loginUri = "https://www.classicube.net/api/login/",
|
||||
listUri = "https://www.classicube.net/api/servers",
|
||||
serverUri = "https://www.classicube.net/api/server/";
|
||||
|
||||
public List<ServerListEntry> Servers = new List<ServerListEntry>();
|
||||
|
||||
public void LoginAsync(string user, string password) {
|
||||
Username = user;
|
||||
Status = "&eSigning in..";
|
||||
Servers = new List<ServerListEntry>();
|
||||
|
||||
BeginWorking();
|
||||
Thread thread = new Thread(LoginWorker, 256 * 1024);
|
||||
thread.Name = "Launcher.CCLoginAsync";
|
||||
thread.Start(password);
|
||||
}
|
||||
|
||||
public void FetchServersAsync() {
|
||||
BeginWorking();
|
||||
Thread thread = new Thread(FetchServersWorker, 256 * 1024);
|
||||
thread.Name = "Launcher.CCFetchAsync";
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
void LoginWorker(object password) {
|
||||
// Sign in to classicube.net
|
||||
try {
|
||||
Login(Username, (string)password);
|
||||
} catch (WebException ex) {
|
||||
Finish(false, ex, "sign in"); return;
|
||||
} catch (InvalidOperationException ex) {
|
||||
Finish(false, null, "&c" + ex.Message); return;
|
||||
}
|
||||
|
||||
FetchServersWorker();
|
||||
if (!Success) Servers = new List<ServerListEntry>();
|
||||
}
|
||||
|
||||
void FetchServersWorker() {
|
||||
// Retrieve list of public servers
|
||||
Status = "&eRetrieving public servers list..";
|
||||
try {
|
||||
Servers = GetPublicServers();
|
||||
} catch (WebException ex) {
|
||||
Finish(false, ex, "retrieving servers list"); return;
|
||||
}
|
||||
Finish(true, null, "&eFetched list");
|
||||
}
|
||||
|
||||
|
||||
void Login(string user, string password) {
|
||||
Username = user;
|
||||
|
||||
// Step 1: GET csrf token from login page.
|
||||
DateTime start = DateTime.UtcNow;
|
||||
string getResponse = Get(loginUri, classicubeNetUri);
|
||||
int index = 0; bool success = true;
|
||||
JsonObject data = (JsonObject)Json.ParseValue(getResponse, ref index, ref success);
|
||||
string token = (string)data["token"];
|
||||
DateTime end = DateTime.UtcNow;
|
||||
Log("cc login took " + (end - start).TotalMilliseconds);
|
||||
|
||||
// Step 2: POST to login page with csrf token.
|
||||
string loginData = String.Format(
|
||||
"username={0}&password={1}&token={2}",
|
||||
Uri.EscapeDataString(user),
|
||||
Uri.EscapeDataString(password),
|
||||
Uri.EscapeDataString(token)
|
||||
);
|
||||
|
||||
start = DateTime.UtcNow;
|
||||
string response = Post(loginUri, loginUri, loginData);
|
||||
index = 0; success = true;
|
||||
data = (JsonObject)Json.ParseValue(response, ref index, ref success);
|
||||
end = DateTime.UtcNow;
|
||||
Log("cc login took " + (end - start).TotalMilliseconds);
|
||||
|
||||
string err = GetLoginError(data);
|
||||
if (err != null) throw new InvalidOperationException(err);
|
||||
Username = (string)data["username"];
|
||||
}
|
||||
|
||||
static string GetLoginError(JsonObject obj) {
|
||||
List<object> errors = (List<object>)obj["errors"];
|
||||
if (errors.Count == 0) return null;
|
||||
|
||||
string err = (string)errors[0];
|
||||
if (err == "username" || err == "password") return "Wrong username or password";
|
||||
if (err == "verification") return "Account verification required";
|
||||
return "Unknown error occurred";
|
||||
}
|
||||
|
||||
ServerListEntry ParseEntry(JsonObject obj) {
|
||||
ServerListEntry entry = new ServerListEntry();
|
||||
entry.Hash = (string)obj["hash"];
|
||||
entry.Name = (string)obj["name"];
|
||||
entry.Players = (string)obj["players"];
|
||||
entry.MaxPlayers = (string)obj["maxplayers"];
|
||||
entry.Uptime = (string)obj["uptime"];
|
||||
entry.Mppass = (string)obj["mppass"];
|
||||
entry.IPAddress = (string)obj["ip"];
|
||||
entry.Port = (string)obj["port"];
|
||||
entry.Software = (string)obj["software"];
|
||||
|
||||
if (obj.ContainsKey("featured")) {
|
||||
entry.Featured = (bool)obj["featured"];
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
public ClientStartData GetConnectInfo(string hash) {
|
||||
string uri = serverUri + hash;
|
||||
string response = Get(uri, classicubeNetUri);
|
||||
|
||||
int index = 0; bool success = true;
|
||||
JsonObject root = (JsonObject)Json.ParseValue(response, ref index, ref success);
|
||||
List<object> list = (List<object>)root["servers"];
|
||||
|
||||
JsonObject obj = (JsonObject)list[0];
|
||||
ServerListEntry entry = ParseEntry(obj);
|
||||
return new ClientStartData(Username, entry.Mppass, entry.IPAddress, entry.Port, entry.Name);
|
||||
}
|
||||
|
||||
public List<ServerListEntry> GetPublicServers() {
|
||||
DateTime start = DateTime.UtcNow;
|
||||
List<ServerListEntry> servers = new List<ServerListEntry>();
|
||||
string response = Get(listUri, classicubeNetUri);
|
||||
int index = 0; bool success = true;
|
||||
JsonObject root = (JsonObject)Json.ParseValue(response, ref index, ref success);
|
||||
List<object> list = (List<object>)root["servers"];
|
||||
|
||||
for (int i = 0; i < list.Count; i++) {
|
||||
JsonObject obj = (JsonObject)list[i];
|
||||
ServerListEntry entry = ParseEntry(obj);
|
||||
servers.Add(entry);
|
||||
}
|
||||
|
||||
DateTime end = DateTime.UtcNow;
|
||||
Log("cc servers took " + (end - start).TotalMilliseconds);
|
||||
return servers;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using ClassicalSharp;
|
||||
|
||||
namespace Launcher.Web {
|
||||
|
||||
/// <summary> Represents a task that performs a series of GET or POST requests asynchronously. </summary>
|
||||
public abstract class IWebTask {
|
||||
|
||||
public virtual void ResetSession() {
|
||||
Username = null;
|
||||
cookies = new CookieContainer();
|
||||
}
|
||||
|
||||
/// <summary> Whether this web task is still performing GET or POST requests asynchronously. </summary>
|
||||
public bool Working;
|
||||
|
||||
/// <summary> Whether this web task has finished. </summary>
|
||||
public bool Done;
|
||||
|
||||
/// <summary> Whether the web task finished with an error or not. </summary>
|
||||
public bool Success;
|
||||
|
||||
/// <summary> Handled exception that was generated by the last GET or POST request. </summary>
|
||||
public WebException Exception;
|
||||
|
||||
/// <summary> Current status of this web task (e.g. downloading page X) </summary>
|
||||
public string Status;
|
||||
|
||||
/// <summary> Username used when performing GET or POST requests, can be left null. </summary>
|
||||
public string Username;
|
||||
|
||||
public void BeginWorking() {
|
||||
Working = true;
|
||||
Done = false;
|
||||
Exception = null;
|
||||
}
|
||||
|
||||
protected void Finish(bool success, WebException ex, string status) {
|
||||
if (!success)
|
||||
Username = null;
|
||||
Working = false;
|
||||
Done = true;
|
||||
Success = success;
|
||||
|
||||
Exception = ex;
|
||||
Status = status;
|
||||
}
|
||||
|
||||
protected CookieContainer cookies = new CookieContainer();
|
||||
|
||||
protected HttpWebResponse MakeRequest(string uri, string referer, string data) {
|
||||
WebRequest.DefaultWebProxy = null;
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
|
||||
request.UserAgent = Program.AppName;
|
||||
request.ReadWriteTimeout = 90 * 1000;
|
||||
request.Timeout = 90 * 1000;
|
||||
request.Referer = referer;
|
||||
request.KeepAlive = true;
|
||||
request.CookieContainer = cookies;
|
||||
|
||||
request.AutomaticDecompression = DecompressionMethods.GZip;
|
||||
if (data != null) {
|
||||
request.Method = "POST";
|
||||
request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8;";
|
||||
byte[] encodedData = Encoding.UTF8.GetBytes(data);
|
||||
request.ContentLength = encodedData.Length;
|
||||
using (Stream stream = request.GetRequestStream()) {
|
||||
stream.Write(encodedData, 0, encodedData.Length);
|
||||
}
|
||||
}
|
||||
return (HttpWebResponse)request.GetResponse();
|
||||
}
|
||||
|
||||
protected string Get(string uri, string referer) {
|
||||
HttpWebResponse response = MakeRequest(uri, referer, null);
|
||||
return GetResponse(response);
|
||||
}
|
||||
|
||||
protected string Post(string uri, string referer, string data) {
|
||||
HttpWebResponse response = MakeRequest(uri, referer, data);
|
||||
return GetResponse(response);
|
||||
}
|
||||
|
||||
protected string GetResponse(HttpWebResponse response) {
|
||||
using (Stream stream = response.GetResponseStream()) {
|
||||
using (StreamReader reader = new StreamReader(stream)) {
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static void Log(string text) { Utils.LogDebug(text); }
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
|
||||
using ClassicalSharp;
|
||||
using ClassicalSharp.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using JsonObject = System.Collections.Generic.Dictionary<string, object>;
|
||||
|
||||
namespace Launcher.Web {
|
||||
|
||||
public class Build {
|
||||
public DateTime TimeBuilt;
|
||||
public string DirectXPath, OpenGLPath;
|
||||
public int DirectXSize, OpenGLSize;
|
||||
public string Version;
|
||||
}
|
||||
|
||||
public sealed class UpdateCheckTask {
|
||||
|
||||
public const string UpdatesIdentifier = "cc-update";
|
||||
public const string UpdatesUri = "http://cs.classicube.net/";
|
||||
public const string BuildsUri = "http://cs.classicube.net/builds.json";
|
||||
public Build LatestDev, LatestStable;
|
||||
public LauncherWindow Game;
|
||||
public bool Completed = false, Success = false;
|
||||
|
||||
public void Init(LauncherWindow game) {
|
||||
Game = game;
|
||||
Completed = false;
|
||||
Success = false;
|
||||
Game.Downloader.DownloadPage(BuildsUri, false, UpdatesIdentifier);
|
||||
}
|
||||
|
||||
public void Tick() {
|
||||
if (Completed) return;
|
||||
Request req;
|
||||
if (!Game.Downloader.TryGetItem(UpdatesIdentifier, out req)) return;
|
||||
|
||||
Completed = true;
|
||||
Success = req != null && req.Data != null;
|
||||
if (!Success) return;
|
||||
ProcessUpdate((string)req.Data);
|
||||
}
|
||||
|
||||
void ProcessUpdate(string response) {
|
||||
int index = 0; bool success = true;
|
||||
JsonObject data = (JsonObject)Json.ParseValue(response, ref index, ref success);
|
||||
|
||||
JsonObject devBuild = (JsonObject)data["latest"];
|
||||
JsonObject releaseBuilds = (JsonObject)data["releases"];
|
||||
LatestDev = MakeBuild(devBuild, false);
|
||||
|
||||
DateTime releaseTime = DateTime.MinValue;
|
||||
foreach (KeyValuePair<string, object> pair in releaseBuilds) {
|
||||
Build build = MakeBuild((JsonObject)pair.Value, true);
|
||||
if (build.TimeBuilt < releaseTime) continue;
|
||||
|
||||
LatestStable = build;
|
||||
releaseTime = build.TimeBuilt;
|
||||
}
|
||||
}
|
||||
|
||||
static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
Build MakeBuild(JsonObject obj, bool release) {
|
||||
Build build = new Build();
|
||||
string timeKey = release ? "release_ts" : "ts";
|
||||
double rawTime = Double.Parse((string)obj[timeKey], CultureInfo.InvariantCulture);
|
||||
build.TimeBuilt = epoch.AddSeconds(rawTime).ToLocalTime();
|
||||
|
||||
build.DirectXSize = Int32.Parse((string)obj["dx_size"]);
|
||||
build.DirectXPath = (string)obj["dx_file"];
|
||||
build.OpenGLSize = Int32.Parse((string)obj["ogl_size"]);
|
||||
build.OpenGLPath = (string)obj["ogl_file"];
|
||||
if (obj.ContainsKey("version"))
|
||||
build.Version = (string)obj["version"];
|
||||
return build;
|
||||
}
|
||||
}
|
||||
}
|
219
Launcher2/WebTasks.cs
Normal file
219
Launcher2/WebTasks.cs
Normal file
@ -0,0 +1,219 @@
|
||||
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
|
||||
using ClassicalSharp;
|
||||
using ClassicalSharp.Network;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System;
|
||||
using System.Net;
|
||||
using JsonObject = System.Collections.Generic.Dictionary<string, object>;
|
||||
|
||||
namespace Launcher.Web {
|
||||
|
||||
public abstract class WebTask {
|
||||
public LauncherWindow Game;
|
||||
public bool Completed = false, Success = false;
|
||||
public WebException WebEx;
|
||||
|
||||
DateTime start;
|
||||
protected string identifier, uri, section;
|
||||
|
||||
public void RunAsync(LauncherWindow game) {
|
||||
Game = game; Completed = false; Success = false;
|
||||
start = DateTime.UtcNow;
|
||||
Init();
|
||||
Begin();
|
||||
}
|
||||
|
||||
public void Tick() {
|
||||
if (Completed) return;
|
||||
Request req;
|
||||
if (!Game.Downloader.TryGetItem(identifier, out req)) return;
|
||||
Utils.LogDebug(identifier + " took " + (DateTime.UtcNow - start).TotalMilliseconds);
|
||||
|
||||
WebEx = req.WebEx;
|
||||
Completed = true;
|
||||
Success = req != null && req.Data != null;
|
||||
if (Success) Handle(req);
|
||||
}
|
||||
|
||||
protected abstract void Init();
|
||||
protected virtual void Begin() {
|
||||
Game.Downloader.AsyncGetString(uri, false, identifier);
|
||||
}
|
||||
protected abstract void Handle(Request req);
|
||||
}
|
||||
|
||||
public sealed class GetCSRFTokenTask : WebTask {
|
||||
public GetCSRFTokenTask() {
|
||||
identifier = "CC get login";
|
||||
uri = "https://www.classicube.net/api/login/";
|
||||
}
|
||||
|
||||
public string Token;
|
||||
protected override void Init() { }
|
||||
|
||||
protected override void Handle(Request req) {
|
||||
int index = 0; bool success = true;
|
||||
JsonObject data = (JsonObject)Json.ParseValue((string)req.Data, ref index, ref success);
|
||||
Token = (string)data["token"];
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SignInTask : WebTask {
|
||||
public SignInTask() {
|
||||
identifier = "CC post login";
|
||||
uri = "https://www.classicube.net/api/login/";
|
||||
}
|
||||
|
||||
public string Username, Password, Token, Error;
|
||||
protected override void Init() { }
|
||||
protected override void Begin() {
|
||||
string data = String.Format(
|
||||
"username={0}&password={1}&token={2}",
|
||||
Uri.EscapeDataString(Username),
|
||||
Uri.EscapeDataString(Password),
|
||||
Uri.EscapeDataString(Token)
|
||||
);
|
||||
Game.Downloader.AsyncPostString(uri, false, identifier, data);
|
||||
}
|
||||
|
||||
protected override void Handle(Request req) {
|
||||
int index = 0; bool success = true;
|
||||
JsonObject data = (JsonObject)Json.ParseValue((string)req.Data, ref index, ref success);
|
||||
|
||||
Error = GetLoginError(data);
|
||||
Username = (string)data["username"];
|
||||
}
|
||||
|
||||
static string GetLoginError(JsonObject obj) {
|
||||
List<object> errors = (List<object>)obj["errors"];
|
||||
if (errors.Count == 0) return null;
|
||||
|
||||
string err = (string)errors[0];
|
||||
if (err == "username" || err == "password") return "Wrong username or password";
|
||||
if (err == "verification") return "Account verification required";
|
||||
return "Unknown error occurred";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class ServerListEntry {
|
||||
public string Hash, Name, Players, MaxPlayers;
|
||||
public string Uptime, IPAddress, Port, Mppass, Software;
|
||||
public bool Featured;
|
||||
}
|
||||
|
||||
public sealed class FetchServerTask : WebTask {
|
||||
public FetchServerTask(string user, string hash) {
|
||||
Username = user;
|
||||
identifier = "CC get servers";
|
||||
uri = "https://www.classicube.net/api/server/" + hash;
|
||||
}
|
||||
|
||||
public static ServerListEntry ParseEntry(JsonObject obj) {
|
||||
ServerListEntry entry = new ServerListEntry();
|
||||
entry.Hash = (string)obj["hash"];
|
||||
entry.Name = (string)obj["name"];
|
||||
entry.Players = (string)obj["players"];
|
||||
entry.MaxPlayers = (string)obj["maxplayers"];
|
||||
entry.Uptime = (string)obj["uptime"];
|
||||
entry.Mppass = (string)obj["mppass"];
|
||||
entry.IPAddress = (string)obj["ip"];
|
||||
entry.Port = (string)obj["port"];
|
||||
entry.Software = (string)obj["software"];
|
||||
|
||||
if (obj.ContainsKey("featured")) {
|
||||
entry.Featured = (bool)obj["featured"];
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
public string Username;
|
||||
public ClientStartData Info;
|
||||
protected override void Init() { }
|
||||
|
||||
protected override void Handle(Request req) {
|
||||
int index = 0; bool success = true;
|
||||
JsonObject root = (JsonObject)Json.ParseValue((string)req.Data, ref index, ref success);
|
||||
List<object> list = (List<object>)root["servers"];
|
||||
|
||||
JsonObject obj = (JsonObject)list[0];
|
||||
ServerListEntry entry = ParseEntry(obj);
|
||||
Info = new ClientStartData(Username, entry.Mppass, entry.IPAddress, entry.Port, entry.Name);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class FetchServersTask : WebTask {
|
||||
public FetchServersTask() {
|
||||
identifier = "CC get servers";
|
||||
uri = "https://www.classicube.net/api/servers";
|
||||
}
|
||||
|
||||
public List<ServerListEntry> Servers;
|
||||
protected override void Init() {
|
||||
Servers = new List<ServerListEntry>();
|
||||
}
|
||||
|
||||
protected override void Handle(Request req) {
|
||||
int index = 0; bool success = true;
|
||||
JsonObject root = (JsonObject)Json.ParseValue((string)req.Data, ref index, ref success);
|
||||
List<object> list = (List<object>)root["servers"];
|
||||
|
||||
for (int i = 0; i < list.Count; i++) {
|
||||
JsonObject obj = (JsonObject)list[i];
|
||||
ServerListEntry entry = FetchServerTask.ParseEntry(obj);
|
||||
Servers.Add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class Build {
|
||||
public DateTime TimeBuilt;
|
||||
public string DirectXPath, OpenGLPath;
|
||||
public int DirectXSize, OpenGLSize;
|
||||
public string Version;
|
||||
}
|
||||
|
||||
public sealed class UpdateCheckTask : WebTask {
|
||||
public UpdateCheckTask() {
|
||||
identifier = "CC update check";
|
||||
uri = "http://cs.classicube.net/builds.json";
|
||||
}
|
||||
|
||||
public Build LatestDev, LatestStable;
|
||||
protected override void Init() { }
|
||||
|
||||
protected override void Handle(Request req) {
|
||||
int index = 0; bool success = true;
|
||||
JsonObject data = (JsonObject)Json.ParseValue((string)req.Data, ref index, ref success);
|
||||
JsonObject latest = (JsonObject)data["latest"], releases = (JsonObject)data["releases"];
|
||||
LatestDev = MakeBuild(latest, false);
|
||||
|
||||
DateTime releaseTime = DateTime.MinValue;
|
||||
foreach (KeyValuePair<string, object> pair in releases) {
|
||||
Build build = MakeBuild((JsonObject)pair.Value, true);
|
||||
if (build.TimeBuilt < releaseTime) continue;
|
||||
|
||||
LatestStable = build;
|
||||
releaseTime = build.TimeBuilt;
|
||||
}
|
||||
}
|
||||
|
||||
static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
Build MakeBuild(JsonObject obj, bool release) {
|
||||
Build build = new Build();
|
||||
string timeKey = release ? "release_ts" : "ts";
|
||||
double rawTime = Double.Parse((string)obj[timeKey], CultureInfo.InvariantCulture);
|
||||
build.TimeBuilt = epoch.AddSeconds(rawTime).ToLocalTime();
|
||||
|
||||
build.DirectXSize = Int32.Parse((string)obj["dx_size"]);
|
||||
build.DirectXPath = (string)obj["dx_file"];
|
||||
build.OpenGLSize = Int32.Parse((string)obj["ogl_size"]);
|
||||
build.OpenGLPath = (string)obj["ogl_file"];
|
||||
if (obj.ContainsKey("version"))
|
||||
build.Version = (string)obj["version"];
|
||||
return build;
|
||||
}
|
||||
}
|
||||
}
|
@ -292,6 +292,7 @@ void Entities_ContextLost(void) {
|
||||
if (Entities_List[i] == NULL) continue;
|
||||
Entities_List[i]->VTABLE->ContextLost(Entities_List[i]);
|
||||
}
|
||||
Gfx_DeleteTexture(&ShadowComponent_ShadowTex);
|
||||
}
|
||||
|
||||
void Entities_ContextRecreated(void) {
|
||||
|
@ -595,7 +595,7 @@ void ShadowComponent_MakeTex(void) {
|
||||
row[x] = dist < half * half ? inPix : outPix;
|
||||
}
|
||||
}
|
||||
ShadowComponent_ShadowTex = Gfx_CreateTexture(&bmp, true, false);
|
||||
ShadowComponent_ShadowTex = Gfx_CreateTexture(&bmp, false, false);
|
||||
}
|
||||
|
||||
void ShadowComponent_Draw(Entity* entity) {
|
||||
|
@ -155,7 +155,7 @@ void Gfx_BindTexture(GfxResourceID texId) {
|
||||
}
|
||||
|
||||
void Gfx_DeleteTexture(GfxResourceID* texId) {
|
||||
if (*texId <= 0) return;
|
||||
if (*texId == NULL) return;
|
||||
glDeleteTextures(1, texId);
|
||||
*texId = NULL;
|
||||
}
|
||||
@ -312,7 +312,7 @@ void Gfx_BindIb(GfxResourceID ib) {
|
||||
}
|
||||
|
||||
void Gfx_DeleteVb(GfxResourceID* vb) {
|
||||
if (*vb <= 0) return;
|
||||
if (*vb == NULL) return;
|
||||
|
||||
if (gl_lists) {
|
||||
if (*vb != gl_DYNAMICLISTID) glDeleteLists(*vb, 1);
|
||||
@ -323,7 +323,7 @@ void Gfx_DeleteVb(GfxResourceID* vb) {
|
||||
}
|
||||
|
||||
void Gfx_DeleteIb(GfxResourceID* ib) {
|
||||
if (gl_lists || *ib <= 0) return;
|
||||
if (gl_lists || *ib == NULL) return;
|
||||
glDeleteBuffers(1, ib);
|
||||
*ib = NULL;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user