mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-03 20:38:13 +03:00
Refactor asset_manager (again)
There are now two types of asset management:
1. ID-indexed assets, where IDs are not necessarily sequential
2. name-indexed assets
Name-indexed assets can have additional archives added at run-time. This
is to support the CGManager.LoadArchive function used in Rance Quest
Magnum.
Name-indexed assets always use .afa archives. ID-indexed assets mostly
use .ald archives, except for Daiteikoku and Shaman's Sanctuary.
asset_get_by_name is now case insensitive and ignores the file
extension.
This commit is contained in:
@@ -36,12 +36,15 @@ enum asset_type {
|
||||
|
||||
const char *asset_strtype(enum asset_type type);
|
||||
void asset_manager_init(void);
|
||||
bool asset_manager_load_archive(enum asset_type type, const char *archive_name);
|
||||
bool asset_exists(enum asset_type type, int no);
|
||||
bool asset_exists_by_name(enum asset_type type, const char *name, int *id_out);
|
||||
struct archive_data *asset_get(enum asset_type type, int no);
|
||||
int asset_name_to_index(enum asset_type type, const char *name);
|
||||
struct archive_data *asset_get_by_name(enum asset_type type, const char *name, int *id_out);
|
||||
|
||||
struct cg *asset_cg_load(int no);
|
||||
struct cg *asset_cg_load_by_name(const char *name, int *no);
|
||||
struct cg *asset_cg_load_by_name(const char *name, int *id_out);
|
||||
bool asset_cg_get_metrics(int no, struct cg_metrics *metrics);
|
||||
bool asset_cg_get_metrics_by_name(const char *name, struct cg_metrics *metrics);
|
||||
|
||||
#endif /* SYSTEM4_ASSET_MANAGER_H */
|
||||
|
||||
@@ -72,4 +72,6 @@ extern bool game_rance02_mg;
|
||||
extern bool game_rance6_mg;
|
||||
extern bool game_rance7_mg;
|
||||
|
||||
extern bool id_indexed_afa;
|
||||
|
||||
#endif /* XSYSTEM4_H */
|
||||
|
||||
+280
-75
@@ -29,6 +29,7 @@
|
||||
#include "system4/cg.h"
|
||||
#include "system4/file.h"
|
||||
#include "system4/hashtable.h"
|
||||
#include "system4/string.h"
|
||||
#include "system4/utfsjis.h"
|
||||
|
||||
#include "xsystem4.h"
|
||||
@@ -55,18 +56,274 @@ const char *asset_strtype(enum asset_type type)
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
static struct archive *archives[ASSET_TYPE_MAX] = {0};
|
||||
#define MAX_ARCHIVES 8
|
||||
|
||||
struct asset_manager {
|
||||
bool (*load_archive)(struct asset_manager *manager, const char *name);
|
||||
bool (*exists_by_id)(struct asset_manager *manager, int id);
|
||||
bool (*exists_by_name)(struct asset_manager *manager, const char *name, int *id_out);
|
||||
struct archive_data *(*get_by_id)(struct asset_manager *manager, int id);
|
||||
struct archive_data *(*get_by_name)(struct asset_manager *manager, const char *name, int *id_out);
|
||||
};
|
||||
|
||||
// XXX: also used for AFAv1 in Daiteikoku, Shaman's Sanctuary
|
||||
struct asset_manager_ald {
|
||||
struct asset_manager manager;
|
||||
struct archive *archive;
|
||||
};
|
||||
|
||||
struct asset_manager_afa {
|
||||
struct asset_manager manager;
|
||||
struct afa_archive *archives[MAX_ARCHIVES];
|
||||
struct hash_table *index;
|
||||
};
|
||||
|
||||
static struct asset_manager *assets[ASSET_TYPE_MAX] = {0};
|
||||
|
||||
bool asset_manager_load_archive(enum asset_type type, const char *archive_name)
|
||||
{
|
||||
if (!assets[type])
|
||||
return false;
|
||||
if (!assets[type]->load_archive)
|
||||
ERROR("load_archive not supported on this archive type");
|
||||
return assets[type]->load_archive(assets[type], archive_name);
|
||||
}
|
||||
|
||||
bool asset_exists(enum asset_type type, int id)
|
||||
{
|
||||
if (!assets[type])
|
||||
return false;
|
||||
return assets[type]->exists_by_id(assets[type], id);
|
||||
}
|
||||
|
||||
bool asset_exists_by_name(enum asset_type type, const char *name, int *id_out)
|
||||
{
|
||||
if (!assets[type])
|
||||
return false;
|
||||
if (!assets[type]->exists_by_name)
|
||||
ERROR("exists_by_name not supported on this archive type");
|
||||
return assets[type]->exists_by_name(assets[type], name, id_out);
|
||||
}
|
||||
|
||||
struct archive_data *asset_get(enum asset_type type, int id)
|
||||
{
|
||||
if (!assets[type])
|
||||
return NULL;
|
||||
return assets[type]->get_by_id(assets[type], id);
|
||||
}
|
||||
|
||||
struct archive_data *asset_get_by_name(enum asset_type type, const char *name, int *id_out)
|
||||
{
|
||||
if (!assets[type])
|
||||
return NULL;
|
||||
if (!assets[type]->get_by_name)
|
||||
ERROR("get_by_name not supported on this archive type");
|
||||
return assets[type]->get_by_name(assets[type], name, id_out);
|
||||
}
|
||||
|
||||
struct cg *asset_cg_load(int id)
|
||||
{
|
||||
struct archive_data *data = asset_get(ASSET_CG, id);
|
||||
if (!data)
|
||||
return NULL;
|
||||
struct cg *cg = cg_load_data(data);
|
||||
archive_free_data(data);
|
||||
return cg;
|
||||
}
|
||||
|
||||
struct cg *asset_cg_load_by_name(const char *name, int *id_out)
|
||||
{
|
||||
struct archive_data *data = asset_get_by_name(ASSET_CG, name, id_out);
|
||||
if (!data)
|
||||
return NULL;
|
||||
struct cg *cg = cg_load_data(data);
|
||||
archive_free_data(data);
|
||||
return cg;
|
||||
}
|
||||
|
||||
bool asset_cg_get_metrics(int id, struct cg_metrics *metrics)
|
||||
{
|
||||
struct archive_data *data = asset_get(ASSET_CG, id);
|
||||
if (!data)
|
||||
return false;
|
||||
bool r = cg_get_metrics_data(data, metrics);
|
||||
archive_free_data(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool asset_cg_get_metrics_by_name(const char *name, struct cg_metrics *metrics)
|
||||
{
|
||||
struct archive_data *data = asset_get_by_name(ASSET_CG, name, NULL);
|
||||
if (!data)
|
||||
return false;
|
||||
bool r = cg_get_metrics_data(data, metrics);
|
||||
archive_free_data(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool ald_exists_by_id(struct asset_manager *_manager, int id)
|
||||
{
|
||||
struct asset_manager_ald *manager = (struct asset_manager_ald*)_manager;
|
||||
return archive_exists(manager->archive, id - 1);
|
||||
}
|
||||
|
||||
static struct archive_data *ald_get_by_id(struct asset_manager *_manager, int id)
|
||||
{
|
||||
struct asset_manager_ald *manager = (struct asset_manager_ald*)_manager;
|
||||
return archive_get(manager->archive, id - 1);
|
||||
}
|
||||
|
||||
static bool afa_load_archive(struct asset_manager *_manager, const char *name)
|
||||
{
|
||||
struct asset_manager_afa *manager = (struct asset_manager_afa*)_manager;
|
||||
if (manager->archives[MAX_ARCHIVES-1])
|
||||
ERROR("Archive limit exceeded");
|
||||
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, PATH_MAX, "%s.afa", name);
|
||||
|
||||
int error;
|
||||
struct afa_archive *ar = afa_open(path, ARCHIVE_MMAP, &error);
|
||||
if (!ar) {
|
||||
snprintf(path, PATH_MAX, "%s.AFA", name);
|
||||
ar = afa_open(path, ARCHIVE_MMAP, &error);
|
||||
if (!ar) {
|
||||
WARNING("Failed to open archive: %s", display_utf0(path));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = MAX_ARCHIVES - 1; i > 0; i++) {
|
||||
manager->archives[i] = manager->archives[i-1];
|
||||
}
|
||||
manager->archives[0] = ar;
|
||||
|
||||
// index needs to be rebuilt
|
||||
if (manager->index) {
|
||||
ht_free(manager->index);
|
||||
manager->index = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _afa_get_by_id(struct asset_manager *_manager, int id, struct afa_archive **ar_out, int *no_out)
|
||||
{
|
||||
struct asset_manager_afa *manager = (struct asset_manager_afa*)_manager;
|
||||
uint32_t no = id - 1;
|
||||
for (int i = 0; i < MAX_ARCHIVES && manager->archives[i]; i++) {
|
||||
if (no < manager->archives[i]->nr_files) {
|
||||
*ar_out = manager->archives[i];
|
||||
*no_out = no;
|
||||
return true;
|
||||
}
|
||||
no -= manager->archives[i]->nr_files;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool afa_exists_by_id(struct asset_manager *manager, int id)
|
||||
{
|
||||
int no;
|
||||
struct afa_archive *ar;
|
||||
return _afa_get_by_id(manager, id, &ar, &no);
|
||||
}
|
||||
|
||||
static struct archive_data *afa_get_by_id(struct asset_manager *manager, int id)
|
||||
{
|
||||
int no;
|
||||
struct afa_archive *ar;
|
||||
if (!_afa_get_by_id(manager, id, &ar, &no))
|
||||
return NULL;
|
||||
// XXX: we don't use archive_get here because it will return the wrong thing
|
||||
// for AFAv1 archives when not using integer indices
|
||||
return afa_entry_to_descriptor(ar, &ar->files[no]);
|
||||
}
|
||||
|
||||
static void afa_index_archive(struct hash_table *index, struct afa_archive *ar, unsigned base)
|
||||
{
|
||||
for (unsigned i = 0; i < ar->nr_files; i++) {
|
||||
// normalize case and remove file extension from file name
|
||||
char *name = strdup(ar->files[i].name->text);
|
||||
char *dot = strrchr(name, '.');
|
||||
if (dot)
|
||||
*dot = '\0';
|
||||
sjis_toupper(name);
|
||||
// add file to index
|
||||
ht_put(index, name, (void*)((uintptr_t)base + i + 1));
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
|
||||
static bool _afa_get_by_name(struct asset_manager *_manager, const char *_name,
|
||||
struct afa_archive **ar_out, int *no_out, int *id_out)
|
||||
{
|
||||
struct asset_manager_afa *manager = (struct asset_manager_afa*)_manager;
|
||||
// initialize index lazily
|
||||
if (!manager->index) {
|
||||
manager->index = ht_create(4096);
|
||||
unsigned base = 0;
|
||||
for (unsigned i = 0; i < MAX_ARCHIVES && manager->archives[i]; i++) {
|
||||
afa_index_archive(manager->index, manager->archives[i], base);
|
||||
base += manager->archives[i]->nr_files;
|
||||
}
|
||||
}
|
||||
|
||||
// normalize name and get id from index
|
||||
char *name = strdup(_name);
|
||||
sjis_toupper(name);
|
||||
uintptr_t id = (uintptr_t)ht_get(manager->index, name, NULL);
|
||||
free(name);
|
||||
|
||||
if (!id)
|
||||
return false;
|
||||
|
||||
if (id_out)
|
||||
*id_out = id;
|
||||
return _afa_get_by_id(_manager, id, ar_out, no_out);
|
||||
}
|
||||
|
||||
static bool afa_exists_by_name(struct asset_manager *manager, const char *name, int *id_out)
|
||||
{
|
||||
int no;
|
||||
struct afa_archive *ar;
|
||||
return _afa_get_by_name(manager, name, &ar, &no, id_out);
|
||||
}
|
||||
|
||||
static struct archive_data *afa_get_by_name(struct asset_manager *manager, const char *name, int *id_out)
|
||||
{
|
||||
int no;
|
||||
struct afa_archive *ar;
|
||||
if (!_afa_get_by_name(manager, name, &ar, &no, id_out))
|
||||
return NULL;
|
||||
return archive_get(&ar->ar, no);
|
||||
}
|
||||
|
||||
static void _ald_init(enum asset_type type, struct archive *ar)
|
||||
{
|
||||
struct asset_manager_ald *manager = xcalloc(1, sizeof(struct asset_manager_ald));
|
||||
manager->manager.exists_by_id = ald_exists_by_id;
|
||||
manager->manager.get_by_id = ald_get_by_id;
|
||||
manager->manager.load_archive = NULL;
|
||||
manager->manager.exists_by_name = NULL;
|
||||
manager->manager.get_by_name = NULL;
|
||||
manager->archive = ar;
|
||||
assets[type] = &manager->manager;
|
||||
}
|
||||
|
||||
static void ald_init(enum asset_type type, char **files, int count)
|
||||
{
|
||||
if (count < 1)
|
||||
return;
|
||||
if (archives[type])
|
||||
if (assets[type])
|
||||
WARNING("Multiple asset archives for type %s", asset_strtype(type));
|
||||
int error = ARCHIVE_SUCCESS;
|
||||
archives[type] = ald_open(files, count, ARCHIVE_MMAP, &error);
|
||||
if (error)
|
||||
|
||||
int error;
|
||||
struct archive *ar = ald_open(files, count, ARCHIVE_MMAP, &error);
|
||||
if (!ar)
|
||||
ERROR("Failed to open ALD file: %s", archive_strerror(error));
|
||||
|
||||
_ald_init(type, ar);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
free(files[i]);
|
||||
}
|
||||
@@ -76,13 +333,27 @@ static void afa_init(enum asset_type type, char *file)
|
||||
{
|
||||
if (!file)
|
||||
return;
|
||||
if (archives[type])
|
||||
if (assets[type])
|
||||
WARNING("Multiple asset archives for type %s", asset_strtype(type));
|
||||
int error = ARCHIVE_SUCCESS;
|
||||
archives[type] = (struct archive*)afa_open(file, ARCHIVE_MMAP, &error);
|
||||
if (error != ARCHIVE_SUCCESS) {
|
||||
|
||||
int error;
|
||||
struct afa_archive *ar = afa_open(file, ARCHIVE_MMAP, &error);
|
||||
if (!ar)
|
||||
ERROR("Failed to open AFA file: %s", archive_strerror(error));
|
||||
|
||||
if (id_indexed_afa) {
|
||||
_ald_init(type, &ar->ar);
|
||||
} else {
|
||||
struct asset_manager_afa *manager = xcalloc(1, sizeof(struct asset_manager_afa));
|
||||
manager->manager.load_archive = afa_load_archive;
|
||||
manager->manager.exists_by_id = afa_exists_by_id;
|
||||
manager->manager.exists_by_name = afa_exists_by_name;
|
||||
manager->manager.get_by_id = afa_get_by_id;
|
||||
manager->manager.get_by_name = afa_get_by_name;
|
||||
manager->archives[0] = ar;
|
||||
assets[type] = &manager->manager;
|
||||
}
|
||||
|
||||
free(file);
|
||||
}
|
||||
|
||||
@@ -212,69 +483,3 @@ void asset_manager_init(void)
|
||||
afa_init(ASSET_PACT, afa_filenames[ASSET_PACT]);
|
||||
afa_init(ASSET_DATA, afa_filenames[ASSET_DATA]);
|
||||
}
|
||||
|
||||
bool asset_exists(enum asset_type type, int no)
|
||||
{
|
||||
return archives[type] && archive_exists(archives[type], no-1);
|
||||
}
|
||||
|
||||
struct archive_data *asset_get(enum asset_type type, int no)
|
||||
{
|
||||
if (!archives[type])
|
||||
return NULL;
|
||||
return archive_get(archives[type], no-1);
|
||||
}
|
||||
|
||||
struct archive_data *asset_get_by_name(enum asset_type type, const char *name)
|
||||
{
|
||||
if (!archives[type])
|
||||
return NULL;
|
||||
return archive_get_by_name(archives[type], name);
|
||||
}
|
||||
|
||||
int asset_name_to_index(enum asset_type type, const char *name)
|
||||
{
|
||||
if (!archives[type])
|
||||
return 0;
|
||||
// FIXME: should have archive_get_descriptor_by_name function to avoid loading data
|
||||
struct archive_data *data = archive_get_by_name(archives[type], name);
|
||||
if (!data)
|
||||
return 0;
|
||||
int index = data->no + 1;
|
||||
archive_free_data(data);
|
||||
return index;
|
||||
}
|
||||
|
||||
struct cg *asset_cg_load(int no)
|
||||
{
|
||||
struct archive_data *data = asset_get(ASSET_CG, no);
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
struct cg *cg = cg_load_data(data);
|
||||
archive_free_data(data);
|
||||
return cg;
|
||||
}
|
||||
|
||||
struct cg *asset_cg_load_by_name(const char *name, int *no)
|
||||
{
|
||||
struct archive_data *data = asset_get_by_name(ASSET_CG, name);
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
struct cg *cg = cg_load_data(data);
|
||||
*no = data->no + 1;
|
||||
archive_free_data(data);
|
||||
return cg;
|
||||
}
|
||||
|
||||
bool asset_cg_get_metrics(int no, struct cg_metrics *metrics)
|
||||
{
|
||||
struct archive_data *data = asset_get(ASSET_CG, no);
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
bool r = cg_get_metrics_data(data, metrics);
|
||||
archive_free_data(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -298,6 +298,7 @@ extern struct static_library lib_AliceLogo5;
|
||||
extern struct static_library lib_AnteaterADVEngine;
|
||||
extern struct static_library lib_BanMisc;
|
||||
extern struct static_library lib_Bitarray;
|
||||
extern struct static_library lib_CGManager;
|
||||
extern struct static_library lib_ChipmunkSpriteEngine;
|
||||
extern struct static_library lib_ChrLoader;
|
||||
extern struct static_library lib_CommonSystemData;
|
||||
@@ -363,6 +364,7 @@ static struct static_library *static_libraries[] = {
|
||||
&lib_AnteaterADVEngine,
|
||||
&lib_BanMisc,
|
||||
&lib_Bitarray,
|
||||
&lib_CGManager,
|
||||
&lib_ChipmunkSpriteEngine,
|
||||
&lib_ChrLoader,
|
||||
&lib_CommonSystemData,
|
||||
|
||||
@@ -36,6 +36,8 @@ bool game_rance02_mg = false;
|
||||
bool game_rance6_mg = false;
|
||||
bool game_rance7_mg = false;
|
||||
|
||||
bool id_indexed_afa = false;
|
||||
|
||||
static void write_instruction0(struct buffer *out, enum opcode op)
|
||||
{
|
||||
buffer_write_int16(out, op);
|
||||
@@ -165,6 +167,8 @@ void apply_game_specific_hacks(struct ain *ain)
|
||||
apply_rance6_hacks(ain);
|
||||
} else if (!strcmp(game_name, "Sengoku Rance")) {
|
||||
apply_rance7_hacks(ain);
|
||||
} else if (!strcmp(game_name, "しゃーまんず・さんくちゅあり 巫女の聖域")) {
|
||||
id_indexed_afa = true;
|
||||
}
|
||||
free(game_name);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
|
||||
*
|
||||
* 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 "system4/string.h"
|
||||
#include "system4/utfsjis.h"
|
||||
#include "asset_manager.h"
|
||||
#include "xsystem4.h"
|
||||
#include "hll.h"
|
||||
|
||||
static bool CGManager_Init(void *imain_system, int cg_cache_size)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CGManager_LoadArchive(struct string *archive_name)
|
||||
{
|
||||
char *name = sjis2utf(archive_name->text, 0);
|
||||
bool r = asset_manager_load_archive(ASSET_CG, name);
|
||||
free(name);
|
||||
return r;
|
||||
}
|
||||
|
||||
//static int CGManager_GetCountOfDataFromArchive(void);
|
||||
//static void CGManager_GetTitleByIndexFromArchive(int index, struct string **cg_name);
|
||||
//static int CGManager_SearchTitleFromArchive(struct string *cg_name);
|
||||
//static int CGManager_PrefixSearchTitleFromArchive(struct string *cg_name);
|
||||
//static int CGManager_SuffixSearchTitleFromArchive(struct string *cg_name);
|
||||
//static int CGManager_GetCountOfSearchDataFromArchive(void);
|
||||
//static void CGManager_GetSearchTitleByIndexFromArchive(int index, struct string **cg_name);
|
||||
|
||||
HLL_LIBRARY(CGManager,
|
||||
HLL_EXPORT(Init, CGManager_Init),
|
||||
HLL_EXPORT(LoadArchive, CGManager_LoadArchive),
|
||||
HLL_TODO_EXPORT(GetCountOfDataFromArchive, CGManager_GetCountOfDataFromArchive),
|
||||
HLL_TODO_EXPORT(GetTitleByIndexFromArchive, CGManager_GetTitleByIndexFromArchive),
|
||||
HLL_TODO_EXPORT(SearchTitleFromArchive, CGManager_SearchTitleFromArchive),
|
||||
HLL_TODO_EXPORT(PrefixSearchTitleFromArchive, CGManager_PrefixSearchTitleFromArchive),
|
||||
HLL_TODO_EXPORT(SuffixSearchTitleFromArchive, CGManager_SuffixSearchTitleFromArchive),
|
||||
HLL_TODO_EXPORT(GetCountOfSearchDataFromArchive, CGManager_GetCountOfSearchDataFromArchive),
|
||||
HLL_TODO_EXPORT(GetSearchTitleByIndexFromArchive, CGManager_GetSearchTitleByIndexFromArchive));
|
||||
|
||||
@@ -62,6 +62,7 @@ xsystem4 = [version_h,
|
||||
'hll/AnteaterADVEngine.c',
|
||||
'hll/BanMisc.c',
|
||||
'hll/Bitarray.c',
|
||||
'hll/CGManager.c',
|
||||
'hll/CharSpriteManager.c',
|
||||
'hll/ChipmunkSpriteEngine.c',
|
||||
'hll/ChrLoader.c',
|
||||
|
||||
@@ -25,6 +25,13 @@
|
||||
|
||||
void parts_cp_op_free(struct parts_cp_op *op)
|
||||
{
|
||||
switch (op->type) {
|
||||
case PARTS_CP_CG:
|
||||
free_string(op->cg.name);
|
||||
break;
|
||||
case PARTS_CP_FILL_ALPHA_COLOR:
|
||||
break;
|
||||
}
|
||||
free(op);
|
||||
}
|
||||
|
||||
@@ -43,15 +50,14 @@ static bool parts_add_cp_op(int parts_no, struct parts_cp_op *op, int state)
|
||||
|
||||
bool PE_AddCreateCGToProcess(int parts_no, struct string *cg_name, int state)
|
||||
{
|
||||
int cg_no = asset_name_to_index(ASSET_CG, cg_name->text);
|
||||
if (!cg_no) {
|
||||
WARNING("Invalid CG name: %s", cg_name);
|
||||
if (!asset_exists_by_name(ASSET_CG, cg_name->text, NULL)) {
|
||||
WARNING("Invalid CG name: %s", display_sjis0(cg_name->text));
|
||||
return false;
|
||||
}
|
||||
|
||||
struct parts_cp_op *op = xcalloc(1, sizeof(struct parts_cp_op));
|
||||
op->type = PARTS_CP_CG;
|
||||
op->cg.no = cg_no;
|
||||
op->cg.name = string_dup(cg_name);
|
||||
|
||||
return parts_add_cp_op(parts_no, op, state);
|
||||
}
|
||||
@@ -71,7 +77,7 @@ bool PE_AddFillAlphaColorToPartsConstructionProcess(int parts_no, int x, int y,
|
||||
static void build_cg(struct parts *parts, struct parts_cp_cg *op, int state)
|
||||
{
|
||||
// TODO: should this allow composing CGs?
|
||||
parts_set_cg_by_index(parts, op->no, state);
|
||||
parts_set_cg_by_name(parts, op->name, state);
|
||||
}
|
||||
|
||||
static void build_fill_alpha_color(struct parts *parts, struct parts_cp_fill_alpha_color *op, int state)
|
||||
|
||||
@@ -126,7 +126,7 @@ enum parts_cp_op_type {
|
||||
};
|
||||
|
||||
struct parts_cp_cg {
|
||||
int no;
|
||||
struct string *name;
|
||||
};
|
||||
|
||||
struct parts_cp_fill_alpha_color {
|
||||
@@ -202,6 +202,7 @@ void parts_set_rotation_z(struct parts *parts, float rot);
|
||||
void parts_set_alpha(struct parts *parts, int alpha);
|
||||
void parts_set_cg_dims(struct parts *parts, struct cg *cg);
|
||||
bool parts_set_cg_by_index(struct parts *parts, int cg_no, int state);
|
||||
bool parts_set_cg_by_name(struct parts *parts, struct string *cg_name, int state);
|
||||
void parts_set_hgauge_rate(struct parts *parts, float rate, int state);
|
||||
void parts_set_vgauge_rate(struct parts *parts, float rate, int state);
|
||||
bool parts_set_number(struct parts *parts, int n, int state);
|
||||
|
||||
+1
-1
Submodule subprojects/libsys4 updated: 60e6e8981e...42a70d0b29
Reference in New Issue
Block a user