mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-14 01:59:19 +03:00
Implement Toushin3Loader HLL library
This commit is contained in:
@@ -346,6 +346,7 @@ extern struct static_library lib_StretchHelper;
|
||||
extern struct static_library lib_SystemService;
|
||||
extern struct static_library lib_SystemServiceEx;
|
||||
extern struct static_library lib_Timer;
|
||||
extern struct static_library lib_Toushin3Loader;
|
||||
extern struct static_library lib_VSFile;
|
||||
|
||||
static struct static_library *static_libraries[] = {
|
||||
@@ -407,6 +408,7 @@ static struct static_library *static_libraries[] = {
|
||||
&lib_SystemService,
|
||||
&lib_SystemServiceEx,
|
||||
&lib_Timer,
|
||||
&lib_Toushin3Loader,
|
||||
&lib_VSFile,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -0,0 +1,359 @@
|
||||
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "little_endian.h"
|
||||
#include "system4/buffer.h"
|
||||
#include "system4/string.h"
|
||||
#include "system4/utfsjis.h"
|
||||
|
||||
#include "hll.h"
|
||||
#include "vm/heap.h"
|
||||
#include "vm/page.h"
|
||||
#include "xsystem4.h"
|
||||
|
||||
enum ts3m_section {
|
||||
TS3M_MAP_INFO = 0,
|
||||
TS3M_OBJECT_INFO = 1,
|
||||
TS3M_BILLBOARD_INFO = 2,
|
||||
TS3M_MAP_DATA = 3,
|
||||
TS3M_MAP_SOUND = 4,
|
||||
};
|
||||
|
||||
struct ts3m_header {
|
||||
uint32_t version;
|
||||
uint32_t offsets[5];
|
||||
};
|
||||
|
||||
struct ts3m_info {
|
||||
uint32_t count;
|
||||
struct buffer buf;
|
||||
};
|
||||
|
||||
static struct ts3m_info *ts3m_map_info;
|
||||
static struct ts3m_info *ts3m_object_info;
|
||||
static struct ts3m_info *ts3m_billboard_info;
|
||||
static struct buffer *ts3m_read_buf;
|
||||
|
||||
static FILE *open_and_read_header(struct ts3m_header *header)
|
||||
{
|
||||
char *path = gamedir_path("Data/Toushin3Map.dat");
|
||||
FILE *fp = fopen(path, "rb");
|
||||
free(path);
|
||||
|
||||
uint8_t buf[28];
|
||||
if (fread(buf, sizeof buf, 1, fp) != 1)
|
||||
goto err_exit;
|
||||
if (memcmp(buf, "TS3M", 4))
|
||||
goto err_exit;
|
||||
header->version = LittleEndian_getDW(buf, 4);
|
||||
if (header->version != 100)
|
||||
goto err_exit;
|
||||
for (int i = 0; i < 5; i++)
|
||||
header->offsets[i] = LittleEndian_getDW(buf, 8 + i * 4);
|
||||
return fp;
|
||||
|
||||
err_exit:
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint8_t *read_compressed_data(FILE *fp, uint32_t *size)
|
||||
{
|
||||
uint8_t *buf = malloc(*size);
|
||||
if (fread(buf, *size, 1, fp) != 1) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
unsigned long raw_size = LittleEndian_getDW(buf, 0);
|
||||
void *raw = malloc(raw_size);
|
||||
if (uncompress(raw, &raw_size, buf + 4, *size - 4) != Z_OK) {
|
||||
WARNING("uncompress failed");
|
||||
free(raw);
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
free(buf);
|
||||
|
||||
*size = raw_size;
|
||||
return raw;
|
||||
}
|
||||
|
||||
static struct ts3m_info *load_ts3m_info(enum ts3m_section section)
|
||||
{
|
||||
struct ts3m_header header;
|
||||
FILE *fp = open_and_read_header(&header);
|
||||
if (!fp)
|
||||
return NULL;
|
||||
|
||||
fseek(fp, header.offsets[section], SEEK_SET);
|
||||
|
||||
uint8_t buf[8];
|
||||
if (fread(buf, sizeof buf, 1, fp) != 1) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
struct ts3m_info *info = xcalloc(1, sizeof(struct ts3m_info));
|
||||
info->count = LittleEndian_getDW(buf, 0);
|
||||
uint32_t size = LittleEndian_getDW(buf, 4);
|
||||
uint8_t *raw = read_compressed_data(fp, &size);
|
||||
fclose(fp);
|
||||
if (!raw) {
|
||||
free(info);
|
||||
return NULL;
|
||||
}
|
||||
buffer_init(&info->buf, raw, size);
|
||||
return info;
|
||||
}
|
||||
|
||||
static void free_ts3m_info(struct ts3m_info *info)
|
||||
{
|
||||
free(info->buf.buf);
|
||||
free(info);
|
||||
}
|
||||
|
||||
static bool unload_ts3m_data(void)
|
||||
{
|
||||
if (!ts3m_read_buf)
|
||||
return false;
|
||||
free(ts3m_read_buf->buf);
|
||||
free(ts3m_read_buf);
|
||||
ts3m_read_buf = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool load_ts3m_data(enum ts3m_section section, int no)
|
||||
{
|
||||
if (unload_ts3m_data()) {
|
||||
WARNING("Previously loaded data wasn't unloaded");
|
||||
}
|
||||
|
||||
struct ts3m_header header;
|
||||
FILE *fp = open_and_read_header(&header);
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
fseek(fp, header.offsets[section], SEEK_SET);
|
||||
|
||||
uint8_t buf[12];
|
||||
if (fread(buf, 4, 1, fp) != 1) {
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
int nr_data = LittleEndian_getDW(buf, 0);
|
||||
for (int i = 0; i < nr_data; i++) {
|
||||
if (fread(buf, 12, 1, fp) != 1) {
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
int data_no = LittleEndian_getDW(buf, 0);
|
||||
uint32_t size = LittleEndian_getDW(buf, 4);
|
||||
uint32_t offset = LittleEndian_getDW(buf, 8);
|
||||
if (data_no == no) {
|
||||
fseek(fp, offset, SEEK_SET);
|
||||
uint8_t *data = read_compressed_data(fp, &size);
|
||||
fclose(fp);
|
||||
if (!data)
|
||||
return false;
|
||||
ts3m_read_buf = xcalloc(1, sizeof(struct buffer));
|
||||
buffer_init(ts3m_read_buf, data, size);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
WARNING("load_ts3m_data(%d, %d): not found", section, no);
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int32_t read_cstring(struct buffer *buf)
|
||||
{
|
||||
struct string *s = cstr_to_string(buffer_strdata(buf));
|
||||
buffer_skip(buf, s->size + 1);
|
||||
return heap_alloc_string(s);
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_LoadMapInfo(void)
|
||||
{
|
||||
if (!ts3m_map_info)
|
||||
ts3m_map_info = load_ts3m_info(TS3M_MAP_INFO);
|
||||
return !!ts3m_map_info;
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_UnloadMapInfo(void)
|
||||
{
|
||||
if (!ts3m_map_info)
|
||||
return false;
|
||||
free_ts3m_info(ts3m_map_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int Toushin3Loader_GetMapInfoCount(void)
|
||||
{
|
||||
if (!ts3m_map_info)
|
||||
return -1;
|
||||
return ts3m_map_info->count;
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_GetMapInfo(struct page **page)
|
||||
{
|
||||
if (!ts3m_map_info)
|
||||
return false;
|
||||
|
||||
union vm_value *out = (*page)->values; // struct tagMapInfo
|
||||
out[0].i = buffer_read_int32(&ts3m_map_info->buf); // m_nNo
|
||||
out[1].i = read_cstring(&ts3m_map_info->buf); // m_szName
|
||||
out[2].i = buffer_read_int32(&ts3m_map_info->buf); // m_nX
|
||||
out[3].i = buffer_read_int32(&ts3m_map_info->buf); // m_nY
|
||||
out[4].i = buffer_read_int32(&ts3m_map_info->buf); // m_nDir
|
||||
out[5].i = read_cstring(&ts3m_map_info->buf); // m_szName2
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_LoadObjectInfo(void)
|
||||
{
|
||||
if (!ts3m_object_info)
|
||||
ts3m_object_info = load_ts3m_info(TS3M_OBJECT_INFO);
|
||||
return !!ts3m_object_info;
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_UnloadObjectInfo(void)
|
||||
{
|
||||
if (!ts3m_object_info)
|
||||
return false;
|
||||
free_ts3m_info(ts3m_object_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int Toushin3Loader_GetObjectInfoCount(void)
|
||||
{
|
||||
if (!ts3m_object_info)
|
||||
return -1;
|
||||
return ts3m_object_info->count;
|
||||
}
|
||||
|
||||
bool Toushin3Loader_GetObjectInfo(struct page **page)
|
||||
{
|
||||
if (!ts3m_object_info)
|
||||
return false;
|
||||
|
||||
union vm_value *out = (*page)->values; // struct tagObjectInfo
|
||||
out[0].i = buffer_read_int32(&ts3m_object_info->buf); // m_nNo
|
||||
out[1].i = read_cstring(&ts3m_object_info->buf); // m_szName
|
||||
out[2].i = buffer_read_int32(&ts3m_object_info->buf); // m_nEnterFlag
|
||||
out[3].i = buffer_read_int32(&ts3m_object_info->buf); // m_nState
|
||||
out[4].i = buffer_read_int32(&ts3m_object_info->buf); // m_nBegin
|
||||
out[5].i = buffer_read_int32(&ts3m_object_info->buf); // m_nEnd
|
||||
out[6].i = buffer_read_int32(&ts3m_object_info->buf); // m_nLoopBegin
|
||||
out[7].i = buffer_read_int32(&ts3m_object_info->buf); // m_nLoopEnd
|
||||
out[8].i = buffer_read_int32(&ts3m_object_info->buf); // m_nFPS
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_LoadBillboardInfo(void)
|
||||
{
|
||||
if (!ts3m_billboard_info)
|
||||
ts3m_billboard_info = load_ts3m_info(TS3M_BILLBOARD_INFO);
|
||||
return !!ts3m_billboard_info;
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_UnloadBillboardInfo(void)
|
||||
{
|
||||
if (!ts3m_billboard_info)
|
||||
return false;
|
||||
free_ts3m_info(ts3m_billboard_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int Toushin3Loader_GetBillboardInfoCount(void)
|
||||
{
|
||||
if (!ts3m_billboard_info)
|
||||
return -1;
|
||||
return ts3m_billboard_info->count;
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_GetBillboardInfo(struct page **page)
|
||||
{
|
||||
if (!ts3m_billboard_info)
|
||||
return false;
|
||||
|
||||
union vm_value *out = (*page)->values; // struct tagBillboardInfo
|
||||
for (int i = 0; i < 14; i++)
|
||||
out[i].i = buffer_read_int32(&ts3m_billboard_info->buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_LoadMapData(int map_no)
|
||||
{
|
||||
return load_ts3m_data(TS3M_MAP_DATA, map_no);
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_LoadMapSound(int map_no)
|
||||
{
|
||||
return load_ts3m_data(TS3M_MAP_SOUND, map_no);
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_GetByte(int *data)
|
||||
{
|
||||
if (!ts3m_read_buf || buffer_remaining(ts3m_read_buf) < 1)
|
||||
return false;
|
||||
*data = buffer_read_u8(ts3m_read_buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_GetInt(int *data)
|
||||
{
|
||||
if (!ts3m_read_buf || buffer_remaining(ts3m_read_buf) < 4)
|
||||
return false;
|
||||
*data = buffer_read_int32(ts3m_read_buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Toushin3Loader_GetFloat(float *data)
|
||||
{
|
||||
if (!ts3m_read_buf || buffer_remaining(ts3m_read_buf) < 4)
|
||||
return false;
|
||||
*data = buffer_read_float(ts3m_read_buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool Toushin3Loader_GetString(struct string **pIString); // unused
|
||||
|
||||
HLL_LIBRARY(Toushin3Loader,
|
||||
HLL_EXPORT(LoadMapInfo, Toushin3Loader_LoadMapInfo),
|
||||
HLL_EXPORT(UnloadMapInfo, Toushin3Loader_UnloadMapInfo),
|
||||
HLL_EXPORT(GetMapInfoCount, Toushin3Loader_GetMapInfoCount),
|
||||
HLL_EXPORT(GetMapInfo, Toushin3Loader_GetMapInfo),
|
||||
HLL_EXPORT(LoadObjectInfo, Toushin3Loader_LoadObjectInfo),
|
||||
HLL_EXPORT(UnloadObjectInfo, Toushin3Loader_UnloadObjectInfo),
|
||||
HLL_EXPORT(GetObjectInfoCount, Toushin3Loader_GetObjectInfoCount),
|
||||
HLL_EXPORT(GetObjectInfo, Toushin3Loader_GetObjectInfo),
|
||||
HLL_EXPORT(LoadBillboardInfo, Toushin3Loader_LoadBillboardInfo),
|
||||
HLL_EXPORT(UnloadBillboardInfo, Toushin3Loader_UnloadBillboardInfo),
|
||||
HLL_EXPORT(GetBillboardInfoCount, Toushin3Loader_GetBillboardInfoCount),
|
||||
HLL_EXPORT(GetBillboardInfo, Toushin3Loader_GetBillboardInfo),
|
||||
HLL_EXPORT(LoadMapData, Toushin3Loader_LoadMapData),
|
||||
HLL_EXPORT(UnloadMapData, unload_ts3m_data),
|
||||
HLL_EXPORT(LoadMapSound, Toushin3Loader_LoadMapSound),
|
||||
HLL_EXPORT(UnloadMapSound, unload_ts3m_data),
|
||||
HLL_EXPORT(GetByte, Toushin3Loader_GetByte),
|
||||
HLL_EXPORT(GetInt, Toushin3Loader_GetInt),
|
||||
HLL_EXPORT(GetFloat, Toushin3Loader_GetFloat),
|
||||
HLL_TODO_EXPORT(GetString, Toushin3Loader_GetString)
|
||||
);
|
||||
@@ -105,6 +105,7 @@ xsystem4 = [version_h,
|
||||
'hll/SystemService.c',
|
||||
'hll/SystemServiceEx.c',
|
||||
'hll/Timer.c',
|
||||
'hll/Toushin3Loader.c',
|
||||
'hll/VSFile.c',
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user