Actually download the C client when updating

This commit is contained in:
UnknownShadow200 2018-10-31 11:11:27 +11:00
parent 869064c5c7
commit dec52c9d53
12 changed files with 344 additions and 192 deletions

View File

@ -20,6 +20,8 @@ namespace Launcher.Gui.Screens {
UpdateCheckTask checkTask;
UpdateDownloadTask fetchTask;
UpdateCClientTask fetchCClientTask;
string buildName;
int buildProgress = -1;
@ -45,6 +47,7 @@ namespace Launcher.Gui.Screens {
Build dev, stable;
public override void Tick() {
TickCClientFetchTask();
TickFetchTask();
TickUpdateCheck();
}
@ -84,21 +87,77 @@ namespace Launcher.Gui.Screens {
void UpdateDevOpenGL(int x, int y) { UpdateBuild(false, false); }
void SwitchToSettings(int x, int y) { game.SetScreen(new SettingsScreen(game)); }
void UpdateStatus() {
Widget widget = widgets[view.statusIndex];
int oldX = widget.X, oldWidth = widget.Width;
int oldY = widget.Y, oldHeight = widget.Height;
view.UpdateStatus();
// if old text is smaller than new
// TODO: This needs to be better. widgets should keep track of their 'last area'.
// and 'RedrawWidget' should also call ResetArea. Widgets should have a bool for if they obscure background or not.
game.ResetArea(Math.Min(widget.X, oldX), Math.Min(widget.Y, oldY),
Math.Max(widget.Width, oldWidth), Math.Max(widget.Height, oldHeight));
RedrawWidget(widgets[view.statusIndex]);
}
static bool IsClient(string name) {
return
Utils.CaselessEq(name, "ClassicalSharp") || Utils.CaselessEq(name, "ClassiCube") ||
Utils.CaselessEq(name, "ClassicalSharp.exe") || Utils.CaselessEq(name, "ClassiCube.exe");
}
static bool CheckClientInstances() {
Process[] processes = Process.GetProcesses();
for (int i = 0; i < processes.Length; i++) {
string name = null;
try {
name = processes[i].ProcessName;
} catch {
continue;
}
if (IsClient(name)) return true;
}
return false;
}
static string GetCExe(bool dx) {
// TODO: OSX, 32 bit linux
if (!OpenTK.Configuration.RunningOnWindows) return "ClassiCube";
if (IntPtr.Size == 8) {
return dx ? "ClassiCube.64.exe" : "ClassiCube.64-opengl.exe";
} else {
return dx ? "ClassiCube.exe" : "ClassiCube.opengl.exe";
}
}
void UpdateBuild(bool release, bool dx) {
DateTime last = release ? view.LastStable : view.LastDev;
Build build = release ? stable : dev;
if (last == DateTime.MinValue || fetchTask != null) return;
if (Client.CClient && fetchCClientTask != null) return;
if (build.DirectXSize < 50000 || build.OpenGLSize < 50000) return;
bool gameOpen = CheckClientInstances();
view.statusText = gameOpen ? "&cThe game must be closed before updating" : "";
UpdateStatus();
if (gameOpen) return;
string path;
string path = dx ? build.DirectXPath : build.OpenGLPath;
path = dx ? build.DirectXPath : build.OpenGLPath;
fetchTask = new UpdateDownloadTask(path);
fetchTask.RunAsync(game);
if (Client.CClient) {
path = GetCExe(dx);
fetchCClientTask = new UpdateCClientTask(path);
fetchCClientTask.RunAsync(game);
}
if (release && dx) buildName = "&eFetching latest release (Direct3D9)";
if (release && !dx) buildName = "&eFetching latest release (OpenGL)";
if (!release && dx) buildName = "&eFetching latest dev build (Direct3D9)";
@ -110,50 +169,60 @@ namespace Launcher.Gui.Screens {
UpdateStatus();
}
void UpdateStatus() {
view.UpdateStatus();
Widget widget = widgets[view.statusIndex];
game.ResetArea(widget.X, widget.Y, widget.Width, widget.Height);
RedrawWidget(widgets[view.statusIndex]);
byte[] csZip, cExe;
void ApplyUpdate() {
Applier.ExtractUpdate(csZip);
game.ShouldExit = true;
game.ShouldUpdate = true;
if (cExe == null) return;
string path = Client.GetExeName();
// TODO: Set last-modified time to actual time of dev build
Platform.WriteAllBytes(path, cExe);
}
bool CheckClientInstances() {
Process[] processes = Process.GetProcesses();
for (int i = 0; i < processes.Length; i++) {
string name = null;
try {
name = processes[i].ProcessName;
} catch {
continue;
}
void TickCClientFetchTask() {
if (fetchCClientTask == null) return;
fetchCClientTask.Tick();
UpdateProgress(fetchCClientTask);
if (!fetchCClientTask.Completed) return;
if (Utils.CaselessEquals(name, "ClassicalSharp")
|| Utils.CaselessEquals(name, "ClassicalSharp.exe"))
return true;
if (!fetchCClientTask.Success) {
view.statusText = "&cFailed to fetch update";
UpdateStatus();
} else {
cExe = fetchCClientTask.File;
ApplyUpdate();
}
return false;
fetchCClientTask = null;
}
void TickFetchTask() {
if (fetchTask == null) return;
fetchTask.Tick();
UpdateFetchProgress();
UpdateProgress(fetchTask);
if (!fetchTask.Completed) return;
if (!fetchTask.Success) {
view.statusText = "&cFailed to fetch update";
UpdateStatus();
} else {
Applier.ExtractUpdate(fetchTask.ZipFile);
game.ShouldExit = true;
game.ShouldUpdate = true;
csZip = fetchTask.ZipFile;
if (!Client.CClient) {
ApplyUpdate();
} else {
buildName = "&eFetching latest C client";
UpdateStatus();
}
}
fetchTask = null;
}
void UpdateFetchProgress() {
void UpdateProgress(WebTask task) {
Request item = game.Downloader.CurrentItem;
if (item == null || item.Identifier != fetchTask.identifier) return;
if (item == null || item.Identifier != task.identifier) return;
int progress = game.Downloader.CurrentItemProgress;
if (progress == buildProgress) return;

View File

@ -231,7 +231,7 @@ namespace Launcher.Web {
public byte[] ZipFile;
protected override void Begin() {
Game.Downloader.AsyncGetData(uri, true, identifier);
Game.Downloader.AsyncGetData(uri, false, identifier);
}
protected override void Handle(Request req) {
@ -239,6 +239,23 @@ namespace Launcher.Web {
}
}
public sealed class UpdateCClientTask : WebTask {
public UpdateCClientTask(string file) {
identifier = "CC CClient download";
uri = "http://cs.classicube.net/c_client/latest/" + file;
}
public byte[] File;
protected override void Begin() {
Game.Downloader.AsyncGetData(uri, false, identifier);
}
protected override void Handle(Request req) {
File = (byte[])req.Data;
}
}
public sealed class FetchFlagsTask : WebTask {
public FetchFlagsTask() {

View File

@ -439,7 +439,6 @@ static void Window_ConnectEvents(void) {
void Window_Create(int x, int y, int width, int height, struct GraphicsMode* mode) {
Rect r;
OSStatus res;
ProcessSerialNumber psn;
r.left = x; r.right = x + width;

View File

@ -321,7 +321,7 @@ static void ErrorHandler_SignalHandler(int sig, siginfo_t* info, void* ctx) {
void ErrorHandler_Init(void) {
struct sigaction sa, old;
sa.sa_handler = ErrorHandler_SignalHandler;
sa.sa_sigaction = ErrorHandler_SignalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
@ -401,12 +401,13 @@ typedef struct {
static void X11Textbox_Measure(X11Textbox* t, XFontStruct* font) {
String str = String_FromReadonly(t->Text);
int direction, ascent, descent, end, lines = 0;
XCharStruct overall;
int direction, ascent, descent;
int end, len, lines = 0;
for (end = 0; end >= 0; lines++) {
end = String_IndexOf(&str, '\n', 0);
int len = end == -1 ? str.length : end;
len = end == -1 ? str.length : end;
XTextExtents(font, str.buffer, len, &direction, &ascent, &descent, &overall);
t->Width = max(overall.width, t->Width);
@ -420,11 +421,12 @@ static void X11Textbox_Measure(X11Textbox* t, XFontStruct* font) {
static void X11Textbox_Draw(X11Textbox* t, X11Window* w) {
String str = String_FromReadonly(t->Text);
int end, y = t->Y + t->LineHeight - t->Descent; /* TODO: is -Descent even right? */
int y = t->Y + t->LineHeight - t->Descent; /* TODO: is -Descent even right? */
int end, len;
for (end = 0; end >= 0; y += t->LineHeight) {
end = String_IndexOf(&str, '\n', 0);
int len = end == -1 ? str.length : end;
len = end == -1 ? str.length : end;
XDrawString(dpy, w->win, w->gc, t->X, y, str.buffer, len);
if (end >= 0) str = String_UNSAFE_SubstringAt(&str, end + 1);
@ -624,7 +626,7 @@ static void ErrorHandler_DumpCommon(String* str, void* ctx) {
void ErrorHandler_ShowDialog(const char* title, const char* msg) {
X11Window w = { 0 };
dpy = DisplayDevice_Meta[0];
dpy = DisplayDevice_Meta;
X11_MessageBox(title, msg, &w);
X11Window_Free(&w);

View File

@ -166,8 +166,10 @@ static void Window_RefreshBorders(void) {
}
static void Window_RefreshBounds(XEvent* e) {
Window_RefreshBorders();
Point2D loc;
Size2D size;
Window_RefreshBorders();
loc.X = e->xconfigure.x - borderLeft;
loc.Y = e->xconfigure.y - borderTop;
@ -178,7 +180,6 @@ static void Window_RefreshBounds(XEvent* e) {
/* Note: width and height denote the internal (client) size.
To get the external (window) size, we need to add the border size. */
Size2D size;
size.Width = e->xconfigure.width + borderLeft + borderRight;
size.Height = e->xconfigure.height + borderTop + borderBottom;
@ -195,9 +196,9 @@ static void Window_RefreshBounds(XEvent* e) {
*#########################################################################################################################*/
static XVisualInfo GLContext_SelectVisual(struct GraphicsMode* mode);
void Window_Create(int x, int y, int width, int height, struct GraphicsMode* mode) {
win_display = DisplayDevice_Meta[0];
win_screen = DisplayDevice_Meta[1];
win_rootWin = DisplayDevice_Meta[2];
win_display = DisplayDevice_Meta;
win_screen = DefaultScreen(win_display);
win_rootWin = RootWindow(win_display, win_screen);
/* Open a display connection to the X server, and obtain the screen and root window */
uintptr_t addr = (uintptr_t)win_display;
@ -263,11 +264,11 @@ String clipboard_paste_text = String_FromArray(clipboard_paste_buffer);
void Window_GetClipboardText(String* value) {
Window owner = XGetSelectionOwner(win_display, xa_clipboard);
int i;
if (!owner) return; /* no window owner */
XConvertSelection(win_display, xa_clipboard, xa_utf8_string, xa_data_sel, win_handle, 0);
clipboard_paste_text.length = 0;
int i;
/* wait up to 1 second for SelectionNotify event to arrive */
for (i = 0; i < 10; i++) {
@ -608,7 +609,7 @@ void Window_ProcessEvents(void) {
int len = Platform_ConvertString(str, &clipboard_copy_text);
XChangeProperty(win_display, reply.xselection.requestor, reply.xselection.property, xa_utf8_string, 8,
PropModeReplace, data, len);
PropModeReplace, str, len);
} else if (e.xselectionrequest.selection == xa_clipboard && e.xselectionrequest.target == xa_targets) {
reply.xselection.property = Window_GetSelectionProperty(&e);
@ -623,28 +624,30 @@ void Window_ProcessEvents(void) {
}
Point2D Window_PointToClient(int x, int y) {
int ox, oy;
Point2D p;
Window child;
XTranslateCoordinates(win_display, win_rootWin, win_handle, x, y, &ox, &oy, &child);
Point2D p = { ox, oy }; return p;
XTranslateCoordinates(win_display, win_rootWin, win_handle, x, y, &p.X, &p.Y, &child);
return p;
}
Point2D Window_PointToScreen(int x, int y) {
int ox, oy;
Point2D p;
Window child;
XTranslateCoordinates(win_display, win_handle, win_rootWin, x, y, &ox, &oy, &child);
Point2D p = { ox, oy }; return p;
XTranslateCoordinates(win_display, win_handle, win_rootWin, x, y, &p.X, &p.Y, &child);
return p;
}
Point2D Window_GetScreenCursorPos(void) {
Window root, child;
int rootX, rootY, childX, childY, mask;
XQueryPointer(win_display, win_rootWin, &root, &child, &rootX, &rootY, &childX, &childY, &mask);
Point2D p = { rootX, rootY }; return p;
Window rootW, childW;
Point2D root, child;
unsigned int mask;
XQueryPointer(win_display, win_rootWin, &rootW, &childW, &root.X, &root.Y, &child.X, &child.Y, &mask);
return root;
}
void Window_SetScreenCursorPos(int x, int y) {
XWarpPointer(win_display, NULL, win_rootWin, 0, 0, 0, 0, x, y);
XWarpPointer(win_display, None, win_rootWin, 0, 0, 0, 0, x, y);
XFlush(win_display); /* TODO: not sure if XFlush call is necessary */
}
@ -700,7 +703,7 @@ void GLContext_Free(void) {
if (!ctx_Handle) return;
if (glXGetCurrentContext() == ctx_Handle) {
glXMakeCurrent(win_display, NULL, NULL);
glXMakeCurrent(win_display, None, NULL);
}
glXDestroyContext(win_display, ctx_Handle);
ctx_Handle = NULL;
@ -716,10 +719,11 @@ void GLContext_SwapBuffers(void) {
}
void GLContext_SetVSync(bool enabled) {
int res;
if (!ctx_supports_vSync) return;
int result = glXSwapIntervalSGI(enabled);
if (result != 0) {Platform_Log1("Set VSync failed, error: %i", &result); }
res = glXSwapIntervalSGI(enabled);
if (res) Platform_Log1("Set VSync failed, error: %i", &res);
}
static void GLContext_GetAttribs(struct GraphicsMode* mode, int* attribs) {
@ -747,16 +751,21 @@ static void GLContext_GetAttribs(struct GraphicsMode* mode, int* attribs) {
static XVisualInfo GLContext_SelectVisual(struct GraphicsMode* mode) {
int attribs[20];
int major, minor;
XVisualInfo* visual = NULL;
int fbcount;
GLXFBConfig* fbconfigs;
XVisualInfo info;
GLContext_GetAttribs(mode, attribs);
int major = 0, minor = 0, fbcount;
if (!glXQueryVersion(win_display, &major, &minor)) {
ErrorHandler_Fail("glXQueryVersion failed");
}
XVisualInfo* visual = NULL;
if (major >= 1 && minor >= 3) {
/* ChooseFBConfig returns an array of GLXFBConfig opaque structures */
GLXFBConfig* fbconfigs = glXChooseFBConfig(win_display, win_screen, attribs, &fbcount);
fbconfigs = glXChooseFBConfig(win_display, win_screen, attribs, &fbcount);
if (fbconfigs && fbcount) {
/* Use the first GLXFBConfig from the fbconfigs array (best match) */
visual = glXGetVisualFromFBConfig(win_display, *fbconfigs);
@ -772,7 +781,7 @@ static XVisualInfo GLContext_SelectVisual(struct GraphicsMode* mode) {
ErrorHandler_Fail("Requested GraphicsMode not available.");
}
XVisualInfo info = *visual;
info = *visual;
XFree(visual);
return info;
}

View File

@ -110,27 +110,33 @@ struct RayTracer tracer;
#define PICKING_BORDER BLOCK_BEDROCK
typedef bool (*IntersectTest)(struct PickedPos* pos);
static BlockID Picking_InsideGetBlock(int x, int y, int z) {
static BlockID Picking_GetInside(int x, int y, int z) {
bool sides;
int height;
if (x >= 0 && z >= 0 && x < World_Width && z < World_Length) {
if (y >= World_Height) return BLOCK_AIR;
if (y >= 0) return World_GetBlock(x, y, z);
}
/* bedrock on bottom or outside map */
bool sides = Env_SidesBlock != BLOCK_AIR;
int height = Env_SidesHeight; if (height < 1) height = 1;
sides = Env_SidesBlock != BLOCK_AIR;
height = Env_SidesHeight; if (height < 1) height = 1;
return sides && y < height ? PICKING_BORDER : BLOCK_AIR;
}
static BlockID Picking_OutsideGetBlock(int x, int y, int z, Vector3I origin) {
static BlockID Picking_GetOutside(int x, int y, int z, Vector3I origin) {
bool sides;
int height;
if (x < 0 || z < 0 || x >= World_Width || z >= World_Length) return BLOCK_AIR;
bool sides = Env_SidesBlock != BLOCK_AIR;
sides = Env_SidesBlock != BLOCK_AIR;
/* handling of blocks inside the map, above, and on borders */
if (y >= World_Height) return BLOCK_AIR;
if (sides && y == -1 && origin.Y > 0) return PICKING_BORDER;
if (sides && y == 0 && origin.Y < 0) return PICKING_BORDER;
int height = Env_SidesHeight; if (height < 1) height = 1;
height = Env_SidesHeight; if (height < 1) height = 1;
if (sides && x == 0 && y >= 0 && y < height && origin.X < 0) return PICKING_BORDER;
if (sides && z == 0 && y >= 0 && y < height && origin.Z < 0) return PICKING_BORDER;
@ -141,30 +147,36 @@ static BlockID Picking_OutsideGetBlock(int x, int y, int z, Vector3I origin) {
}
static bool Picking_RayTrace(Vector3 origin, Vector3 dir, float reach, struct PickedPos* pos, IntersectTest intersect) {
Vector3I pOrigin;
bool insideMap;
float reachSq;
Vector3 v, minBB, maxBB;
float dxMin, dxMax, dx;
float dyMin, dyMax, dy;
float dzMin, dzMax, dz;
int i, x, y, z;
RayTracer_SetVectors(&tracer, origin, dir);
float reachSq = reach * reach;
Vector3I pOrigin; Vector3I_Floor(&pOrigin, &origin);
bool insideMap = World_IsValidPos_3I(pOrigin);
Vector3I_Floor(&pOrigin, &origin);
insideMap = World_IsValidPos_3I(pOrigin);
reachSq = reach * reach;
int i;
Vector3 coords;
for (i = 0; i < 25000; i++) {
int x = tracer.X, y = tracer.Y, z = tracer.Z;
coords.X = (float)x; coords.Y = (float)y; coords.Z = (float)z;
tracer.Block = insideMap ?
Picking_InsideGetBlock(x, y, z) : Picking_OutsideGetBlock(x, y, z, pOrigin);
x = tracer.X; y = tracer.Y; z = tracer.Z;
v.X = (float)x; v.Y = (float)y; v.Z = (float)z;
Vector3 minPos, maxPos;
Vector3_Add(&minPos, &coords, &Block_RenderMinBB[tracer.Block]);
Vector3_Add(&maxPos, &coords, &Block_RenderMaxBB[tracer.Block]);
tracer.Block = insideMap ? Picking_GetInside(x, y, z) : Picking_GetOutside(x, y, z, pOrigin);
Vector3_Add(&minBB, &v, &Block_RenderMinBB[tracer.Block]);
Vector3_Add(&maxBB, &v, &Block_RenderMaxBB[tracer.Block]);
float dxMin = Math_AbsF(origin.X - minPos.X), dxMax = Math_AbsF(origin.X - maxPos.X);
float dyMin = Math_AbsF(origin.Y - minPos.Y), dyMax = Math_AbsF(origin.Y - maxPos.Y);
float dzMin = Math_AbsF(origin.Z - minPos.Z), dzMax = Math_AbsF(origin.Z - maxPos.Z);
float dx = min(dxMin, dxMax), dy = min(dyMin, dyMax), dz = min(dzMin, dzMax);
dxMin = Math_AbsF(origin.X - minBB.X); dxMax = Math_AbsF(origin.X - maxBB.X);
dyMin = Math_AbsF(origin.Y - minBB.Y); dyMax = Math_AbsF(origin.Y - maxBB.Y);
dzMin = Math_AbsF(origin.Z - minBB.Z); dzMax = Math_AbsF(origin.Z - maxBB.Z);
dx = min(dxMin, dxMax); dy = min(dyMin, dyMax); dz = min(dzMin, dzMax);
if (dx * dx + dy * dy + dz * dz > reachSq) return false;
tracer.Min = minPos; tracer.Max = maxPos;
tracer.Min = minBB; tracer.Max = maxBB;
if (intersect(pos)) return true;
RayTracer_Step(&tracer);
}
@ -174,22 +186,21 @@ static bool Picking_RayTrace(Vector3 origin, Vector3 dir, float reach, struct Pi
}
static bool Picking_ClipBlock(struct PickedPos* pos) {
Vector3 scaledDir, intersect;
float lenSq, reach;
float t0, t1;
if (!Game_CanPick(tracer.Block)) return false;
if (!Game_CanPick(tracer.Block)) return false;
/* This cell falls on the path of the ray. Now perform an additional AABB test,
since some blocks do not occupy a whole cell. */
if (!Intersection_RayIntersectsBox(tracer.Origin, tracer.Dir, tracer.Min, tracer.Max, &t0, &t1)) {
return false;
}
if (!Intersection_RayIntersectsBox(tracer.Origin, tracer.Dir, tracer.Min, tracer.Max, &t0, &t1)) return false;
Vector3 scaledDir, intersect;
Vector3_Mul1(&scaledDir, &tracer.Dir, t0); /* scaledDir = dir * t0 */
Vector3_Add(&intersect, &tracer.Origin, &scaledDir); /* intersect = origin + scaledDir */
/* Only pick the block if the block is precisely within reach distance. */
float lenSq = Vector3_LengthSquared(&scaledDir);
float reach = LocalPlayer_Instance.ReachDistance;
lenSq = Vector3_LengthSquared(&scaledDir);
reach = LocalPlayer_Instance.ReachDistance;
if (lenSq <= reach * reach) {
PickedPos_SetAsValid(pos, &tracer, intersect);
@ -201,8 +212,10 @@ static bool Picking_ClipBlock(struct PickedPos* pos) {
static Vector3 picking_adjust = { 0.1f, 0.1f, 0.1f };
static bool Picking_ClipCamera(struct PickedPos* pos) {
if (Block_Draw[tracer.Block] == DRAW_GAS || Block_Collide[tracer.Block] != COLLIDE_SOLID) return false;
Vector3 intersect;
float t0, t1;
if (Block_Draw[tracer.Block] == DRAW_GAS || Block_Collide[tracer.Block] != COLLIDE_SOLID) return false;
if (!Intersection_RayIntersectsBox(tracer.Origin, tracer.Dir, tracer.Min, tracer.Max, &t0, &t1)) return false;
/* Need to collide with slightly outside block, to avoid camera clipping issues */
@ -210,7 +223,6 @@ static bool Picking_ClipCamera(struct PickedPos* pos) {
Vector3_Add(&tracer.Max, &tracer.Max, &picking_adjust);
Intersection_RayIntersectsBox(tracer.Origin, tracer.Dir, tracer.Min, tracer.Max, &t0, &t1);
Vector3 intersect;
Vector3_Mul1(&intersect, &tracer.Dir, t0); /* intersect = dir * t0 */
Vector3_Add(&intersect, &tracer.Origin, &intersect); /* intersect = origin + dir * t0 */
PickedPos_SetAsValid(pos, &tracer, intersect);

View File

@ -355,20 +355,29 @@ uint64_t Stopwatch_Measure(void) {
*#########################################################################################################################*/
#ifdef CC_BUILD_WIN
bool Directory_Exists(const String* path) {
WCHAR str[300]; Platform_ConvertString(str, path);
DWORD attribs = GetFileAttributesW(str);
WCHAR str[300];
DWORD attribs;
Platform_ConvertString(str, path);
attribs = GetFileAttributesW(str);
return attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY);
}
ReturnCode Directory_Create(const String* path) {
WCHAR str[300]; Platform_ConvertString(str, path);
BOOL success = CreateDirectoryW(str, NULL);
WCHAR str[300];
BOOL success;
Platform_ConvertString(str, path);
success = CreateDirectoryW(str, NULL);
return Win_Return(success);
}
bool File_Exists(const String* path) {
WCHAR str[300]; Platform_ConvertString(str, path);
DWORD attribs = GetFileAttributesW(str);
WCHAR str[300];
DWORD attribs;
Platform_ConvertString(str, path);
attribs = GetFileAttributesW(str);
return attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY);
}
@ -429,7 +438,8 @@ ReturnCode File_GetModifiedTime_MS(const String* path, TimeMS* time) {
}
ReturnCode File_Do(void** file, const String* path, DWORD access, DWORD createMode) {
WCHAR str[300]; Platform_ConvertString(str, path);
WCHAR str[300];
Platform_ConvertString(str, path);
*file = CreateFileW(str, access, FILE_SHARE_READ, NULL, createMode, 0, NULL);
return Win_Return(*file != INVALID_HANDLE_VALUE);
}
@ -478,33 +488,39 @@ ReturnCode File_Length(void* file, uint32_t* length) {
#endif
#ifdef CC_BUILD_POSIX
bool Directory_Exists(const String* path) {
char str[600]; Platform_ConvertString(str, path);
char str[600];
struct stat sb;
Platform_ConvertString(str, path);
return stat(str, &sb) == 0 && S_ISDIR(sb.st_mode);
}
ReturnCode Directory_Create(const String* path) {
char str[600]; Platform_ConvertString(str, path);
char str[600];
Platform_ConvertString(str, path);
/* read/write/search permissions for owner and group, and with read/search permissions for others. */
/* TODO: Is the default mode in all cases */
return Nix_Return(mkdir(str, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != -1);
}
bool File_Exists(const String* path) {
char str[600]; Platform_ConvertString(str, path);
char str[600];
struct stat sb;
Platform_ConvertString(str, path);
return stat(str, &sb) == 0 && S_ISREG(sb.st_mode);
}
ReturnCode Directory_Enum(const String* dirPath, void* obj, Directory_EnumCallback callback) {
char str[600]; Platform_ConvertString(str, dirPath);
DIR* dirPtr = opendir(str);
if (!dirPtr) return errno;
char str[600];
DIR* dirPtr;
struct dirent* entry;
int res;
Platform_ConvertString(str, dirPath);
dirPtr = opendir(str);
if (!dirPtr) return errno;
char pathBuffer[FILENAME_SIZE];
String path = String_FromArray(pathBuffer);
struct dirent* entry;
/* POSIX docs: "When the end of the directory is encountered, a null pointer is returned and errno is not changed." */
/* errno is sometimes leftover from previous calls, so always reset it before readdir gets called */
@ -537,8 +553,9 @@ ReturnCode Directory_Enum(const String* dirPath, void* obj, Directory_EnumCallba
}
ReturnCode File_GetModifiedTime_MS(const String* path, TimeMS* time) {
char str[600]; Platform_ConvertString(str, path);
char str[600];
struct stat sb;
Platform_ConvertString(str, path);
if (stat(str, &sb) == -1) return errno;
*time = (uint64_t)sb.st_mtime * 1000 + UNIX_EPOCH;
@ -546,7 +563,8 @@ ReturnCode File_GetModifiedTime_MS(const String* path, TimeMS* time) {
}
ReturnCode File_Do(void** file, const String* path, int mode) {
char str[600]; Platform_ConvertString(str, path);
char str[600];
Platform_ConvertString(str, path);
*file = open(str, mode, (6 << 6) | (4 << 3) | 4); /* rw|r|r */
return Nix_Return(*file != -1);
}
@ -770,11 +788,14 @@ static void Font_Init(void);
static unsigned long Font_ReadWrapper(FT_Stream s, unsigned long offset, unsigned char* buffer, unsigned long count) {
struct Stream* stream;
ReturnCode res;
if (!count && offset > s->size) return 1;
struct Stream* stream = s->descriptor.pointer;
stream = s->descriptor.pointer;
if (s->pos != offset) stream->Seek(stream, offset);
ReturnCode res = Stream_Read(stream, buffer, count);
res = Stream_Read(stream, buffer, count);
return res ? 0 : count;
}
@ -843,6 +864,11 @@ void Font_GetNames(StringsBuffer* buffer) {
}
void Font_Make(FontDesc* desc, const String* fontName, int size, int style) {
FT_Stream stream;
FT_Open_Args args;
FT_Face face;
FT_Error err;
desc->Size = size;
desc->Style = style;
if (!norm_fonts.Count) Font_Init();
@ -859,27 +885,28 @@ void Font_Make(FontDesc* desc, const String* fontName, int size, int style) {
if (idx == -1) ErrorHandler_Fail("Unknown font");
String path = StringsBuffer_UNSAFE_Get(entries, idx - 1);
FT_Stream stream = Mem_AllocCleared(1, sizeof(FT_StreamRec), "leaky font"); /* TODO: LEAKS MEMORY!!! */
FT_Open_Args args;
stream = Mem_AllocCleared(1, sizeof(FT_StreamRec), "leaky font"); /* TODO: LEAKS MEMORY!!! */
if (!Font_MakeArgs(&path, stream, &args)) return;
FT_Face face;
FT_Error err = FT_Open_Face(ft_lib, &args, 0, &face);
err = FT_Open_Face(ft_lib, &args, 0, &face);
if (err) ErrorHandler_Fail2(err, "Creating font failed");
desc->Handle = face;
err = FT_Set_Char_Size(face, size * 64, 0, DPI_DEVICE, 0); /* TODO: Check error */
err = FT_Set_Char_Size(face, size * 64, 0, DPI_DEVICE, 0);
if (err) ErrorHandler_Fail2(err, "Resizing font failed");
}
void Font_Free(FontDesc* desc) {
FT_Face face;
FT_Error err;
desc->Size = 0;
desc->Style = 0;
/* NULL for fonts created by Drawer2D_MakeFont and bitmapped text mode is on */
if (!desc->Handle) return;
FT_Face face = desc->Handle;
FT_Error err = FT_Done_Face(face);
face = desc->Handle;
err = FT_Done_Face(face);
if (err) ErrorHandler_Fail2(err, "Deleting font failed");
desc->Handle = NULL;
}
@ -907,11 +934,12 @@ static void Font_Add(const String* path, FT_Face face, StringsBuffer* entries, c
static void Font_DirCallback(const String* path, void* obj) {
FT_StreamRec stream = { 0 };
FT_Open_Args args;
if (!Font_MakeArgs(path, &stream, &args)) return;
FT_Face face;
FT_Error error = FT_Open_Face(ft_lib, &args, 0, &face);
if (error) { stream.close(&stream); return; }
FT_Error err;
if (!Font_MakeArgs(path, &stream, &args)) return;
err = FT_Open_Face(ft_lib, &args, 0, &face);
if (err) { stream.close(&stream); return; }
if (face->style_flags == FT_STYLE_FLAG_BOLD) {
Font_Add(path, face, &bold_fonts, "Bold");
@ -1056,14 +1084,15 @@ ReturnCode Socket_GetError(SocketPtr socket, ReturnCode* result) {
}
ReturnCode Socket_Connect(SocketPtr socket, const String* ip, int port) {
struct RAW_IPV4_ADDR { int16_t Family; uint8_t Port[2], IP[4], Pad[8]; } addr;
addr.Family = AF_INET;
struct { int16_t Family; uint8_t Port[2], IP[4], Pad[8]; } addr;
ReturnCode res;
addr.Family = AF_INET;
Stream_SetU16_BE(addr.Port, port);
Utils_ParseIP(ip, addr.IP);
ReturnCode result = connect(socket, (struct sockaddr*)(&addr), sizeof(addr));
return result == -1 ? Socket__Error() : 0;
res = connect(socket, (struct sockaddr*)(&addr), sizeof(addr));
return res == -1 ? Socket__Error() : 0;
}
ReturnCode Socket_Read(SocketPtr socket, uint8_t* buffer, uint32_t count, uint32_t* modified) {
@ -1333,11 +1362,14 @@ static size_t Http_GetData(char *buffer, size_t size, size_t nitems, struct Asyn
}
ReturnCode Http_Do(struct AsyncRequest* req, volatile int* progress) {
curl_easy_reset(curl);
struct curl_slist* list;
String url = String_FromRawArray(req->URL);
char urlStr[600]; Platform_ConvertString(urlStr, &url);
char urlStr[600];
long status = 0;
struct curl_slist* list = Http_Make(req);
Platform_ConvertString(urlStr, &url);
curl_easy_reset(curl);
list = Http_Make(req);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_setopt(curl, CURLOPT_URL, urlStr);
@ -1357,7 +1389,6 @@ ReturnCode Http_Do(struct AsyncRequest* req, volatile int* progress) {
CURLcode res = curl_easy_perform(curl);
*progress = 100;
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
req->StatusCode = status;
@ -1387,9 +1418,11 @@ struct AudioContext {
struct AudioContext Audio_Contexts[20];
void Audio_Init(AudioHandle* handle, int buffers) {
struct AudioContext* ctx;
int i, j;
for (i = 0; i < Array_Elems(Audio_Contexts); i++) {
struct AudioContext* ctx = &Audio_Contexts[i];
ctx = &Audio_Contexts[i];
if (ctx->Count) continue;
for (j = 0; j < buffers; j++) {
@ -1405,9 +1438,10 @@ void Audio_Init(AudioHandle* handle, int buffers) {
ReturnCode Audio_Free(AudioHandle handle) {
struct AudioContext* ctx = &Audio_Contexts[handle];
ReturnCode res;
if (!ctx->Count) return 0;
ReturnCode res = waveOutClose(ctx->Handle);
res = waveOutClose(ctx->Handle);
ctx->Handle = NULL;
ctx->Count = 0;
@ -1419,9 +1453,9 @@ ReturnCode Audio_Free(AudioHandle handle) {
ReturnCode Audio_SetFormat(AudioHandle handle, struct AudioFormat* format) {
struct AudioContext* ctx = &Audio_Contexts[handle];
struct AudioFormat* cur = &ctx->Format;
if (AudioFormat_Eq(cur, format)) return 0;
ReturnCode res;
if (AudioFormat_Eq(cur, format)) return 0;
if (ctx->Handle && (res = waveOutClose(ctx->Handle))) return res;
int sampleSize = format->Channels * format->BitsPerSample / 8;
@ -1441,13 +1475,13 @@ ReturnCode Audio_SetFormat(AudioHandle handle, struct AudioFormat* format) {
ReturnCode Audio_BufferData(AudioHandle handle, int idx, void* data, uint32_t dataSize) {
struct AudioContext* ctx = &Audio_Contexts[handle];
WAVEHDR* hdr = &ctx->Headers[idx];
Mem_Set(hdr, 0, sizeof(WAVEHDR));
ReturnCode res;
Mem_Set(hdr, 0, sizeof(WAVEHDR));
hdr->lpData = data;
hdr->dwBufferLength = dataSize;
hdr->dwLoops = 1;
ReturnCode res;
if ((res = waveOutPrepareHeader(ctx->Handle, hdr, sizeof(WAVEHDR)))) return res;
if ((res = waveOutWrite(ctx->Handle, hdr, sizeof(WAVEHDR)))) return res;
return 0;
@ -1525,8 +1559,8 @@ static void Audio_DestroyContext(void) {
}
static ALenum Audio_FreeSource(struct AudioContext* ctx) {
if (ctx->Source == -1) return 0;
ALenum err;
if (ctx->Source == -1) return 0;
alDeleteSources(1, &ctx->Source);
ctx->Source = -1;
@ -1665,12 +1699,13 @@ ReturnCode Audio_IsCompleted(AudioHandle handle, int idx, bool* completed) {
ReturnCode Audio_IsFinished(AudioHandle handle, bool* finished) {
struct AudioContext* ctx = &Audio_Contexts[handle];
if (ctx->Source == -1) { *finished = true; return 0; }
ALint state = 0;
ReturnCode res;
ReturnCode res = Audio_AllCompleted(handle, finished);
if (ctx->Source == -1) { *finished = true; return 0; }
res = Audio_AllCompleted(handle, finished);
if (res) return res;
ALint state = 0;
alGetSourcei(ctx->Source, AL_SOURCE_STATE, &state);
*finished = state != AL_PLAYING; return 0;
}
@ -1696,8 +1731,8 @@ struct AudioFormat* Audio_GetFormat(AudioHandle handle) {
}
ReturnCode Audio_StopAndFree(AudioHandle handle) {
Audio_Stop(handle);
bool finished;
Audio_Stop(handle);
Audio_IsFinished(handle, &finished); /* unqueue buffers */
return Audio_Free(handle);
}
@ -1771,8 +1806,10 @@ void Platform_SetWorkingDir(void) {
void Platform_Exit(ReturnCode code) { ExitProcess(code); }
ReturnCode Platform_StartShell(const String* args) {
WCHAR str[300]; Platform_ConvertString(str, args);
HINSTANCE instance = ShellExecuteW(NULL, NULL, str, NULL, NULL, SW_SHOWNORMAL);
WCHAR str[300];
HINSTANCE instance;
Platform_ConvertString(str, args);
instance = ShellExecuteW(NULL, NULL, str, NULL, NULL, SW_SHOWNORMAL);
return instance > 32 ? 0 : (ReturnCode)instance;
}
@ -1848,8 +1885,9 @@ void Platform_Free(void) {
void Platform_Exit(ReturnCode code) { exit(code); }
int Platform_GetCommandLineArgs(int argc, STRING_REF const char** argv, String* args) {
argc--; /* skip path argument*/
int i, count = min(argc, PROGRAM_MAX_CMDARGS);
int i, count;
argc--; /* skip executable path argument */
count = min(argc, PROGRAM_MAX_CMDARGS);
for (i = 0; i < count; i++) {
args[i] = String_FromReadonly(argv[i + 1]);
@ -1894,10 +1932,11 @@ void Platform_SetWorkingDir(void) {
static void Platform_InitDisplay(void) {
Display* display = XOpenDisplay(NULL);
int screen;
if (!display) ErrorHandler_Fail("Failed to open display");
int screen = XDefaultScreen(display);
Window rootWin = XRootWindow(display, screen);
DisplayDevice_Meta = display;
screen = DefaultScreen(display);
sw_freqDiv = 1000;
/* TODO: Use Xinerama and XRandR for querying these */
@ -1906,10 +1945,6 @@ static void Platform_InitDisplay(void) {
DisplayDevice_Default.Bounds.Width = DisplayWidth(display, screen);
DisplayDevice_Default.Bounds.Height = DisplayHeight(display, screen);
DisplayDevice_Default.BitsPerPixel = DefaultDepth(display, screen);
DisplayDevice_Meta[0] = display;
DisplayDevice_Meta[1] = screen;
DisplayDevice_Meta[2] = rootWin;
}
#endif
#ifdef CC_BUILD_OSX

View File

@ -34,7 +34,7 @@ extern ReturnCode ReturnCode_InvalidArg;
/* Data for a display device. (usually a monitor) */
struct DisplayDevice { int BitsPerPixel; Rect2D Bounds; };
struct DisplayDevice DisplayDevice_Default;
void* DisplayDevice_Meta[3];
void* DisplayDevice_Meta;
struct GraphicsMode {
int R,G,B,A, BitsPerPixel, IsIndexed; /* Colour buffer data */

View File

@ -1006,6 +1006,7 @@ static bool ChatScreen_MouseDown(void* screen, int x, int y, MouseButton btn) {
static void ChatScreen_ColCodeChanged(void* screen, int code) {
struct ChatScreen* s = screen;
double caretAcc;
if (Gfx_LostContext) return;
SpecialInputWidget_UpdateCols(&s->AltText);
@ -1016,7 +1017,7 @@ static void ChatScreen_ColCodeChanged(void* screen, int code) {
/* Some servers have plugins that redefine colours constantly */
/* Preserve caret accumulator so caret blinking stays consistent */
double caretAcc = s->Input.Base.CaretAccumulator;
caretAcc = s->Input.Base.CaretAccumulator;
Elem_Recreate(&s->Input.Base);
s->Input.Base.CaretAccumulator = caretAcc;
}
@ -1101,14 +1102,17 @@ static void ChatScreen_Init(void* screen) {
static void ChatScreen_Render(void* screen, double delta) {
struct ChatScreen* s = screen;
struct Texture tex;
int i, y;
ChatScreen_CheckOtherStatuses(s);
if (!Game_PureClassic) { Elem_Render(&s->Status, delta); }
Elem_Render(&s->BottomRight, delta);
ChatScreen_UpdateChatYOffset(s, false);
int i, y = s->ClientStatus.Y + s->ClientStatus.Height;
y = s->ClientStatus.Y + s->ClientStatus.Height;
for (i = 0; i < s->ClientStatus.LinesCount; i++) {
struct Texture tex = s->ClientStatus.Textures[i];
tex = s->ClientStatus.Textures[i];
if (!tex.ID) continue;
y -= tex.Height; tex.Y = y;
@ -1121,11 +1125,11 @@ static void ChatScreen_Render(void* screen, double delta) {
} else {
/* Only render recent chat */
for (i = 0; i < s->Chat.LinesCount; i++) {
struct Texture tex = s->Chat.Textures[i];
tex = s->Chat.Textures[i];
int logIdx = s->ChatIndex + i;
if (!tex.ID) continue;
if (logIdx < 0 || logIdx >= Chat_Log.Count) continue;
if (logIdx < 0 || logIdx >= Chat_Log.Count) continue;
if (Chat_GetLogTime(logIdx) + (10 * 1000) >= now) Texture_Render(&tex);
}
}

View File

@ -463,18 +463,20 @@ void Net_Set(uint8_t opcode, Net_Handler handler, int packetSize) {
}
void Net_SendPacket(void) {
uint32_t count = (uint32_t)(ServerConnection_WriteBuffer - net_writeBuffer);
uint32_t left, wrote;
uint8_t* cur;
ReturnCode res;
left = (uint32_t)(ServerConnection_WriteBuffer - net_writeBuffer);
ServerConnection_WriteBuffer = net_writeBuffer;
if (ServerConnection_Disconnected) return;
/* NOTE: Not immediately disconnecting here, as otherwise we sometimes miss out on kick messages */
uint32_t wrote = 0;
uint8_t* ptr = net_writeBuffer;
while (count) {
ReturnCode res = Socket_Write(net_socket, ptr, count, &wrote);
cur = net_writeBuffer;
while (left) {
res = Socket_Write(net_socket, cur, left, &wrote);
if (res || !wrote) { net_writeFailed = true; break; }
ptr += wrote; count -= wrote;
cur += wrote; left -= wrote;
}
}

View File

@ -1,7 +1,6 @@
#include "String.h"
#include "Funcs.h"
#include "ErrorHandler.h"
#include "ExtMath.h"
#include "Platform.h"
#include "Stream.h"
@ -223,7 +222,7 @@ bool String_AppendFloat(String* str, float num, int fracDigits) {
for (i = 0; i < fracDigits; i++) {
frac *= 10;
digit = Math_AbsI((int)frac) % 10;
digit = (int)frac % 10;
if (!String_Append(str, '0' + digit)) return false;
}
return true;
@ -278,10 +277,11 @@ bool String_AppendString(String* str, const String* src) {
}
bool String_AppendColorless(String* str, const String* src) {
char c;
int i;
for (i = 0; i < src->length; i++) {
char c = src->buffer[i];
c = src->buffer[i];
if (c == '&') { i++; continue; } /* Skip over the following colour code */
if (!String_Append(str, c)) return false;
}

View File

@ -448,10 +448,10 @@ static bool HotbarWidget_MouseDown(void* widget, int x, int y, MouseButton btn)
int i;
for (i = 0; i < INVENTORY_BLOCKS_PER_HOTBAR; i++) {
int winX = (int)(w->X + width * i);
int winY = (int)(w->Y + (w->Height - height));
int cellX = (int)(w->X + width * i);
int cellY = (int)(w->Y + (w->Height - height));
if (Gui_Contains(winX, winY, width, height, x, y)) {
if (Gui_Contains(cellX, cellY, width, height, x, y)) {
Inventory_SetSelectedIndex(i);
return true;
}
@ -776,10 +776,10 @@ static bool TableWidget_MouseMove(void* widget, int x, int y) {
if (Gui_Contains(w->X, w->Y + 3, w->Width, maxHeight - 3 * 2, x, y)) {
int i;
for (i = 0; i < w->ElementsCount; i++) {
int winX, winY;
TableWidget_GetCoords(w, i, &winX, &winY);
int cellX, cellY;
TableWidget_GetCoords(w, i, &cellX, &cellY);
if (Gui_Contains(winX, winY, blockSize, blockSize, x, y)) {
if (Gui_Contains(cellX, cellY, blockSize, blockSize, x, y)) {
w->SelectedIndex = i;
break;
}
@ -1490,8 +1490,11 @@ static void MenuInputWidget_RemakeTexture(void* widget) {
static bool MenuInputWidget_AllowedChar(void* widget, char c) {
struct InputWidget* w = widget;
if (c == '&' || !Utils_IsValidInputChar(c, true)) return false;
struct MenuInputValidator* v = &((struct MenuInputWidget*)w)->Validator;
struct MenuInputValidator* v;
bool valid;
if (c == '&') return false;
v = &((struct MenuInputWidget*)w)->Validator;
if (!v->VTABLE->IsValidChar(v, c)) return false;
int maxChars = w->GetMaxLines() * INPUTWIDGET_LEN;
@ -1499,7 +1502,7 @@ static bool MenuInputWidget_AllowedChar(void* widget, char c) {
/* See if the new string is in valid format */
InputWidget_AppendChar(w, c);
bool valid = v->VTABLE->IsValidString(v, &w->Text);
valid = v->VTABLE->IsValidString(v, &w->Text);
InputWidget_DeleteChar(w);
return valid;
}