mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-18 20:15:35 -04:00
Actually download the C client when updating
This commit is contained in:
parent
869064c5c7
commit
dec52c9d53
@ -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;
|
||||
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 = dx ? build.DirectXPath : build.OpenGLPath;
|
||||
string path;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (Utils.CaselessEquals(name, "ClassicalSharp")
|
||||
|| Utils.CaselessEquals(name, "ClassicalSharp.exe"))
|
||||
return true;
|
||||
void TickCClientFetchTask() {
|
||||
if (fetchCClientTask == null) return;
|
||||
fetchCClientTask.Tick();
|
||||
UpdateProgress(fetchCClientTask);
|
||||
if (!fetchCClientTask.Completed) return;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -321,15 +321,15 @@ 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;
|
||||
|
||||
sigaction(SIGSEGV, &sa, &old);
|
||||
sigaction(SIGBUS, &sa, &old);
|
||||
sigaction(SIGILL, &sa, &old);
|
||||
sigaction(SIGBUS, &sa, &old);
|
||||
sigaction(SIGILL, &sa, &old);
|
||||
sigaction(SIGABRT, &sa, &old);
|
||||
sigaction(SIGFPE, &sa, &old);
|
||||
sigaction(SIGFPE, &sa, &old);
|
||||
}
|
||||
|
||||
void ErrorHandler_Fail2(ReturnCode result, const char* raw_msg) {
|
||||
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
@ -177,8 +179,7 @@ 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;
|
||||
To get the external (window) size, we need to add the border 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++) {
|
||||
@ -452,7 +453,7 @@ Atom Window_GetSelectionProperty(XEvent* e) {
|
||||
}
|
||||
|
||||
bool Window_GetPendingEvent(XEvent* e) {
|
||||
return XCheckWindowEvent(win_display, win_handle, win_eventMask, e) ||
|
||||
return XCheckWindowEvent(win_display, win_handle, win_eventMask, e) ||
|
||||
XCheckTypedWindowEvent(win_display, win_handle, ClientMessage, e) ||
|
||||
XCheckTypedWindowEvent(win_display, win_handle, SelectionNotify, e) ||
|
||||
XCheckTypedWindowEvent(win_display, win_handle, SelectionRequest, e);
|
||||
@ -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];
|
||||
GLContext_GetAttribs(mode, attribs);
|
||||
int major = 0, minor = 0, fbcount;
|
||||
int major, minor;
|
||||
XVisualInfo* visual = NULL;
|
||||
|
||||
int fbcount;
|
||||
GLXFBConfig* fbconfigs;
|
||||
XVisualInfo info;
|
||||
|
||||
GLContext_GetAttribs(mode, attribs);
|
||||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
int i;
|
||||
Vector3 coords;
|
||||
Vector3I_Floor(&pOrigin, &origin);
|
||||
insideMap = World_IsValidPos_3I(pOrigin);
|
||||
reachSq = reach * reach;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Vector3 scaledDir, intersect;
|
||||
Vector3_Mul1(&scaledDir, &tracer.Dir, t0); /* scaledDir = dir * t0 */
|
||||
Vector3_Add(&intersect, &tracer.Origin, &scaledDir); /* intersect = origin + scaledDir */
|
||||
if (!Intersection_RayIntersectsBox(tracer.Origin, tracer.Dir, tracer.Min, tracer.Max, &t0, &t1)) return false;
|
||||
|
||||
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,18 +212,19 @@ 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 */
|
||||
Vector3_Sub(&tracer.Min, &tracer.Min, &picking_adjust);
|
||||
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 */
|
||||
|
||||
Vector3_Mul1(&intersect, &tracer.Dir, t0); /* intersect = dir * t0 */
|
||||
Vector3_Add(&intersect, &tracer.Origin, &intersect); /* intersect = origin + dir * t0 */
|
||||
PickedPos_SetAsValid(pos, &tracer, intersect);
|
||||
return true;
|
||||
}
|
||||
|
157
src/Platform.c
157
src/Platform.c
@ -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; }
|
||||
|
||||
ReturnCode res = Audio_AllCompleted(handle, finished);
|
||||
if (res) return res;
|
||||
|
||||
ALint state = 0;
|
||||
ReturnCode res;
|
||||
|
||||
if (ctx->Source == -1) { *finished = true; return 0; }
|
||||
res = Audio_AllCompleted(handle, finished);
|
||||
if (res) return res;
|
||||
|
||||
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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user