Fix crash if opening audio device fails, more work on porting launcher to C

This commit is contained in:
UnknownShadow200 2018-12-02 02:48:28 +11:00
parent 55a5008913
commit a3b8cd48c2
26 changed files with 795 additions and 88 deletions

View File

@ -97,7 +97,7 @@ namespace ClassicalSharp.Audio {
void PlaySound(IAudioOutput output, float volume) {
try {
output.SetVolume(volume);
output.SetFormat(format);
output.SetFormat(format);
output.PlayData(0, chunk);
} catch (InvalidOperationException ex) {
ErrorHandler.LogError("AudioPlayer.PlayCurrentSound()", ex);

View File

@ -94,6 +94,7 @@ namespace SharpWave {
public override void Play() { }
public override void Stop() {
if (devHandle == IntPtr.Zero) return;
uint result = WinMM.waveOutReset(devHandle);
CheckError(result, "Reset");
}

View File

@ -105,7 +105,7 @@ static ReturnCode Sound_ReadWave(const String* filename, struct Sound* snd) {
ReturnCode res;
String_InitArray(path, pathBuffer);
String_Format2(&path, "audio%r%s", &Directory_Separator, filename);
String_Format1(&path, "audio/%s", filename);
res = Stream_OpenFile(&stream, &path);
if (res) return res;
@ -460,7 +460,7 @@ static void Music_RunLoop(void) {
file = StringsBuffer_UNSAFE_Get(&files, musicFiles[idx]);
path.length = 0;
String_Format2(&path, "audio%r%s", &Directory_Separator, &file);
String_Format1(&path, "audio/%s", &file);
Platform_Log1("playing music file: %s", &file);
res = Stream_OpenFile(&stream, &path);

View File

@ -101,7 +101,7 @@ static void Chat_OpenLog(struct DateTime* now) {
/* Ensure multiple instances do not end up overwriting each other's log entries. */
for (i = 0; i < 20; i++) {
path->length = 0;
String_Format4(path, "logs%r%p4-%p2-%p2 ", &Directory_Separator, &now->Year, &now->Month, &now->Day);
String_Format3(path, "logs/%p4-%p2-%p2 ", &now->Year, &now->Month, &now->Day);
if (i > 0) {
String_Format2(path, "%s _%i.log", &Chat_LogName, &i);

View File

@ -210,6 +210,7 @@
<ClInclude Include="Gui.h" />
<ClInclude Include="HeldBlockRenderer.h" />
<ClInclude Include="Launcher.h" />
<ClInclude Include="LWidgets.h" />
<ClInclude Include="Model.h" />
<ClInclude Include="Input.h" />
<ClInclude Include="InputHandler.h" />
@ -226,6 +227,7 @@
<ClInclude Include="BlockPhysics.h" />
<ClInclude Include="Picking.h" />
<ClInclude Include="PickedPosRenderer.h" />
<ClInclude Include="Resources.h" />
<ClInclude Include="Screens.h" />
<ClInclude Include="SelectionBox.h" />
<ClInclude Include="ServerConnection.h" />
@ -271,6 +273,7 @@
<ClCompile Include="InputHandler.c" />
<ClCompile Include="Inventory.c" />
<ClCompile Include="Launcher.c" />
<ClCompile Include="LWidgets.c" />
<ClCompile Include="MapGenerator.c" />
<ClCompile Include="Deflate.c" />
<ClCompile Include="Model.c" />
@ -290,6 +293,7 @@
<ClCompile Include="Picking.c" />
<ClCompile Include="Platform.c" />
<ClCompile Include="Program.c" />
<ClCompile Include="Resources.c" />
<ClCompile Include="Screens.c" />
<ClCompile Include="SelectionBox.c" />
<ClCompile Include="ServerConnection.c" />

View File

@ -306,6 +306,12 @@
<ClInclude Include="Launcher.h">
<Filter>Header Files\Launcher</Filter>
</ClInclude>
<ClInclude Include="Resources.h">
<Filter>Header Files\Launcher</Filter>
</ClInclude>
<ClInclude Include="LWidgets.h">
<Filter>Header Files\Launcher</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="String.c">
@ -545,5 +551,11 @@
<ClCompile Include="Launcher.c">
<Filter>Source Files\Launcher</Filter>
</ClCompile>
<ClCompile Include="Resources.c">
<Filter>Source Files\Launcher</Filter>
</ClCompile>
<ClCompile Include="LWidgets.c">
<Filter>Source Files\Launcher</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -95,8 +95,8 @@ bool Drawer2D_Clamp(Bitmap* bmp, int* x, int* y, int* width, int* height) {
}
#define Drawer2D_ClampPixel(p) (p < 0 ? 0 : (p > 255 ? 255 : p))
void Gradient_Noise(Bitmap* bmp, int x, int y, int width, int height,
BitmapCol col, int variation) {
void Gradient_Noise(Bitmap* bmp, BitmapCol col, int variation,
int x, int y, int width, int height) {
BitmapCol* dst;
int xx, yy, n;
float noise;
@ -122,8 +122,8 @@ void Gradient_Noise(Bitmap* bmp, int x, int y, int width, int height,
}
}
void Gradient_Vertical(Bitmap* bmp, int x, int y, int width, int height,
PackedCol a, PackedCol b) {
void Gradient_Vertical(Bitmap* bmp, BitmapCol a, BitmapCol b,
int x, int y, int width, int height) {
BitmapCol* row, col;
int xx, yy;
float t;
@ -142,8 +142,8 @@ void Gradient_Vertical(Bitmap* bmp, int x, int y, int width, int height,
}
}
void Gradient_Blend(Bitmap* bmp, int x, int y, int width, int height,
PackedCol col, int blend) {
void Gradient_Blend(Bitmap* bmp, BitmapCol col, int blend,
int x, int y, int width, int height) {
BitmapCol* dst;
int xx, yy, t;
if (!Drawer2D_Clamp(bmp, &x, &y, &width, &height)) return;

View File

@ -30,12 +30,12 @@ extern BitmapCol Drawer2D_Cols[DRAWER2D_MAX_COLS];
/* Returns false if rectangle is completely outside bitmap's rectangle. */
bool Drawer2D_Clamp(Bitmap* bmp, int* x, int* y, int* width, int* height);
void Gradient_Noise(Bitmap* bmp, int x, int y, int width, int height,
BitmapCol col, int variation);
void Gradient_Vertical(Bitmap* bmp, int x, int y, int width, int height,
PackedCol a, PackedCol b);
void Gradient_Blend(Bitmap* bmp, int x, int y, int width, int height,
PackedCol col, int blend);
void Gradient_Noise(Bitmap* bmp, BitmapCol col, int variation,
int x, int y, int width, int height);
void Gradient_Vertical(Bitmap* bmp, BitmapCol a, BitmapCol b,
int x, int y, int width, int height);
void Gradient_Blend(Bitmap* bmp, BitmapCol col, int blend,
int x, int y, int width, int height);
void Drawer2D_BmpIndexed(Bitmap* bmp, int x, int y, int size,
uint8_t* indices, BitmapCol* palette);

View File

@ -894,10 +894,9 @@ static void EnvRenderer_EnvVariableChanged(void* obj, int envVar) {
*--------------------------------------------------EnvRenderer component--------------------------------------------------*
*#########################################################################################################################*/
static void EnvRenderer_Init(void) {
String renderType; char renderTypeBuffer[STRING_SIZE];
String renderType;
int flags;
String_InitArray(renderType, renderTypeBuffer);
Options_Get(OPT_RENDER_TYPE, &renderType, "normal");
Options_UNSAFE_Get(OPT_RENDER_TYPE, &renderType);
flags = Game_CalcRenderType(&renderType);
if (flags == -1) flags = 0;

View File

@ -130,7 +130,7 @@ void Game_GetDefaultTexturePack(String* texPack) {
String texPath; char texPathBuffer[STRING_SIZE];
String_InitArray(texPath, texPathBuffer);
String_Format2(&texPath, "texpacks%r%s", &Directory_Separator, &game_defTexPack);
String_Format1(&texPath, "texpacks/%s", &game_defTexPack);
if (File_Exists(&texPath) && !Game_ClassicMode) {
String_AppendString(texPack, &game_defTexPack);
@ -421,7 +421,7 @@ static void Game_LoadGuiOptions(void) {
Game_TabAutocomplete = Options_GetBool(OPT_TAB_AUTOCOMPLETE, false);
Options_Get(OPT_FONT_NAME, &Game_FontName, Font_DefaultName);
if (Game_ClassicMode) {
if (!Game_ClassicMode) {
Game_FontName.length = 0;
String_AppendConst(&Game_FontName, Font_DefaultName);
}
@ -641,7 +641,7 @@ void Game_TakeScreenshot(void) {
String_Format3(&filename, "screenshot_%p2-%p2-%p4", &now.Day, &now.Month, &now.Year);
String_Format3(&filename, "-%p2-%p2-%p2.png", &now.Hour, &now.Minute, &now.Second);
String_InitArray(path, pathBuffer);
String_Format2(&path, "screenshots%r%s", &Directory_Separator, &filename);
String_Format1(&path, "screenshots/%s", &filename);
res = Stream_CreateFile(&stream, &path);
if (res) { Chat_LogError2(res, "creating", &path); return; }

View File

@ -74,7 +74,7 @@ void InputHandler_ScreenChanged(struct Screen* oldScreen, struct Screen* newScre
static bool InputHandler_IsShutdown(Key key) {
if (key == KEY_F4 && Key_IsAltPressed()) return true;
/* On OSX, Cmd+Q should also terminate the process. */
/* On OSX, Cmd+Q should also terminate the process */
#ifdef CC_BUILD_OSX
return key == KEY_Q && Key_IsWinPressed();
#else

181
src/LWidgets.c Normal file
View File

@ -0,0 +1,181 @@
#include "LWidgets.h"
#include "Gui.h"
#include "Game.h"
#include "Drawer2D.h"
#include "Launcher.h"
#include "ExtMath.h"
void LWidget_SetLocation(void* widget, uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset) {
struct Widget* w = widget;
w->HorAnchor = horAnchor; w->VerAnchor = verAnchor;
w->XOffset = xOffset; w->YOffset = yOffset;
LWidget_CalcPosition(widget);
}
void LWidget_CalcPosition(void* widget) {
struct LWidget* w = widget;
w->X = Gui_CalcPos(w->HorAnchor, w->XOffset, w->Width, Game_Width);
w->Y = Gui_CalcPos(w->VerAnchor, w->YOffset, w->Height, Game_Height);
}
void LWidget_Reset(void* widget) {
struct LWidget* w = widget;
w->Active = false;
w->Hidden = false;
w->X = 0; w->Y = 0;
w->Width = 0; w->Height = 0;
w->HorAnchor = ANCHOR_MIN;
w->VerAnchor = ANCHOR_MIN;
w->XOffset = 0; w->YOffset = 0;
w->TabSelectable = false;
w->OnClick = NULL;
w->Redraw = NULL;
}
/*########################################################################################################################*
*------------------------------------------------------ButtonWidget-------------------------------------------------------*
*#########################################################################################################################*/
#define BTN_BORDER 1
static BitmapCol Expand(BitmapCol a, int amount) {
int r, g, b;
r = a.R + amount; Math_Clamp(r, 0, 255); a.R = r;
g = a.G + amount; Math_Clamp(g, 0, 255); a.G = g;
b = a.B + amount; Math_Clamp(b, 0, 255); a.B = b;
return a;
}
static void LButton_DrawBackground(struct LButton* w) {
BitmapCol activeCol = BITMAPCOL_CONST(126, 136, 191, 255);
BitmapCol inactiveCol = BITMAPCOL_CONST(111, 111, 111, 255);
BitmapCol col;
if (Launcher_ClassicBackground) {
col = w->Active ? activeCol : inactiveCol;
Gradient_Noise(&Launcher_Framebuffer, col, 8,
w->X + BTN_BORDER, w->Y + BTN_BORDER,
w->Width - 2 * BTN_BORDER, w->Height - 2 * BTN_BORDER);
} else {
col = w->Active ? Launcher_ButtonForeActiveCol : Launcher_ButtonForeCol;
BitmapCol top = Expand(col, 8), bottom = Expand(col, -8);
Gradient_Vertical(&Launcher_Framebuffer, top, bottom,
w->X + BTN_BORDER, w->Y + BTN_BORDER,
w->Width - 2 * BTN_BORDER, w->Height - 2 * BTN_BORDER);
}
}
static void LButton_DrawBorder(struct LButton* w) {
BitmapCol black = BITMAPCOL_CONST(0, 0, 0, 255);
BitmapCol backCol = Launcher_ClassicBackground ? black : Launcher_ButtonBorderCol;
Drawer2D_Clear(&Launcher_Framebuffer, backCol,
w->X + BTN_BORDER, w->Y,
w->Width - 2 * BTN_BORDER, BTN_BORDER);
Drawer2D_Clear(&Launcher_Framebuffer, backCol,
w->X + BTN_BORDER, w->Y + w->Height - BTN_BORDER,
w->Width - 2 * BTN_BORDER, BTN_BORDER);
Drawer2D_Clear(&Launcher_Framebuffer, backCol,
w->X, w->Y + BTN_BORDER,
BTN_BORDER, w->Height - 2 * BTN_BORDER);
Drawer2D_Clear(&Launcher_Framebuffer, backCol,
w->X + w->Width - BTN_BORDER, w->Y + BTN_BORDER,
BTN_BORDER, w->Height - 2 * BTN_BORDER);
}
static void LButton_DrawHighlight(struct LButton* w) {
BitmapCol activeCol = BITMAPCOL_CONST(189, 198, 255, 255);
BitmapCol inactiveCol = BITMAPCOL_CONST(168, 168, 168, 255);
BitmapCol highlightCol;
if (Launcher_ClassicBackground) {
highlightCol = w->Active ? activeCol : inactiveCol;
Drawer2D_Clear(&Launcher_Framebuffer, highlightCol,
w->X + BTN_BORDER * 2, w->Y + BTN_BORDER,
w->Width - BTN_BORDER * 4, BTN_BORDER);
Drawer2D_Clear(&Launcher_Framebuffer, highlightCol,
w->X + BTN_BORDER, w->Y + BTN_BORDER * 2,
BTN_BORDER, w->Height - BTN_BORDER * 4);
} else if (!w->Active) {
Drawer2D_Clear(&Launcher_Framebuffer, Launcher_ButtonHighlightCol,
w->X + BTN_BORDER * 2, w->Y + BTN_BORDER,
w->Width - BTN_BORDER * 4, BTN_BORDER);
}
}
static void LButton_Redraw(void* widget) {
struct DrawTextArgs args;
struct LButton* w = widget;
int xOffset, yOffset;
if (w->Hidden) return;
xOffset = w->Width - w->__TextSize.Width;
yOffset = w->Height - w->__TextSize.Height;
DrawTextArgs_Make(&args, &w->Text, &w->Font, true);
LButton_DrawBackground(w);
LButton_DrawBorder(w);
LButton_DrawHighlight(w);
if (!w->Active) Drawer2D_Cols['f'] = Drawer2D_Cols['7'];
Drawer2D_DrawText(&Launcher_Framebuffer, &args,
w->X + xOffset / 2, w->Y + yOffset / 2);
if (!w->Active) Drawer2D_Cols['f'] = Drawer2D_Cols['F'];
}
void LButton_Init(struct LButton* w, int width, int height) {
Widget_Reset(w);
w->TabSelectable = true;
w->Width = width; w->Height = height;
w->Redraw = LButton_Redraw;
String_InitArray(w->Text, w->__TextBuffer);
}
void LButton_SetText(struct LButton* w, const String* text, const FontDesc* font) {
struct DrawTextArgs args;
w->Font = *font;
String_Copy(&w->Text, text);
DrawTextArgs_Make(&args, text, font, true);
w->__TextSize = Drawer2D_MeasureText(&args);
}
CC_NOINLINE void LInput_Init(struct LInput* w, int width, int height, const char* hintText, const FontDesc* hintFont);
CC_NOINLINE void LInput_SetText(struct LInput* w, const String* text, const FontDesc* font);
static void LLabel_Redraw(void* widget) {
struct DrawTextArgs args;
struct LLabel* w = widget;
if (w->Hidden) return;
DrawTextArgs_Make(&args, &w->Text, &w->Font, true);
Drawer2D_DrawText(&Launcher_Framebuffer, &args, w->X, w->Y);
}
void LLabel_Init(struct LLabel* w) {
Widget_Reset(w);
w->Redraw = LLabel_Redraw;
String_InitArray(w->Text, w->__TextBuffer);
}
void LLabel_SetText(struct LLabel* w, const String* text, const FontDesc* font) {
struct DrawTextArgs args;
Size2D size;
w->Font = *font;
String_Copy(&w->Text, text);
DrawTextArgs_Make(&args, &w->Text, &w->Font, true);
size = Drawer2D_MeasureText(&args);
w->Width = size.Width; w->Height = size.Height;
LWidget_CalcPosition(w);
}
static void LSlider_Redraw(void* widget) {
struct LSlider* w = widget;
}
void LSlider_Init(struct LSlider* w, int width, int height);

69
src/LWidgets.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef CC_LWIDGETS_H
#define CC_LWIDGETS_H
#include "Bitmap.h"
#include "String.h"
#include "Constants.h"
/* Describes and manages individual 2D GUI elements in the launcher.
Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
*/
#define LWidget_Layout \
int X, Y, Width, Height; /* Top left corner, and dimensions, of this widget */ \
bool Active; /* Whether this widget is currently being moused over*/ \
bool Hidden; /* Whether this widget is hidden from view */ \
bool TabSelectable; /* Whether this widget gets selected when pressing tab */ \
uint8_t HorAnchor, VerAnchor; /* Specifies the reference point for when this widget is resized */ \
int XOffset, YOffset; /* Offset from the reference point */ \
void (*OnClick)(void* widget, int x, int y); /* Called when widget is clicked */ \
void (*Redraw)(void* widget); /* Called to redraw contents of this widget */
/* Represents an individual 2D gui component in the launcher. */
struct LWidget { LWidget_Layout };
void LWidget_SetLocation(void* widget, uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset);
void LWidget_CalcPosition(void* widget);
void LWidget_Reset(void* widget);
struct LButton {
LWidget_Layout
String Text;
FontDesc Font;
Size2D __TextSize;
char __TextBuffer[STRING_SIZE];
};
CC_NOINLINE void LButton_Init(struct LButton* w, int width, int height);
CC_NOINLINE void LButton_SetText(struct LButton* w, const String* text, const FontDesc* font);
struct LInput {
LWidget_Layout
int BaseWidth, RealWidth;
/* Text displayed when the user has not entered anything in the text field. */
const char* HintText;
/* Whether all characters should be rendered as *. */
bool Password;
FontDesc Font, HintFont;
String Text;
int __TextHeight;
char __TextBuffer[STRING_SIZE];
};
CC_NOINLINE void LInput_Init(struct LInput* w, int width, int height, const char* hintText, const FontDesc* hintFont);
CC_NOINLINE void LInput_SetText(struct LInput* w, const String* text, const FontDesc* font);
struct LLabel {
LWidget_Layout
FontDesc Font;
String Text;
Size2D __TextSize;
char __TextBuffer[STRING_SIZE];
};
CC_NOINLINE void LLabel_Init(struct LLabel* w);
CC_NOINLINE void LLabel_SetText(struct LLabel* w, const String* text, const FontDesc* font);
/* Represents a slider bar that may or may not be modifiable by the user. */
struct LSlider {
LWidget_Layout
int Value, MaxValue;
BitmapCol ProgCol;
};
CC_NOINLINE void LSlider_Init(struct LSlider* w, int width, int height);
#endif

View File

@ -3,21 +3,189 @@
#include "Game.h"
#include "Deflate.h"
#include "Stream.h"
#include "Utils.h"
#include "Input.h"
#include "Window.h"
#include "GameStructs.h"
struct LSCreen* Launcher_Screen;
bool Launcher_Dirty, Launcher_PendingRedraw;
Rect2D Launcher_DirtyArea;
Bitmap Launcher_Framebuffer;
bool Launcher_ClassicBackground;
bool Launcher_ClassicBackground;
bool Launcher_ShouldExit, Launcher_ShouldUpdate;
TimeMS Launcher_PatchTime;
struct ServerListEntry* Launcher_PublicServers;
int Launcher_NumServers;
/* TODO: FIX THESE STUBS!!! */
void Launcher_ShowError(ReturnCode res, const char* place) { }
void Launcher_SecureSetOpt(const char* opt, const String* data, const String* key) { }
/*internal UpdateCheckTask checkTask;
bool fullRedraw;
Font logoFont;
static void Launcher_Init(void) {
BitmapCol col = BITMAPCOL_CONST(125, 125, 125, 255);
Window.Resize += Resize;
Window.FocusedChanged += RedrawAll;
Window.WindowStateChanged += Resize;
Window.Redraw += RedrawPending;
Keyboard.KeyDown += KeyDown;
Options_Load();
Options_Get(OPT_FONT_NAME, &Game_FontName, Font_DefaultName);
/* TODO: Handle Arial font not working */
/*logoFont = new Font(FontName, 32, FontStyle.Regular);
Drawer2D_Cols['g'] = col;
Utils_EnsureDirectory("texpacks");
Utils_EnsureDirectory("audio");
}
void Resize() {
UpdateClientSize();
platformDrawer.Resize();
RedrawAll();
}
void RedrawPending() {
// in case we get multiple of these events
pendingRedraw = true;
Dirty = true;
}
void RedrawAll() {
RedrawBackground();
if (Screen != null) Screen.Resize();
fullRedraw = true;
}
void SetScreen(Screen screen) {
if (Launcher_Screen) Screen.Dispose();
Launcher_ResetPixels();
Screen = screen;
screen.Init();
// for selecting active button etc
Screen.MouseMove(0, 0);
}
void UpdateClientSize() {
Size size = Window.ClientSize;
Width = Math.Max(size.Width, 1);
Height = Math.Max(size.Height, 1);
}
void Run() {
Window = Factory.CreateWindow(640, 400, Program.AppName,
GraphicsMode.Default, DisplayDevice.Default);
Window_SetVisible(true);
Drawer2D_Component.Init();
UpdateClientSize();
Launcher_Init();
Launcher_TryLoadTexturePack();
Launcher_Framebuffer.Width = Game_Width;
Launcher_Framebuffer.Height = Game_Height;
Window_InitRaw(&Launcher_Framebuffer);
Downloader = new AsyncDownloader(Drawer);
Downloader.Init("");
Downloader.Cookies = new CookieContainer();
Downloader.KeepAlive = true;
fetcher = new ResourceFetcher();
fetcher.CheckResourceExistence();
checkTask = new UpdateCheckTask();
checkTask.RunAsync(this);
if (!fetcher.AllResourcesExist) {
SetScreen(new ResourcesScreen(this));
} else {
SetScreen(new MainScreen(this));
}
while (true) {
Window_ProcessEvents();
if (!Window_Exists) break;
if (Launcher_ShouldExit) break;
checkTask.Tick();
Screen.Tick();
if (Launcher_Dirty) Launcher_Display();
Thread_Sleep(10);
}
if (Options.Load()) {
LauncherSkin.SaveToOptions();
Options.Save();
}
if (Launcher_Screen) {
Screen.Dispose();
Launcher_Screen = NULL;
}
if (Launcher_ShouldUpdate)
Updater.Applier.ApplyUpdate();
if (Window_Exists)
Window_Close();
}
void Display() {
if (pendingRedraw) {
RedrawAll();
pendingRedraw = false;
}
Screen.OnDisplay();
Dirty = false;
Rectangle rec = new Rectangle(0, 0, Framebuffer.Width, Framebuffer.Height);
if (!fullRedraw && DirtyArea.Width > 0) {
rec = DirtyArea;
}
Window_DrawRaw(rec);
DirtyArea = Rectangle.Empty;
fullRedraw = false;
}
void KeyDown(Key key) {
if (IsShutdown(key)) Launcher_ShouldExit = true;
}
void Dispose() {
Window.Resize -= Resize;
Window.FocusedChanged -= RedrawAll;
Window.WindowStateChanged -= Resize;
Window.Redraw -= RedrawPending;
Keyboard.KeyDown -= KeyDown;
List<FastBitmap> bitmaps = FetchFlagsTask.Bitmaps;
for (int i = 0; i < bitmaps.Count; i++) {
bitmaps[i].Dispose();
bitmaps[i].Bitmap.Dispose();
}
logoFont.Dispose();
}*/
static bool Launcher_IsShutdown(Key key) {
if (key == KEY_F4 && Key_IsAltPressed()) return true;
/* On OSX, Cmd+Q should also terminate the process */
#ifdef CC_BUILD_OSX
return key == Key.Q && Key_IsWinPressed();
#else
return false;
#endif
}
/*########################################################################################################################*
*---------------------------------------------------------Colours/Skin-----------------------------------------------------*
*---------------------------------------------------------Colours/Skin----------------------------------------------------*
*#########################################################################################################################*/
BitmapCol Launcher_BackgroundCol = BITMAPCOL_CONST(153, 127, 172, 255);
BitmapCol Launcher_ButtonBorderCol = BITMAPCOL_CONST( 97, 81, 110, 255);
@ -40,13 +208,13 @@ void Launcher_ResetSkin(void) {
Launcher_ButtonHighlightCol = defaultButtonHighlightCol;
}
/*CC_NOINLINE static void Launcher_GetCol(const char* key, BitmapCol* col) {
CC_NOINLINE static void Launcher_GetCol(const char* key, BitmapCol* col) {
PackedCol tmp;
string value = Options.Get(key, null);
if (String.IsNullOrEmpty(value)) return;
String value;
if (!Options_UNSAFE_Get(key, &value)) return;
if (!PackedCol_TryParseHex(&value, &tmp)) return;
if (!PackedCol.TryParse(value, out col))
col = defaultCol;
col->R = tmp.R; col->G = tmp.G; col->B = tmp.B;
}
void Launcher_LoadSkin(void) {
@ -58,12 +226,13 @@ void Launcher_LoadSkin(void) {
}
CC_NOINLINE static void Launcher_SetCol(const char* key, BitmapCol col) {
String value; char valueBuffer[8];
PackedCol tmp;
string value = Options.Get(key, null);
if (String.IsNullOrEmpty(value)) return;
if (!PackedCol.TryParse(value, out col))
col = defaultCol;
tmp.R = col.R; tmp.G = col.G; tmp.B = col.B; tmp.A = 0;
String_InitArray(value, valueBuffer);
PackedCol_ToHex(&value, tmp);
Options_Set(key, &value);
}
void Launcher_SaveSkin(void) {
@ -72,7 +241,7 @@ void Launcher_SaveSkin(void) {
Launcher_SetCol("launcher-btn-fore-active-col", Launcher_ButtonForeActiveCol);
Launcher_SetCol("launcher-btn-fore-inactive-col", Launcher_ButtonForeCol);
Launcher_SetCol("launcher-btn-highlight-inactive-col", Launcher_ButtonHighlightCol);
}*/
}
/*########################################################################################################################*
@ -150,28 +319,30 @@ static void Launcher_ExtractTexturePack(const String* path) {
stream.Close(&stream);
}
/*void Launcher_TryLoadTexturePack(void) {
if (Options.Get("nostalgia-classicbg", null) != null) {
void Launcher_TryLoadTexturePack(void) {
static String defZipPath = String_FromConst("texpacks/default.zip");
String path; char pathBuffer[FILENAME_SIZE];
String texPack;
if (Options_UNSAFE_Get("nostalgia-classicbg", &texPack)) {
Launcher_ClassicBackground = Options_GetBool("nostalgia-classicbg", false);
} else {
Launcher_ClassicBackground = Options_GetBool(OPT_CLASSIC_MODE, false);
}
string texPack = Options.Get(OptionsKey.DefaultTexturePack, "default.zip");
string texPath = Path.Combine("texpacks", texPack);
Options_UNSAFE_Get(OPT_DEFAULT_TEX_PACK, &texPack);
String_InitArray(path, pathBuffer);
String_Format1(&path, "texpacks/", &texPack);
if (!Platform_FileExists(texPath)) {
texPath = Path.Combine("texpacks", "default.zip");
}
if (!Platform_FileExists(texPath)) return;
if (!texPack.length || !File_Exists(&path)) path = defZipPath;
if (!File_Exists(&path)) return;
Launcher_ExtractTexturePack(texPath);
// user selected texture pack is missing some required .png files
Launcher_ExtractTexturePack(&path);
/* user selected texture pack is missing some required .png files */
if (!fontBmp.Scan0 || !terrainBmp.Scan0) {
texPath = Path.Combine("texpacks", "default.zip");
ExtractTexturePack(texPath);
Launcher_ExtractTexturePack(&defZipPath);
}
}*/
}
static void Launcher_ClearTile(int x, int y, int width, int height, int srcX) {
Drawer2D_BmpTiled(&Launcher_Framebuffer, x, y, width, height,
@ -182,7 +353,7 @@ void Launcher_ResetArea(int x, int y, int width, int height) {
if (Launcher_ClassicBackground && terrainBmp.Scan0) {
Launcher_ClearTile(x, y, width, height, 0);
} else {
Gradient_Noise(&Launcher_Framebuffer, x, y, width, height, Launcher_BackgroundCol, 6);
Gradient_Noise(&Launcher_Framebuffer, Launcher_BackgroundCol, 6, x, y, width, height);
}
}
@ -211,3 +382,51 @@ void Launcher_ResetPixels(void) {
Drawer2D_BitmappedText = false;
Launcher_Dirty = true;
}
static TimeMS lastJoin;
bool Launcher_StartGame(const String* user, const String* mppass, const String* ip, const String* port, const String* server) {
#ifdef CC_BUILD_WINDOWS
static String exe = String_FromConst("ClassiCube.exe");
#else
static String exe = String_FromConst("ClassiCube");
#endif
String args; char argsBuffer[512];
TimeMS now;
ReturnCode res;
now = DateTime_CurrentUTC_MS();
if (lastJoin + 1000 < now) return false;
lastJoin = now;
/* Make sure if the client has changed some settings in the meantime, we keep the changes */
Options_Load();
Launcher_ShouldExit = Options_GetBool(OPT_AUTO_CLOSE_LAUNCHER, false);
/* Save resume info */
if (server) {
Options_Set("launcher-server", server);
Options_Set("launcher-username", user);
Options_Set("launcher-ip", ip);
Options_Set("launcher-port", port);
Launcher_SecureSetOpt("launcher-mppass", mppass, user);
Options_Save();
}
String_InitArray(args, argsBuffer);
String_AppendString(&args, user);
if (mppass->length) String_Format3(&args, "%s %s %s", mppass, ip, port);
res = Platform_StartProcess(&exe, &args);
#ifdef CC_BUILD_WINDOWS
/* TODO: Check this*/
/* HRESULT when user clicks 'cancel' to 'are you sure you want to run ClassiCube.exe' */
if (res == 0x80004005) return;
#endif
if (res) {
Launcher_ShowError(res, "starting game");
Launcher_ShouldExit = false;
return false;
}
return true;
}

View File

@ -2,7 +2,9 @@
#define CC_LAUNCHER_H
#include "Bitmap.h"
#include "String.h"
/* Implements the launcher part of the game.
Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
*/
struct LScreen;
/* Currently active screen/menu. */
@ -11,7 +13,7 @@ extern struct LSCreen* Launcher_Screen;
extern bool Launcher_Dirty, Launcher_PendingRedraw;
/* The specific area/region of the window that needs to be redrawn. */
extern Rect2D Launcher_DirtyArea;
/* Pixels containing contents of the window.*/
/* Contains the pixels that are drawn to the window. */
extern Bitmap Launcher_Framebuffer;
/* Whether to use stone tile background like minecraft.net. */
extern bool Launcher_ClassicBackground;
@ -67,8 +69,12 @@ void Launcher_SetScreen(struct LScreen* screen);
bool Launcher_ConnectToServer(const String* hash);
/* Launcher main loop. */
void Launcher_Run();
/* Shows a message box for an error. */
void Launcher_ShowError(ReturnCode res, const char* place);
/* Attempts to securely encode an option. */
/* NOTE: Not all platforms support secure saving, DO NOT rely on this being secure. */
void Launcher_SecureSetOpt(const char* opt, const String* data, const String* key);
/* Starts the game from the given arguments. */
bool Launcher_StartGame(const String* user, const String* mppass, const String* ip, const String* port, const String* server);

View File

@ -1284,7 +1284,7 @@ static void SaveLevelScreen_Save(void* screen, void* widget, const char* ext) {
SaveLevelScreen_MakeDesc(s, &fileMsg); return;
}
String_InitArray(path, pathBuffer);
String_Format3(&path, "maps%r%s%c", &Directory_Separator, &file, ext);
String_Format2(&path, "maps/%s%c", &file, ext);
if (File_Exists(&path) && !btn->OptName) {
ButtonWidget_Set(btn, &overMsg, &s->TitleFont);
@ -1387,7 +1387,7 @@ static void TexturePackScreen_EntryClick(void* screen, void* widget) {
filename = ListScreen_UNSAFE_GetCur(s, widget);
String_InitArray(path, pathBuffer);
String_Format2(&path, "texpacks%r%s", &Directory_Separator, &filename);
String_Format1(&path, "texpacks/%s", &filename);
if (!File_Exists(&path)) return;
idx = s->CurrentIndex;
@ -1573,7 +1573,7 @@ static void LoadLevelScreen_EntryClick(void* screen, void* widget) {
filename = ListScreen_UNSAFE_GetCur(s, widget);
String_InitArray(path, pathBuffer);
String_Format2(&path, "maps%r%s", &Directory_Separator, &filename);
String_Format1(&path, "maps/%s", &filename);
if (!File_Exists(&path)) return;
Map_LoadFrom(&path);

View File

@ -31,7 +31,7 @@ bool Options_HasChanged(const String* key) {
return false;
}
static bool Options_TryGetValue(const char* keyRaw, String* value) {
bool Options_UNSAFE_Get(const char* keyRaw, String* value) {
int idx;
String key = String_FromReadonly(keyRaw);
@ -50,7 +50,7 @@ static bool Options_TryGetValue(const char* keyRaw, String* value) {
void Options_Get(const char* key, String* value, const char* defValue) {
String str;
Options_TryGetValue(key, &str);
Options_UNSAFE_Get(key, &str);
value->length = 0;
if (str.length) {
@ -63,7 +63,7 @@ void Options_Get(const char* key, String* value, const char* defValue) {
int Options_GetInt(const char* key, int min, int max, int defValue) {
String str;
int value;
if (!Options_TryGetValue(key, &str)) return defValue;
if (!Options_UNSAFE_Get(key, &str)) return defValue;
if (!Convert_TryParseInt(&str, &value)) return defValue;
Math_Clamp(value, min, max);
@ -73,7 +73,7 @@ int Options_GetInt(const char* key, int min, int max, int defValue) {
bool Options_GetBool(const char* key, bool defValue) {
String str;
bool value;
if (!Options_TryGetValue(key, &str)) return defValue;
if (!Options_UNSAFE_Get(key, &str)) return defValue;
if (!Convert_TryParseBool(&str, &value)) return defValue;
return value;
@ -82,7 +82,7 @@ bool Options_GetBool(const char* key, bool defValue) {
float Options_GetFloat(const char* key, float min, float max, float defValue) {
String str;
float value;
if (!Options_TryGetValue(key, &str)) return defValue;
if (!Options_UNSAFE_Get(key, &str)) return defValue;
if (!Convert_TryParseFloat(&str, &value)) return defValue;
Math_Clamp(value, min, max);
@ -91,7 +91,7 @@ float Options_GetFloat(const char* key, float min, float max, float defValue) {
int Options_GetEnum(const char* key, int defValue, const char** names, int namesCount) {
String str;
if (!Options_TryGetValue(key, &str)) return defValue;
if (!Options_UNSAFE_Get(key, &str)) return defValue;
return Utils_ParseEnum(&str, defValue, names, namesCount);
}

View File

@ -76,6 +76,9 @@ bool Options_HasAnyChanged(void);
/* Frees any memory allocated in storing options. */
void Options_Free(void);
/* Sets value to value of option directly in Options.Buffer if found, String_Empty if not. */
/* Returns whether the option was actually found. */
STRING_REF bool Options_UNSAFE_Get(const char* keyRaw, String* value);
/* Returns value of given option, or defalt value if not found. */
CC_EXPORT void Options_Get(const char* key, String* value, const char* defValue);
/* Returns value of given option as an integer, or defalt value if could not be converted. */

View File

@ -44,7 +44,6 @@ void* DisplayDevice_Meta;
static HANDLE heap;
char* Platform_NewLine = "\r\n";
char Directory_Separator = '\\';
char* Font_DefaultName = "Arial";
const ReturnCode ReturnCode_FileShareViolation = ERROR_SHARING_VIOLATION;
@ -77,7 +76,6 @@ const ReturnCode ReturnCode_SocketWouldBlock = WSAEWOULDBLOCK;
#define Nix_Return(success) ((success) ? 0 : errno)
char* Platform_NewLine = "\n";
char Directory_Separator = '/'; /* TODO: Is this right for old OSX though?? */
pthread_mutex_t event_mutex;
const ReturnCode ReturnCode_FileShareViolation = 1000000000; /* TODO: not used apparently */
@ -412,7 +410,7 @@ ReturnCode Directory_Enum(const String* dirPath, void* obj, Directory_EnumCallba
do {
path.length = 0;
String_Format2(&path, "%s%r", dirPath, &Directory_Separator);
String_Format1(&path, "%s/", dirPath);
/* ignore . and .. entry */
TCHAR* src = entry.cFileName;
@ -545,7 +543,7 @@ ReturnCode Directory_Enum(const String* dirPath, void* obj, Directory_EnumCallba
while ((entry = readdir(dirPtr))) {
path.length = 0;
String_Format2(&path, "%s%r", dirPath, &Directory_Separator);
String_Format1(&path, "%s/", dirPath);
/* ignore . and .. entry */
src = entry->d_name;
@ -1587,9 +1585,9 @@ ReturnCode Audio_Free(AudioHandle handle) {
ReturnCode res;
ctx = &Audio_Contexts[handle];
if (!ctx->Count) return 0;
ctx->Count = 0;
ctx->Format = fmt;
if (!ctx->Handle) return 0;
res = waveOutClose(ctx->Handle);
ctx->Handle = NULL;
@ -1637,6 +1635,7 @@ ReturnCode Audio_Play(AudioHandle handle) { return 0; }
ReturnCode Audio_Stop(AudioHandle handle) {
struct AudioContext* ctx = &Audio_Contexts[handle];
if (!ctx->Handle) return 0;
return waveOutReset(ctx->Handle);
}

View File

@ -23,8 +23,6 @@ enum File_SeekFrom { FILE_SEEKFROM_BEGIN, FILE_SEEKFROM_CURRENT, FILE_SEEKFROM_E
/* Newline for console and text files. */
extern char* Platform_NewLine;
/* Character in a path that distinguishes directories. (usually / or \) */
extern char Directory_Separator;
/* Name of default system font used. (e.g. Arial) */
extern char* Font_DefaultName;
extern const ReturnCode ReturnCode_FileShareViolation;

View File

@ -40,8 +40,8 @@ int main_imdct() {
#endif
int main(int argc, char** argv) {
String defPath; char defPathBuffer[STRING_SIZE];
String title; char titleBuffer[STRING_SIZE];
static String defPath = String_FromConst("texpacks/default.zip");
String title; char titleBuffer[STRING_SIZE];
String args[PROGRAM_MAX_CMDARGS];
int argsCount;
@ -67,9 +67,6 @@ int main(int argc, char** argv) {
Utils_EnsureDirectory("texpacks");
Utils_EnsureDirectory("texturecache");
String_InitArray(defPath, defPathBuffer);
String_Format1(&defPath, "texpacks%rdefault.zip", &Directory_Separator);
if (!File_Exists(&defPath)) {
Window_ShowDialog("Missing file",
"default.zip is missing, try running launcher first.\n\nThe game will still run, but without any textures");

182
src/Resources.c Normal file
View File

@ -0,0 +1,182 @@
#include "Resources.h"
#include "Funcs.h"
#include "String.h"
#include "Constants.h"
#include "Deflate.h"
#include "Stream.h"
#include "Platform.h"
#include "Launcher.h"
#include "Utils.h"
/*########################################################################################################################*
*---------------------------------------------------------List/Checker----------------------------------------------------*
*#########################################################################################################################*/
bool DigSoundsExist, StepSoundsExist;
int Resources_Size, Resources_Count;
static void Resources_CheckFiles(void) {
int flags = Resources_GetFetchFlags();
if (flags & FLAG_CLASSIC) { Resources_Size += 291; Resources_Count++; }
if (flags & FLAG_MODERN) { Resources_Size += 4621; Resources_Count++; }
if (flags & FLAG_TERRAIN) { Resources_Size += 7; Resources_Count++; }
if (flags & FLAG_GUI) { Resources_Size += 21; Resources_Count++; }
}
static void Resources_CheckMusic(void) {
String path; char pathBuffer[FILENAME_SIZE];
int i = 0;
String_InitArray(path, pathBuffer);
for (i = 0; i < Array_Elems(Resources_Music); i++) {
path.length = 0;
String_Format1(&path, "audio/%c", Resources_Music[i].Name);
Resources_Music[i].Exists = File_Exists(&path);
if (Resources_Music[i].Exists) continue;
Resources_Size += Resources_Music[i].Size;
Resources_Count++;
}
}
CC_NOINLINE static bool Resources_CheckExist(const char* prefix, struct ResourceSound* sounds, int count) {
String path; char pathBuffer[FILENAME_SIZE];
int i = 0;
String_InitArray(path, pathBuffer);
for (i = 0; i < count; i++) {
path.length = 0;
String_Format2(&path, "audio/%c_%c", prefix, sounds[i].Name);
if (!File_Exists(&path)) return false;
}
return true;
}
static void Resources_CheckSounds(void) {
DigSoundsExist = Resources_CheckExist("dig", Resources_Dig, Array_Elems(Resources_Dig));
if (!DigSoundsExist) {
Resources_Count += Array_Elems(Resources_Dig);
Resources_Size += 173;
}
StepSoundsExist = Resources_CheckExist("step", Resources_Step, Array_Elems(Resources_Step));
if (!StepSoundsExist) {
Resources_Count += Array_Elems(Resources_Step);
Resources_Size += 244;
}
}
static bool Resources_SelectZipEntry(const String* path) {
String name;
int i;
name = *path;
Utils_UNSAFE_GetFilename(&name);
for (i = 0; i < Array_Elems(Resources_Files); i++) {
if (Resources_Files[i].Exists) continue;
if (!String_CaselessEqualsConst(&name, Resources_Files[i].Filename)) continue;
Resources_Files[i].Exists = true;
break;
}
return false;
}
static void Resources_CheckDefaultZip(void) {
static String path = String_FromConst("texpacks/default.zip");
struct Stream stream;
struct ZipState state;
ReturnCode res;
if (!File_Exists(&path)) return;
res = Stream_OpenFile(&stream, &path);
if (res) { Launcher_ShowError(res, "checking default.zip"); return; }
Zip_Init(&state, &stream);
state.SelectEntry = Resources_SelectZipEntry;
res = Zip_Extract(&state);
stream.Close(&stream);
if (res) { Launcher_ShowError(res, "inspecting default.zip"); }
}
int Resources_GetFetchFlags(void) {
int flags = 0, i;
for (i = 0; i < Array_Elems(Resources_Files); i++) {
if (Resources_Files[i].Exists) continue;
flags |= Resources_Files[i].Flags;
}
return flags;
}
void Resources_CheckExistence(void) {
Resources_CheckDefaultZip();
Resources_CheckFiles();
Resources_CheckMusic();
Resources_CheckSounds();
}
struct ResourceFile Resources_Files[19] = {
/* classic jar files */
{ "char.png", FLAG_CLASSIC }, { "clouds.png", FLAG_CLASSIC },
{ "default.png", FLAG_CLASSIC }, { "particles.png", FLAG_CLASSIC },
{ "rain.png", FLAG_CLASSIC }, { "gui_classic.png", FLAG_CLASSIC },
{ "icons.png", FLAG_CLASSIC },
{ "terrain.png", FLAG_CLASSIC | FLAG_TERRAIN | FLAG_MODERN },
{ "creeper.png", FLAG_CLASSIC }, { "pig.png", FLAG_CLASSIC },
{ "sheep.png", FLAG_CLASSIC }, { "sheep_fur.png", FLAG_CLASSIC },
{ "skeleton.png", FLAG_CLASSIC }, { "spider.png", FLAG_CLASSIC },
{ "zombie.png", FLAG_CLASSIC }, /* "arrows.png", "sign.png" */
/* other files */
{ "snow.png", FLAG_MODERN }, { "chicken.png", FLAG_MODERN },
{ "animations.png", FLAG_MODERN }, { "gui.png", FLAG_GUI }
};
struct ResourceSound Resources_Dig[31] = {
{ "cloth1", "5f/5fd568d724ba7d53911b6cccf5636f859d2662e8" }, { "cloth2", "56/56c1d0ac0de2265018b2c41cb571cc6631101484" },
{ "cloth3", "9c/9c63f2a3681832dc32d206f6830360bfe94b5bfc" }, { "cloth4", "55/55da1856e77cfd31a7e8c3d358e1f856c5583198" },
{ "grass1", "41/41cbf5dd08e951ad65883854e74d2e034929f572" }, { "grass2", "86/86cb1bb0c45625b18e00a64098cd425a38f6d3f2" },
{ "grass3", "f7/f7d7e5c7089c9b45fa5d1b31542eb455fad995db" }, { "grass4", "c7/c7b1005d4926f6a2e2387a41ab1fb48a72f18e98" },
{ "gravel1", "e8/e8b89f316f3e9989a87f6e6ff12db9abe0f8b09f" }, { "gravel2", "c3/c3b3797d04cb9640e1d3a72d5e96edb410388fa3" },
{ "gravel3", "48/48f7e1bb098abd36b9760cca27b9d4391a23de26" }, { "gravel4", "7b/7bf3553a4fe41a0078f4988a13d6e1ed8663ef4c" },
{ "sand1", "9e/9e59c3650c6c3fc0a475f1b753b2fcfef430bf81" }, { "sand2", "0f/0fa4234797f336ada4e3735e013e44d1099afe57" },
{ "sand3", "c7/c75589cc0087069f387de127dd1499580498738e" }, { "sand4", "37/37afa06f97d58767a1cd1382386db878be1532dd" },
{ "snow1", "e9/e9bab7d3d15541f0aaa93fad31ad37fd07e03a6c" }, { "snow2", "58/5887d10234c4f244ec5468080412f3e6ef9522f3" },
{ "snow3", "a4/a4bc069321a96236fde04a3820664cc23b2ea619" }, { "snow4", "e2/e26fa3036cdab4c2264ceb19e1cd197a2a510227" },
{ "stone1", "4e/4e094ed8dfa98656d8fec52a7d20c5ee6098b6ad" }, { "stone2", "9c/9c92f697142ae320584bf64c0d54381d59703528" },
{ "stone3", "8f/8f23c02475d388b23e5faa680eafe6b991d7a9d4" }, { "stone4", "36/363545a76277e5e47538b2dd3a0d6aa4f7a87d34" },
{ "wood1", "9b/9bc2a84d0aa98113fc52609976fae8fc88ea6333" }, { "wood2", "98/98102533e6085617a2962157b4f3658f59aea018" },
{ "wood3", "45/45b2aef7b5049e81b39b58f8d631563fadcc778b" }, { "wood4", "dc/dc66978374a46ab2b87db6472804185824868095" },
{ "glass1", "72/7274a2231ed4544a37e599b7b014e589e5377094" }, { "glass2", "87/87c47bda3645c68f18a49e83cbf06e5302d087ff" },
{ "glass3", "ad/ad7d770b7fff3b64121f75bd60cecfc4866d1cd6" }
};
struct ResourceSound Resources_Step[28] = {
{ "cloth1", "5f/5fd568d724ba7d53911b6cccf5636f859d2662e8" }, { "cloth2", "56/56c1d0ac0de2265018b2c41cb571cc6631101484" },
{ "cloth3", "9c/9c63f2a3681832dc32d206f6830360bfe94b5bfc" }, { "cloth4", "55/55da1856e77cfd31a7e8c3d358e1f856c5583198" },
{ "grass1", "22/227ab99bf7c6cf0b2002e0f7957d0ff7e5cb0c96" }, { "grass2", "5c/5c971029d9284676dce1dda2c9d202f8c47163b2" },
{ "grass3", "76/76de0a736928eac5003691d73bdc2eda92116198" }, { "grass4", "bc/bc28801224a0aa77fdc93bb7c6c94beacdf77331" },
{ "gravel1", "1d/1d761cb3bcb45498719e4fba0751e1630e134f1a" }, { "gravel2", "ac/ac7a7c8d106e26abc775b1b46150c083825d8ddc" },
{ "gravel3", "c1/c109b985a7e6d5d3828c92e00aefa49deca0eb8c" }, { "gravel4", "a4/a47adece748059294c5f563c0fcac02fa0e4bab4" },
{ "sand1", "98/9813c8185197f4a4296649f27a9d738c4a6dfc78" }, { "sand2", "bd/bd1750c016f6bab40934eff0b0fb64c41c86e44b" },
{ "sand3", "ab/ab07279288fa49215bada5c17627e6a54ad0437c" }, { "sand4", "a4/a474236fb0c75bd65a6010e87dbc000d345fc185" },
{ "snow1", "e9/e9bab7d3d15541f0aaa93fad31ad37fd07e03a6c" }, { "snow2", "58/5887d10234c4f244ec5468080412f3e6ef9522f3" },
{ "snow3", "a4/a4bc069321a96236fde04a3820664cc23b2ea619" }, { "snow4", "e2/e26fa3036cdab4c2264ceb19e1cd197a2a510227" },
{ "stone1", "4a/4a2e3795ffd4d3aab0834b7e41903af3a8f7d197" }, { "stone2", "22/22a383d9c22342305a4f16fec0bb479a885f8da2" },
{ "stone3", "a5/a533e7ae975e62592de868e0d0572778614bd587" }, { "stone4", "d5/d5218034051a13322d7b5efc0b5a9af739615f04" },
{ "wood1", "af/afb01196e2179e3b15b48f3373cea4c155d56b84" }, { "wood2", "1e/1e82a43c30cf8fcbe05d0bc2760ecba5d2320314" },
{ "wood3", "27/27722125968ac60c0f191a961b17e406f1351c6e" }, { "wood4", "29/29586f60bfe6f521dbc748919d4f0dc5b28beefd" }
};
struct ResourceMusic Resources_Music[7] = {
{ "calm1.ogg", "50/50a59a4f56e4046701b758ddbb1c1587efa4cadf", 2472 },
{ "calm2.ogg", "74/74da65c99aa578486efa7b69983d3533e14c0d6e", 1931 },
{ "calm3.ogg", "14/14ae57a6bce3d4254daa8be2b098c2d99743cc3f", 2181 },
{ "hal1.ogg", "df/df1ff11b79757432c5c3f279e5ecde7b63ceda64", 1926 },
{ "hal2.ogg", "ce/ceaaaa1d57dfdfbb0bd4da5ea39628b42897a687", 1714 },
{ "hal3.ogg", "dd/dd85fb564e96ee2dbd4754f711ae9deb08a169f9", 1879 },
{ "hal4.ogg", "5e/5e7d63e75c6e042f452bc5e151276911ef92fed8", 2499 }
};

37
src/Resources.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef CC_RESOURCES_H
#define CC_RESOURCES_H
#include "Core.h"
/* Implements checking, fetching, and patching the default game assets.
Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
*/
#define FLAG_CLASSIC 0x01 /* file depends on classic.jar */
#define FLAG_MODERN 0x02 /* file depends on modern jar */
#define FLAG_GUI 0x04 /* file depends on patched gui.png */
#define FLAG_TERRAIN 0x08 /* file depends on patched terrain.png */
extern struct ResourceFile {
const char* Filename;
uint8_t Flags;
bool Exists;
} Resources_Files[19];
extern bool DigSoundsExist, StepSoundsExist;
/* Number and total size of resources that need to be downloaded. */
extern int Resources_Size, Resources_Count;
/* Returns flags of files that need to be fetched. */
int Resources_GetFetchFlags(void);
extern struct ResourceSound {
const char* Name;
const char* Hash;
} Resources_Dig[31], Resources_Step[28];
extern struct ResourceMusic {
const char* Name;
const char* Hash;
uint16_t Size;
bool Exists;
} Resources_Music[7];
#endif

View File

@ -143,6 +143,7 @@ int PingList_AveragePingMs(void) {
/*########################################################################################################################*
*-------------------------------------------------Singleplayer connection-------------------------------------------------*
*#########################################################################################################################*/
#define SP_HasDir(path) (String_IndexOf(&path, '/', 0) >= 0 || String_IndexOf(&path, '\\', 0) >= 0)
static void SPConnection_BeginConnect(void) {
static String logName = String_FromConst("Singleplayer");
String path;
@ -161,7 +162,7 @@ static void SPConnection_BeginConnect(void) {
/* For when user drops a map file onto ClassiCube.exe */
path = Game_Username;
if (String_IndexOf(&path, Directory_Separator, 0) >= 0 && File_Exists(&path)) {
if (SP_HasDir(path) && File_Exists(&path)) {
Map_LoadFrom(&path);
Gui_CloseActive();
return;

View File

@ -267,12 +267,12 @@ static void Animations_Apply(struct AnimationData* data) {
}
static bool Animations_IsDefaultZip(void) {
String texPack; char texPackBuffer[STRING_SIZE];
String texPack;
bool optExists;
if (World_TextureUrl.length) return false;
String_InitArray(texPack, texPackBuffer);
Options_Get(OPT_DEFAULT_TEX_PACK, &texPack, "default.zip");
return String_CaselessEqualsConst(&texPack, "default.zip");
optExists = Options_UNSAFE_Get(OPT_DEFAULT_TEX_PACK, &texPack);
return !optExists || String_CaselessEqualsConst(&texPack, "default.zip");
}
static void Animations_Clear(void) {
@ -497,16 +497,15 @@ void Atlas_Free(void) {
/*########################################################################################################################*
*------------------------------------------------------TextureCache-------------------------------------------------------*
*#########################################################################################################################*/
#define TEXCACHE_FOLDER "texturecache"
/* Because I didn't store milliseconds in original C# client */
#define TEXCACHE_TICKS_PER_MS 10000
static struct EntryList cache_accepted, cache_denied, cache_eTags, cache_lastModified;
void TextureCache_Init(void) {
EntryList_Init(&cache_accepted, TEXCACHE_FOLDER, "acceptedurls.txt", ' ');
EntryList_Init(&cache_denied, TEXCACHE_FOLDER, "deniedurls.txt", ' ');
EntryList_Init(&cache_eTags, TEXCACHE_FOLDER, "etags.txt", ' ');
EntryList_Init(&cache_lastModified, TEXCACHE_FOLDER, "lastmodified.txt", ' ');
EntryList_Init(&cache_accepted, "texturecache", "acceptedurls.txt", ' ');
EntryList_Init(&cache_denied, "texturecache", "deniedurls.txt", ' ');
EntryList_Init(&cache_eTags, "texturecache", "etags.txt", ' ');
EntryList_Init(&cache_lastModified, "texturecache", "lastmodified.txt", ' ');
}
bool TextureCache_HasAccepted(const String* url) { return EntryList_Find(&cache_accepted, url) >= 0; }
@ -526,7 +525,7 @@ CC_NOINLINE static void TextureCache_MakePath(String* path, const String* url) {
String_InitArray(key, keyBuffer);
String_AppendUInt32(&key, Utils_CRC32(url->buffer, url->length));
String_Format2(path, TEXCACHE_FOLDER "%r%s", &Directory_Separator, &key);
String_Format1(path, "texturecache/%s", &key);
}
bool TextureCache_Has(const String* url) {
@ -589,7 +588,7 @@ void TextureCache_Set(const String* url, uint8_t* data, uint32_t length) {
String_InitArray(path, pathBuffer);
TextureCache_MakePath(&path, url);
if (!Utils_EnsureDirectory(TEXCACHE_FOLDER)) return;
if (!Utils_EnsureDirectory("texturecache")) return;
res = Stream_CreateFile(&stream, &path);
if (res) { Chat_LogError2(res, "creating cache for", &path); return; }
@ -650,7 +649,7 @@ void TexturePack_ExtractZip_File(const String* filename) {
ReturnCode res;
String_InitArray(path, pathBuffer);
String_Format2(&path, "texpacks%r%s", &Directory_Separator, filename);
String_Format1(&path, "texpacks/%s", filename);
res = Stream_OpenFile(&stream, &path);
if (res) { Chat_LogError2(res, "opening", &path); return; }

View File

@ -241,7 +241,7 @@ void EntryList_Load(struct EntryList* list, EntryList_Filter filter) {
String_InitArray(path, pathBuffer);
if (list->Folder) {
String_Format3(&path, "%c%r%c", list->Folder, &Directory_Separator, list->Filename);
String_Format2(&path, "%c/c", list->Folder, list->Filename);
} else {
String_AppendConst(&path, list->Filename);
}
@ -281,7 +281,7 @@ void EntryList_Save(struct EntryList* list) {
String_InitArray(path, pathBuffer);
if (list->Folder) {
String_Format3(&path, "%c%r%c", list->Folder, &Directory_Separator, list->Filename);
String_Format2(&path, "%c/%c", list->Folder, list->Filename);
if (!Utils_EnsureDirectory(list->Folder)) return;
} else {
String_AppendConst(&path, list->Filename);