diff --git a/ClassicalSharp/Commands/Commands.cs b/ClassicalSharp/Commands/Commands.cs
index 1364aac5a..c6217135a 100644
--- a/ClassicalSharp/Commands/Commands.cs
+++ b/ClassicalSharp/Commands/Commands.cs
@@ -129,7 +129,11 @@ namespace ClassicalSharp.Commands {
}
public override void Execute(string[] args) {
- foreach (IGameComponent comp in game.Components) { comp.Dispose(); }
+ if (args.Length == 1) {
+ game.Chat.Add("&e/client model: &cYou didn't specify a model name.");
+ } else {
+ game.LocalPlayer.SetModel(args[1]);
+ }
}
}
diff --git a/src/ClassiCube.vcxproj b/src/ClassiCube.vcxproj
index b4b83c732..1bfeefeec 100644
--- a/src/ClassiCube.vcxproj
+++ b/src/ClassiCube.vcxproj
@@ -210,6 +210,8 @@
+
+
@@ -273,6 +275,8 @@
+
+
diff --git a/src/ClassiCube.vcxproj.filters b/src/ClassiCube.vcxproj.filters
index 21f341a01..fa7421eea 100644
--- a/src/ClassiCube.vcxproj.filters
+++ b/src/ClassiCube.vcxproj.filters
@@ -312,6 +312,12 @@
Header Files\Launcher
+
+ Header Files\Launcher
+
+
+ Header Files\Launcher
+
@@ -557,5 +563,11 @@
Source Files\Launcher
+
+ Source Files\Launcher
+
+
+ Source Files\Launcher
+
\ No newline at end of file
diff --git a/src/LScreens.c b/src/LScreens.c
new file mode 100644
index 000000000..6a87281d8
--- /dev/null
+++ b/src/LScreens.c
@@ -0,0 +1,149 @@
+#include "LScreens.h"
+#include "LWidgets.h"
+#include "Launcher.h"
+#include "Gui.h"
+
+static void LScreen_NullFunc(struct LScreen* s) { }
+static void LScreen_DrawAll(struct LScreen* s) {
+ struct LWidget* widget;
+ int i;
+
+ for (i = 0; i < s->NumWidgets; i++) {
+ widget = s->Widgets[i];
+ widget->VTABLE->Redraw(widget);
+ }
+}
+
+static void LScreen_HoverWidget(struct LScreen* s, struct LWidget* w) {
+ if (!w) return;
+ w->Hovered = true;
+ if (w->VTABLE->OnHover) w->VTABLE->OnHover(w);
+}
+
+static void LScreen_UnhoverWidget(struct LScreen* s, struct LWidget* w) {
+ if (!w) return;
+ w->Hovered = false;
+ if (w->VTABLE->OnUnhover) w->VTABLE->OnUnhover(w);
+}
+
+CC_NOINLINE static void LScreen_Reset(struct LScreen* s) {
+ int i;
+
+ s->Init = NULL; /* screens should always override this */
+ s->Free = LScreen_NullFunc;
+ s->DrawAll = LScreen_DrawAll;
+ s->Tick = LScreen_NullFunc;
+ s->OnDisplay = LScreen_NullFunc;
+ s->HoverWidget = LScreen_HoverWidget;
+ s->UnhoverWidget = LScreen_UnhoverWidget;
+
+ /* reset all widgets to unselected */
+ for (i = 0; i < s->NumWidgets; i++) {
+ s->Widgets[i]->Hovered = false;
+ }
+}
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------Widget init-----------------------------------------------------*
+*#########################################################################################################################*/
+CC_NOINLINE static void LScreen_Button(struct LScreen* s, struct LButton* w, int width, int height, const char* text,
+ uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset) {
+ String str = String_FromReadonly(text);
+ LButton_Init(w, width, height);
+ LButton_SetText(w, &str, &Launcher_TitleFont);
+
+ w->Hovered = false;
+ s->Widgets[s->NumWidgets++] = (struct LWidget*)w;
+ LWidget_SetLocation(w, horAnchor, verAnchor, xOffset, yOffset);
+}
+
+CC_NOINLINE static void LScreen_Label(struct LScreen* s, struct LLabel* w, const char* text,
+ uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset) {
+ String str = String_FromReadonly(text);
+ LLabel_Init(w);
+ LLabel_SetText(w, &str, &Launcher_TextFont);
+
+ w->Hovered = false;
+ s->Widgets[s->NumWidgets++] = (struct LWidget*)w;
+ LWidget_SetLocation(w, horAnchor, verAnchor, xOffset, yOffset);
+}
+
+CC_NOINLINE static void LScreen_Slider(struct LScreen* s, struct LSlider* w, int width, int height,
+ int initValue, int maxValue, BitmapCol progressCol,
+ uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset) {
+ LSlider_Init(w, width, height);
+ w->Value = initValue; w->MaxValue = maxValue;
+ w->ProgressCol = progressCol;
+
+ w->Hovered = false;
+ s->Widgets[s->NumWidgets++] = (struct LWidget*)w;
+ LWidget_SetLocation(w, horAnchor, verAnchor, xOffset, yOffset);
+}
+
+/*########################################################################################################################*
+*--------------------------------------------------------SettingsScreen---------------------------------------------------*
+*#########################################################################################################################*/
+/*static struct SettingsScreen {
+ LScreen_Layout
+ struct LWidget* Widgets[7];
+ struct LButton BtnUpdates, BtnMode, BtnColours, BtnBack;
+ struct LLabel LblUpdates, LblMode, LblColours;
+} SettingsScreen_Instance;
+
+static void SettingsScreen_InitWidgets(struct SettingsScreen* s) {
+ struct LScreen* s_ = (struct LScreen*)s;
+
+ LScreen_Button(s_, &s->BtnUpdates, 110, 35, "Updates",
+ ANCHOR_CENTRE, ANCHOR_CENTRE, -135, -120);
+ LScreen_Label(s_, &s->LblUpdates, "&eGet the latest stuff",
+ ANCHOR_CENTRE, ANCHOR_CENTRE, 10, -120);
+
+ LScreen_Button(s_, &s->BtnMode, 110, 35, "Mode",
+ ANCHOR_CENTRE, ANCHOR_CENTRE, -135, -70);
+ LScreen_Label(s_, &s->LblMode, "&eChange the enabled features",
+ ANCHOR_CENTRE, ANCHOR_CENTRE, 55, -70);
+
+ LScreen_Button(s_, &s->BtnColours, 110, 35, "Colours",
+ ANCHOR_CENTRE, ANCHOR_CENTRE, -135, -20);
+ LScreen_Label(s_, &s->LblColours, "&eChange how the launcher looks",
+ ANCHOR_CENTRE, ANCHOR_CENTRE, 65, -20);
+
+ LScreen_Button(s_, &s->BtnBack, 80, 35, "Back",
+ ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 170);
+}
+
+static void SwitchToChooseMode(void* w, int x, int y) {
+ Launcher_SetScreen(ChooseModeScreen_MakeInstance(false));
+}
+static void SwitchToUpdates(void* w, int x, int y) {
+ Launcher_SetScreen(UpdatesScreen_MakeInstance());
+}
+static void SwitchToColours(void* w, int x, int y) {
+ Launcher_SetScreen(ColoursScreen_MakeInstance());
+}
+static void SwitchToMain(void* w, int x, int y) {
+ Launcher_SetScreen(MainScreen_MakeInstance());
+}
+
+static void SettingsScreen_Init(struct LScreen* s_) {
+ struct SettingsScreen* s = (struct SettingsScreen*)s_;
+ if (!s->NumWidgets) SettingsScreen_InitWidgets(s);
+
+ s->BtnColours.Hidden = Launcher_ClassicBackground;
+ s->LblColours.Hidden = Launcher_ClassicBackground;
+
+ s->BtnMode.OnClick = SwitchToChooseMode;
+ s->BtnUpdates.OnClick = SwitchToUpdates;
+ s->BtnColours.OnClick = SwitchToColours;
+ s->BtnBack.OnClick = SwitchToMain;
+ s->DrawAll(s);
+}
+
+struct LScreen* SettingsScreen_MakeInstance(void) {
+ struct SettingsScreen* s = &SettingsScreen_Instance;
+ LScreen_Reset((struct LScreen*)s);
+ s->Init = SettingsScreen_Init;
+ return (struct LScreen*)s;
+}
+*/
\ No newline at end of file
diff --git a/src/LScreens.h b/src/LScreens.h
new file mode 100644
index 000000000..1f97a4aa2
--- /dev/null
+++ b/src/LScreens.h
@@ -0,0 +1,41 @@
+#ifndef CC_LSCREENS_H
+#define CC_LSCREENS_H
+#include "AsyncDownloader.h"
+#include "String.h"
+/* Implements screens/menus for the launcher.
+ Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
+*/
+struct LWidget;
+struct LScreen;
+
+typedef void (*LScreen_Func)(struct LScreen* s);
+typedef void (*LWidget_Func)(struct LScreen* s, struct LWidget* w);
+
+#define LScreen_Layout \
+ LScreen_Func Init; /* Initialises widgets and other data. */ \
+ LScreen_Func Free; /* Cleans up all native resources. */ \
+ LScreen_Func DrawAll; /* Redraws all widgets. */ \
+ LScreen_Func Tick; /* Repeatedly called multiple times every second. */ \
+ LScreen_Func OnDisplay; /* Called when framebuffer is about to be displayed. */ \
+ LWidget_Func HoverWidget; /* Called when mouse is moved over a given widget. */ \
+ LWidget_Func UnhoverWidget; /* Called when the mouse is moved away from a previously hovered widget. */ \
+ struct LWidget* HoveredWidget; /* Widget the mouse is currently hovering over. */ \
+ int NumWidgets; /* Number of widgets actually used. */
+
+struct LScreen {
+ LScreen_Layout
+ /* All widgets in the screen. */
+ /* NOTE: This is vriable sized, so must be the last member. */
+ /* (e.g. derived screens might use: struct LWidget* Widgets[10];) */
+ struct LWidget** Widgets;
+};
+
+struct LScreen* ChooseModeScreen_MakeInstance(void);
+struct LScreen* ColoursScreen_MakeInstance(void);
+struct LScreen* DirectConnectScreen_MakeInstance(void);
+struct LScreen* MainScreen_MakeInstance(void);
+struct LScreen* ResourcesScreen_MakeInstance(void);
+struct LScreen* ServersScreen_MakeInstance(void);
+struct LScreen* SettingsScreen_MakeInstance(void);
+struct LScreen* UpdateScreen_MakeInstance(void);
+#endif
diff --git a/src/LWeb.c b/src/LWeb.c
new file mode 100644
index 000000000..2cdf4af22
--- /dev/null
+++ b/src/LWeb.c
@@ -0,0 +1,277 @@
+#include "LWeb.h"
+#include "Platform.h"
+
+static void LWebTask_Reset(struct LWebTask* task) {
+ task->Completed = false;
+ task->Success = false;
+ task->Start = DateTime_CurrentUTC_MS();
+}
+
+void LWebTask_StartAsync(struct LWebTask* task) {
+ LWebTask_Reset(task);
+ task->Begin(task);
+}
+
+void LWebTask_Tick(struct LWebTask* task) {
+ struct AsyncRequest req;
+ int delta;
+ if (task->Completed) return;
+
+ if (!AsyncDownloader_Get(&task->Identifier, &req)) return;
+ delta = (int)(DateTime_CurrentUTC_MS() - task->Start);
+ Platform_Log2("%s took %i", &task->Identifier, &delta);
+
+ task->Completed = true;
+ task->Success = req.ResultData && req.ResultSize;
+ if (task->Success) task->Handle(task, req.ResultData, req.ResultSize);
+}
+
+static void LWebTask_DefaultBegin(struct LWebTask* task) {
+ AsyncDownloader_GetData(&task->URL, false, &task->Identifier);
+}
+
+/*protected static JsonObject ParseJson(Request req) {
+ JsonContext ctx = new JsonContext();
+ ctx.Val = (string)req.Data;
+ return (JsonObject)Json.ParseStream(ctx);
+}
+
+public sealed class GetCSRFTokenTask : WebTask {
+ public GetCSRFTokenTask() {
+ identifier = "CC get login";
+ uri = "https://www.classicube.net/api/login/";
+ }
+ public string Token;
+
+ protected override void Handle(Request req) {
+ JsonObject data = ParseJson(req);
+ 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 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) {
+ JsonObject data = ParseJson(req);
+ Error = GetLoginError(data);
+ Username = (string)data["username"];
+ }
+
+ static string GetLoginError(JsonObject obj) {
+ List