-WIP moved code to load channels into external game booter

This commit is contained in:
fix94.1 2012-09-07 20:10:04 +00:00
parent f1767d5082
commit e229aca6a5
15 changed files with 490 additions and 139 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 77 KiB

View File

@ -82,7 +82,7 @@ s32 Apploader_Run(entry_point *entry, u8 vidMode, GXRModeObj *vmode, bool vipatc
free_wip(); free_wip();
if(hooktype != 0 && hookpatched) if(hooktype != 0 && hookpatched)
ocarina_do_code(); ocarina_do_code(0);
/* Set entry point from apploader */ /* Set entry point from apploader */
*entry = appldr_final(); *entry = appldr_final();

View File

@ -0,0 +1,48 @@
#include <ogcsys.h>
#include <locale.h>
#include <malloc.h>
#include <ogc/isfs.h>
#include <string.h>
#include "fs.h"
#include "utils.h"
static fstats stats ATTRIBUTE_ALIGN(32);
u8 *ISFS_GetFile(u8 *path, u32 *size, s32 length)
{
*size = 0;
s32 fd = ISFS_Open((const char *)path, ISFS_OPEN_READ);
u8 *buf = NULL;
if(fd >= 0)
{
memset(&stats, 0, sizeof(fstats));
if(ISFS_GetFileStats(fd, &stats) >= 0)
{
if(length <= 0)
length = stats.file_length;
if(length > 0)
buf = (u8 *)memalign(32, ALIGN32(length));
if(buf)
{
*size = stats.file_length;
if(ISFS_Read(fd, (char*)buf, length) != length)
{
*size = 0;
free(buf);
}
}
}
ISFS_Close(fd);
}
if(*size > 0)
{
DCFlushRange(buf, *size);
ICInvalidateRange(buf, *size);
}
return buf;
}

View File

@ -0,0 +1,15 @@
#ifndef _FS_H_
#define _FS_H_
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
u8 *ISFS_GetFile(u8 *path, u32 *size, s32 length);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@ -32,7 +32,7 @@ extern u8 debuggerselect;
void app_gameconfig_set(u32 *gameconfig, u32 tempgameconfsize); void app_gameconfig_set(u32 *gameconfig, u32 tempgameconfsize);
void ocarina_set_codes(void *list, u8 *listend, u8 *cheats, u32 cheatSize); void ocarina_set_codes(void *list, u8 *listend, u8 *cheats, u32 cheatSize);
int ocarina_do_code(); int ocarina_do_code(u64 chantitle);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -0,0 +1,215 @@
/*******************************************************************************
* lz77.c
*
* Copyright (c) 2009 The Lemon Man
* Copyright (c) 2009 Nicksasa
* Copyright (c) 2009 WiiPower
*
* Distributed under the terms of the GNU General Public License (v2)
* See http://www.gnu.org/licenses/gpl-2.0.txt for more info.
*
* Description:
* -----------
*
******************************************************************************/
#include <gccore.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
#include "lz77.h"
#include "utils.h"
u32 packBytes(int a, int b, int c, int d)
{
return (d << 24) | (c << 16) | (b << 8) | (a);
}
s32 __decompressLZ77_11(u8 *in, u32 inputLen, u8 **output, u32 *outputLen)
{
int x, y;
u8 *out = NULL;
u32 compressedPos = 0x4;
u32 decompressedPos = 0x0;
u32 decompressedSize = 0;
decompressedSize = packBytes(in[0], in[1], in[2], in[3]) >> 8;
if (!decompressedSize)
{
decompressedSize = packBytes(in[4], in[5], in[6], in[7]);
compressedPos += 0x4;
}
//printf("Decompressed size : %i\n", decompressedSize);
out = malloc(ALIGN32(decompressedSize));
if (out == NULL)
{
printf("Out of memory\n");
return -1;
}
while (compressedPos < inputLen && decompressedPos < decompressedSize)
{
u8 byteFlag = in[compressedPos];
compressedPos++;
for (x = 7; x >= 0; x--)
{
if ((byteFlag & (1 << x)) > 0)
{
u8 first = in[compressedPos];
u8 second = in[compressedPos + 1];
u32 pos, copyLen;
if (first < 0x20)
{
u8 third = in[compressedPos + 2];
if (first >= 0x10)
{
u32 fourth = in[compressedPos + 3];
pos = (u32)(((third & 0xF) << 8) | fourth) + 1;
copyLen = (u32)((second << 4) | ((first & 0xF) << 12) | (third >> 4)) + 273;
compressedPos += 4;
} else
{
pos = (u32)(((second & 0xF) << 8) | third) + 1;
copyLen = (u32)(((first & 0xF) << 4) | (second >> 4)) + 17;
compressedPos += 3;
}
} else
{
pos = (u32)(((first & 0xF) << 8) | second) + 1;
copyLen = (u32)(first >> 4) + 1;
compressedPos += 2;
}
for (y = 0; y < (int)copyLen; y++)
{
out[decompressedPos + y] = out[decompressedPos - pos + y];
}
decompressedPos += copyLen;
} else
{
out[decompressedPos] = in[compressedPos];
decompressedPos++;
compressedPos++;
}
if (compressedPos >= inputLen || decompressedPos >= decompressedSize)
break;
}
}
*output = out;
*outputLen = decompressedSize;
return 0;
}
s32 __decompressLZ77_10(u8 *in, u8 **output, u32 *outputLen)
{
int x, y;
u8 *out = NULL;
u32 compressedPos = 0;
u32 decompressedSize = 0x4;
u32 decompressedPos = 0;
decompressedSize = packBytes(in[0], in[1], in[2], in[3]) >> 8;
//int compressionType = (packBytes(in[0], in[1], in[2], in[3]) >> 4) & 0xF;
//printf("Decompressed size : %i\n", decompressedSize);
out = malloc(ALIGN32(decompressedSize));
if (out == NULL)
{
printf("Out of memory\n");
return -1;
}
compressedPos += 0x4;
while (decompressedPos < decompressedSize)
{
u8 flag = *(u8*)(in + compressedPos);
compressedPos += 1;
for (x = 0; x < 8; x++)
{
if (flag & 0x80)
{
u8 first = in[compressedPos];
u8 second = in[compressedPos + 1];
u16 pos = (u16)((((first << 8) + second) & 0xFFF) + 1);
u8 copyLen = (u8)(3 + ((first >> 4) & 0xF));
for (y = 0; y < copyLen; y++)
{
out[decompressedPos + y] = out[decompressedPos - pos + (y % pos)];
}
compressedPos += 2;
decompressedPos += copyLen;
} else
{
out[decompressedPos] = in[compressedPos];
compressedPos += 1;
decompressedPos += 1;
}
flag <<= 1;
if (decompressedPos >= decompressedSize)
break;
}
}
*output = out;
*outputLen = decompressedSize;
return 0;
}
int isLZ77compressed(u8 *buffer)
{
if ((buffer[0] == LZ77_0x10_FLAG) || (buffer[0] == LZ77_0x11_FLAG))
{
return 1;
}
return 0;
}
int decompressLZ77content(u8 *buffer, u32 length, u8 **output, u32 *outputLen)
{
int ret;
switch (buffer[0])
{
case LZ77_0x10_FLAG:
//printf("LZ77 variant 0x10 compressed content...unpacking may take a while...\n");
ret = __decompressLZ77_10(buffer, output, outputLen);
break;
case LZ77_0x11_FLAG:
//printf("LZ77 variant 0x11 compressed content...unpacking may take a while...\n");
ret = __decompressLZ77_11(buffer, length, output, outputLen);
break;
default:
//printf("Not compressed ...\n");
ret = -1;
break;
}
return ret;
}

View File

@ -0,0 +1,34 @@
/*******************************************************************************
* lz77.h
*
* Copyright (c) 2009 The Lemon Man
* Copyright (c) 2009 Nicksasa
* Copyright (c) 2009 WiiPower
*
* Distributed under the terms of the GNU General Public License (v2)
* See http://www.gnu.org/licenses/gpl-2.0.txt for more info.
*
* Description:
* -----------
*
******************************************************************************/
#ifndef _LZ77_MODULE
#define _LZ77_MODULE
#define LZ77_0x10_FLAG 0x10
#define LZ77_0x11_FLAG 0x11
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int isLZ77compressed(u8 *buffer);
int decompressLZ77content(u8 *buffer, u32 length, u8 **output, u32 *outputLen);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@ -26,7 +26,10 @@
#include "patchcode.h" #include "patchcode.h"
#include "cios.h" #include "cios.h"
#include "disc.h" #include "disc.h"
#include "fs.h"
#include "fst.h" #include "fst.h"
#include "lz77.h"
#include "utils.h"
#include "videopatch.h" #include "videopatch.h"
using namespace std; using namespace std;
@ -51,10 +54,7 @@ typedef struct _the_CFG {
u32 gameconfsize; u32 gameconfsize;
u8 BootType; u8 BootType;
/* needed for channels */ /* needed for channels */
void *dolchunkoffset[18]; u64 title;
u32 dolchunksize[18];
u32 dolchunkcount;
u32 startPoint;
} the_CFG; } the_CFG;
static the_CFG *conf = (the_CFG*)0x90000000; static the_CFG *conf = (the_CFG*)0x90000000;
@ -68,21 +68,146 @@ u32 AppEntrypoint;
extern "C" { extern void __exception_closeall(); } extern "C" { extern void __exception_closeall(); }
typedef struct _dolheader
{
u32 section_pos[18];
u32 section_start[18];
u32 section_size[18];
u32 bss_start;
u32 bss_size;
u32 entry_point;
u32 padding[7];
} __attribute__((packed)) dolheader;
void *dolchunkoffset[18];
u32 dolchunksize[18];
u32 dolchunkcount;
void PatchChannel(u8 vidMode, GXRModeObj *vmode, bool vipatch, bool countryString, u8 patchVidModes, int aspectRatio) void PatchChannel(u8 vidMode, GXRModeObj *vmode, bool vipatch, bool countryString, u8 patchVidModes, int aspectRatio)
{ {
for(u32 i = 0; i < conf->dolchunkcount; i++) for(u32 i = 0; i < dolchunkcount; i++)
{ {
patchVideoModes(conf->dolchunkoffset[i], conf->dolchunksize[i], vidMode, vmode, patchVidModes); patchVideoModes(dolchunkoffset[i], dolchunksize[i], vidMode, vmode, patchVidModes);
if(vipatch) vidolpatcher(conf->dolchunkoffset[i], conf->dolchunksize[i]); if(vipatch) vidolpatcher(dolchunkoffset[i], dolchunksize[i]);
if(configbytes[0] != 0xCD) langpatcher(conf->dolchunkoffset[i], conf->dolchunksize[i]); if(configbytes[0] != 0xCD) langpatcher(dolchunkoffset[i], dolchunksize[i]);
if(countryString) PatchCountryStrings(conf->dolchunkoffset[i], conf->dolchunksize[i]); if(countryString) PatchCountryStrings(dolchunkoffset[i], dolchunksize[i]);
if(aspectRatio != -1) PatchAspectRatio(conf->dolchunkoffset[i], conf->dolchunksize[i], aspectRatio); if(aspectRatio != -1) PatchAspectRatio(dolchunkoffset[i], dolchunksize[i], aspectRatio);
if(hooktype != 0) if(hooktype != 0)
dogamehooks(conf->dolchunkoffset[i], conf->dolchunksize[i], true); dogamehooks(dolchunkoffset[i], dolchunksize[i], true);
} }
} }
static u8 *GetDol(u32 bootcontent)
{
char filepath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32);
sprintf(filepath, "/title/%08x/%08x/content/%08x.app", TITLE_UPPER(conf->title), TITLE_LOWER(conf->title), bootcontent);
u32 contentSize = 0;
u8 *data = ISFS_GetFile((u8 *) &filepath, &contentSize, -1);
if(data != NULL && contentSize != 0)
{
if(isLZ77compressed(data))
{
u8 *decompressed;
u32 size = 0;
if(decompressLZ77content(data, contentSize, &decompressed, &size) < 0)
{
free(data);
return NULL;
}
free(data);
data = decompressed;
}
return data;
}
return NULL;
}
static bool GetAppNameFromTmd(char *app, bool dol, u32 *bootcontent)
{
bool ret = false;
char tmd[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32);
sprintf(tmd, "/title/%08x/%08x/content/title.tmd", TITLE_UPPER(conf->title), TITLE_LOWER(conf->title));
u32 size;
u8 *data = ISFS_GetFile((u8 *) &tmd, &size, -1);
if (data == NULL || size < 0x208)
return ret;
_tmd *tmd_file = (_tmd *)SIGNATURE_PAYLOAD((u32 *)data);
u16 i;
for(i = 0; i < tmd_file->num_contents; ++i)
{
if(tmd_file->contents[i].index == (dol ? tmd_file->boot_index : 0))
{
*bootcontent = tmd_file->contents[i].cid;
sprintf(app, "/title/%08x/%08x/content/%08x.app", TITLE_UPPER(conf->title), TITLE_LOWER(conf->title), *bootcontent);
ret = true;
break;
}
}
free(data);
return ret;
}
static u32 MoveDol(u8 *buffer)
{
dolchunkcount = 0;
dolheader *dolfile = (dolheader *)buffer;
if(dolfile->bss_start)
{
if(!(dolfile->bss_start & 0x80000000))
dolfile->bss_start |= 0x80000000;
memset((void *)dolfile->bss_start, 0, dolfile->bss_size);
DCFlushRange((void *)dolfile->bss_start, dolfile->bss_size);
ICInvalidateRange((void *)dolfile->bss_start, dolfile->bss_size);
}
int i;
for(i = 0; i < 18; i++)
{
if(!dolfile->section_size[i])
continue;
if(dolfile->section_pos[i] < sizeof(dolheader))
continue;
if(!(dolfile->section_start[i] & 0x80000000))
dolfile->section_start[i] |= 0x80000000;
dolchunkoffset[dolchunkcount] = (void *)dolfile->section_start[i];
dolchunksize[dolchunkcount] = dolfile->section_size[i];
//gprintf("Moving section %u from offset %08x to %08x-%08x...\n", i, dolfile->section_pos[i], dolchunkoffset[dolchunkcount], (u32)dolchunkoffset[dolchunkcount]+dolchunksize[dolchunkcount]);
memmove(dolchunkoffset[dolchunkcount], buffer + dolfile->section_pos[i], dolchunksize[dolchunkcount]);
DCFlushRange(dolchunkoffset[dolchunkcount], dolchunksize[dolchunkcount]);
ICInvalidateRange(dolchunkoffset[dolchunkcount], dolchunksize[dolchunkcount]);
dolchunkcount++;
}
return dolfile->entry_point;
}
u32 LoadChannel()
{
char app[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32);
u32 bootcontent;
u32 entry = 0;
if(!GetAppNameFromTmd(app, true, &bootcontent))
return entry;
u8 *data = GetDol(bootcontent);
entry = MoveDol(data);
free(data);
return entry;
}
int main() int main()
{ {
VIDEO_Init(); VIDEO_Init();
@ -118,12 +243,13 @@ int main()
} }
else if(conf->BootType == TYPE_CHANNEL) else if(conf->BootType == TYPE_CHANNEL)
{ {
if(hooktype != 0) ISFS_Initialize();
ocarina_do_code(); AppEntrypoint = LoadChannel();
PatchChannel(conf->vidMode, vmode, conf->vipatch, conf->countryString, PatchChannel(conf->vidMode, vmode, conf->vipatch, conf->countryString,
conf->patchVidMode, conf->aspectRatio); conf->patchVidMode, conf->aspectRatio);
AppEntrypoint = conf->startPoint; if(hooktype != 0)
ocarina_do_code(conf->title);
ISFS_Deinitialize();
} }
/* Set time */ /* Set time */

View File

@ -0,0 +1,26 @@
#ifndef _UTILS_H_
#define _UTILS_H_
#include <gctypes.h>
#define KB_SIZE 1024.0
#define MB_SIZE 1048576.0
#define GB_SIZE 1073741824.0
#define MAX_FAT_PATH 1024
#define round_up(x,n) (-(-(x) & -(n)))
#define ALIGN(n, x) (((x) + (n - 1)) & ~(n - 1))
#define ALIGN32(x) (((x) + 31) & ~31)
#define TITLE_ID(x,y) (((u64)(x) << 32) | (y))
#define TITLE_UPPER(x) ((u32)((x) >> 32))
#define TITLE_LOWER(x) ((u32)(x) & 0xFFFFFFFF)
#define Write8(addr, val) *(u8 *)addr = val; DCFlushRange((void *)addr, sizeof(u8));
#define Write16(addr, val) *(u16 *)addr = val; DCFlushRange((void *)addr, sizeof(u16));
#define Write32(addr, val) *(u32 *)addr = val; DCFlushRange((void *)addr, sizeof(u32));
#endif

View File

@ -15,24 +15,7 @@
#include "unzip/lz77.h" #include "unzip/lz77.h"
#include "types.h" #include "types.h"
typedef void (*entrypoint) (void); s32 BootChannel(u64 chantitle, u32 ios, u8 vidMode, bool vipatch, bool countryString, u8 patchVidMode, int aspectRatio)
typedef struct _dolheader
{
u32 section_pos[18];
u32 section_start[18];
u32 section_size[18];
u32 bss_start;
u32 bss_size;
u32 entry_point;
u32 padding[7];
} __attribute__((packed)) dolheader;
void *dolchunkoffset[18];
u32 dolchunksize[18];
u32 dolchunkcount;
s32 BootChannel(u32 entry, u64 chantitle, u32 ios, u8 vidMode, bool vipatch, bool countryString, u8 patchVidMode, int aspectRatio)
{ {
// IOS Version Check // IOS Version Check
*Real_IOSVersion = ((ios << 16)) | 0xFFFF; *Real_IOSVersion = ((ios << 16)) | 0xFFFF;
@ -45,49 +28,10 @@ s32 BootChannel(u32 entry, u64 chantitle, u32 ios, u8 vidMode, bool vipatch, boo
*Disc_ID = TITLE_LOWER(chantitle); *Disc_ID = TITLE_LOWER(chantitle);
DCFlushRange((void*)Disc_ID, 4); DCFlushRange((void*)Disc_ID, 4);
ExternalBooter_ChannelSetup(dolchunkoffset, dolchunksize, dolchunkcount, entry);
WiiFlow_ExternalBooter(vidMode, vipatch, countryString, patchVidMode, aspectRatio, 0, TYPE_CHANNEL); WiiFlow_ExternalBooter(vidMode, vipatch, countryString, patchVidMode, aspectRatio, 0, TYPE_CHANNEL);
return 0; return 0;
} }
u32 LoadChannel(u8 *buffer)
{
dolchunkcount = 0;
dolheader *dolfile = (dolheader *)buffer;
if(dolfile->bss_start)
{
if(!(dolfile->bss_start & 0x80000000))
dolfile->bss_start |= 0x80000000;
memset((void *)dolfile->bss_start, 0, dolfile->bss_size);
DCFlushRange((void *)dolfile->bss_start, dolfile->bss_size);
ICInvalidateRange((void *)dolfile->bss_start, dolfile->bss_size);
}
int i;
for(i = 0; i < 18; i++)
{
if(!dolfile->section_size[i])
continue;
if(dolfile->section_pos[i] < sizeof(dolheader))
continue;
if(!(dolfile->section_start[i] & 0x80000000))
dolfile->section_start[i] |= 0x80000000;
dolchunkoffset[dolchunkcount] = (void *)dolfile->section_start[i];
dolchunksize[dolchunkcount] = dolfile->section_size[i];
gprintf("Moving section %u from offset %08x to %08x-%08x...\n", i, dolfile->section_pos[i], dolchunkoffset[dolchunkcount], (u32)dolchunkoffset[dolchunkcount]+dolchunksize[dolchunkcount]);
memmove(dolchunkoffset[dolchunkcount], buffer + dolfile->section_pos[i], dolchunksize[dolchunkcount]);
DCFlushRange(dolchunkoffset[dolchunkcount], dolchunksize[dolchunkcount]);
ICInvalidateRange(dolchunkoffset[dolchunkcount], dolchunksize[dolchunkcount]);
dolchunkcount++;
}
return dolfile->entry_point;
}
bool Identify_GenerateTik(signed_blob **outbuf, u32 *outlen) bool Identify_GenerateTik(signed_blob **outbuf, u32 *outlen)
{ {
signed_blob *buffer = (signed_blob *)memalign(32, ALIGN32(STD_SIGNED_TIK_SIZE)); signed_blob *buffer = (signed_blob *)memalign(32, ALIGN32(STD_SIGNED_TIK_SIZE));
@ -177,34 +121,3 @@ bool Identify(u64 titleid)
return ret < 0 ? false : true; return ret < 0 ? false : true;
} }
u8 *GetDol(u64 title, u32 bootcontent)
{
char filepath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32);
sprintf(filepath, "/title/%08x/%08x/content/%08x.app", TITLE_UPPER(title), TITLE_LOWER(title), bootcontent);
gprintf("Loading DOL: %s...", filepath);
u32 contentSize = 0;
u8 *data = ISFS_GetFile((u8 *) &filepath, &contentSize, -1);
if (data != NULL && contentSize != 0)
{
gprintf("Done!\n");
if (isLZ77compressed(data))
{
u8 *decompressed;
u32 size = 0;
if (decompressLZ77content(data, contentSize, &decompressed, &size) < 0)
{
gprintf("Decompression failed\n");
free(data);
return NULL;
}
free(data);
data = decompressed;
}
return data;
}
gprintf("Failed!\n");
return NULL;
}

View File

@ -4,7 +4,7 @@
#include <gctypes.h> #include <gctypes.h>
#include <gccore.h> #include <gccore.h>
s32 BootChannel(u32 entry, u64 chantitle, u32 ios, u8 vidMode, bool vipatch, bool countryString, u8 patchVidMode, int aspectRatio); s32 BootChannel(u64 chantitle, u32 ios, u8 vidMode, bool vipatch, bool countryString, u8 patchVidMode, int aspectRatio);
u32 LoadChannel(u8 *buffer); u32 LoadChannel(u8 *buffer);
void PatchChannel(u8 vidMode, GXRModeObj *vmode, bool vipatch, bool countryString, u8 patchVidModes, int aspectRatio); void PatchChannel(u8 vidMode, GXRModeObj *vmode, bool vipatch, bool countryString, u8 patchVidModes, int aspectRatio);

View File

@ -67,24 +67,6 @@ Channels::~Channels()
{ {
} }
u32 Channels::Load(u64 title)
{
char app[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32);
u32 bootcontent;
u32 entry = 0;
if(!GetAppNameFromTmd(title, app, true, &bootcontent))
return entry;
u8 *data = GetDol(title, bootcontent);
Identify(title);
entry = LoadChannel(data);
free(data);
return entry;
}
u8 Channels::GetRequestedIOS(u64 title) u8 Channels::GetRequestedIOS(u64 title)
{ {
u8 IOS = 0; u8 IOS = 0;

View File

@ -54,10 +54,7 @@ typedef struct _the_CFG {
u32 gameconfsize; u32 gameconfsize;
u8 BootType; u8 BootType;
/* needed for channels */ /* needed for channels */
void *dolchunkoffset[18]; u64 title;
u32 dolchunksize[18];
u32 dolchunkcount;
u32 startPoint;
} the_CFG; } the_CFG;
the_CFG normalCFG; the_CFG normalCFG;
@ -98,15 +95,9 @@ void WiiFlow_ExternalBooter(u8 vidMode, bool vipatch, bool countryString, u8 pat
BootHomebrew(); BootHomebrew();
} }
void ExternalBooter_ChannelSetup(void *dolchunkoffset[18], u32 dolchunksize[18], u32 dolchunkcount, u32 StartPoint) void ExternalBooter_ChannelSetup(u64 title)
{ {
for(u8 i = 0; i < 18; i++) normalCFG.title = title;
{
normalCFG.dolchunkoffset[i] = dolchunkoffset[i];
normalCFG.dolchunksize[i] = dolchunksize[i];
}
normalCFG.dolchunkcount = dolchunkcount;
normalCFG.startPoint = StartPoint;
} }
void ShutdownBeforeExit(bool KeepPatches) void ShutdownBeforeExit(bool KeepPatches)

View File

@ -30,7 +30,7 @@ extern u32 hooktype;
void WiiFlow_ExternalBooter(u8 vidMode, bool vipatch, bool countryString, u8 patchVidMode, void WiiFlow_ExternalBooter(u8 vidMode, bool vipatch, bool countryString, u8 patchVidMode,
int aspectRatio, u32 returnTo, u8 BootType); int aspectRatio, u32 returnTo, u8 BootType);
void ExternalBooter_ChannelSetup(void *dolchunkoffset[18], u32 dolchunksize[18], u32 dolchunkcount, u32 StartPoint); void ExternalBooter_ChannelSetup(u64 title);
void ShutdownBeforeExit(bool KeepPatches = false); void ShutdownBeforeExit(bool KeepPatches = false);
#endif #endif

View File

@ -1134,14 +1134,15 @@ void CMenu::_launchChannel(dir_discHdr *hdr)
} }
else else
{ {
entry = channel.Load(gameTitle);
setLanguage(language); setLanguage(language);
SmartBuf cheatFile; SmartBuf cheatFile;
u32 cheatSize = 0; u32 cheatSize = 0;
if(cheat) if(cheat)
_loadFile(cheatFile, cheatSize, m_cheatDir.c_str(), fmt("%s.gct", id.c_str())); _loadFile(cheatFile, cheatSize, m_cheatDir.c_str(), fmt("%s.gct", id.c_str()));
ocarina_load_code(cheatFile.get(), cheatSize); ocarina_load_code(cheatFile.get(), cheatSize);
BootChannel(entry, gameTitle, gameIOS, videoMode, vipatch, countryPatch, patchVidMode, aspectRatio); Identify(gameTitle);
ExternalBooter_ChannelSetup(gameTitle);
BootChannel(gameTitle, gameIOS, videoMode, vipatch, countryPatch, patchVidMode, aspectRatio);
} }
} }