[Add] First release of unidiff - Save changes to the universe in a diff format.
This commit is contained in:
parent
fef6cefe05
commit
fdd5e930f5
@ -1,6 +1,6 @@
|
|||||||
# OPTIONS.
|
# OPTIONS.
|
||||||
DEBUG := 1
|
#DEBUG := 1
|
||||||
#DEBUG_PARANOID := 1
|
DEBUG_PARANOID := 1
|
||||||
|
|
||||||
OS := LINUX
|
OS := LINUX
|
||||||
#OS := WIN32
|
#OS := WIN32
|
||||||
|
11
dat/unidiff.xml
Normal file
11
dat/unidiff.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<unidiffs>
|
||||||
|
<unidiff name="collective_dead">
|
||||||
|
<system name="C-28">
|
||||||
|
<planet name="S38729">remove</planet>
|
||||||
|
<fleet name="Collective Sml Swarm" chance="60">remove</fleet>
|
||||||
|
<fleet name="Collective Sml Swarm" chance="60">remove</fleet>
|
||||||
|
<fleet name="Collective Drone" chance="80">remove</fleet>
|
||||||
|
</system>
|
||||||
|
</unidiff>
|
||||||
|
</unidiffs>
|
@ -23,6 +23,7 @@
|
|||||||
#include "ltime.h"
|
#include "ltime.h"
|
||||||
#include "xml.h"
|
#include "xml.h"
|
||||||
#include "music.h"
|
#include "music.h"
|
||||||
|
#include "unidiff.h"
|
||||||
#include "misn_lua.h"
|
#include "misn_lua.h"
|
||||||
|
|
||||||
/* Similar to lua vars, but with less variety. */
|
/* Similar to lua vars, but with less variety. */
|
||||||
@ -156,6 +157,17 @@ static const luaL_reg hook_methods[] = {
|
|||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Diffs. */
|
||||||
|
static int diff_applyL(lua_State* L);
|
||||||
|
static int diff_removeL(lua_State* L);
|
||||||
|
static int diff_isappliedL(lua_State* L);
|
||||||
|
static const luaL_reg diff_methods[] = {
|
||||||
|
{ "apply", diff_applyL },
|
||||||
|
{ "remove", diff_removeL },
|
||||||
|
{ "isApplied", diff_isappliedL },
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
/* Register all the libaries. */
|
/* Register all the libaries. */
|
||||||
int misn_loadLibs(lua_State* L) {
|
int misn_loadLibs(lua_State* L) {
|
||||||
lua_loadLephisto(L);
|
lua_loadLephisto(L);
|
||||||
@ -915,3 +927,74 @@ static int hook_pilot(lua_State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup DIFF Universe Diff Lua Bindings.
|
||||||
|
*
|
||||||
|
* @brief Lua bindings to apply/remove Universe Diffs.
|
||||||
|
*
|
||||||
|
* Functions should be called like:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* diff.function(parameters)
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn static int diff_applyL(lua_State* L)
|
||||||
|
*
|
||||||
|
* @brief apply(string name)
|
||||||
|
*
|
||||||
|
* Applies a diff by name.
|
||||||
|
* @param name Name of the diff to apply.
|
||||||
|
*/
|
||||||
|
static int diff_applyL(lua_State* L) {
|
||||||
|
char* name;
|
||||||
|
|
||||||
|
if(lua_isstring(L, 1)) name = (char*)lua_tostring(L, 1);
|
||||||
|
else LLUA_INVALID_PARAMETER();
|
||||||
|
|
||||||
|
diff_apply(name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn static int diff_removeL(lua_State* L)
|
||||||
|
*
|
||||||
|
* @brief remove(string name)
|
||||||
|
*
|
||||||
|
* Removes a diff by name.
|
||||||
|
* @param name Name of the diff to remove.
|
||||||
|
*/
|
||||||
|
static int diff_removeL(lua_State* L) {
|
||||||
|
char* name;
|
||||||
|
|
||||||
|
if(lua_isstring(L, 1)) name = (char*)lua_tostring(L, 1);
|
||||||
|
else LLUA_INVALID_PARAMETER();
|
||||||
|
|
||||||
|
diff_remove(name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn static int diff_isappliedL(lua_State* L)
|
||||||
|
*
|
||||||
|
* @brief bool isApplied(string name)
|
||||||
|
*
|
||||||
|
* Check to see if a diff is currently applied.
|
||||||
|
* @param name Name of the diff to check.
|
||||||
|
* @return true if it is applied, false if it isn't.
|
||||||
|
*/
|
||||||
|
static int diff_isappliedL(lua_State* L) {
|
||||||
|
char* name;
|
||||||
|
if(lua_isstring(L, 1)) name = (char*)lua_tostring(L, 1);
|
||||||
|
else LLUA_INVALID_PARAMETER();
|
||||||
|
|
||||||
|
lua_pushboolean(L, diff_isApplied(name));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@ extern int hook_save(xmlTextWriterPtr writer); /* Hooks. */
|
|||||||
extern int hook_load(xmlNodePtr parent);
|
extern int hook_load(xmlNodePtr parent);
|
||||||
extern int space_sysSave(xmlTextWriterPtr writer); /* Space stuff. */
|
extern int space_sysSave(xmlTextWriterPtr writer); /* Space stuff. */
|
||||||
extern int space_sysLoad(xmlNodePtr parent);
|
extern int space_sysLoad(xmlNodePtr parent);
|
||||||
|
extern int diff_save(xmlTextWriterPtr writer);
|
||||||
|
extern int diff_load(xmlNodePtr parent);
|
||||||
extern void menu_main_close(void);
|
extern void menu_main_close(void);
|
||||||
/* Static. */
|
/* Static. */
|
||||||
static int save_data(xmlTextWriterPtr writer);
|
static int save_data(xmlTextWriterPtr writer);
|
||||||
@ -48,6 +50,7 @@ static int save_data(xmlTextWriterPtr writer) {
|
|||||||
if(var_save(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;
|
||||||
if(hook_save(writer) < 0) return -1;
|
if(hook_save(writer) < 0) return -1;
|
||||||
|
if(diff_save(writer) < 0) return -1;
|
||||||
if(space_sysSave(writer) < 0) return -1;
|
if(space_sysSave(writer) < 0) return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -212,6 +215,7 @@ static int load_game(char* file) {
|
|||||||
missions_loadActive(node);
|
missions_loadActive(node);
|
||||||
pfaction_load(node);
|
pfaction_load(node);
|
||||||
hook_load(node);
|
hook_load(node);
|
||||||
|
diff_load(node);
|
||||||
space_sysLoad(node);
|
space_sysLoad(node);
|
||||||
|
|
||||||
/* Need to run takeoff hooks since player just "took off". */
|
/* Need to run takeoff hooks since player just "took off". */
|
||||||
|
108
src/space.c
108
src/space.c
@ -727,6 +727,89 @@ static int planet_parse(Planet* planet, const xmlNodePtr parent) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn int system_addPlanet(StarSystem* sys, char* planetname)
|
||||||
|
*
|
||||||
|
* @brief Add a planet to a star system.
|
||||||
|
* @param sys Star System to add planet to.
|
||||||
|
* @param planetname Name of the planet to add.
|
||||||
|
* @return 0 on success.
|
||||||
|
*/
|
||||||
|
int system_addPlanet(StarSystem* sys, char* planetname) {
|
||||||
|
Planet* planet;
|
||||||
|
|
||||||
|
if(sys == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Check if need to grow the star system planet stack. */
|
||||||
|
sys->nplanets++;
|
||||||
|
if(sys->planets == NULL) {
|
||||||
|
sys->planets = malloc(sizeof(Planet*) * CHUNK_SIZE_SMALL);
|
||||||
|
}
|
||||||
|
else if(sys->nplanets > CHUNK_SIZE_SMALL) {
|
||||||
|
sys->planets = realloc(sys->planets, sizeof(Planet*) * sys->nplanets);
|
||||||
|
}
|
||||||
|
planet = planet_get(planetname);
|
||||||
|
sys->planets[sys->nplanets-1] = planet;
|
||||||
|
|
||||||
|
/* Add planet <-> star system to name stack. */
|
||||||
|
spacename_nstack++;
|
||||||
|
if(spacename_nstack > spacename_mstack) {
|
||||||
|
spacename_stack += CHUNK_SIZE;
|
||||||
|
planetname_stack = realloc(planetname_stack,
|
||||||
|
sizeof(char*) * spacename_mstack);
|
||||||
|
systemname_stack = realloc(systemname_stack,
|
||||||
|
sizeof(char*) * spacename_mstack);
|
||||||
|
}
|
||||||
|
planetname_stack[spacename_nstack-1] = planet->name;
|
||||||
|
systemname_stack[spacename_nstack-1] = sys->name;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn int system_rmPlanet(StarSystem* sys, char* planetname)
|
||||||
|
*
|
||||||
|
* @brief Remove a planet from a star system.
|
||||||
|
* @param sys Star System to remove planet from.
|
||||||
|
* @param planetname Name of the planet to remove.
|
||||||
|
* @return 0 on success.
|
||||||
|
*/
|
||||||
|
int system_rmPlanet(StarSystem* sys, char* planetname) {
|
||||||
|
int i;
|
||||||
|
Planet* planet;
|
||||||
|
|
||||||
|
if(sys == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Try to find planet. */
|
||||||
|
planet = planet_get(planetname);
|
||||||
|
for(i = 0; i < sys->nplanets; i++)
|
||||||
|
if(sys->planets[i] == planet)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Planet not found. */
|
||||||
|
if(i >= sys->nplanets)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Remove planet from system. */
|
||||||
|
sys->nplanets--;
|
||||||
|
memmove(&sys->planets[i], &sys->planets[i+1], sizeof(Planet*) * (sys->nplanets-i));
|
||||||
|
|
||||||
|
/* Remove from the name stack thingy. */
|
||||||
|
for(i = 0; i < spacename_nstack; i++)
|
||||||
|
if(strcmp(planetname, planetname_stack[i])==0) {
|
||||||
|
spacename_nstack--;
|
||||||
|
memmove(&planetname_stack[i], &planetname_stack[i+1],
|
||||||
|
sizeof(char*) * (spacename_nstack-i));
|
||||||
|
memmove(&systemname_stack[i], &systemname_stack[i+1],
|
||||||
|
sizeof(char*) * (spacename_nstack-i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse node 'parent' which should be the node of a system. */
|
/* Parse node 'parent' which should be the node of a system. */
|
||||||
/* Return the StarSystem fully loaded. */
|
/* Return the StarSystem fully loaded. */
|
||||||
static StarSystem* system_parse(StarSystem* sys, const xmlNodePtr parent) {
|
static StarSystem* system_parse(StarSystem* sys, const xmlNodePtr parent) {
|
||||||
@ -790,29 +873,8 @@ static StarSystem* system_parse(StarSystem* sys, const xmlNodePtr parent) {
|
|||||||
else if(xml_isNode(node, "planets")) {
|
else if(xml_isNode(node, "planets")) {
|
||||||
cur = node->children;
|
cur = node->children;
|
||||||
do {
|
do {
|
||||||
if(cur && xml_isNode(cur, "planet")) {
|
if(xml_isNode(cur, "planet"))
|
||||||
/* Add planet to system. */
|
system_addPlanet(sys, xml_get(cur));
|
||||||
sys->nplanets++;
|
|
||||||
if(sys->nplanets > size) {
|
|
||||||
size += CHUNK_SIZE_SMALL;
|
|
||||||
sys->planets = realloc(sys->planets, sizeof(Planet*) * size);
|
|
||||||
}
|
|
||||||
planet = planet_get(xml_get(cur));
|
|
||||||
sys->planets[sys->nplanets-1] = planet;
|
|
||||||
|
|
||||||
/* Add planet <-> star system to name stack. */
|
|
||||||
spacename_nstack++;
|
|
||||||
if(spacename_nstack > spacename_mstack) {
|
|
||||||
spacename_mstack += CHUNK_SIZE;
|
|
||||||
planetname_stack = realloc(planetname_stack,
|
|
||||||
sizeof(char*) * spacename_mstack);
|
|
||||||
systemname_stack = realloc(systemname_stack,
|
|
||||||
sizeof(char*) * spacename_mstack);
|
|
||||||
}
|
|
||||||
planetname_stack[spacename_nstack-1] = planet->name;
|
|
||||||
|
|
||||||
systemname_stack[spacename_nstack-1] = sys->name;
|
|
||||||
}
|
|
||||||
} while(xml_nextNode(cur));
|
} while(xml_nextNode(cur));
|
||||||
}
|
}
|
||||||
/* Load all the fleets. */
|
/* Load all the fleets. */
|
||||||
|
@ -142,6 +142,8 @@ void space_exit(void);
|
|||||||
char* planet_getSystem(char* planetname);
|
char* planet_getSystem(char* planetname);
|
||||||
Planet* planet_get(char* planetname);
|
Planet* planet_get(char* planetname);
|
||||||
char planet_getClass(Planet* p);
|
char planet_getClass(Planet* p);
|
||||||
|
int system_addPlanet(StarSystem* sys, char* planetname);
|
||||||
|
int system_rmPlanet(StarSystem* sys, char* planetname);
|
||||||
|
|
||||||
/* Render. */
|
/* Render. */
|
||||||
void space_render(const double dt);
|
void space_render(const double dt);
|
||||||
|
508
src/unidiff.c
Normal file
508
src/unidiff.c
Normal file
@ -0,0 +1,508 @@
|
|||||||
|
/**
|
||||||
|
* @file unidiff.c
|
||||||
|
*
|
||||||
|
* @brief Handles the application and removal of 'diffs' to the universe.
|
||||||
|
*
|
||||||
|
* Diffs allow changing planets, fleets, factions etc.. in the universe.
|
||||||
|
* These are meant to be applied after the player triggers them, mostly
|
||||||
|
* through missions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "lephisto.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "xml.h"
|
||||||
|
#include "space.h"
|
||||||
|
#include "pack.h"
|
||||||
|
#include "unidiff.h"
|
||||||
|
|
||||||
|
#define CHUNK_SIZE 32 /**< Size of chunk to allocate. */
|
||||||
|
#define DIFF_DATA "../dat/unidiff.xml" /**< Unidff XML file. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum UniHunkTargetType_t
|
||||||
|
*
|
||||||
|
* @brief Represents the possible hunk targets.
|
||||||
|
*/
|
||||||
|
typedef enum UniHunkTargetType_ {
|
||||||
|
HUNK_TARGET_NONE,
|
||||||
|
HUNK_TARGET_SYSTEM
|
||||||
|
} UniHunkTargetType_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct UniHunkTarget_t
|
||||||
|
*
|
||||||
|
* @brief Represents the hunks target.
|
||||||
|
*/
|
||||||
|
typedef struct UniHunkTarget_ {
|
||||||
|
UniHunkTargetType_t type;
|
||||||
|
union {
|
||||||
|
char* name;
|
||||||
|
} u;
|
||||||
|
} UniHunkTarget_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum UniHunkType_t
|
||||||
|
*
|
||||||
|
* @brief Represents the different type of hunk actions.
|
||||||
|
*/
|
||||||
|
typedef enum UniHunkType_ {
|
||||||
|
HUNK_TYPE_NONE,
|
||||||
|
/* Target should be system. */
|
||||||
|
HUNK_TYPE_PLANET_ADD,
|
||||||
|
HUNK_TYPE_PLANET_REMOVE,
|
||||||
|
HUNK_TYPE_FLEET_ADD,
|
||||||
|
HUNK_TYPE_FLEET_REMOVE
|
||||||
|
} UniHunkType_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct UniHunk_t
|
||||||
|
*
|
||||||
|
* @brief Represents a single hunk in the diff.
|
||||||
|
*/
|
||||||
|
typedef struct UniHunk_ {
|
||||||
|
UniHunkTarget_t target; /**< Hunk's target. */
|
||||||
|
|
||||||
|
UniHunkType_t type; /**< Type of hunk it is. */
|
||||||
|
union {
|
||||||
|
char* name;
|
||||||
|
} u; /* Actual data to patch. */
|
||||||
|
} UniHunk_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct UniDiff_t
|
||||||
|
*
|
||||||
|
* @brief Represents each Universe Diff.
|
||||||
|
*/
|
||||||
|
typedef struct UniDiff_ {
|
||||||
|
char* name; /**< Name of the diff. */
|
||||||
|
|
||||||
|
UniHunk_t* applied; /**< Applied hunks. */
|
||||||
|
int napplied; /**< Number of applied hunks. */
|
||||||
|
int mapplied; /**< Memory of applied hunks. */
|
||||||
|
|
||||||
|
UniHunk_t* failed; /**< Failed hunks. */
|
||||||
|
int nfailed; /**< Number of failed hunks. */
|
||||||
|
int mfailed; /**< Memory of failed hunks. */
|
||||||
|
} UniDiff_t;
|
||||||
|
|
||||||
|
/* Diff stack. */
|
||||||
|
static UniDiff_t* diff_stack = NULL; /**< Currently applied universe diffs. */
|
||||||
|
static int diff_nstack = 0; /**< Number of diffs in the stack. */
|
||||||
|
static int diff_mstack = 0; /**< Currently allocated diffs. */
|
||||||
|
|
||||||
|
static UniDiff_t* diff_get(char* name);
|
||||||
|
static UniDiff_t* diff_newDiff(void);
|
||||||
|
static int diff_removeDiff(UniDiff_t* diff);
|
||||||
|
static int diff_patch(xmlNodePtr parent);
|
||||||
|
static int diff_patchHunk(UniHunk_t* hunk);
|
||||||
|
static void diff_hunkFailed(UniDiff_t* diff, UniHunk_t* hunk);
|
||||||
|
static void diff_hunkSuccess(UniDiff_t* diff, UniHunk_t* hunk);
|
||||||
|
static void diff_cleanup(UniDiff_t* diff);
|
||||||
|
static void diff_cleanupHunk(UniHunk_t* hunk);
|
||||||
|
/* Externed. */
|
||||||
|
int diff_save(xmlTextWriterPtr writer);
|
||||||
|
int diff_load(xmlNodePtr parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn int diff_isApplied(char* name)
|
||||||
|
*
|
||||||
|
* @brief Check if a diff is currently applied.
|
||||||
|
* @param name Diff to check.
|
||||||
|
* @return 0 if it's not applied, 1 if it is.
|
||||||
|
*/
|
||||||
|
int diff_isApplied(char* name) {
|
||||||
|
if(diff_get(name) != NULL)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn static UniDiff_t* diff_get(char* name)
|
||||||
|
*
|
||||||
|
* @brief Get a diff by name.
|
||||||
|
* @param name Name of the diff to get.
|
||||||
|
* @return The diff if found or NULL if not found.
|
||||||
|
*/
|
||||||
|
static UniDiff_t* diff_get(char* name) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < diff_nstack; i++)
|
||||||
|
if(strcmp(diff_stack[i].name, name)==0)
|
||||||
|
return &diff_stack[i];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn int diff_apply(char* name)
|
||||||
|
*
|
||||||
|
* @brief Applies a diff to the universe.
|
||||||
|
* @param name Diff to apply.
|
||||||
|
* @return 0 on success.
|
||||||
|
*/
|
||||||
|
int diff_apply(char* name) {
|
||||||
|
xmlNodePtr node;
|
||||||
|
xmlDocPtr doc;
|
||||||
|
uint32_t bufsize;
|
||||||
|
char* buf;
|
||||||
|
char* diffname;
|
||||||
|
|
||||||
|
/* Check if already applied. */
|
||||||
|
if(diff_isApplied(name))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
buf = pack_readfile(DATA, DIFF_DATA, &bufsize);
|
||||||
|
|
||||||
|
node = doc->xmlChildrenNode;
|
||||||
|
if(strcmp((char*)node->name, "unidiffs")) {
|
||||||
|
WARN("Malformed unidiff file: missing root element 'unidiffs'");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = node->xmlChildrenNode; /* First system node. */
|
||||||
|
if(node == NULL) {
|
||||||
|
ERR("Malformed unidiff file: does not contain elements");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(xml_isNode(node, "unidiff")) {
|
||||||
|
/* Check to see if it's the diff we're looking for. */
|
||||||
|
xmlr_attr(node, "name", diffname);
|
||||||
|
if(strcmp(diffname, name)==0) {
|
||||||
|
diff_patch(node);
|
||||||
|
free(diffname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
free(diffname);
|
||||||
|
}
|
||||||
|
} while(xml_nextNode(node));
|
||||||
|
|
||||||
|
WARN("UniDiff '%s' not found in "DIFF_DATA".", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn static int diff_patch(xmlNodePtr parent)
|
||||||
|
*
|
||||||
|
* @brief Actually applies a diff in XML node form.
|
||||||
|
* @param parent Node containing the diff information.
|
||||||
|
* @return 0 on success.
|
||||||
|
*/
|
||||||
|
static int diff_patch(xmlNodePtr parent) {
|
||||||
|
UniDiff_t* diff;
|
||||||
|
UniHunk_t base, hunk;
|
||||||
|
xmlNodePtr node, cur;
|
||||||
|
char* buf;
|
||||||
|
|
||||||
|
/* Prepare it. */
|
||||||
|
diff = diff_newDiff();
|
||||||
|
memset(diff, 0, sizeof(UniDiff_t));
|
||||||
|
xmlr_attr(parent, "name", diff->name);
|
||||||
|
|
||||||
|
node = parent->xmlChildrenNode;
|
||||||
|
do {
|
||||||
|
if(xml_isNode(node, "system")) {
|
||||||
|
/* Set the target. */
|
||||||
|
memset(&base, 0, sizeof(UniHunk_t));
|
||||||
|
base.target.type = HUNK_TARGET_SYSTEM;
|
||||||
|
xmlr_attr(node, "name", base.target.u.name);
|
||||||
|
if(base.target.u.name == NULL)
|
||||||
|
WARN("UniDiff '%s' has a system node without a 'name' tag", diff->name);
|
||||||
|
|
||||||
|
/* Now parse the possible changes. */
|
||||||
|
cur = node->xmlChildrenNode;
|
||||||
|
do {
|
||||||
|
if(xml_isNode(cur, "planet")) {
|
||||||
|
memcpy(&hunk, &base, sizeof(UniHunk_t));
|
||||||
|
|
||||||
|
/* Get the planet to modify. */
|
||||||
|
xmlr_attr(cur, "name", hunk.u.name);
|
||||||
|
|
||||||
|
/* Get the type. */
|
||||||
|
buf = xml_get(cur);
|
||||||
|
if(strcmp(buf, "add")==0) {
|
||||||
|
hunk.type = HUNK_TYPE_PLANET_ADD;
|
||||||
|
}
|
||||||
|
else if(strcmp(buf, "remove")==0) {
|
||||||
|
hunk.type = HUNK_TYPE_PLANET_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(diff_patchHunk(&hunk) < 0)
|
||||||
|
diff_hunkFailed(diff, &hunk);
|
||||||
|
else
|
||||||
|
diff_hunkSuccess(diff, &hunk);
|
||||||
|
}
|
||||||
|
else if(xml_isNode(cur, "fleet")) {
|
||||||
|
memcpy(&hunk, &base, sizeof(UniHunk_t));
|
||||||
|
|
||||||
|
/* Get the planet to modify. */
|
||||||
|
xmlr_attr(cur, "name", hunk.u.name);
|
||||||
|
|
||||||
|
/* Get the type. */
|
||||||
|
buf = xml_get(cur);
|
||||||
|
if(strcmp(buf, "add")==0) {
|
||||||
|
hunk.type = HUNK_TYPE_FLEET_ADD;
|
||||||
|
}
|
||||||
|
else if(strcmp(buf, "remove")==0) {
|
||||||
|
hunk.type = HUNK_TYPE_FLEET_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(diff_patchHunk(&hunk) < 0)
|
||||||
|
diff_hunkFailed(diff, &hunk);
|
||||||
|
else
|
||||||
|
diff_hunkSuccess(diff, &hunk);
|
||||||
|
}
|
||||||
|
} while(xml_nextNode(cur));
|
||||||
|
}
|
||||||
|
} while(xml_nextNode(node));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn static int diff_patchHunk(UniHunk_t* hunk)
|
||||||
|
*
|
||||||
|
* @brief Applies a hunk and adds it to the diff.
|
||||||
|
* @param diff Diff to which the hunk belongs.
|
||||||
|
* @param hunk Hunk to apply.
|
||||||
|
*/
|
||||||
|
static int diff_patchHunk(UniHunk_t* hunk) {
|
||||||
|
switch(hunk->type) {
|
||||||
|
/* Adding a planet. */
|
||||||
|
case HUNK_TYPE_PLANET_ADD:
|
||||||
|
return system_addPlanet(system_get(hunk->target.u.name), hunk->u.name);
|
||||||
|
/* Removing a planet. */
|
||||||
|
case HUNK_TYPE_PLANET_REMOVE:
|
||||||
|
return system_rmPlanet(system_get(hunk->target.u.name), hunk->u.name);
|
||||||
|
|
||||||
|
case HUNK_TYPE_FLEET_ADD:
|
||||||
|
break;
|
||||||
|
case HUNK_TYPE_FLEET_REMOVE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARN("Unkown hunk type '%d'.", hunk->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn static void diff_hunkFailed(UniDiff_t* diff, UniHunk_t* hunk)
|
||||||
|
*
|
||||||
|
* @brief Add a hunk to the failed list.
|
||||||
|
* @param diff Diff to add hunk to.
|
||||||
|
* @param hunk Hunk that failed to apply.
|
||||||
|
*/
|
||||||
|
static void diff_hunkFailed(UniDiff_t* diff, UniHunk_t* hunk) {
|
||||||
|
if(diff == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
diff->nfailed++;
|
||||||
|
if(diff->nfailed > diff->mfailed) {
|
||||||
|
diff->mfailed += CHUNK_SIZE;
|
||||||
|
diff->failed = realloc(diff->failed, sizeof(UniHunk_t) * diff->mfailed);
|
||||||
|
}
|
||||||
|
memcpy(&diff->failed[diff->nfailed-1], &hunk, sizeof(UniHunk_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn static void diff_hunkSuccess(UniDiff_t* diff, UniHunk_t* hunk)
|
||||||
|
*
|
||||||
|
* @brief Add a hunk to the applied list.
|
||||||
|
* @param diff Diff to add hunk to.
|
||||||
|
* @param hunk Hunk that applied correctly.
|
||||||
|
*/
|
||||||
|
static void diff_hunkSuccess(UniDiff_t* diff, UniHunk_t* hunk) {
|
||||||
|
if(diff == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
diff->napplied++;
|
||||||
|
if(diff->napplied > diff->mapplied) {
|
||||||
|
diff->mapplied += CHUNK_SIZE;
|
||||||
|
diff->applied = realloc(diff->applied, sizeof(UniHunk_t) * diff->mapplied);
|
||||||
|
}
|
||||||
|
memcpy(&diff->applied[diff->napplied-1], &hunk, sizeof(UniHunk_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn void diff_remove(char* name)
|
||||||
|
*
|
||||||
|
* @brief Remove a diff from the universe.
|
||||||
|
* @param name Diff to remove.
|
||||||
|
*/
|
||||||
|
void diff_remove(char* name) {
|
||||||
|
UniDiff_t* diff;
|
||||||
|
|
||||||
|
/* check if already applied. */
|
||||||
|
diff = diff_get(name);
|
||||||
|
if(diff == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
diff_removeDiff(diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn void diff_clear(void)
|
||||||
|
*/
|
||||||
|
void diff_clear(void) {
|
||||||
|
while(diff_nstack > 0) {
|
||||||
|
diff_removeDiff(&diff_stack[diff_nstack-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn static UniDiff_t* diff_newDiff(void)
|
||||||
|
*
|
||||||
|
* @brief Creates a new UniDiff_t for usage.
|
||||||
|
* @return A newly created UniDiff_t.
|
||||||
|
*/
|
||||||
|
static UniDiff_t* diff_newDiff(void) {
|
||||||
|
/* Check if needs initialization. */
|
||||||
|
if(diff_stack == NULL) {
|
||||||
|
diff_mstack = CHUNK_SIZE;
|
||||||
|
diff_stack = malloc(diff_mstack * sizeof(UniDiff_t));
|
||||||
|
diff_nstack = 0;
|
||||||
|
return &diff_stack[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
diff_nstack++;
|
||||||
|
/* Check if need to grow. */
|
||||||
|
if(diff_nstack > diff_mstack) {
|
||||||
|
diff_mstack += CHUNK_SIZE;
|
||||||
|
diff_stack = realloc(diff_stack, diff_mstack * sizeof(UniDiff_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
return &diff_stack[diff_nstack-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn static int diff_removeDiff(UniDiff_t* diff)
|
||||||
|
*
|
||||||
|
* @brief Removes a diff.
|
||||||
|
* @param diff Diff to remove.
|
||||||
|
* @return 0 on success.
|
||||||
|
*/
|
||||||
|
static int diff_removeDiff(UniDiff_t* diff) {
|
||||||
|
int i;
|
||||||
|
UniHunk_t hunk;
|
||||||
|
|
||||||
|
for(i = 0; i < diff->napplied; i++) {
|
||||||
|
memcpy(&hunk, &diff->applied[i], sizeof(UniHunk_t));
|
||||||
|
/* Invert the type for reverting. */
|
||||||
|
switch(hunk.type) {
|
||||||
|
case HUNK_TYPE_PLANET_ADD:
|
||||||
|
hunk.type = HUNK_TYPE_PLANET_REMOVE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HUNK_TYPE_PLANET_REMOVE:
|
||||||
|
hunk.type = HUNK_TYPE_PLANET_ADD;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HUNK_TYPE_FLEET_ADD:
|
||||||
|
hunk.type = HUNK_TYPE_FLEET_REMOVE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HUNK_TYPE_FLEET_REMOVE:
|
||||||
|
hunk.type = HUNK_TYPE_FLEET_ADD;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
WARN("Unkown Hunk type '%d'.", hunk.type);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff_patchHunk(&hunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff_cleanup(diff);
|
||||||
|
diff_nstack--;
|
||||||
|
i = diff - diff_stack;
|
||||||
|
memmove(&diff_stack[i], &diff_stack[i+1], sizeof(UniDiff_t) * (diff_nstack-i));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn static void diff_cleanup(UniDiff_t* diff)
|
||||||
|
*
|
||||||
|
* @brief Clean up a diff.
|
||||||
|
* @param diff Diff to clean up.
|
||||||
|
*/
|
||||||
|
static void diff_cleanup(UniDiff_t* diff) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
free(diff->name);
|
||||||
|
for(i = 0; i < diff->napplied; i++)
|
||||||
|
diff_cleanupHunk(&diff->applied[i]);
|
||||||
|
if(diff->applied != NULL)
|
||||||
|
free(diff->applied);
|
||||||
|
for(i = 0; i < diff->nfailed; i++)
|
||||||
|
diff_cleanupHunk(&diff->failed[i]);
|
||||||
|
if(diff->failed != NULL)
|
||||||
|
free(diff->failed);
|
||||||
|
memset(diff, 0, sizeof(UniDiff_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn static void diff_cleanupHunk(UniHunk_t* hunk)
|
||||||
|
*
|
||||||
|
* @brief Clean up a hunk.
|
||||||
|
* @param hunk Hunk to clean up.
|
||||||
|
*/
|
||||||
|
static void diff_cleanupHunk(UniHunk_t* hunk) {
|
||||||
|
if(hunk->target.u.name != NULL)
|
||||||
|
free(hunk->target.u.name);
|
||||||
|
if(hunk->u.name != NULL)
|
||||||
|
free(hunk->u.name);
|
||||||
|
memset(hunk, 0, sizeof(UniHunk_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn int diff_save(xmlTextWriterPtr writer)
|
||||||
|
*
|
||||||
|
* @brief Save the active diffs.
|
||||||
|
* @param writer XML Writer to use.
|
||||||
|
* @return 0 on success.
|
||||||
|
*/
|
||||||
|
int diff_save(xmlTextWriterPtr writer) {
|
||||||
|
int i;
|
||||||
|
UniDiff_t* diff;
|
||||||
|
|
||||||
|
xmlw_startElem(writer, "diffs");
|
||||||
|
for(i = 0; i < diff_nstack; i++) {
|
||||||
|
diff = &diff_stack[i];
|
||||||
|
|
||||||
|
xmlw_elem(writer, "diff", diff->name);
|
||||||
|
}
|
||||||
|
xmlw_endElem(writer); /* "diffs" */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn int diff_load(xmlNodePtr parent)
|
||||||
|
*
|
||||||
|
* @brief Loads the diffs.
|
||||||
|
* @param parent Parent node containing diffs.
|
||||||
|
* @return 0 on success.
|
||||||
|
*/
|
||||||
|
int diff_load(xmlNodePtr parent) {
|
||||||
|
xmlNodePtr node, cur;
|
||||||
|
|
||||||
|
diff_clear();
|
||||||
|
|
||||||
|
node = parent->xmlChildrenNode;
|
||||||
|
do {
|
||||||
|
if(xml_isNode(node, "diffs")) {
|
||||||
|
cur = node->xmlChildrenNode;
|
||||||
|
do {
|
||||||
|
if(xml_isNode(cur, "diff"))
|
||||||
|
diff_apply(xml_get(cur));
|
||||||
|
} while(xml_nextNode(cur));
|
||||||
|
}
|
||||||
|
} while(xml_nextNode(node));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
7
src/unidiff.h
Normal file
7
src/unidiff.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int diff_apply(char* name);
|
||||||
|
void diff_remove(char* name);
|
||||||
|
void diff_clear(void);
|
||||||
|
int diff_isApplied(char* name);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user