Maps folder: Halo PC maps there are explained, not a blue screen

A maps folder holding Halo PC's maps (one pointed at a Halo PC install's,
say) had its ui.map, a Custom Edition or retail Halo PC cache file, loaded
as the Xbox's: game_load() failed, and the player got a blue screen.
Before the window opens the desktop builds now read ui.map's header: when
it is Halo PC's, or there is no ui.map, the game says where the Xbox maps
go (the data root's maps folder, named in full) and that Custom Edition
maps go in custom_maps beside it, and quits. Halo PC maps in maps/ itself,
which play only from custom_maps, are named in a warning. Runs with no
window log it instead. The README's game data section says so.

(cherry picked from commit 223c4aaf16b2819c57cd31d470d5dd04c9daa4f7, made again for
OpenCE's custom_maps folder in place of that fork's maps/ce and md_maps,
and not on the web build)
This commit is contained in:
Milenko authored and MrBruh committed 2026-10-19 22:57:53 +13:00
1 parent 76984235b7
commit e075fffa28
4 files changed
+199 -1

No files matched your search

+4
View File
@@ -58,6 +58,10 @@ so players of the two versions can play together.
says to put the disc image next to the executable, and stops.
3. The game extracts the `maps/` folder. Then the game starts.
The `maps/` folder holds the Xbox maps only. If it holds Halo PC's maps
instead (a Halo PC or Custom Edition install's `maps` folder), the game says
so and stops: Custom Edition maps go in `custom_maps/`, beside `maps/`.
On Linux and Windows, the game puts `maps/` next to the executable. On
Android, copy the disc image to the phone first. The app puts `maps/` in its
data folder. Refer to [port/android/README.md](port/android/README.md). On
+24
View File
@@ -105,6 +105,30 @@ const char *platform_custom_edition_root(void);
out of an Xbox disc image into destination (sdl_platform.c), and quits if
the player declines; nonzero once destination has one */
BOOL platform_offer_game_data(const char *destination);
/* what the data root's maps folder holds, which should be the Xbox maps
(sdl_platform.c tells the player when it is not, rather than the game
failing on Halo PC's ui.map) */
enum
{
_maps_folder_xbox,
/* its ui.map is Halo PC's (retail's, version 7, or Custom Edition's, 609) */
_maps_folder_halo_pc,
/* it has no ui.map (or one that is not a map) */
_maps_folder_no_ui,
};
#define PLATFORM_MAPS_FOLDER_NAMED 4
struct platform_maps_folder
{
int state;
/* the data root, whole */
char root[1024];
long ui_version;
/* Halo PC maps in maps/ itself, which play only from custom_maps: how
many, and the first PLATFORM_MAPS_FOLDER_NAMED's names */
long stray_pc_maps;
char stray_names[256];
};
void platform_maps_folder_check(struct platform_maps_folder *maps);
/* asks the player, in a box of its own that waits for the answer (before
the window opens, or between frames), with `count` buttons (3 at most: Android's),
`default_index` Enter's and Escape's: the index of the one chosen, or -1
+59 -1
View File
@@ -112,6 +112,61 @@ extern const unsigned long platform_window_icon_size;
#endif
#endif
#if !defined(HALO_ANDROID) && !defined(HALO_WEB)
/* the maps folder checked to hold the Xbox maps (platform_maps_folder_check).
When it holds Halo PC's instead, or no ui.map, the player is told where each
kind goes and the game quits, rather than failing to load Halo PC's ui.map
as the Xbox's (game_load). Halo PC maps in maps/ itself, which play only from
custom_maps, are warned of */
static void data_check_maps(void)
{
struct platform_maps_folder maps;
char message[2048];
char where[1200];
BOOL quiet = config_boolean("debug.hidden_window") || config_real("debug.exit_after") > 0.0 ||
config_string("debug.network_test")[0];
platform_maps_folder_check(&maps);
snprintf(where, sizeof(where),
"Put the Xbox maps from your Halo: Combat Evolved disc image in %s/maps. Halo Custom Edition "
"maps go in a custom_maps folder beside it.",
maps.root);
switch (maps.state)
{
case _maps_folder_xbox:
if (!maps.stray_pc_maps)
return;
snprintf(message, sizeof(message),
"These maps in the maps folder are Halo PC maps, which play only from custom_maps: %s%s.\n\n%s",
maps.stray_names, maps.stray_pc_maps > PLATFORM_MAPS_FOLDER_NAMED ? " and more" : "", where);
platform_log("maps folder: %ld Halo PC maps in %s/maps (%s)", maps.stray_pc_maps, maps.root,
maps.stray_names);
if (!quiet)
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "Halo", message, NULL);
return;
case _maps_folder_halo_pc:
snprintf(message, sizeof(message),
"The maps folder holds Halo PC maps, not the Xbox maps: its ui.map is from %s.\n\n%s\n\n"
"To copy the Xbox maps out of your disc image again, move this maps folder aside and "
"start the game.",
maps.ui_version == 609 ? "Halo PC (Custom Edition)" : "Halo PC", where);
break;
default:
snprintf(message, sizeof(message),
"Halo's Xbox maps were not found: %s/maps has no ui.map.\n\n%s\n\n"
"To copy the Xbox maps out of your disc image, move the maps folder aside and start the game.",
maps.root, where);
break;
}
platform_log("maps folder: %s/maps is not the Xbox maps (ui.map version %ld): quitting", maps.root,
maps.ui_version);
platform_log("%s", message);
if (!quiet)
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Halo", message, NULL);
exit(EXIT_FAILURE);
}
#endif
BOOL platform_sdl_initialize(void)
{
if (platform_sdl_started)
@@ -159,8 +214,11 @@ BOOL platform_sdl_initialize(void)
platform_sdl_started = TRUE;
#ifndef HALO_ANDROID
/* found (or offered to the player, platform_offer_game_data) before the
game's window opens */
game's window opens, and checked to be the Xbox maps */
platform_data_root();
#ifndef HALO_WEB
data_check_maps();
#endif
/* (a new version looked for meanwhile, updater_poll asking about it) */
updater_start();
#endif
+112
View File
@@ -268,6 +268,118 @@ void platform_translate_path(const char *xbox_path, char *host_path, unsigned lo
snprintf(host_path, host_path_size, "%s", resolved);
}
/* ---------- the maps folder's maps */
enum
{
/* a cache file's header: 'head' and its version */
MAP_HEADER_SIGNATURE = 0x68656164,
/* (Halo PC's: retail's, and Custom Edition's) */
HALO_PC_MAP_VERSION = 7,
CUSTOM_EDITION_MAP_VERSION = 609,
};
/* a map file's cache version, by its header; 0 if it is not a cache file */
static long map_file_version(const char *path)
{
unsigned char header[8];
FILE *file = fopen(path, "rb");
long version = 0;
if (!file)
return 0;
if (fread(header, 1, sizeof(header), file) == sizeof(header) &&
(header[0] | header[1] << 8 | header[2] << 16 | (unsigned long)header[3] << 24) == MAP_HEADER_SIGNATURE)
{
version = (long)(header[4] | header[5] << 8 | header[6] << 16 | (unsigned long)header[7] << 24);
}
fclose(file);
return version;
}
static BOOL map_version_is_pc(long version)
{
return version == HALO_PC_MAP_VERSION || version == CUSTOM_EDITION_MAP_VERSION;
}
static BOOL name_ends_with(const char *name, const char *ending)
{
size_t length = strlen(name);
size_t ending_length = strlen(ending);
size_t index;
if (length < ending_length)
return FALSE;
for (index = 0; index < ending_length; index++)
{
if (tolower((unsigned char)name[length - ending_length + index]) != tolower((unsigned char)ending[index]))
return FALSE;
}
return TRUE;
}
/* the Halo PC maps in the maps folder, which play only from custom_maps:
how many, and the first PLATFORM_MAPS_FOLDER_NAMED's names */
static long pc_maps_in_maps(char *names, unsigned long names_size)
{
char folder[1024];
char name[256];
long count = 0;
void *directory;
platform_translate_path("d:\\maps", folder, sizeof(folder));
directory = posix_directory_open(folder);
if (!directory)
return 0;
while (posix_directory_next(directory, name, sizeof(name)))
{
char path[1300];
if (!name_ends_with(name, ".map"))
continue;
snprintf(path, sizeof(path), "%s/%s", folder, name);
if (!map_version_is_pc(map_file_version(path)))
continue;
if (count < PLATFORM_MAPS_FOLDER_NAMED)
{
size_t length = strlen(names);
snprintf(names + length, names_size - length, "%s%s", length ? ", " : "", name);
}
count++;
}
posix_directory_close(directory);
return count;
}
void platform_maps_folder_check(struct platform_maps_folder *maps)
{
const char *root = platform_data_root();
char path[1024];
memset(maps, 0, sizeof(*maps));
/* the data root as the player finds it (whole: Windows' is the
executable's folder's, or paths.data's) */
#ifndef _WIN32
if (root[0] != '/' && getcwd(maps->root, sizeof(maps->root)))
{
size_t length = strlen(maps->root);
if (strcmp(root, "."))
snprintf(maps->root + length, sizeof(maps->root) - length, "/%s", root);
}
else
#endif
{
snprintf(maps->root, sizeof(maps->root), "%s", root);
}
platform_translate_path("d:\\maps\\ui.map", path, sizeof(path));
maps->ui_version = map_file_version(path);
maps->state = map_version_is_pc(maps->ui_version) ? _maps_folder_halo_pc :
!maps->ui_version ? _maps_folder_no_ui : _maps_folder_xbox;
maps->stray_pc_maps = pc_maps_in_maps(maps->stray_names, sizeof(maps->stray_names));
}
/* ---------- file handles */
struct platform_file