mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-14 10:05:44 -04:00
work on making default.zip (disabled still as doesn't work properly yet)
This commit is contained in:
parent
bb4efbe388
commit
eb0251a7f9
24
src/Bitmap.c
24
src/Bitmap.c
@ -507,27 +507,6 @@ ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream) {
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------------PNG encoder--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static ReturnCode Bitmap_Crc32StreamWrite(struct Stream* stream, const uint8_t* data, uint32_t count, uint32_t* modified) {
|
||||
struct Stream* source;
|
||||
uint32_t i, crc32 = stream->Meta.CRC32.CRC32;
|
||||
|
||||
/* TODO: Optimise this calculation */
|
||||
for (i = 0; i < count; i++) {
|
||||
crc32 = Utils_Crc32Table[(crc32 ^ data[i]) & 0xFF] ^ (crc32 >> 8);
|
||||
}
|
||||
stream->Meta.CRC32.CRC32 = crc32;
|
||||
|
||||
source = stream->Meta.CRC32.Source;
|
||||
return source->Write(source, data, count, modified);
|
||||
}
|
||||
|
||||
static void Bitmap_Crc32Stream(struct Stream* stream, struct Stream* underlying) {
|
||||
Stream_Init(stream);
|
||||
stream->Meta.CRC32.Source = underlying;
|
||||
stream->Meta.CRC32.CRC32 = 0xFFFFFFFFUL;
|
||||
stream->Write = Bitmap_Crc32StreamWrite;
|
||||
}
|
||||
|
||||
static void Png_Filter(uint8_t filter, uint8_t* cur, uint8_t* prior, uint8_t* best, int lineLen) {
|
||||
/* 3 bytes per pixel constant */
|
||||
uint8_t a, b, c;
|
||||
@ -616,6 +595,7 @@ static void Png_EncodeRow(const BitmapCol* src, uint8_t* cur, uint8_t* prior, ui
|
||||
if (bestFilter != PNG_FILTER_PAETH) {
|
||||
Png_Filter(bestFilter, cur, prior, dst, lineLen);
|
||||
}
|
||||
|
||||
best[0] = bestFilter;
|
||||
}
|
||||
|
||||
@ -633,7 +613,7 @@ ReturnCode Png_Encode(Bitmap* bmp, struct Stream* stream, Png_RowSelector select
|
||||
|
||||
if (!selectRow) selectRow = Png_SelectRow;
|
||||
if ((res = Stream_Write(stream, png_sig, PNG_SIG_SIZE))) return res;
|
||||
Bitmap_Crc32Stream(&chunk, stream);
|
||||
Stream_WriteonlyCrc32(&chunk, stream);
|
||||
|
||||
/* Write header chunk */
|
||||
Stream_SetU32_BE(&tmp[0], PNG_IHDR_SIZE);
|
||||
|
@ -1095,13 +1095,14 @@ static ReturnCode Zip_ReadLocalFileHeader(struct ZipState* state, struct ZipEntr
|
||||
|
||||
if (method == 0) {
|
||||
Stream_ReadonlyPortion(&portion, stream, uncompressedSize);
|
||||
state->ProcessEntry(&path, &portion, entry);
|
||||
return state->ProcessEntry(&path, &portion, state->Obj);
|
||||
} else if (method == 8) {
|
||||
Stream_ReadonlyPortion(&portion, stream, compressedSize);
|
||||
Inflate_MakeStream(&compStream, &inflate, &portion);
|
||||
state->ProcessEntry(&path, &compStream, entry);
|
||||
return state->ProcessEntry(&path, &compStream, state->Obj);
|
||||
} else {
|
||||
Platform_Log1("Unsupported.zip entry compression method: %i", &method);
|
||||
/* TODO: Should this be an error */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1113,7 +1114,6 @@ static ReturnCode Zip_ReadCentralDirectory(struct ZipState* state, struct ZipEnt
|
||||
ReturnCode res;
|
||||
if ((res = Stream_Read(stream, header, sizeof(header)))) return res;
|
||||
|
||||
entry->Crc32 = Stream_GetU32_LE(&header[12]);
|
||||
entry->CompressedSize = Stream_GetU32_LE(&header[16]);
|
||||
entry->UncompressedSize = Stream_GetU32_LE(&header[20]);
|
||||
|
||||
@ -1144,10 +1144,11 @@ enum ZipSig {
|
||||
ZIP_SIG_LOCALFILEHEADER = 0x04034b50
|
||||
};
|
||||
|
||||
static void Zip_DefaultProcessor(const String* path, struct Stream* data, struct ZipEntry* entry) { }
|
||||
static ReturnCode Zip_DefaultProcessor(const String* path, struct Stream* data, void* obj) { return 0; }
|
||||
static bool Zip_DefaultSelector(const String* path) { return true; }
|
||||
void Zip_Init(struct ZipState* state, struct Stream* input) {
|
||||
state->Input = input;
|
||||
state->Obj = NULL;
|
||||
state->EntriesCount = 0;
|
||||
state->ProcessEntry = Zip_DefaultProcessor;
|
||||
state->SelectEntry = Zip_DefaultSelector;
|
||||
|
@ -110,7 +110,7 @@ struct ZLibState { struct DeflateState Base; uint32_t Adler32; };
|
||||
CC_API void ZLib_MakeStream(struct Stream* stream, struct ZLibState* state, struct Stream* underlying);
|
||||
|
||||
/* Minimal data needed to describe an entry in a .zip archive. */
|
||||
struct ZipEntry { uint32_t CompressedSize, UncompressedSize, LocalHeaderOffset, Crc32; };
|
||||
struct ZipEntry { uint32_t CompressedSize, UncompressedSize, LocalHeaderOffset; };
|
||||
#define ZIP_MAX_ENTRIES 2048
|
||||
|
||||
/* Stores state for reading and processing entries in a .zip archive. */
|
||||
@ -118,11 +118,15 @@ struct ZipState {
|
||||
/* Source of the .zip archive data. Must be seekable. */
|
||||
struct Stream* Input;
|
||||
/* Callback function to process the data in a .zip archive entry. */
|
||||
/* NOTE: data stream may not be seekable. (entry data might be compressed) */
|
||||
void (*ProcessEntry)(const String* path, struct Stream* data, struct ZipEntry* entry);
|
||||
/* obj is user specified in state.Obj variable */
|
||||
/* Return non-zero to indicate an error and stop further processing. */
|
||||
/* NOTE: data stream MAY NOT be seekable. (i.e. entry data might be compressed) */
|
||||
ReturnCode (*ProcessEntry)(const String* path, struct Stream* data, void* obj);
|
||||
/* Predicate used to select which entries in a .zip archive get proessed. */
|
||||
/* NOTE: returning false entirely skips the entry. (avoids pointless seek to entry) */
|
||||
bool (*SelectEntry)(const String* path);
|
||||
/* Generic object/pointer passed to ProcessEntry callback. */
|
||||
void* Obj;
|
||||
/* Number of entries in the .zip archive. */
|
||||
int EntriesCount;
|
||||
/* Data for each entry in the .zip archive. */
|
||||
|
@ -148,6 +148,7 @@ static void Launcher_MouseUp(void* obj, int btn) {
|
||||
}
|
||||
|
||||
static void Launcher_MouseMove(void* obj, int deltaX, int deltaY) {
|
||||
if (!Launcher_Screen) return;
|
||||
Launcher_Screen->MouseMove(Launcher_Screen, deltaX, deltaY);
|
||||
}
|
||||
|
||||
@ -376,30 +377,31 @@ static void Launcher_LoadTextures(Bitmap* bmp) {
|
||||
0, 0, TILESIZE, TILESIZE);
|
||||
}
|
||||
|
||||
static void Launcher_ProcessZipEntry(const String* path, struct Stream* data, struct ZipEntry* entry) {
|
||||
static ReturnCode Launcher_ProcessZipEntry(const String* path, struct Stream* data, void* obj) {
|
||||
Bitmap bmp;
|
||||
ReturnCode res;
|
||||
|
||||
if (String_CaselessEqualsConst(path, "default.png")) {
|
||||
if (fontBmp.Scan0) return;
|
||||
if (fontBmp.Scan0) return 0;
|
||||
res = Png_Decode(&fontBmp, data);
|
||||
|
||||
if (res) {
|
||||
Launcher_ShowError(res, "decoding default.png"); return;
|
||||
Launcher_ShowError(res, "decoding default.png"); return res;
|
||||
} else {
|
||||
Drawer2D_SetFontBitmap(&fontBmp);
|
||||
useBitmappedFont = !Options_GetBool(OPT_USE_CHAT_FONT, false);
|
||||
}
|
||||
} else if (String_CaselessEqualsConst(path, "terrain.png")) {
|
||||
if (terrainBmp.Scan0) return;
|
||||
if (terrainBmp.Scan0) return 0;
|
||||
res = Png_Decode(&bmp, data);
|
||||
|
||||
if (res) {
|
||||
Launcher_ShowError(res, "decoding terrain.png"); return;
|
||||
Launcher_ShowError(res, "decoding terrain.png"); return res;
|
||||
} else {
|
||||
Launcher_LoadTextures(&bmp);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Launcher_ExtractTexturePack(const String* path) {
|
||||
|
397
src/Resources.c
397
src/Resources.c
@ -13,19 +13,19 @@
|
||||
/*########################################################################################################################*
|
||||
*---------------------------------------------------------List/Checker----------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
bool SoundsExist;
|
||||
bool Textures_AllExist, Sounds_AllExist;
|
||||
int Resources_Count, Resources_Size;
|
||||
static int texturesFound;
|
||||
|
||||
static void Resources_CheckFiles(void) {
|
||||
int i, flags;
|
||||
|
||||
flags = Resources_GetFetchFlags();
|
||||
for (i = 0; i < Array_Elems(Resources_Files); i++) {
|
||||
if (!(flags & Resources_Files[i].Flag)) continue;
|
||||
CC_NOINLINE static struct ResourceTexture* Resources_FindTex(const String* name) {
|
||||
struct ResourceTexture* tex;
|
||||
int i;
|
||||
|
||||
Resources_Size += Resources_Files[i].Size;
|
||||
Resources_Count++;
|
||||
for (i = 0; i < Array_Elems(Resources_Textures); i++) {
|
||||
tex = &Resources_Textures[i];
|
||||
if (String_CaselessEqualsConst(name, tex->Filename)) return tex;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void Resources_CheckMusic(void) {
|
||||
@ -37,8 +37,8 @@ static void Resources_CheckMusic(void) {
|
||||
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_Music[i].Downloaded = File_Exists(&path);
|
||||
if (Resources_Music[i].Downloaded) continue;
|
||||
|
||||
Resources_Size += Resources_Music[i].Size;
|
||||
Resources_Count++;
|
||||
@ -55,32 +55,24 @@ static void Resources_CheckSounds(void) {
|
||||
String_Format1(&path, "audio/%c.wav", Resources_Sounds[i].Name);
|
||||
|
||||
if (File_Exists(&path)) continue;
|
||||
SoundsExist = false;
|
||||
Sounds_AllExist = false;
|
||||
|
||||
Resources_Count += Array_Elems(Resources_Sounds);
|
||||
Resources_Size += 417;
|
||||
return;
|
||||
}
|
||||
SoundsExist = true;
|
||||
Sounds_AllExist = true;
|
||||
}
|
||||
|
||||
static bool Resources_SelectZipEntry(const String* path) {
|
||||
String name;
|
||||
int i;
|
||||
|
||||
name = *path;
|
||||
String name = *path;
|
||||
Utils_UNSAFE_GetFilename(&name);
|
||||
for (i = 0; i < Array_Elems(Resources_Textures); i++) {
|
||||
if (Resources_Textures[i].Exists) continue;
|
||||
|
||||
if (!String_CaselessEqualsConst(&name, Resources_Textures[i].Filename)) continue;
|
||||
Resources_Textures[i].Exists = true;
|
||||
break;
|
||||
}
|
||||
if (Resources_FindTex(&name)) texturesFound++;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Resources_CheckDefaultZip(void) {
|
||||
static void Resources_CheckTextures(void) {
|
||||
const static String path = String_FromConst("texpacks/default.zip");
|
||||
struct Stream stream;
|
||||
struct ZipState state;
|
||||
@ -95,46 +87,41 @@ static void Resources_CheckDefaultZip(void) {
|
||||
|
||||
res = Zip_Extract(&state);
|
||||
stream.Close(&stream);
|
||||
if (res) { Launcher_ShowError(res, "inspecting default.zip"); }
|
||||
}
|
||||
if (res) Launcher_ShowError(res, "inspecting default.zip");
|
||||
|
||||
int Resources_GetFetchFlags(void) {
|
||||
int flags = 0, i;
|
||||
for (i = 0; i < Array_Elems(Resources_Textures); i++) {
|
||||
if (Resources_Textures[i].Exists) continue;
|
||||
|
||||
flags |= Resources_Textures[i].Flags;
|
||||
}
|
||||
return flags;
|
||||
/* if somehow have say "gui.png", "GUI.png" */
|
||||
Textures_AllExist = texturesFound >= Array_Elems(Resources_Textures);
|
||||
}
|
||||
|
||||
void Resources_CheckExistence(void) {
|
||||
Resources_CheckDefaultZip();
|
||||
Resources_CheckFiles();
|
||||
int i;
|
||||
Resources_CheckTextures();
|
||||
Resources_CheckMusic();
|
||||
Resources_CheckSounds();
|
||||
|
||||
if (Textures_AllExist) return;
|
||||
for (i = 0; i < Array_Elems(Resources_Files); i++) {
|
||||
Resources_Count++;
|
||||
Resources_Size += Resources_Files[i].Size;
|
||||
}
|
||||
}
|
||||
|
||||
struct ResourceFile Resources_Files[4] = {
|
||||
{ "classic jar", "http://launcher.mojang.com/mc/game/c0.30_01c/client/54622801f5ef1bcc1549a842c5b04cb5d5583005/client.jar", 291, FLAG_CLASSIC },
|
||||
{ "1.6.2 jar", "http://launcher.mojang.com/mc/game/1.6.2/client/b6cb68afde1d9cf4a20cbf27fa90d0828bf440a4/client.jar", 4621, FLAG_MODERN },
|
||||
{ "gui.png patch", "http://static.classicube.net/terrain-patch2.png", 7, FLAG_GUI },
|
||||
{ "terrain.png patch", "http://static.classicube.net/gui.png", 21, FLAG_TERRAIN }
|
||||
{ "classic jar", "http://launcher.mojang.com/mc/game/c0.30_01c/client/54622801f5ef1bcc1549a842c5b04cb5d5583005/client.jar", 291 },
|
||||
{ "1.6.2 jar", "http://launcher.mojang.com/mc/game/1.6.2/client/b6cb68afde1d9cf4a20cbf27fa90d0828bf440a4/client.jar", 4621 },
|
||||
{ "gui.png patch", "http://static.classicube.net/terrain-patch2.png", 7 },
|
||||
{ "terrain.png patch", "http://static.classicube.net/gui.png", 21 }
|
||||
};
|
||||
|
||||
struct ResourceTexture Resources_Textures[19] = {
|
||||
struct ResourceTexture Resources_Textures[20] = {
|
||||
/* 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" */
|
||||
{ "char.png" }, { "clouds.png" }, { "default.png" }, { "particles.png" },
|
||||
{ "rain.png" }, { "gui_classic.png" }, { "icons.png" }, { "terrain.png" },
|
||||
{ "creeper.png" }, { "pig.png" }, { "sheep.png" }, { "sheep_fur.png" },
|
||||
{ "skeleton.png" }, { "spider.png" }, { "zombie.png" }, /* "arrows.png", "sign.png" */
|
||||
/* other files */
|
||||
{ "snow.png", FLAG_MODERN }, { "chicken.png", FLAG_MODERN },
|
||||
{ "animations.png", FLAG_MODERN }, { "gui.png", FLAG_GUI }
|
||||
{ "snow.png" }, { "chicken.png" }, { "gui.png" },
|
||||
{ "animations.png" }, { "animations.txt" }
|
||||
};
|
||||
|
||||
struct ResourceSound Resources_Sounds[59] = {
|
||||
@ -182,9 +169,262 @@ struct ResourceMusic Resources_Music[7] = {
|
||||
};
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*---------------------------------------------------------Zip writer------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static ReturnCode ZipPatcher_LocalFile(struct Stream* s, struct ResourceTexture* entry) {
|
||||
String name = String_FromReadonly(entry->Filename);
|
||||
uint8_t header[30 + STRING_SIZE];
|
||||
ReturnCode res;
|
||||
if ((res = s->Position(s, &entry->Offset))) return res;
|
||||
|
||||
Stream_SetU32_LE(&header[0], 0x04034b50); /* signature */
|
||||
Stream_SetU16_LE(&header[4], 20); /* version needed */
|
||||
Stream_SetU16_LE(&header[6], 0); /* bitflags */
|
||||
Stream_SetU16_LE(&header[8] , 0); /* compression method */
|
||||
Stream_SetU16_LE(&header[10], 0); /* last modified */
|
||||
Stream_SetU16_LE(&header[12], 0); /* last modified */
|
||||
|
||||
Stream_SetU32_LE(&header[14], 0); /* CRC32 */
|
||||
Stream_SetU32_LE(&header[18], 0); /* Compressed size */
|
||||
Stream_SetU32_LE(&header[22], 0); /* Uncompressed size */
|
||||
|
||||
Stream_SetU16_LE(&header[26], name.length); /* name length */
|
||||
Stream_SetU16_LE(&header[28], 0); /* extra field length */
|
||||
|
||||
Mem_Copy(&header[30], name.buffer, name.length);
|
||||
return Stream_Write(s, header, 30 + name.length);
|
||||
}
|
||||
|
||||
static ReturnCode ZipPatcher_CentralDir(struct Stream* s, struct ResourceTexture* res) {
|
||||
String name = String_FromReadonly(res->Filename);
|
||||
uint8_t header[46 + STRING_SIZE];
|
||||
struct DateTime now;
|
||||
int modTime, modDate;
|
||||
|
||||
DateTime_CurrentLocal(&now);
|
||||
modTime = (now.Second / 2) | (now.Minute << 5) | (now.Hour << 11);
|
||||
modDate = (now.Day) | (now.Month << 5) | ((now.Year - 1980) << 9);
|
||||
|
||||
Stream_SetU32_LE(&header[0], 0x02014b50); /* signature */
|
||||
Stream_SetU16_LE(&header[4], 20); /* version */
|
||||
Stream_SetU16_LE(&header[6], 20); /* version needed */
|
||||
Stream_SetU16_LE(&header[8], 0); /* bitflags */
|
||||
Stream_SetU16_LE(&header[10], 0); /* compression method */
|
||||
Stream_SetU16_LE(&header[12], modTime); /* last modified */
|
||||
Stream_SetU16_LE(&header[14], modDate); /* last modified */
|
||||
|
||||
Stream_SetU32_LE(&header[16], res->Crc32); /* CRC32 */
|
||||
Stream_SetU32_LE(&header[20], res->Size); /* compressed size */
|
||||
Stream_SetU32_LE(&header[24], res->Size); /* uncompressed size */
|
||||
|
||||
Stream_SetU16_LE(&header[28], name.length); /* name length */
|
||||
Stream_SetU16_LE(&header[30], 0); /* extra field length */
|
||||
Stream_SetU16_LE(&header[32], 0); /* file comment length */
|
||||
Stream_SetU16_LE(&header[34], 0); /* disk number */
|
||||
Stream_SetU16_LE(&header[36], 0); /* internal attributes */
|
||||
Stream_SetU32_LE(&header[38], 0); /* external attributes */
|
||||
Stream_SetU32_LE(&header[42], res->Offset); /* local header offset */
|
||||
|
||||
Mem_Copy(&header[46], name.buffer, name.length);
|
||||
return Stream_Write(s, header, 46 + name.length);
|
||||
}
|
||||
|
||||
static ReturnCode ZipPatcher_EndOfCentralDir(struct Stream* s, uint32_t centralDirBeg, uint32_t centralDirEnd) {
|
||||
uint8_t header[22];
|
||||
|
||||
Stream_SetU32_LE(&header[0], 0x06054b50); /* signature */
|
||||
Stream_SetU16_LE(&header[4], 0); /* disk number */
|
||||
Stream_SetU16_LE(&header[6], 0); /* disk number of start */
|
||||
Stream_SetU16_LE(&header[8], Array_Elems(Resources_Textures)); /* disk entries */
|
||||
Stream_SetU16_LE(&header[10], Array_Elems(Resources_Textures)); /* total entries */
|
||||
Stream_SetU32_LE(&header[12], centralDirEnd - centralDirBeg); /* central dir size */
|
||||
Stream_SetU32_LE(&header[16], centralDirBeg); /* central dir start */
|
||||
Stream_SetU16_LE(&header[20], 0); /* comment length */
|
||||
return Stream_Write(s, header, 22);
|
||||
}
|
||||
|
||||
static ReturnCode ZipPatcher_WriteData(struct Stream* s, struct ResourceTexture* tex, const uint8_t* data, uint32_t len) {
|
||||
ReturnCode res;
|
||||
tex->Size = len;
|
||||
tex->Crc32 = Utils_CRC32(data, len);
|
||||
|
||||
res = ZipPatcher_LocalFile(s, tex);
|
||||
if (res) return res;
|
||||
return Stream_Write(s, data, len);
|
||||
}
|
||||
|
||||
static ReturnCode ZipPatcher_WriteStream(struct Stream* s, struct ResourceTexture* tex, struct Stream* src) {
|
||||
uint8_t tmp[2048];
|
||||
uint32_t read;
|
||||
struct Stream crc32;
|
||||
ReturnCode res;
|
||||
|
||||
res = ZipPatcher_LocalFile(s, tex);
|
||||
if (res) return res;
|
||||
Stream_WriteonlyCrc32(&crc32, s);
|
||||
|
||||
for (tex->Size = 0; ; tex->Size += read) {
|
||||
res = src->Read(src, tmp, sizeof(tmp), &read);
|
||||
if (res) return res;
|
||||
if (!read) break;
|
||||
|
||||
res = Stream_Write(&crc32, tmp, read);
|
||||
if (res) return res;
|
||||
}
|
||||
|
||||
tex->Crc32 = crc32.Meta.CRC32.CRC32 ^ 0xFFFFFFFFUL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------Texture patcher---------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#define ANIMS_TXT_CONTENTS \
|
||||
"# This file defines the animations used in a texture pack for ClassicalSharp and other supporting applications.\r\n" \
|
||||
"# Each line is in the format : <TileX> <TileY> <FrameX> <FrameY> <Frame size> <Frames count> <Tick delay>\r\n" \
|
||||
"# - TileX and TileY are the coordinates of the tile in terrain.png that will be replaced by the animation frames.\r\n" \
|
||||
"# Essentially, TileX and TileY are the remainder and quotient of an ID in F10 menu divided by 16\r\n" \
|
||||
"# For instance, obsidian texture(37) has TileX of 5, and TileY of 2\r\n" \
|
||||
"# - FrameX and FrameY are the pixel coordinates of the first animation frame in animations.png.\r\n" \
|
||||
"# - Frame Size is the size in pixels of an animation frame.\r\n" \
|
||||
"# - Frames count is the number of used frames. The first frame is located at\r\n" \
|
||||
"# (FrameX, FrameY), the second one at (FrameX + FrameSize, FrameY) and so on.\r\n" \
|
||||
"# - Tick delay is the number of ticks a frame doesn't change. For instance, delay of 0\r\n" \
|
||||
"# means that the tile would be replaced every tick, while delay of 2 means\r\n" \
|
||||
"# 'replace with frame 1, don't change frame, don't change frame, replace with frame 2'.\r\n" \
|
||||
"# NOTE: If a file called 'uselavaanim' is in the texture pack, ClassicalSharp 0.99.2 onwards uses its built - in dynamic generation for the lava texture animation.\r\n" \
|
||||
"# NOTE : If a file called 'usewateranim' is in the texture pack, ClassicalSharp 0.99.5 onwards uses its built - in dynamic generation for the water texture animation.\r\n" \
|
||||
"\r\n" \
|
||||
"# fire\r\n" \
|
||||
"6 2 0 0 16 32 0"
|
||||
|
||||
static bool TexPatcher_ClassicSelect(const String* path ) {
|
||||
String name = *path;
|
||||
Utils_UNSAFE_GetFilename(&name);
|
||||
return Resources_FindTex(&name) != NULL;
|
||||
}
|
||||
|
||||
static ReturnCode TexPatcher_ClassicProcess(const String* path, struct Stream* data, void* obj) {
|
||||
static const String guiClassicPng = String_FromConst("gui_classic.png");
|
||||
struct Stream* s = obj;
|
||||
struct ResourceTexture* entry;
|
||||
|
||||
String name = *path;
|
||||
Utils_UNSAFE_GetFilename(&name);
|
||||
if (String_CaselessEqualsConst(&name, "gui.png")) name = guiClassicPng;
|
||||
|
||||
entry = Resources_FindTex(&name);
|
||||
return ZipPatcher_WriteStream(s, entry, data);
|
||||
}
|
||||
|
||||
static ReturnCode TexPatcher_ClassicFiles(struct Stream* s) {
|
||||
struct ZipState zip;
|
||||
struct Stream src;
|
||||
ReturnCode res;
|
||||
|
||||
Stream_ReadonlyMemory(&src, Resources_Files[0].Data, Resources_Files[0].Len);
|
||||
Zip_Init(&zip, &src);
|
||||
|
||||
zip.Obj = s;
|
||||
zip.SelectEntry = TexPatcher_ClassicSelect;
|
||||
zip.ProcessEntry = TexPatcher_ClassicProcess;
|
||||
return Zip_Extract(&zip);
|
||||
}
|
||||
|
||||
static bool TexPatcher_ModernSelect(const String* path) {
|
||||
return
|
||||
String_CaselessEqualsConst(path, "assets/minecraft/textures/environment/snow.png") ||
|
||||
String_CaselessEqualsConst(path, "assets/minecraft/textures/entity/chicken.png");
|
||||
}
|
||||
|
||||
static ReturnCode TexPatcher_ModernProcess(const String* path, struct Stream* data, void* obj) {
|
||||
struct Stream* s = obj;
|
||||
struct ResourceTexture* entry;
|
||||
|
||||
String name = *path;
|
||||
Utils_UNSAFE_GetFilename(&name);
|
||||
|
||||
entry = Resources_FindTex(&name);
|
||||
return ZipPatcher_WriteStream(s, entry, data);
|
||||
}
|
||||
|
||||
static ReturnCode TexPatcher_ModernFiles(struct Stream* s) {
|
||||
struct ZipState zip;
|
||||
struct Stream src;
|
||||
ReturnCode res;
|
||||
|
||||
Stream_ReadonlyMemory(&src, Resources_Files[1].Data, Resources_Files[1].Len);
|
||||
Zip_Init(&zip, &src);
|
||||
|
||||
zip.Obj = s;
|
||||
zip.SelectEntry = TexPatcher_ModernSelect;
|
||||
zip.ProcessEntry = TexPatcher_ModernProcess;
|
||||
return Zip_Extract(&zip);
|
||||
}
|
||||
|
||||
static ReturnCode TexPatcher_NewFiles(struct Stream* s) {
|
||||
static const String guiPng = String_FromConst("gui.png");
|
||||
static const String animsTxt = String_FromConst("animations.txt");
|
||||
struct ResourceTexture* entry;
|
||||
ReturnCode res;
|
||||
|
||||
/* make our own animations.txt */
|
||||
entry = Resources_FindTex(&animsTxt);
|
||||
res = ZipPatcher_WriteData(s, entry, ANIMS_TXT_CONTENTS, sizeof(ANIMS_TXT_CONTENTS) - 1);
|
||||
if (res) return res;
|
||||
|
||||
/* make ClassiCube gui.png */
|
||||
entry = Resources_FindTex(&guiPng);
|
||||
res = ZipPatcher_WriteData(s, entry, Resources_Files[3].Data, Resources_Files[3].Len);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ReturnCode TexPatcher_WriteEntries(struct Stream* s) {
|
||||
static const String guiPng = String_FromConst("gui.png");
|
||||
static const String animsTxt = String_FromConst("animations.txt");
|
||||
struct ResourceTexture* entry;
|
||||
|
||||
uint32_t beg, end;
|
||||
int i;
|
||||
ReturnCode res;
|
||||
|
||||
if ((res = TexPatcher_ClassicFiles(s))) return res;
|
||||
if ((res = TexPatcher_ModernFiles(s))) return res;
|
||||
if ((res = TexPatcher_NewFiles(s))) return res;
|
||||
|
||||
if ((res = s->Position(s, &beg))) return res;
|
||||
for (i = 0; i < Array_Elems(Resources_Textures); i++) {
|
||||
if ((res = ZipPatcher_CentralDir(s, &Resources_Textures[i]))) return res;
|
||||
}
|
||||
|
||||
if ((res = s->Position(s, &end))) return res;
|
||||
return ZipPatcher_EndOfCentralDir(s, beg, end);
|
||||
}
|
||||
|
||||
static void TexPatcher_MakeDefaultZip(void) {
|
||||
const static String path = String_FromConst("texpacks/default.zip");
|
||||
struct Stream s;
|
||||
int i;
|
||||
ReturnCode res;
|
||||
|
||||
res = Stream_CreateFile(&s, &path);
|
||||
if (res) {
|
||||
Launcher_ShowError(res, "creating default.zip");
|
||||
} else {
|
||||
res = TexPatcher_WriteEntries(&s);
|
||||
if (res) Launcher_ShowError(res, "making default.zip");
|
||||
|
||||
res = s.Close(&s);
|
||||
if (res) Launcher_ShowError(res, "closing default.zip");
|
||||
}
|
||||
|
||||
for (i = 0; i < Array_Elems(Resources_Files); i++) {
|
||||
Mem_Free(Resources_Files[i].Data);
|
||||
Resources_Files[i].Data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
@ -192,7 +432,7 @@ struct ResourceMusic Resources_Music[7] = {
|
||||
*#########################################################################################################################*/
|
||||
#define WAV_FourCC(a, b, c, d) (((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | (uint32_t)d)
|
||||
|
||||
static void Patcher_FixupWaveHeader(struct Stream* s, struct VorbisState* ctx) {
|
||||
static void SoundPatcher_FixupHeader(struct Stream* s, struct VorbisState* ctx) {
|
||||
uint8_t header[44];
|
||||
uint32_t length;
|
||||
ReturnCode res;
|
||||
@ -202,9 +442,9 @@ static void Patcher_FixupWaveHeader(struct Stream* s, struct VorbisState* ctx) {
|
||||
res = s->Seek(s, 0);
|
||||
if (res) { Launcher_ShowError(res, "seeking to .wav start"); return; }
|
||||
|
||||
Stream_SetU32_BE(&header[0], WAV_FourCC('R','I','F','F'));
|
||||
Stream_SetU32_LE(&header[4], length - 8);
|
||||
Stream_SetU32_BE(&header[8], WAV_FourCC('W','A','V','E'));
|
||||
Stream_SetU32_BE(&header[0], WAV_FourCC('R','I','F','F'));
|
||||
Stream_SetU32_LE(&header[4], length - 8);
|
||||
Stream_SetU32_BE(&header[8], WAV_FourCC('W','A','V','E'));
|
||||
Stream_SetU32_BE(&header[12], WAV_FourCC('f','m','t',' '));
|
||||
Stream_SetU32_LE(&header[16], 16); /* fmt chunk size */
|
||||
Stream_SetU16_LE(&header[20], 1); /* PCM audio format */
|
||||
@ -221,7 +461,7 @@ static void Patcher_FixupWaveHeader(struct Stream* s, struct VorbisState* ctx) {
|
||||
if (res) Launcher_ShowError(res, "fixing .wav header");
|
||||
}
|
||||
|
||||
static void Patcher_DecodeSound(struct Stream* s, struct VorbisState* ctx) {
|
||||
static void SoundPatcher_DecodeAudio(struct Stream* s, struct VorbisState* ctx) {
|
||||
int16_t* samples;
|
||||
int count;
|
||||
ReturnCode res;
|
||||
@ -247,7 +487,7 @@ static void Patcher_DecodeSound(struct Stream* s, struct VorbisState* ctx) {
|
||||
Mem_Free(samples);
|
||||
}
|
||||
|
||||
static void Patcher_SaveSound(struct ResourceSound* sound, struct AsyncRequest* req) {
|
||||
static void SoundPatcher_Save(struct ResourceSound* sound, struct AsyncRequest* req) {
|
||||
String path; char pathBuffer[STRING_SIZE];
|
||||
uint8_t buffer[OGG_BUFFER_SIZE];
|
||||
struct Stream src, ogg, dst;
|
||||
@ -264,14 +504,14 @@ static void Patcher_SaveSound(struct ResourceSound* sound, struct AsyncRequest*
|
||||
Ogg_MakeStream(&ogg, buffer, &src);
|
||||
ctx.Source = &ogg;
|
||||
|
||||
Patcher_DecodeSound(&dst, &ctx);
|
||||
Patcher_FixupWaveHeader(&dst, &ctx);
|
||||
SoundPatcher_DecodeAudio(&dst, &ctx);
|
||||
SoundPatcher_FixupHeader(&dst, &ctx);
|
||||
|
||||
res = dst.Close(&dst);
|
||||
if (res) Launcher_ShowError(res, "closing .wav file");
|
||||
}
|
||||
|
||||
static void Patcher_SaveMusic(struct ResourceMusic* music, struct AsyncRequest* req) {
|
||||
static void MusicPatcher_Save(struct ResourceMusic* music, struct AsyncRequest* req) {
|
||||
String path; char pathBuffer[STRING_SIZE];
|
||||
ReturnCode res;
|
||||
|
||||
@ -302,7 +542,7 @@ CC_NOINLINE static void Fetcher_DownloadAudio(const char* name, const char* hash
|
||||
|
||||
void Fetcher_Run(void) {
|
||||
String id, url;
|
||||
int i, flags;
|
||||
int i;
|
||||
|
||||
if (Fetcher_Working) return;
|
||||
Fetcher_Error = 0;
|
||||
@ -311,10 +551,9 @@ void Fetcher_Run(void) {
|
||||
|
||||
Fetcher_Working = true;
|
||||
Fetcher_Completed = false;
|
||||
flags = Resources_GetFetchFlags();
|
||||
|
||||
for (i = 0; i < Array_Elems(Resources_Files); i++) {
|
||||
if (!(flags & Resources_Files[i].Flag)) continue;
|
||||
if (Textures_AllExist) continue;
|
||||
|
||||
id = String_FromReadonly(Resources_Files[i].Name);
|
||||
url = String_FromReadonly(Resources_Files[i].Url);
|
||||
@ -322,11 +561,11 @@ void Fetcher_Run(void) {
|
||||
}
|
||||
|
||||
for (i = 0; i < Array_Elems(Resources_Music); i++) {
|
||||
if (Resources_Music[i].Exists) continue;
|
||||
if (Resources_Music[i].Downloaded) continue;
|
||||
Fetcher_DownloadAudio(Resources_Music[i].Name, Resources_Music[i].Hash);
|
||||
}
|
||||
for (i = 0; i < Array_Elems(Resources_Sounds); i++) {
|
||||
if (SoundsExist) continue;
|
||||
if (Sounds_AllExist) continue;
|
||||
Fetcher_DownloadAudio(Resources_Sounds[i].Name, Resources_Sounds[i].Hash);
|
||||
}
|
||||
}
|
||||
@ -357,13 +596,24 @@ CC_NOINLINE static bool Fetcher_Get(const String* id, struct AsyncRequest* req)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Fetcher_CheckFile(struct ResourceFile* file) {
|
||||
String id = String_FromReadonly(file->Name);
|
||||
struct AsyncRequest req;
|
||||
if (!Fetcher_Get(&id, &req)) return;
|
||||
|
||||
file->Downloaded = true;
|
||||
file->Data = req.Data;
|
||||
file->Len = req.Size;
|
||||
/* don't free request */
|
||||
}
|
||||
|
||||
static void Fetcher_CheckMusic(struct ResourceMusic* music) {
|
||||
String id = String_FromReadonly(music->Name);
|
||||
struct AsyncRequest req;
|
||||
if (!Fetcher_Get(&id, &req)) return;
|
||||
|
||||
music->Exists = true;
|
||||
Patcher_SaveMusic(music, &req);
|
||||
music->Downloaded = true;
|
||||
MusicPatcher_Save(music, &req);
|
||||
ASyncRequest_Free(&req);
|
||||
}
|
||||
|
||||
@ -372,16 +622,23 @@ static void Fetcher_CheckSound(struct ResourceSound* sound) {
|
||||
struct AsyncRequest req;
|
||||
if (!Fetcher_Get(&id, &req)) return;
|
||||
|
||||
Patcher_SaveSound(sound, &req);
|
||||
SoundPatcher_Save(sound, &req);
|
||||
ASyncRequest_Free(&req);
|
||||
}
|
||||
|
||||
/* TODO: Implement this.. */
|
||||
/* TODO: How expensive is it to constantly do 'Get' over and make all these strings */
|
||||
void Fetcher_Update(void) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < Array_Elems(Resources_Files); i++) {
|
||||
if (Resources_Files[i].Downloaded) continue;
|
||||
Fetcher_CheckFile(&Resources_Files[i]);
|
||||
}
|
||||
//if (Resources_Files[3].Data) TexPatcher_MakeDefaultZip();
|
||||
|
||||
for (i = 0; i < Array_Elems(Resources_Music); i++) {
|
||||
if (Resources_Music[i].Exists) continue;
|
||||
if (Resources_Music[i].Downloaded) continue;
|
||||
Fetcher_CheckMusic(&Resources_Music[i]);
|
||||
}
|
||||
|
||||
@ -391,4 +648,4 @@ void Fetcher_Update(void) {
|
||||
|
||||
if (Fetcher_Downloaded != Resources_Count) return;
|
||||
Fetcher_Finish();
|
||||
}
|
||||
}
|
||||
|
@ -14,15 +14,16 @@ extern struct ResourceFile {
|
||||
const char* Name;
|
||||
const char* Url;
|
||||
uint16_t Size;
|
||||
uint8_t Flag;
|
||||
bool Downloaded;
|
||||
/* downloaded archive */
|
||||
uint8_t* Data; uint32_t Len;
|
||||
} Resources_Files[4];
|
||||
|
||||
extern struct ResourceTexture {
|
||||
const char* Filename;
|
||||
uint8_t Flags;
|
||||
bool Exists;
|
||||
} Resources_Textures[19];
|
||||
/* zip data */
|
||||
uint32_t Size, Offset, Crc32;
|
||||
} Resources_Textures[20];
|
||||
|
||||
extern struct ResourceSound {
|
||||
const char* Name;
|
||||
@ -33,16 +34,17 @@ extern struct ResourceMusic {
|
||||
const char* Name;
|
||||
const char* Hash;
|
||||
uint16_t Size;
|
||||
bool Exists;
|
||||
bool Downloaded;
|
||||
} Resources_Music[7];
|
||||
|
||||
extern bool SoundsExist;
|
||||
/* Whether all textures exist. */
|
||||
extern bool Textures_AllExist;
|
||||
/* Whether all sounds exist. */
|
||||
extern bool Sounds_AllExist;
|
||||
/* Number of resources that need to be downloaded. */
|
||||
extern int Resources_Count;
|
||||
/* Total size of resources that need to be downloaded. */
|
||||
extern int Resources_Size;
|
||||
/* Returns flags of files that need to be fetched. */
|
||||
int Resources_GetFetchFlags(void);
|
||||
/* Checks existence of all assets. */
|
||||
void Resources_CheckExistence(void);
|
||||
|
||||
@ -57,8 +59,10 @@ extern int Fetcher_StatusCode;
|
||||
/* Error (if any) that occurs when downloaded resources. */
|
||||
extern ReturnCode Fetcher_Error;
|
||||
|
||||
/* Starts asynchronous download of required resources. */
|
||||
/* Starts asynchronous download of missing resources. */
|
||||
void Fetcher_Run(void);
|
||||
/* Checks if any resources have finished downloading. */
|
||||
/* If any have, performs required patching and saving. */
|
||||
void Fetcher_Update(void);
|
||||
|
||||
#endif
|
||||
|
27
src/Stream.c
27
src/Stream.c
@ -3,6 +3,7 @@
|
||||
#include "Funcs.h"
|
||||
#include "ErrorHandler.h"
|
||||
#include "Errors.h"
|
||||
#include "Utils.h"
|
||||
|
||||
/*########################################################################################################################*
|
||||
*---------------------------------------------------------Stream----------------------------------------------------------*
|
||||
@ -362,6 +363,32 @@ void Stream_ReadonlyBuffered(struct Stream* s, struct Stream* source, void* data
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-----------------------------------------------------CRC32Stream---------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static ReturnCode Stream_Crc32Write(struct Stream* stream, const uint8_t* data, uint32_t count, uint32_t* modified) {
|
||||
struct Stream* source;
|
||||
uint32_t i, crc32 = stream->Meta.CRC32.CRC32;
|
||||
|
||||
/* TODO: Optimise this calculation */
|
||||
for (i = 0; i < count; i++) {
|
||||
crc32 = Utils_Crc32Table[(crc32 ^ data[i]) & 0xFF] ^ (crc32 >> 8);
|
||||
}
|
||||
stream->Meta.CRC32.CRC32 = crc32;
|
||||
|
||||
source = stream->Meta.CRC32.Source;
|
||||
return source->Write(source, data, count, modified);
|
||||
}
|
||||
|
||||
void Stream_WriteonlyCrc32(struct Stream* s, struct Stream* source) {
|
||||
Stream_Init(s);
|
||||
s->Write = Stream_Crc32Write;
|
||||
|
||||
s->Meta.CRC32.Source = source;
|
||||
s->Meta.CRC32.CRC32 = 0xFFFFFFFFUL;
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------Read/Write primitives---------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
|
@ -67,6 +67,10 @@ CC_API void Stream_WriteonlyMemory(struct Stream* s, void* data, uint32_t len);
|
||||
/* Wraps another Stream, reading through an intermediary buffer. (Useful for files, since each read call is expensive) */
|
||||
CC_API void Stream_ReadonlyBuffered(struct Stream* s, struct Stream* source, void* data, uint32_t size);
|
||||
|
||||
/* Wraps another Stream, calculating a running CRC32 as data is written. */
|
||||
/* To get the final CRC32, xor it with 0xFFFFFFFFUL */
|
||||
void Stream_WriteonlyCrc32(struct Stream* s, struct Stream* source);
|
||||
|
||||
/* Reads a little-endian 16 bit unsigned integer from memory. */
|
||||
uint16_t Stream_GetU16_LE(const uint8_t* data);
|
||||
/* Reads a big-endian 16 bit unsigned integer from memory. */
|
||||
|
@ -621,9 +621,11 @@ void TextureCache_SetLastModified(const String* url, const TimeMS* lastModified)
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------TexturePack-------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static void TexturePack_ProcessZipEntry(const String* path, struct Stream* stream, struct ZipEntry* entry) {
|
||||
String name = *path; Utils_UNSAFE_GetFilename(&name);
|
||||
static ReturnCode TexturePack_ProcessZipEntry(const String* path, struct Stream* stream, void* obj) {
|
||||
String name = *path;
|
||||
Utils_UNSAFE_GetFilename(&name);
|
||||
Event_RaiseEntry(&TextureEvents_FileChanged, stream, &name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ReturnCode TexturePack_ExtractZip(struct Stream* stream) {
|
||||
|
@ -2115,6 +2115,8 @@ static void Window_ConnectEvents(void) {
|
||||
|
||||
target = GetApplicationEventTarget();
|
||||
/* TODO: Use EventTargetRef target = GetWindowEventTarget(windowRef); instead?? */
|
||||
/* need WindowEventTargetRef, otherwise message boxes don't work */
|
||||
/* but if use WindowEventTargetRef, can't click quit/move buttons anymore */
|
||||
res = InstallEventHandler(target, NewEventHandlerUPP(Window_EventHandler),
|
||||
Array_Elems(eventTypes), eventTypes, NULL, NULL);
|
||||
if (res) ErrorHandler_Fail2(res, "Connecting events");
|
||||
|
Loading…
x
Reference in New Issue
Block a user