mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-08 22:59:57 +03:00
Fix loading of arrays
Array rank can't be inferred from JSON data since arrays and structs are indistinguishable. So we get it from the ain file instead. Sengoku Rance is mostly playable as of this commit.
This commit is contained in:
+1
-1
@@ -108,7 +108,7 @@ static struct variable *page_ref(struct page *page, int i)
|
||||
return NULL;
|
||||
|
||||
struct variable *v = malloc(sizeof(struct variable));
|
||||
v->data_type = variable_type(page, i, &v->struct_type);
|
||||
v->data_type = variable_type(page, i, &v->struct_type, NULL);
|
||||
v->name = to_utf(variable_name(page, i));
|
||||
v->varno = i;
|
||||
v->value = &page->values[i];
|
||||
|
||||
@@ -141,24 +141,32 @@ enum ain_data_type array_type(enum ain_data_type type)
|
||||
}
|
||||
}
|
||||
|
||||
enum ain_data_type variable_type(struct page *page, int varno, int *struct_type)
|
||||
enum ain_data_type variable_type(struct page *page, int varno, int *struct_type, int *array_rank)
|
||||
{
|
||||
switch (page->type) {
|
||||
case GLOBAL_PAGE:
|
||||
if (struct_type)
|
||||
*struct_type = ain->globals[varno].struct_type;
|
||||
if (array_rank)
|
||||
*array_rank = ain->globals[varno].array_dimensions;
|
||||
return ain->globals[varno].data_type;
|
||||
case LOCAL_PAGE:
|
||||
if (struct_type)
|
||||
*struct_type = ain->functions[page->index].vars[varno].struct_type;
|
||||
if (array_rank)
|
||||
*array_rank = ain->functions[page->index].vars[varno].array_dimensions;
|
||||
return ain->functions[page->index].vars[varno].data_type;
|
||||
case STRUCT_PAGE:
|
||||
if (struct_type)
|
||||
*struct_type = ain->structures[page->index].members[varno].struct_type;
|
||||
if (array_rank)
|
||||
*array_rank = ain->structures[page->index].members[varno].array_dimensions;
|
||||
return ain->structures[page->index].members[varno].data_type;
|
||||
case ARRAY_PAGE:
|
||||
if (struct_type)
|
||||
*struct_type = page->struct_type;
|
||||
if (array_rank)
|
||||
*array_rank = page->rank - 1;
|
||||
return page->rank > 1 ? page->a_type : array_type(page->a_type);
|
||||
}
|
||||
return AIN_VOID;
|
||||
@@ -167,7 +175,7 @@ enum ain_data_type variable_type(struct page *page, int varno, int *struct_type)
|
||||
void delete_page(struct page *page)
|
||||
{
|
||||
for (int i = 0; i < page->nr_vars; i++) {
|
||||
variable_fini(page->values[i], variable_type(page, i, NULL));
|
||||
variable_fini(page->values[i], variable_type(page, i, NULL, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +190,7 @@ struct page *copy_page(struct page *src)
|
||||
dst->struct_type = src->struct_type;
|
||||
dst->rank = src->rank;
|
||||
for (int i = 0; i < src->nr_vars; i++) {
|
||||
dst->values[i] = vm_copy(src->values[i], variable_type(src, i, NULL));
|
||||
dst->values[i] = vm_copy(src->values[i], variable_type(src, i, NULL, NULL));
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
@@ -221,7 +229,7 @@ void create_struct(int no, union vm_value *var)
|
||||
init_struct(no, var->i);
|
||||
}
|
||||
|
||||
struct page *alloc_array(int rank, union vm_value *dimensions, int data_type, int struct_type, bool init_structs)
|
||||
struct page *alloc_array(int rank, union vm_value *dimensions, enum ain_data_type data_type, int struct_type, bool init_structs)
|
||||
{
|
||||
if (rank < 1)
|
||||
return NULL;
|
||||
@@ -247,7 +255,7 @@ struct page *alloc_array(int rank, union vm_value *dimensions, int data_type, in
|
||||
return page;
|
||||
}
|
||||
|
||||
struct page *realloc_array(struct page *src, int rank, union vm_value *dimensions, int data_type, int struct_type, bool init_structs)
|
||||
struct page *realloc_array(struct page *src, int rank, union vm_value *dimensions, enum ain_data_type data_type, int struct_type, bool init_structs)
|
||||
{
|
||||
if (rank < 1)
|
||||
ERROR("Tried to allocate 0-rank array");
|
||||
@@ -267,7 +275,7 @@ struct page *realloc_array(struct page *src, int rank, union vm_value *dimension
|
||||
// if shrinking array, unref orphaned children
|
||||
if (dimensions->i < src->nr_vars) {
|
||||
for (int i = dimensions->i; i < src->nr_vars; i++) {
|
||||
variable_fini(src->values[i], variable_type(src, i, NULL));
|
||||
variable_fini(src->values[i], variable_type(src, i, NULL, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +361,7 @@ int array_fill(struct page *dst, int dst_i, int n, union vm_value v)
|
||||
return n;
|
||||
}
|
||||
|
||||
void array_pushback(struct page **dst, union vm_value v, int data_type, int struct_type)
|
||||
void array_pushback(struct page **dst, union vm_value v, enum ain_data_type data_type, int struct_type)
|
||||
{
|
||||
if (*dst) {
|
||||
if ((*dst)->type != ARRAY_PAGE)
|
||||
@@ -415,7 +423,7 @@ bool array_erase(struct page **_page, int i)
|
||||
return true;
|
||||
}
|
||||
|
||||
void array_insert(struct page **_page, int i, union vm_value v, int data_type, int struct_type)
|
||||
void array_insert(struct page **_page, int i, union vm_value v, enum ain_data_type data_type, int struct_type)
|
||||
{
|
||||
struct page *page = *_page;
|
||||
if (!page) {
|
||||
|
||||
@@ -74,7 +74,7 @@ static inline void page_set(int pageno, int varno, union vm_value v)
|
||||
// variables
|
||||
union vm_value variable_initval(enum ain_data_type type);
|
||||
void variable_fini(union vm_value v, enum ain_data_type type);
|
||||
enum ain_data_type variable_type(struct page *page, int varno, int *struct_type);
|
||||
enum ain_data_type variable_type(struct page *page, int varno, int *struct_type, int *array_rank);
|
||||
|
||||
// pages
|
||||
struct page *alloc_page(enum page_type type, int type_index, int nr_vars);
|
||||
@@ -89,15 +89,15 @@ void create_struct(int no, union vm_value *var);
|
||||
|
||||
// arrays
|
||||
enum ain_data_type array_type(enum ain_data_type type);
|
||||
struct page *alloc_array(int rank, union vm_value *dimensions, int data_type, int struct_type, bool init_structs);
|
||||
struct page *realloc_array(struct page *src, int rank, union vm_value *dimensions, int data_type, int struct_type, bool init_structs);
|
||||
struct page *alloc_array(int rank, union vm_value *dimensions, enum ain_data_type data_type, int struct_type, bool init_structs);
|
||||
struct page *realloc_array(struct page *src, int rank, union vm_value *dimensions, enum ain_data_type data_type, int struct_type, bool init_structs);
|
||||
int array_numof(struct page *page, int rank);
|
||||
void array_copy(struct page *dst, int dst_i, struct page *src, int src_i, int n);
|
||||
int array_fill(struct page *dst, int dst_i, int n, union vm_value v);
|
||||
void array_pushback(struct page **dst, union vm_value v, int data_type, int struct_type);
|
||||
void array_pushback(struct page **dst, union vm_value v, enum ain_data_type data_type, int struct_type);
|
||||
void array_popback(struct page **dst);
|
||||
bool array_erase(struct page **page, int i);
|
||||
void array_insert(struct page **_page, int i, union vm_value v, int data_type, int struct_type);
|
||||
void array_insert(struct page **_page, int i, union vm_value v, enum ain_data_type data_type, int struct_type);
|
||||
void array_sort(struct page *page, int compare_fno);
|
||||
int array_find(struct page *page, int start, int end, union vm_value v, int compare_fno);
|
||||
void array_reverse(struct page *page);
|
||||
|
||||
+20
-24
@@ -24,9 +24,12 @@
|
||||
#include "vm.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
static int current_global;
|
||||
|
||||
#define invalid_save_data(msg, data) { \
|
||||
char *str = data ? cJSON_Print(data) : strdup("NULL"); \
|
||||
WARNING("Invalid save data: " msg ": %s", data); \
|
||||
if (!str) str = strdup("PRINTING FAILED"); \
|
||||
WARNING("Invalid save data (%d): " msg ": %s", current_global, data); \
|
||||
free(str); \
|
||||
}
|
||||
|
||||
@@ -49,7 +52,7 @@ static cJSON *page_to_json(int index)
|
||||
|
||||
cJSON *values = cJSON_CreateArray();
|
||||
for (int i = 0; i < page->nr_vars; i++) {
|
||||
cJSON_AddItemToArray(values, vm_value_to_json(variable_type(page, i, NULL), page->values[i]));
|
||||
cJSON_AddItemToArray(values, vm_value_to_json(variable_type(page, i, NULL, NULL), page->values[i]));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
@@ -173,26 +176,15 @@ int save_group(const char *keyname, const char *filename, const char *group_name
|
||||
return write_save_data(&data, filename);
|
||||
}
|
||||
|
||||
static union vm_value json_to_vm_value(enum ain_data_type type, enum ain_data_type struct_type, cJSON *json);
|
||||
static union vm_value json_to_vm_value(enum ain_data_type type, enum ain_data_type struct_type, int array_rank, cJSON *json);
|
||||
|
||||
int get_json_array_rank(cJSON *json, union vm_value **dims)
|
||||
void get_array_dims(cJSON *json, int rank, union vm_value *dims)
|
||||
{
|
||||
// count rank
|
||||
int rank = 1;
|
||||
cJSON *array = json;
|
||||
while (cJSON_GetArraySize(array) > 0 && !cJSON_IsArray((array = cJSON_GetArrayItem(array, 0)))) {
|
||||
rank++;
|
||||
}
|
||||
|
||||
// count dims
|
||||
array = json;
|
||||
*dims = xmalloc(sizeof(union vm_value) * rank);
|
||||
for (int i = 0; i < rank; i++) {
|
||||
(*dims)[i].i = cJSON_GetArraySize(array);
|
||||
dims[i].i = cJSON_GetArraySize(array);
|
||||
array = cJSON_GetArrayItem(array, 0);
|
||||
}
|
||||
|
||||
return rank;
|
||||
}
|
||||
|
||||
static void load_page(struct page *page, cJSON *vars)
|
||||
@@ -200,18 +192,19 @@ static void load_page(struct page *page, cJSON *vars)
|
||||
int i = 0;
|
||||
cJSON *v;
|
||||
cJSON_ArrayForEach(v, vars) {
|
||||
int struct_type;
|
||||
enum ain_data_type data_type = variable_type(page, i, &struct_type);
|
||||
page->values[i] = json_to_vm_value(data_type, struct_type, v);
|
||||
int struct_type, array_rank;
|
||||
enum ain_data_type data_type = variable_type(page, i, &struct_type, &array_rank);
|
||||
page->values[i] = json_to_vm_value(data_type, struct_type, array_rank, v);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
static union vm_value json_to_vm_value(enum ain_data_type type, enum ain_data_type struct_type, cJSON *json)
|
||||
static union vm_value json_to_vm_value(enum ain_data_type type, enum ain_data_type struct_type, int array_rank, cJSON *json)
|
||||
{
|
||||
char *str;
|
||||
int slot, rank;
|
||||
int slot;
|
||||
union vm_value *dims;
|
||||
struct page *page;
|
||||
switch (type) {
|
||||
case AIN_INT:
|
||||
case AIN_BOOL:
|
||||
@@ -265,8 +258,10 @@ static union vm_value json_to_vm_value(enum ain_data_type type, enum ain_data_ty
|
||||
heap[slot].page = NULL;
|
||||
return vm_int(slot);
|
||||
}
|
||||
rank = get_json_array_rank(json, &dims);
|
||||
heap[slot].page = alloc_array(rank, dims, array_type(type), struct_type, false);
|
||||
dims = xmalloc(sizeof(union vm_value) * array_rank);
|
||||
get_array_dims(json, array_rank, dims);
|
||||
page = alloc_array(array_rank, dims, type, struct_type, false);
|
||||
heap[slot].page = page;
|
||||
free(dims);
|
||||
load_page(heap[slot].page, json);
|
||||
return vm_int(slot);
|
||||
@@ -356,7 +351,8 @@ int load_globals(const char *keyname, const char *filename, const char *group_na
|
||||
invalid_save_data("Invalid global index", index);
|
||||
goto cleanup;
|
||||
}
|
||||
global_set(i, json_to_vm_value(ain->globals[i].data_type, ain->globals[i].struct_type, value));
|
||||
current_global = i;
|
||||
global_set(i, json_to_vm_value(ain->globals[i].data_type, ain->globals[i].struct_type, ain->globals[i].array_dimensions, value));
|
||||
if (n)
|
||||
(*n)++;
|
||||
}
|
||||
|
||||
@@ -270,6 +270,8 @@ static union vm_value *stack_pop_var(void)
|
||||
{
|
||||
int32_t page_index = stack_pop().i;
|
||||
int32_t heap_index = stack_pop().i;
|
||||
if (heap_index < 0 || (size_t)heap_index >= heap_size)
|
||||
VM_ERROR("Out of bounds heap index: %d/%d", heap_index, page_index);
|
||||
if (!heap[heap_index].page || page_index >= heap[heap_index].page->nr_vars)
|
||||
VM_ERROR("Out of bounds page index: %d/%d", heap_index, page_index);
|
||||
return &heap[heap_index].page->values[page_index];
|
||||
@@ -460,15 +462,35 @@ static void function_return(void)
|
||||
call_stack_ptr--;
|
||||
}
|
||||
|
||||
enum syscall_code {
|
||||
SYS_EXIT = 0x00,
|
||||
SYS_GLOBAL_SAVE = 0x01,
|
||||
SYS_GLOBAL_LOAD = 0x02,
|
||||
SYS_LOCK_PEEK = 0x03,
|
||||
SYS_UNLOCK_PEEK = 0x04,
|
||||
SYS_OUTPUT = 0x06,
|
||||
SYS_EXISTS_FILE = 0x0A,
|
||||
SYS_GET_SAVE_FOLDER_NAME = 0x0C,
|
||||
SYS_GET_TIME = 0x0D,
|
||||
SYS_ERROR = 0x0F,
|
||||
SYS_EXISTS_SAVE_FILE = 0x10,
|
||||
SYS_IS_DEBUG_MODE = 0x11,
|
||||
SYS_GET_FUNC_STACK_NAME = 0x13,
|
||||
SYS_PEEK = 0x14,
|
||||
SYS_SLEEP = 0x15,
|
||||
SYS_GROUP_SAVE = 0x18,
|
||||
SYS_GROUP_LOAD = 0x19
|
||||
};
|
||||
|
||||
static void system_call(int32_t code)
|
||||
{
|
||||
char *utf;
|
||||
struct string *str;
|
||||
switch (code) {
|
||||
case 0x0: // system.Exit(int nResult)
|
||||
case SYS_EXIT: // system.Exit(int nResult)
|
||||
vm_exit(stack_pop().i);
|
||||
break;
|
||||
case 0x1: { // system.GlobalSave(string szKeyName, string szFileName)
|
||||
case SYS_GLOBAL_SAVE: { // system.GlobalSave(string szKeyName, string szFileName)
|
||||
int filename = stack_pop().i;
|
||||
int keyname = stack_pop().i;
|
||||
stack_push(save_globals(heap[keyname].s->text, heap[filename].s->text));
|
||||
@@ -476,7 +498,7 @@ static void system_call(int32_t code)
|
||||
heap_unref(keyname);
|
||||
break;
|
||||
}
|
||||
case 0x2: { // system.GlobalLoad(string szKeyName, string szFileName)
|
||||
case SYS_GLOBAL_LOAD: { // system.GlobalLoad(string szKeyName, string szFileName)
|
||||
int filename = stack_pop().i;
|
||||
int keyname = stack_pop().i;
|
||||
stack_push(load_globals(heap[keyname].s->text, heap[filename].s->text, NULL, NULL));
|
||||
@@ -484,18 +506,18 @@ static void system_call(int32_t code)
|
||||
heap_unref(keyname);
|
||||
break;
|
||||
}
|
||||
case 0x3: // system.LockPeek(void)
|
||||
case 0x4: // system.UnlockPeek(void)
|
||||
case SYS_LOCK_PEEK: // system.LockPeek(void)
|
||||
case SYS_UNLOCK_PEEK: // system.UnlockPeek(void)
|
||||
stack_push(1);
|
||||
break;
|
||||
case 0x6: // system.Output(string szText)
|
||||
case SYS_OUTPUT: // system.Output(string szText)
|
||||
str = stack_peek_string(0);
|
||||
utf = sjis2utf(str->text, str->size);
|
||||
sys_message("%s", utf);
|
||||
free(utf);
|
||||
// XXX: caller S_POPs
|
||||
break;
|
||||
case 0xA: { // system.ExistsFile(string szFileName)
|
||||
case SYS_EXISTS_FILE: { // system.ExistsFile(string szFileName)
|
||||
int str = stack_pop().i;
|
||||
char *path = unix_path(heap[str].s->text);
|
||||
stack_push(file_exists(path));
|
||||
@@ -503,23 +525,23 @@ static void system_call(int32_t code)
|
||||
free(path);
|
||||
break;
|
||||
}
|
||||
case 0xC: // system.GetSaveFolderName(void)
|
||||
case SYS_GET_SAVE_FOLDER_NAME: // system.GetSaveFolderName(void)
|
||||
if (config.save_dir)
|
||||
stack_push_string(make_string(config.save_dir, strlen(config.save_dir)));
|
||||
else
|
||||
stack_push_string(string_ref(&EMPTY_STRING));
|
||||
break;
|
||||
case 0xD: // system.GetTime(void)
|
||||
case SYS_GET_TIME: // system.GetTime(void)
|
||||
stack_push(vm_time());
|
||||
break;
|
||||
case 0xF: // system.Error(string szText)
|
||||
case SYS_ERROR: // system.Error(string szText)
|
||||
str = stack_peek_string(0);
|
||||
utf = sjis2utf(str->text, str->size);
|
||||
sys_warning("*GAME ERROR*: %s\n", utf);
|
||||
free(utf);
|
||||
// XXX: caller S_POPs
|
||||
break;
|
||||
case 0x10: {
|
||||
case SYS_EXISTS_SAVE_FILE: {
|
||||
int slot = stack_pop().i;
|
||||
struct string *name = heap[slot].s;
|
||||
size_t dir_len = strlen(config.save_dir);
|
||||
@@ -532,14 +554,13 @@ static void system_call(int32_t code)
|
||||
|
||||
stack_push(file_exists(path));
|
||||
heap_unref(slot);
|
||||
NOTICE("-----PATH=%s", path);
|
||||
free(path);
|
||||
break;
|
||||
}
|
||||
case 0x11: // system.IsDebugMode(void)
|
||||
case SYS_IS_DEBUG_MODE: // system.IsDebugMode(void)
|
||||
stack_push(0);
|
||||
break;
|
||||
case 0x13: { // system.GetFuncStackName(int nIndex)
|
||||
case SYS_GET_FUNC_STACK_NAME: { // system.GetFuncStackName(int nIndex)
|
||||
int i = call_stack_ptr - (1 + stack_pop().i);
|
||||
if (i < 0 || i >= call_stack_ptr) {
|
||||
const char *msg = "Invalid stack index";
|
||||
@@ -551,12 +572,12 @@ static void system_call(int32_t code)
|
||||
stack_push_string(make_string(fun->name, strlen(fun->name)));
|
||||
break;
|
||||
}
|
||||
case 0x14: // system.Peek(void)
|
||||
case SYS_PEEK: // system.Peek(void)
|
||||
break;
|
||||
case 0x15: // system.Sleep(int nSleep)
|
||||
case SYS_SLEEP: // system.Sleep(int nSleep)
|
||||
stack_pop();
|
||||
break;
|
||||
case 0x18: { // system.GroupSave(string szKeyName, string szFileName, string szGroupName, ref int nNumofLoad)
|
||||
case SYS_GROUP_SAVE: { // system.GroupSave(string szKeyName, string szFileName, string szGroupName, ref int nNumofLoad)
|
||||
union vm_value *n = stack_pop_var();
|
||||
int groupname = stack_pop().i;
|
||||
int filename = stack_pop().i;
|
||||
@@ -567,7 +588,7 @@ static void system_call(int32_t code)
|
||||
heap_unref(keyname);
|
||||
break;
|
||||
}
|
||||
case 0x19: { // system.GroupLoad(string szKeyName, string szFileName, string szGroupName, ref int nNumofLoad)
|
||||
case SYS_GROUP_LOAD: { // system.GroupLoad(string szKeyName, string szFileName, string szGroupName, ref int nNumofLoad)
|
||||
union vm_value *n = stack_pop_var();
|
||||
int groupname = stack_pop().i;
|
||||
int filename = stack_pop().i;
|
||||
@@ -1451,7 +1472,7 @@ static void execute_instruction(enum opcode opcode)
|
||||
int varno = stack_peek(rank).i;
|
||||
int pageno = stack_peek(rank+1).i;
|
||||
int array = heap[pageno].page->values[varno].i;
|
||||
enum ain_data_type data_type = variable_type(heap[pageno].page, varno, &struct_type);
|
||||
enum ain_data_type data_type = variable_type(heap[pageno].page, varno, &struct_type, NULL);
|
||||
heap_set_page(array, alloc_array(rank, stack_peek_ptr(rank-1), data_type, struct_type, true));
|
||||
stack_ptr -= rank + 2;
|
||||
break;
|
||||
@@ -1462,7 +1483,7 @@ static void execute_instruction(enum opcode opcode)
|
||||
int varno = stack_peek(rank).i;
|
||||
int pageno = stack_peek(rank+1).i;
|
||||
int array = heap[pageno].page->values[varno].i;
|
||||
enum ain_data_type data_type = variable_type(heap[pageno].page, varno, &struct_type);
|
||||
enum ain_data_type data_type = variable_type(heap[pageno].page, varno, &struct_type, NULL);
|
||||
heap_set_page(array, realloc_array(heap[array].page, rank, stack_peek_ptr(rank-1), data_type, struct_type, true));
|
||||
stack_ptr -= rank + 2;
|
||||
break;
|
||||
@@ -1513,7 +1534,7 @@ static void execute_instruction(enum opcode opcode)
|
||||
int varno = stack_pop().i;
|
||||
int pageno = stack_pop().i;
|
||||
int array = heap[pageno].page->values[varno].i;
|
||||
enum ain_data_type data_type = variable_type(heap[pageno].page, varno, &struct_type);
|
||||
enum ain_data_type data_type = variable_type(heap[pageno].page, varno, &struct_type, NULL);
|
||||
array_pushback(&heap[array].page, val, data_type, struct_type);
|
||||
break;
|
||||
}
|
||||
@@ -1539,7 +1560,7 @@ static void execute_instruction(enum opcode opcode)
|
||||
int varno = stack_pop().i;
|
||||
int pageno = stack_pop().i;
|
||||
int array = heap[pageno].page->values[varno].i;
|
||||
enum ain_data_type data_type = variable_type(heap[pageno].page, varno, &struct_type);
|
||||
enum ain_data_type data_type = variable_type(heap[pageno].page, varno, &struct_type, NULL);
|
||||
array_insert(&heap[array].page, i, val, data_type, struct_type);
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user