[Add] mission/hook save disabled right now - Pluto is still being a bitch!

This commit is contained in:
Allanis 2013-05-30 18:33:15 +01:00
parent 2bd4edfa09
commit 304bc81ea1
6 changed files with 235 additions and 52 deletions

View File

@ -291,11 +291,8 @@ static void persistfunction(PersistInfo *pi)
/* It's a C function. For now, we aren't going to allow
* persistence of C closures, even if the "C proto" is
* already in the permanents table. */
/*
lua_pushstring(pi->L, "Attempt to persist a C function");
lua_error(pi->L);
*/
return; /* we don't save C closures, they'll have to get repushed */
} else {
/* It's a Lua closure. */
{

View File

@ -3,11 +3,12 @@
#include "log.h"
#include "lephisto.h"
#include "xml.h"
#include "hook.h"
// The hook.
typedef struct Hook_ {
int id; // Unique id.
unsigned int id; // Unique id.
unsigned int parent; // Mission it's connected to.
char* func; // Function returned.
char* stack; // Stack it's a part of.
@ -26,6 +27,9 @@ static int hook_runningstack = 0; // Check if stack is running.
extern int misn_run(Mission* misn, char* func);
// Intern.
static int hook_run(Hook* hook);
static void hook_free(Hook* h);
static int hook_needSave(Hook* h);
static int hook_parse(xmlNodePtr base);
static int hook_run(Hook* hook) {
int i;
@ -52,7 +56,7 @@ static int hook_run(Hook* hook) {
}
// Add/Remove hooks.
int hook_add(unsigned int parent, char* func, char* stack) {
unsigned int hook_add(unsigned int parent, char* func, char* stack) {
Hook* new_hook;
// If the memory must grow.
@ -65,8 +69,8 @@ int hook_add(unsigned int parent, char* func, char* stack) {
new_hook = &hook_stack[hook_nstack];
new_hook->id = ++hook_id;
new_hook->parent = parent;
new_hook->func = func;
new_hook->stack = stack;
new_hook->func = strdup(func);
new_hook->stack = strdup(stack);
new_hook->delete = 0;
hook_nstack++;
@ -74,7 +78,7 @@ int hook_add(unsigned int parent, char* func, char* stack) {
return new_hook->id;
}
void hook_rm(int id) {
void hook_rm(unsigned int id) {
int l, m, h;
l = 0;
h = hook_nstack-1;
@ -93,12 +97,13 @@ void hook_rm(int id) {
// Last hook, just clip the stack.
if(m == (hook_nstack-1)) {
hook_free(&hook_stack[m]);
hook_nstack--;
return;
}
// Move it!
memmove(&hook_stack[m], &hook_stack[m], sizeof(Hook)*(hook_nstack-(m+1)));
memmove(&hook_stack[m], &hook_stack[m+1], sizeof(Hook)*(hook_nstack-(m+1)));
hook_nstack--;
}
@ -132,7 +137,7 @@ int hooks_run(char* stack) {
}
// Run a single hook by id.
void hook_runID(int id) {
void hook_runID(unsigned int id) {
int i;
for(i = 0; i < hook_nstack; i++)
@ -143,8 +148,18 @@ void hook_runID(int id) {
DEBUG("Attempting to run hook of id '%d' which is not in the stack", id);
}
// Free a hook.
static void hook_free(Hook* h) {
if(h->func != NULL) free(h->func);
if(h->stack != NULL) free(h->stack);
}
// Clean upi after ourselves.
void hook_cleanup(void) {
int i;
for(i = 0; i < hook_nstack; i++)
hook_free(&hook_stack[i]);
free(hook_stack);
hook_stack = NULL;
// Sane defaults just in case.
@ -152,3 +167,83 @@ void hook_cleanup(void) {
hook_mstack = 0;
}
// Save the hooks.
static int hook_needSave(Hook* h) {
int i;
char* nosave[] = { "death", "end" };
for(i = 0; strcmp(nosave[i], "end") != 0; i++)
if(strcmp(nosave[i], h->stack)==0) return 0;
return 1;
}
int hook_save(xmlTextWriterPtr writer) {
int i;
Hook* h;
xmlw_startElem(writer, "hooks");
for(i = 0; i < hook_nstack; i++) {
h = &hook_stack[i];
if(!hook_needSave(h)) continue; // No need to save it.
xmlw_startElem(writer, "hook");
//xmlw_attr(writer, "id", "%u", h->id); // I don't think it's needed.
xmlw_elem(writer, "parent", "%u", h->parent);
xmlw_elem(writer, "func", "%s", h->func);
xmlw_elem(writer, "stack", "%s", h->stack);
xmlw_endElem(writer); // Hook.
}
xmlw_endElem(writer); // Hooks.
return 0;
}
// Load hooks for a player.
int hook_load(xmlNodePtr parent) {
xmlNodePtr node;
hook_cleanup();
node = parent->xmlChildrenNode;
do {
if(xml_isNode(node, "hooks"))
hook_parse(node);
} while(xml_nextNode(node));
return 0;
}
static int hook_parse(xmlNodePtr base) {
xmlNodePtr node, cur;
char* func, *stack;
unsigned int parent;
node = base->xmlChildrenNode;
do {
if(xml_isNode(node, "hook")) {
parent = 0;
func = NULL;
stack = NULL;
cur = node->xmlChildrenNode;
do {
xmlr_long(cur, "parent", parent);
xmlr_str(cur, "func", func);
xmlr_str(cur, "stack", stack);
} while(xml_nextNode(cur));
if((parent == 0) || (func == NULL) || (stack == NULL)) {
WARN("Invalid hook.");
return -1;
}
hook_add(parent, func, stack);
}
} while(xml_nextNode(node));
return 0;
}

View File

@ -2,15 +2,15 @@
#include "mission.h"
// Add/Run hooks.
int hook_add(unsigned int parent, char* func, char* stack);
void hook_rm(int id);
unsigned int hook_add(unsigned int parent, char* func, char* stack);
void hook_rm(unsigned int id);
void hook_rmParent(unsigned int parent);
// ========================================================
// Run Hooks:
//
// Currently used:
// -- "land" - When landed.
// -- "land" - When landed.
// -- "takeoff" - When taking off.
// -- "jump" - When changing systems.
// -- "time" - When time is increment drastically
@ -18,7 +18,7 @@ void hook_rmParent(unsigned int parent);
// ========================================================
int hooks_run(char* stack);
void hook_runID(int id); // Runs hook of specific id.
void hook_runID(unsigned int id); // Runs hook of specific id.
// Destroy hook.
void hook_cleanup(void);

View File

@ -55,7 +55,7 @@ static int misn_delete = 0; // If 1 delete current mission.
static int var_add(misn_var* var);
static void var_free(misn_var* var);
static int hook_generic(lua_State* L, char* stack);
static unsigned int hook_generic(lua_State* L, char* stack);
// -- Libraries. --
@ -872,7 +872,7 @@ static int tk_input(lua_State* L) {
}
// -- HOOK --
static int hook_generic(lua_State* L, char* stack) {
static unsigned int hook_generic(lua_State* L, char* stack) {
int i;
char* func;
@ -893,8 +893,7 @@ static int hook_generic(lua_State* L, char* stack) {
cur_mission->data->name);
return 0;
}
i = hook_add(cur_mission->id, func, stack);
return i;
return hook_add(cur_mission->id, func, stack);
}
static int hook_land(lua_State* L) {
@ -919,8 +918,7 @@ static int hook_enter(lua_State* L) {
static int hook_pilotDeath(lua_State* L) {
MIN_ARGS(2);
int h;
unsigned int p;
unsigned int h, p;
if(lua_isnumber(L, -2)) p = (unsigned int) lua_tonumber(L, -2);
else MISN_INVALID_PARAMETER();

View File

@ -48,6 +48,8 @@ static int mission_matchFaction(MissionData* misn, int faction);
static int mission_location(char* loc);
static MissionData* mission_parse(const xmlNodePtr parent);
static int missions_parseActive(xmlNodePtr parent);
static int mission_persistTable(lua_State* L);
static int mission_unpersistTable(lua_State* L);
// Generate a new id for the mission.
static unsigned int mission_genID(void) {
@ -104,7 +106,7 @@ static int mission_init(Mission* mission, MissionData* misn) {
return -1;
}
luaopen_base(mission->L); // Can be useful.
//luaopen_base(mission->L); // Can be useful.
luaopen_string(mission->L); // string.format can be very useful.
misn_loadLibs(mission->L); // Load our custom libraries.
@ -224,18 +226,33 @@ void mission_unlinkCargo(Mission* misn, unsigned int cargo_id) {
// Clean up a mission.
void mission_cleanup(Mission* misn) {
int i;
if(misn->id) hook_rmParent(misn->id); // Remove existing hooks.
if(misn->title) free(misn->title);
if(misn->desc) free(misn->desc);
if(misn->reward) free(misn->reward);
if(misn->id != 0) {
hook_rmParent(misn->id); // Remove existing hooks.
misn->id = 0;
}
if(misn->title != NULL) {
free(misn->title);
misn->title = NULL;
}
if(misn->desc != NULL) {
free(misn->desc);
misn->desc = NULL;
}
if(misn->reward) {
free(misn->reward);
misn->reward = NULL;
}
if(misn->cargo) {
for(i = 0; i < misn->ncargo; i++)
mission_unlinkCargo(misn, misn->cargo[i]);
free(misn->cargo);
misn->cargo = NULL;
misn->ncargo = 0;
}
if(misn->L) lua_close(misn->L);
memset(misn, 0, sizeof(Mission));
if(misn->L) {
lua_close(misn->L);
misn->L = NULL;
}
}
// Free a mission.
@ -432,6 +449,7 @@ void missions_cleanup(void) {
mission_cleanup(&player_missions[i]);
}
// Memory buffer structure to handle lua writers/readers.
typedef struct MBuf_ {
char* data;
ssize_t len, alloc; // Size of each data chunk, chunks to alloc when growing.
@ -482,6 +500,53 @@ static int mission_writeLua(lua_State* L, const void* p, size_t sz, void* ud) {
return 0;
}
static int mission_persistTable(lua_State* L) {
lua_newtable(L);
// Table.
lua_pushnil(L);
// table, nil.
while(lua_next(L, LUA_GLOBALSINDEX) != 0) {
// table, key, value.
switch(lua_type(L, -1)) {
case LUA_TNUMBER:
case LUA_TBOOLEAN:
case LUA_TSTRING:
lua_pushvalue(L, -2); // Copy key.
// table, key, value, key.
lua_insert(L, -3); // key << 2.
// table, key, key, value.
lua_settable(L, -4); // table[key] = value.
// table, key.
break;
default:
lua_pop(L, 1);
// table, key.
continue;
}
}
// table.
return 0;
}
static int mission_unpersistTable(lua_State* L) {
// Table.
lua_pushnil(L);
// Table, Nil.
while(lua_next(L, -2) != 0) {
// Table, key, value.
lua_pushvalue(L, -2); // Copy key.
// Table, key, value, key.
lua_insert(L, -3); // key << 2.
// table, key, key, value.
lua_settable(L, LUA_GLOBALSINDEX);
// table, key.
}
// Table.
lua_pop(L, 1);
return 0;
}
int missions_saveActive(xmlTextWriterPtr writer) {
MBuf* buf;
char* data;
@ -494,8 +559,9 @@ int missions_saveActive(xmlTextWriterPtr writer) {
if(player_missions[i].id != 0) {
xmlw_startElem(writer, "mission");
xmlw_elem(writer, "data", player_missions[i].data->name);
xmlw_elem(writer, "id", "%u", player_missions[i].id);
// Data and id are attributes because they must be loaded first.
xmlw_attr(writer, "data", player_missions[i].data->name);
xmlw_attr(writer, "id", "%u", player_missions[i].id);
xmlw_elem(writer, "title", player_missions[i].title);
xmlw_elem(writer, "desc", player_missions[i].desc);
@ -506,14 +572,25 @@ int missions_saveActive(xmlTextWriterPtr writer) {
xmlw_elem(writer, "cargo", "%u", player_missions[i].cargo[j]);
xmlw_endElem(writer); // Cargo.
// Write lua magic.
xmlw_startElem(writer, "lua");
// We need to use a special data struct.
buf = mbuf_create(1, 128);
lua_pushvalue(player_missions[i].L, LUA_GLOBALSINDEX);
// Prepare the data.
lua_pushnil(player_missions[i].L);
mission_persistTable(player_missions[i].L); // We don't save it all.
pluto_persist(player_missions[i].L, mission_writeLua, buf);
// Now process it to save it.
data = base64_encode(&sz, buf->data, buf->ndata);
mbuf_free(buf);
xmlw_raw(writer, data, sz);
// Cleanup.
mbuf_free(buf);
free(data);
xmlw_endElem(writer); // Lua.
xmlw_endElem(writer); // Mission.
@ -529,21 +606,23 @@ const char* mission_readLua(lua_State* L, void* data, size_t* size) {
MBuf* dat;
char* pos;
char* buf;
size_t len;
dat = (MBuf*) data;
len = dat->alloc * dat->len;
pos = dat->data;
buf = &pos[dat->ndata];
if(dat->mdata >= dat->ndata) {
if(dat->ndata >= dat->mdata) {
(*size) = 0;
return NULL;
}
if(dat->mdata < (dat->ndata + dat->alloc * dat->len)) { // Last chunk.
if(dat->mdata < (dat->ndata + len)) { // Last chunk.
(*size) = dat->mdata - dat->ndata;
dat->ndata = dat->mdata;
} else {
(*size) = dat->alloc * dat->len;
dat->ndata += dat->alloc * dat->len;
(*size) = len;
dat->ndata += len;
}
return buf;
}
@ -566,7 +645,7 @@ int missions_loadActive(xmlNodePtr parent) {
static int missions_parseActive(xmlNodePtr parent) {
Mission* misn;
int m;
char* buf;
char* buf, *str;
MBuf dat;
xmlNodePtr node, cur, nest;
@ -576,16 +655,19 @@ static int missions_parseActive(xmlNodePtr parent) {
do {
if(xml_isNode(node, "mission")) {
misn = &player_missions[m];
mission_init(misn, NULL); // Won't set data nor id.
// Process the attributes to create the mission.
xmlr_attr(node, "data", buf);
mission_init(misn, mission_get(mission_getID(buf)));
free(buf);
// This will orphan an identifier.
xmlr_attr(node, "id", buf);
misn->id = atol(buf);
free(buf);
cur = node->xmlChildrenNode;
do {
if(xml_isNode(cur, "data")) {
buf = xml_get(cur);
misn->data = mission_get(mission_getID(buf));
}
xmlr_long(cur, "id", misn->id);
xmlr_strd(cur, "title", misn->title);
xmlr_strd(cur, "desc", misn->desc);
xmlr_strd(cur, "reward", misn->reward);
@ -599,12 +681,20 @@ static int missions_parseActive(xmlNodePtr parent) {
}
if(xml_isNode(cur, "lua")) {
buf = xml_get(cur);
// Prepare the data.
str = xml_get(cur);
dat.ndata = 0;
dat.len = 1;
dat.len = 1024;
dat.alloc = 128;
dat.data = base64_decode(&dat.mdata, buf, strlen(buf));
dat.data = base64_decode(&dat.mdata, str, strlen(str));
// Start the unpersist routine.
lua_pushnil(misn->L);
pluto_unpersist(misn->L, mission_readLua, &dat);
mission_unpersistTable(misn->L);
// Cleanup.
free(dat.data);
}
} while(xml_nextNode(cur));

View File

@ -14,14 +14,16 @@
#define BUTTON_HEIGHT 30
// Externs.
extern int player_save(xmlTextWriterPtr writer); // A lot of stuff.
extern int player_save(xmlTextWriterPtr writer); // A lot of stuff.
extern int player_load(xmlNodePtr parent);
extern int missions_saveActive(xmlTextWriterPtr writer); // Active missions.
extern int missions_loadActive(xmlNodePtr parent);
extern int var_save(xmlTextWriterPtr writer); // misn var.
extern int var_save(xmlTextWriterPtr writer); // misn var.
extern int var_load(xmlNodePtr parent);
extern int pfaction_save(xmlTextWriterPtr writer); // Faction data.
extern int pfaction_save(xmlTextWriterPtr writer); // Faction data.
extern int pfaction_load(xmlNodePtr parent);
extern int hook_save(xmlTextWriterPtr writer); // Hooks.
extern int hook_load(xmlNodePtr parent);
extern void menu_main_close(void);
// Static.
static int save_data(xmlTextWriterPtr writer);
@ -33,9 +35,9 @@ static int load_game(char* file);
static int save_data(xmlTextWriterPtr writer) {
// The data itself.
if(player_save(writer) < 0) return -1;
if(missions_saveActive(writer) < 0) return -1;
//if(missions_saveActive(writer) < 0) return -1;
if(var_save(writer) < 0) return -1;
if(pfaction_save(writer) < 0) return -1;
//if(pfaction_save(writer) < 0) return -1;
return 0;
}
@ -171,8 +173,9 @@ static int load_game(char* file) {
player_load(node);
var_load(node);
missions_loadActive(node);
//missions_loadActive(node);
pfaction_load(node);
//hook_load(node);
xmlFreeDoc(doc);