naev 0.10.4
unidiff.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
14#include <stdlib.h>
15
16#include "naev.h"
19#include "unidiff.h"
20
21#include "conf.h"
22#include "array.h"
23#include "economy.h"
24#include "log.h"
25#include "map_overlay.h"
26#include "ndata.h"
27#include "nstring.h"
28#include "nxml.h"
29#include "safelanes.h"
30#include "space.h"
31#include "player.h"
32
36typedef struct UniDiffData_ {
37 char *name;
38 char *filename;
47typedef enum UniHunkTargetType_ {
48 HUNK_TARGET_NONE,
49 HUNK_TARGET_SYSTEM,
50 HUNK_TARGET_SPOB,
51 HUNK_TARGET_TECH,
52 HUNK_TARGET_FACTION,
54
60typedef struct UniHunkTarget_ {
62 union {
63 char *name;
64 } u;
66
72typedef enum UniHunkType_ {
73 HUNK_TYPE_NONE,
74 /* Target should be system. */
75 HUNK_TYPE_SPOB_ADD,
76 HUNK_TYPE_SPOB_REMOVE,
77 HUNK_TYPE_VSPOB_ADD,
78 HUNK_TYPE_VSPOB_REMOVE,
79 HUNK_TYPE_JUMP_ADD,
80 HUNK_TYPE_JUMP_REMOVE,
81 HUNK_TYPE_SSYS_BACKGROUND,
82 HUNK_TYPE_SSYS_BACKGROUND_REVERT, /* For internal usage. */
83 HUNK_TYPE_SSYS_FEATURES,
84 HUNK_TYPE_SSYS_FEATURES_REVERT, /* For internal usage. */
85 /* Target should be tech. */
86 HUNK_TYPE_TECH_ADD,
87 HUNK_TYPE_TECH_REMOVE,
88 /* Target should be spob. */
89 HUNK_TYPE_SPOB_FACTION,
90 HUNK_TYPE_SPOB_FACTION_REMOVE, /* For internal usage. */
91 HUNK_TYPE_SPOB_POPULATION,
92 HUNK_TYPE_SPOB_POPULATION_REMOVE, /* For internal usage. */
93 HUNK_TYPE_SPOB_DISPLAYNAME,
94 HUNK_TYPE_SPOB_DISPLAYNAME_REVERT, /* For internal usage. */
95 HUNK_TYPE_SPOB_DESCRIPTION,
96 HUNK_TYPE_SPOB_DESCRIPTION_REVERT, /* For internal usage. */
97 HUNK_TYPE_SPOB_BAR,
98 HUNK_TYPE_SPOB_BAR_REVERT, /* For internal usage. */
99 HUNK_TYPE_SPOB_SERVICE_ADD,
100 HUNK_TYPE_SPOB_SERVICE_REMOVE,
101 HUNK_TYPE_SPOB_TECH_ADD,
102 HUNK_TYPE_SPOB_TECH_REMOVE,
103 HUNK_TYPE_SPOB_TAG_ADD,
104 HUNK_TYPE_SPOB_TAG_REMOVE,
105 HUNK_TYPE_SPOB_SPACE,
106 HUNK_TYPE_SPOB_SPACE_REVERT, /* For internal usage. */
107 HUNK_TYPE_SPOB_EXTERIOR,
108 HUNK_TYPE_SPOB_EXTERIOR_REVERT, /* For internal usage. */
109 HUNK_TYPE_SPOB_LUA,
110 HUNK_TYPE_SPOB_LUA_REVERT, /* For internal usage. */
111 /* Target should be faction. */
112 HUNK_TYPE_FACTION_VISIBLE,
113 HUNK_TYPE_FACTION_INVISIBLE,
114 HUNK_TYPE_FACTION_ALLY,
115 HUNK_TYPE_FACTION_ENEMY,
116 HUNK_TYPE_FACTION_NEUTRAL,
117 HUNK_TYPE_FACTION_REALIGN, /* For internal usage. */
119
125typedef struct UniHunk_ {
129 xmlNodePtr node;
130 union {
131 char *name;
132 int data;
133 } u;
134 union {
135 const char *name; /* We just save the pointer, so keep as const. */
136 int data;
137 } o;
138} UniHunk_t;
139
145typedef struct UniDiff_ {
146 char *name;
149} UniDiff_t;
150
151/*
152 * Diff stack.
153 */
154static UniDiff_t *diff_stack = NULL;
156/* Useful variables. */
157static int diff_universe_changed = 0;
158static int diff_universe_defer = 0;
160/*
161 * Prototypes.
162 */
163static int diff_applyInternal( const char *name, int oneshot );
164NONNULL( 1 ) static UniDiff_t *diff_get( const char *name );
165static UniDiff_t *diff_newDiff (void);
166static int diff_removeDiff( UniDiff_t *diff );
167static int diff_patchSystem( UniDiff_t *diff, xmlNodePtr node );
168static int diff_patchTech( UniDiff_t *diff, xmlNodePtr node );
169static int diff_patch( xmlNodePtr parent );
170static int diff_patchHunk( UniHunk_t *hunk );
171static void diff_hunkFailed( UniDiff_t *diff, UniHunk_t *hunk );
172static void diff_hunkSuccess( UniDiff_t *diff, UniHunk_t *hunk );
173static void diff_cleanup( UniDiff_t *diff );
174static void diff_cleanupHunk( UniHunk_t *hunk );
175/* Misc. */;
176static int diff_checkUpdateUniverse (void);
177/* Externed. */
178int diff_save( xmlTextWriterPtr writer );
179int diff_load( xmlNodePtr parent );
184static int diff_cmp( const void *p1, const void *p2 )
185{
186 const UniDiffData_t *d1, *d2;
187 d1 = (const UniDiffData_t*) p1;
188 d2 = (const UniDiffData_t*) p2;
189 return strcmp( d1->name, d2->name );
190}
191
198{
199 Uint32 time = SDL_GetTicks();
200 char **diff_files = ndata_listRecursive( UNIDIFF_DATA_PATH );
202 for (int i=0; i<array_size(diff_files); i++ ) {
203 xmlDocPtr doc;
204 xmlNodePtr node;
205 UniDiffData_t *diff;
206
207 /* Parse the header. */
208 doc = xml_parsePhysFS( diff_files[i] );
209 if (doc == NULL) {
210 free( diff_files[i] );
211 continue;
212 }
213
214 node = doc->xmlChildrenNode;
215 if (!xml_isNode(node,"unidiff")) {
216 WARN( _("Malformed XML header for '%s' UniDiff: missing root element '%s'"), diff_files[i], "unidiff" );
217 xmlFreeDoc( doc );
218 free( diff_files[i] );
219 continue;
220 }
221
222 diff = &array_grow(&diff_available);
223 diff->filename = diff_files[i];
224 xmlr_attr_strd(node, "name", diff->name);
225 xmlFreeDoc(doc);
226 }
227 array_free( diff_files );
229
230 /* Sort and warn about duplicates. */
231 qsort( diff_available, array_size(diff_available), sizeof(UniDiffData_t), diff_cmp );
232 for (int i=0; i<array_size(diff_available)-1; i++) {
234 UniDiffData_t *dn = &diff_available[i+1];
235 if (strcmp( d->name, dn->name )==0)
236 WARN(_("Two unidiff have the same name '%s'!"), d->name );
237 }
238
239 if (conf.devmode) {
240 time = SDL_GetTicks() - time;
241 DEBUG( n_("Loaded %d UniDiff in %.3f s", "Loaded %d UniDiffs in %.3f s", array_size(diff_available) ), array_size(diff_available), time/1000. );
242 }
243 else
244 DEBUG( n_("Loaded %d UniDiff", "Loaded %d UniDiffs", array_size(diff_available) ), array_size(diff_available) );
245
246 return 0;
247}
248
255int diff_isApplied( const char *name )
256{
257 if (diff_get(name) != NULL)
258 return 1;
259 return 0;
260}
261
268static UniDiff_t* diff_get( const char *name )
269{
270 for (int i=0; i<array_size(diff_stack); i++)
271 if (strcmp(diff_stack[i].name,name)==0)
272 return &diff_stack[i];
273 return NULL;
274}
275
282int diff_apply( const char *name )
283{
284 return diff_applyInternal( name, 1 );
285}
286
294static int diff_applyInternal( const char *name, int oneshot )
295{
296 xmlNodePtr node;
297 xmlDocPtr doc;
299
300 /* Check if already applied. */
301 if (diff_isApplied(name))
302 return 0;
303
304 /* Reset change variable. */
305 if (oneshot && !diff_universe_defer)
307
308 const UniDiffData_t q = { .name = (char*)name };
309 d = bsearch( &q, diff_available, array_size(diff_available), sizeof(UniDiffData_t), diff_cmp );
310 if (d == NULL) {
311 WARN(_("UniDiff '%s' not found in %s!"), name, UNIDIFF_DATA_PATH);
312 return -1;
313 }
314
315 doc = xml_parsePhysFS( d->filename );
316
317 node = doc->xmlChildrenNode;
318 if (strcmp((char*)node->name,"unidiff")) {
319 ERR(_("Malformed unidiff file: missing root element 'unidiff'"));
320 return 0;
321 }
322
323 /* Apply it. */
324 diff_patch( node );
325
326 xmlFreeDoc(doc);
327
328 /* Update universe. */
329 if (oneshot)
331
332 return 0;
333}
334
342static int diff_patchSystem( UniDiff_t *diff, xmlNodePtr node )
343{
344 UniHunk_t base, hunk;
345 xmlNodePtr cur;
346 char *buf;
347
348 /* Set the target. */
349 memset(&base, 0, sizeof(UniHunk_t));
350 base.target.type = HUNK_TARGET_SYSTEM;
351 xmlr_attr_strd(node,"name",base.target.u.name);
352 if (base.target.u.name==NULL) {
353 WARN(_("Unidiff '%s' has a system node without a 'name' tag, not applying."), diff->name);
354 return -1;
355 }
356
357 /* Now parse the possible changes. */
358 cur = node->xmlChildrenNode;
359 do {
360 xml_onlyNodes(cur);
361 if (xml_isNode(cur,"spob")) {
362 buf = xml_get( cur );
363 if ( buf == NULL ) {
364 WARN( _( "Unidiff '%s': Null hunk type." ), diff->name );
365 continue;
366 }
367
368 hunk.target.type = base.target.type;
369 hunk.target.u.name = strdup(base.target.u.name);
370
371 /* Get the spob to modify. */
372 xmlr_attr_strd(cur,"name",hunk.u.name);
373
374 /* Get the type. */
375 if (strcmp(buf,"add")==0)
376 hunk.type = HUNK_TYPE_SPOB_ADD;
377 else if (strcmp(buf,"remove")==0)
378 hunk.type = HUNK_TYPE_SPOB_REMOVE;
379 else
380 WARN(_("Unidiff '%s': Unknown hunk type '%s' for spob '%s'."), diff->name, buf, hunk.u.name);
381
382 /* Apply diff. */
383 if (diff_patchHunk( &hunk ) < 0)
384 diff_hunkFailed( diff, &hunk );
385 else
386 diff_hunkSuccess( diff, &hunk );
387 continue;
388 }
389 else if (xml_isNode(cur,"spob_virtual")) {
390 buf = xml_get( cur );
391 if ( buf == NULL ) {
392 WARN( _( "Unidiff '%s': Null hunk type." ), diff->name );
393 continue;
394 }
395
396 hunk.target.type = base.target.type;
397 hunk.target.u.name = strdup(base.target.u.name);
398
399 /* Get the spob to modify. */
400 xmlr_attr_strd(cur,"name",hunk.u.name);
401
402 /* Get the type. */
403 if (strcmp(buf,"add")==0)
404 hunk.type = HUNK_TYPE_VSPOB_ADD;
405 else if (strcmp(buf,"remove")==0)
406 hunk.type = HUNK_TYPE_VSPOB_REMOVE;
407 else
408 WARN(_("Unidiff '%s': Unknown hunk type '%s' for virtual spob '%s'."), diff->name, buf, hunk.u.name);
409
410 /* Apply diff. */
411 if (diff_patchHunk( &hunk ) < 0)
412 diff_hunkFailed( diff, &hunk );
413 else
414 diff_hunkSuccess( diff, &hunk );
415 continue;
416 }
417 else if (xml_isNode(cur,"jump")) {
418 buf = xml_get( cur );
419 if (buf == NULL) {
420 WARN( _( "Unidiff '%s': Null hunk type." ), diff->name );
421 continue;
422 }
423
424 hunk.target.type = base.target.type;
425 hunk.target.u.name = strdup(base.target.u.name);
426
427 /* Get the jump point to modify. */
428 xmlr_attr_strd(cur,"target",hunk.u.name);
429
430 /* Get the type. */
431 if (strcmp(buf,"add")==0)
432 hunk.type = HUNK_TYPE_JUMP_ADD;
433 else if (strcmp(buf,"remove")==0)
434 hunk.type = HUNK_TYPE_JUMP_REMOVE;
435 else
436 WARN(_("Unidiff '%s': Unknown hunk type '%s' for jump '%s'."), diff->name, buf, hunk.u.name);
437
438 hunk.node = cur;
439
440 /* Apply diff. */
441 if (diff_patchHunk( &hunk ) < 0)
442 diff_hunkFailed( diff, &hunk );
443 else
444 diff_hunkSuccess( diff, &hunk );
445 continue;
446 }
447 else if (xml_isNode(cur,"background")) {
448 hunk.target.type = base.target.type;
449 hunk.target.u.name = strdup(base.target.u.name);
450 hunk.type = HUNK_TYPE_SSYS_BACKGROUND;
451 hunk.u.name = xml_getStrd(cur);
452
453 /* Apply diff. */
454 if (diff_patchHunk( &hunk ) < 0)
455 diff_hunkFailed( diff, &hunk );
456 else
457 diff_hunkSuccess( diff, &hunk );
458 continue;
459 }
460 else if (xml_isNode(cur,"features")) {
461 hunk.target.type = base.target.type;
462 hunk.target.u.name = strdup(base.target.u.name);
463 hunk.type = HUNK_TYPE_SSYS_FEATURES;
464 hunk.u.name = xml_getStrd(cur);
465
466 /* Apply diff. */
467 if (diff_patchHunk( &hunk ) < 0)
468 diff_hunkFailed( diff, &hunk );
469 else
470 diff_hunkSuccess( diff, &hunk );
471 continue;
472 }
473 WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, node->name);
474 } while (xml_nextNode(cur));
475
476 /* Clean up some stuff. */
477 free(base.target.u.name);
478 base.target.u.name = NULL;
479
480 return 0;
481}
482
490static int diff_patchTech( UniDiff_t *diff, xmlNodePtr node )
491{
492 UniHunk_t base, hunk;
493 xmlNodePtr cur;
494
495 /* Set the target. */
496 memset(&base, 0, sizeof(UniHunk_t));
497 base.target.type = HUNK_TARGET_TECH;
498 xmlr_attr_strd(node,"name",base.target.u.name);
499 if (base.target.u.name==NULL) {
500 WARN(_("Unidiff '%s' has an target node without a 'name' tag"), diff->name);
501 return -1;
502 }
503
504 /* Now parse the possible changes. */
505 cur = node->xmlChildrenNode;
506 do {
507 xml_onlyNodes(cur);
508 if (xml_isNode(cur,"add")) {
509 hunk.target.type = base.target.type;
510 hunk.target.u.name = strdup(base.target.u.name);
511
512 /* Outfit type is constant. */
513 hunk.type = HUNK_TYPE_TECH_ADD;
514
515 /* Get the data. */
516 hunk.u.name = xml_getStrd(cur);
517
518 /* Apply diff. */
519 if (diff_patchHunk( &hunk ) < 0)
520 diff_hunkFailed( diff, &hunk );
521 else
522 diff_hunkSuccess( diff, &hunk );
523 continue;
524 }
525 else if (xml_isNode(cur,"remove")) {
526 hunk.target.type = base.target.type;
527 hunk.target.u.name = strdup(base.target.u.name);
528
529 /* Outfit type is constant. */
530 hunk.type = HUNK_TYPE_TECH_REMOVE;
531
532 /* Get the data. */
533 hunk.u.name = xml_getStrd(cur);
534
535 /* Apply diff. */
536 if (diff_patchHunk( &hunk ) < 0)
537 diff_hunkFailed( diff, &hunk );
538 else
539 diff_hunkSuccess( diff, &hunk );
540 continue;
541 }
542 WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, node->name);
543 } while (xml_nextNode(cur));
544
545 /* Clean up some stuff. */
546 free(base.target.u.name);
547 base.target.u.name = NULL;
548
549 return 0;
550}
551
559static int diff_patchSpob( UniDiff_t *diff, xmlNodePtr node )
560{
561 UniHunk_t base, hunk;
562 xmlNodePtr cur;
563
564 /* Set the target. */
565 memset(&base, 0, sizeof(UniHunk_t));
566 base.target.type = HUNK_TARGET_SPOB;
567 xmlr_attr_strd(node,"name",base.target.u.name);
568 if (base.target.u.name==NULL) {
569 WARN(_("Unidiff '%s' has an target node without a 'name' tag"), diff->name);
570 return -1;
571 }
572
573 /* Now parse the possible changes. */
574 cur = node->xmlChildrenNode;
575 do {
576 xml_onlyNodes(cur);
577 if (xml_isNode(cur,"faction")) {
578 hunk.target.type = base.target.type;
579 hunk.target.u.name = strdup(base.target.u.name);
580 hunk.type = HUNK_TYPE_SPOB_FACTION;
581 hunk.u.name = xml_getStrd(cur);
582
583 /* Apply diff. */
584 if (diff_patchHunk( &hunk ) < 0)
585 diff_hunkFailed( diff, &hunk );
586 else
587 diff_hunkSuccess( diff, &hunk );
588 continue;
589 }
590 else if (xml_isNode(cur,"population")) {
591 hunk.target.type = base.target.type;
592 hunk.target.u.name = strdup(base.target.u.name);
593 hunk.type = HUNK_TYPE_SPOB_POPULATION;
594 hunk.u.data = xml_getUInt(cur);
595
596 /* Apply diff. */
597 if (diff_patchHunk( &hunk ) < 0)
598 diff_hunkFailed( diff, &hunk );
599 else
600 diff_hunkSuccess( diff, &hunk );
601 continue;
602 }
603 else if (xml_isNode(cur,"displayname")) {
604 hunk.target.type = base.target.type;
605 hunk.target.u.name = strdup(base.target.u.name);
606 hunk.type = HUNK_TYPE_SPOB_DISPLAYNAME;
607 hunk.u.name = xml_getStrd(cur);
608
609 /* Apply diff. */
610 if (diff_patchHunk( &hunk ) < 0)
611 diff_hunkFailed( diff, &hunk );
612 else
613 diff_hunkSuccess( diff, &hunk );
614 continue;
615 }
616 else if (xml_isNode(cur,"description")) {
617 hunk.target.type = base.target.type;
618 hunk.target.u.name = strdup(base.target.u.name);
619 hunk.type = HUNK_TYPE_SPOB_DESCRIPTION;
620 hunk.u.name = xml_getStrd(cur);
621
622 /* Apply diff. */
623 if (diff_patchHunk( &hunk ) < 0)
624 diff_hunkFailed( diff, &hunk );
625 else
626 diff_hunkSuccess( diff, &hunk );
627 continue;
628 }
629 else if (xml_isNode(cur,"bar")) {
630 hunk.target.type = base.target.type;
631 hunk.target.u.name = strdup(base.target.u.name);
632 hunk.type = HUNK_TYPE_SPOB_BAR;
633 hunk.u.name = xml_getStrd(cur);
634
635 /* Apply diff. */
636 if (diff_patchHunk( &hunk ) < 0)
637 diff_hunkFailed( diff, &hunk );
638 else
639 diff_hunkSuccess( diff, &hunk );
640 continue;
641 }
642 else if (xml_isNode(cur,"service_add")) {
643 hunk.target.type = base.target.type;
644 hunk.target.u.name = strdup(base.target.u.name);
645 hunk.type = HUNK_TYPE_SPOB_SERVICE_ADD;
646 hunk.u.data = spob_getService( xml_get(cur) );
647
648 /* Apply diff. */
649 if (diff_patchHunk( &hunk ) < 0)
650 diff_hunkFailed( diff, &hunk );
651 else
652 diff_hunkSuccess( diff, &hunk );
653 continue;
654 }
655 else if (xml_isNode(cur,"service_remove")) {
656 hunk.target.type = base.target.type;
657 hunk.target.u.name = strdup(base.target.u.name);
658 hunk.type = HUNK_TYPE_SPOB_SERVICE_REMOVE;
659 hunk.u.data = spob_getService( xml_get(cur) );
660
661 /* Apply diff. */
662 if (diff_patchHunk( &hunk ) < 0)
663 diff_hunkFailed( diff, &hunk );
664 else
665 diff_hunkSuccess( diff, &hunk );
666 continue;
667 }
668 else if (xml_isNode(cur,"tech_add")) {
669 hunk.target.type = base.target.type;
670 hunk.target.u.name = strdup(base.target.u.name);
671 hunk.type = HUNK_TYPE_SPOB_TECH_ADD;
672 hunk.u.name = xml_getStrd(cur);
673
674 /* Apply diff. */
675 if (diff_patchHunk( &hunk ) < 0)
676 diff_hunkFailed( diff, &hunk );
677 else
678 diff_hunkSuccess( diff, &hunk );
679 continue;
680 }
681 else if (xml_isNode(cur,"tech_remove")) {
682 hunk.target.type = base.target.type;
683 hunk.target.u.name = strdup(base.target.u.name);
684 hunk.type = HUNK_TYPE_SPOB_TECH_REMOVE;
685 hunk.u.name = xml_getStrd(cur);
686
687 /* Apply diff. */
688 if (diff_patchHunk( &hunk ) < 0)
689 diff_hunkFailed( diff, &hunk );
690 else
691 diff_hunkSuccess( diff, &hunk );
692 continue;
693 }
694 else if (xml_isNode(cur,"tag_add")) {
695 hunk.target.type = base.target.type;
696 hunk.target.u.name = strdup(base.target.u.name);
697 hunk.type = HUNK_TYPE_SPOB_TAG_ADD;
698 hunk.u.name = xml_getStrd(cur);
699
700 /* Apply diff. */
701 if (diff_patchHunk( &hunk ) < 0)
702 diff_hunkFailed( diff, &hunk );
703 else
704 diff_hunkSuccess( diff, &hunk );
705 continue;
706 }
707 else if (xml_isNode(cur,"tag_remove")) {
708 hunk.target.type = base.target.type;
709 hunk.target.u.name = strdup(base.target.u.name);
710 hunk.type = HUNK_TYPE_SPOB_TAG_REMOVE;
711 hunk.u.name = xml_getStrd(cur);
712
713 /* Apply diff. */
714 if (diff_patchHunk( &hunk ) < 0)
715 diff_hunkFailed( diff, &hunk );
716 else
717 diff_hunkSuccess( diff, &hunk );
718 continue;
719 }
720 else if (xml_isNode(cur,"gfx_space")) {
721 char str[PATH_MAX];
722 hunk.target.type = base.target.type;
723 hunk.target.u.name = strdup(base.target.u.name);
724 hunk.type = HUNK_TYPE_SPOB_SPACE;
725 snprintf( str, sizeof(str), SPOB_GFX_SPACE_PATH"%s", xml_get(cur));
726 hunk.u.name = strdup(str);
727
728 /* Apply diff. */
729 if (diff_patchHunk( &hunk ) < 0)
730 diff_hunkFailed( diff, &hunk );
731 else
732 diff_hunkSuccess( diff, &hunk );
733 continue;
734 }
735 else if (xml_isNode(cur,"gfx_exterior")) {
736 char str[PATH_MAX];
737 hunk.target.type = base.target.type;
738 hunk.target.u.name = strdup(base.target.u.name);
739 hunk.type = HUNK_TYPE_SPOB_EXTERIOR;
740 snprintf( str, sizeof(str), SPOB_GFX_EXTERIOR_PATH"%s", xml_get(cur));
741 hunk.u.name = strdup(str);
742
743 /* Apply diff. */
744 if (diff_patchHunk( &hunk ) < 0)
745 diff_hunkFailed( diff, &hunk );
746 else
747 diff_hunkSuccess( diff, &hunk );
748 continue;
749 }
750 else if (xml_isNode(cur,"lua")) {
751 char *str;
752 hunk.target.type = base.target.type;
753 hunk.target.u.name = strdup(base.target.u.name);
754 hunk.type = HUNK_TYPE_SPOB_LUA;
755 str = xml_get(cur);
756 if (str != NULL)
757 hunk.u.name = strdup( str );
758 else
759 hunk.u.name = NULL;
760
761 /* Apply diff. */
762 if (diff_patchHunk( &hunk ) < 0)
763 diff_hunkFailed( diff, &hunk );
764 else
765 diff_hunkSuccess( diff, &hunk );
766 continue;
767 }
768 WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, cur->name);
769 } while (xml_nextNode(cur));
770
771 /* Clean up some stuff. */
772 free(base.target.u.name);
773 base.target.u.name = NULL;
774
775 return 0;
776}
777
785static int diff_patchFaction( UniDiff_t *diff, xmlNodePtr node )
786{
787 UniHunk_t base, hunk;
788 xmlNodePtr cur;
789 char *buf;
790
791 /* Set the target. */
792 memset(&base, 0, sizeof(UniHunk_t));
793 base.target.type = HUNK_TARGET_FACTION;
794 xmlr_attr_strd(node,"name",base.target.u.name);
795 if (base.target.u.name==NULL) {
796 WARN(_("Unidiff '%s' has an target node without a 'name' tag"), diff->name);
797 return -1;
798 }
799
800 /* Now parse the possible changes. */
801 cur = node->xmlChildrenNode;
802 do {
803 xml_onlyNodes(cur);
804 if (xml_isNode(cur,"visible")) {
805 hunk.target.type = base.target.type;
806 hunk.target.u.name = strdup(base.target.u.name);
807
808 /* Faction type is constant. */
809 hunk.type = HUNK_TYPE_FACTION_VISIBLE;
810
811 /* There is no name. */
812 hunk.u.name = NULL;
813
814 /* Apply diff. */
815 if (diff_patchHunk( &hunk ) < 0)
816 diff_hunkFailed( diff, &hunk );
817 else
818 diff_hunkSuccess( diff, &hunk );
819 continue;
820 }
821 else if (xml_isNode(cur,"invisible")) {
822 hunk.target.type = base.target.type;
823 hunk.target.u.name = strdup(base.target.u.name);
824
825 /* Faction type is constant. */
826 hunk.type = HUNK_TYPE_FACTION_INVISIBLE;
827
828 /* There is no name. */
829 hunk.u.name = NULL;
830
831 /* Apply diff. */
832 if (diff_patchHunk( &hunk ) < 0)
833 diff_hunkFailed( diff, &hunk );
834 else
835 diff_hunkSuccess( diff, &hunk );
836 continue;
837 }
838 else if (xml_isNode(cur,"faction")) {
839 buf = xml_get( cur );
840 if ( buf == NULL ) {
841 WARN( _( "Unidiff '%s': Null hunk type." ), diff->name );
842 continue;
843 }
844
845 hunk.target.type = base.target.type;
846 hunk.target.u.name = strdup(base.target.u.name);
847
848 /* Get the faction to set the association of. */
849 xmlr_attr_strd(cur,"name",hunk.u.name);
850
851 /* Get the type. */
852 if (strcmp(buf,"ally")==0)
853 hunk.type = HUNK_TYPE_FACTION_ALLY;
854 else if (strcmp(buf,"enemy")==0)
855 hunk.type = HUNK_TYPE_FACTION_ENEMY;
856 else if (strcmp(buf,"neutral")==0)
857 hunk.type = HUNK_TYPE_FACTION_NEUTRAL;
858 else
859 WARN(_("Unidiff '%s': Unknown hunk type '%s' for faction '%s'."), diff->name, buf, hunk.u.name);
860
861 /* Apply diff. */
862 if (diff_patchHunk( &hunk ) < 0)
863 diff_hunkFailed( diff, &hunk );
864 else
865 diff_hunkSuccess( diff, &hunk );
866 continue;
867 }
868 WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, node->name);
869 } while (xml_nextNode(cur));
870
871 /* Clean up some stuff. */
872 free(base.target.u.name);
873 base.target.u.name = NULL;
874
875 return 0;
876}
877
884static int diff_patch( xmlNodePtr parent )
885{
886 UniDiff_t *diff;
887 xmlNodePtr node;
888 int nfailed;
889
890 /* Prepare it. */
891 diff = diff_newDiff();
892 memset(diff, 0, sizeof(UniDiff_t));
893 xmlr_attr_strd(parent,"name",diff->name);
894
895 node = parent->xmlChildrenNode;
896 do {
897 xml_onlyNodes(node);
898 if (xml_isNode(node,"system")) {
900 diff_patchSystem( diff, node );
901 }
902 else if (xml_isNode(node, "tech"))
903 diff_patchTech( diff, node );
904 else if (xml_isNode(node, "spob")) {
906 diff_patchSpob( diff, node );
907 }
908 else if (xml_isNode(node, "faction")) {
910 diff_patchFaction( diff, node );
911 }
912 else
913 WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, node->name);
914 } while (xml_nextNode(node));
915
916 nfailed = array_size(diff->failed);
917 if (nfailed > 0) {
918 WARN(
919 n_( "Unidiff '%s' failed to apply %d hunk.", "Unidiff '%s' failed to apply %d hunks.", nfailed ),
920 diff->name, nfailed );
921 for (int i=0; i<nfailed; i++) {
922 UniHunk_t *fail = &diff->failed[i];
923 char *target = fail->target.u.name;
924 switch (fail->type) {
925 case HUNK_TYPE_SPOB_ADD:
926 WARN(_(" [%s] spob add: '%s'"), target, fail->u.name);
927 break;
928 case HUNK_TYPE_SPOB_REMOVE:
929 WARN(_(" [%s] spob remove: '%s'"), target, fail->u.name);
930 break;
931 case HUNK_TYPE_VSPOB_ADD:
932 WARN(_(" [%s] virtual spob add: '%s'"), target, fail->u.name);
933 break;
934 case HUNK_TYPE_VSPOB_REMOVE:
935 WARN(_(" [%s] virtual spob remove: '%s'"), target, fail->u.name);
936 break;
937 case HUNK_TYPE_JUMP_ADD:
938 WARN(_(" [%s] jump add: '%s'"), target, fail->u.name);
939 break;
940 case HUNK_TYPE_JUMP_REMOVE:
941 WARN(_(" [%s] jump remove: '%s'"), target, fail->u.name);
942 break;
943 case HUNK_TYPE_TECH_ADD:
944 WARN(_(" [%s] tech add: '%s'"), target,
945 fail->u.name );
946 break;
947 case HUNK_TYPE_TECH_REMOVE:
948 WARN(_(" [%s] tech remove: '%s'"), target,
949 fail->u.name );
950 break;
951 case HUNK_TYPE_SPOB_FACTION:
952 WARN(_(" [%s] spob faction: '%s'"), target,
953 fail->u.name );
954 break;
955 case HUNK_TYPE_SPOB_FACTION_REMOVE:
956 WARN(_(" [%s] spob faction removal: '%s'"), target,
957 fail->u.name );
958 break;
959 case HUNK_TYPE_SPOB_POPULATION:
960 WARN(_(" [%s] spob population: '%s'"), target,
961 fail->u.name );
962 break;
963 case HUNK_TYPE_SPOB_POPULATION_REMOVE:
964 WARN(_(" [%s] spob population removal: '%s'"), target,
965 fail->u.name );
966 break;
967 case HUNK_TYPE_SPOB_DISPLAYNAME:
968 WARN(_(" [%s] spob displayname: '%s'"), target,
969 fail->u.name );
970 break;
971 case HUNK_TYPE_SPOB_DISPLAYNAME_REVERT:
972 WARN(_(" [%s] spob displayname revert: '%s'"), target,
973 fail->u.name );
974 break;
975 case HUNK_TYPE_SPOB_DESCRIPTION:
976 WARN(_(" [%s] spob description: '%s'"), target,
977 fail->u.name );
978 break;
979 case HUNK_TYPE_SPOB_DESCRIPTION_REVERT:
980 WARN(_(" [%s] spob description revert: '%s'"), target,
981 fail->u.name );
982 break;
983 case HUNK_TYPE_SPOB_BAR:
984 WARN(_(" [%s] spob bar: '%s'"), target,
985 fail->u.name );
986 break;
987 case HUNK_TYPE_SPOB_BAR_REVERT:
988 WARN(_(" [%s] spob bar revert: '%s'"), target,
989 fail->u.name );
990 break;
991 case HUNK_TYPE_SPOB_SPACE:
992 WARN(_(" [%s] spob space: '%s'"), target,
993 fail->u.name );
994 break;
995 case HUNK_TYPE_SPOB_SPACE_REVERT:
996 WARN(_(" [%s] spob space revert: '%s'"), target,
997 fail->u.name );
998 break;
999 case HUNK_TYPE_SPOB_EXTERIOR:
1000 WARN(_(" [%s] spob exterior: '%s'"), target,
1001 fail->u.name );
1002 break;
1003 case HUNK_TYPE_SPOB_EXTERIOR_REVERT:
1004 WARN(_(" [%s] spob exterior revert: '%s'"), target,
1005 fail->u.name );
1006 break;
1007 case HUNK_TYPE_SPOB_LUA:
1008 WARN(_(" [%s] spob lua: '%s'"), target,
1009 fail->u.name );
1010 break;
1011 case HUNK_TYPE_SPOB_LUA_REVERT:
1012 WARN(_(" [%s] spob lua revert: '%s'"), target,
1013 fail->u.name );
1014 break;
1015 case HUNK_TYPE_SPOB_SERVICE_ADD:
1016 WARN(_(" [%s] spob service add: '%s'"), target,
1017 spob_getServiceName(fail->u.data) );
1018 break;
1019 case HUNK_TYPE_SPOB_SERVICE_REMOVE:
1020 WARN(_(" [%s] spob service remove: '%s'"), target,
1021 spob_getServiceName(fail->u.data) );
1022 break;
1023 case HUNK_TYPE_SPOB_TECH_ADD:
1024 WARN(_(" [%s] spob tech add: '%s'"), target,
1025 spob_getServiceName(fail->u.data) );
1026 break;
1027 case HUNK_TYPE_SPOB_TECH_REMOVE:
1028 WARN(_(" [%s] spob tech remove: '%s'"), target,
1029 spob_getServiceName(fail->u.data) );
1030 break;
1031 case HUNK_TYPE_SPOB_TAG_ADD:
1032 WARN(_(" [%s] spob tech add: '%s'"), target,
1033 spob_getServiceName(fail->u.data) );
1034 break;
1035 case HUNK_TYPE_SPOB_TAG_REMOVE:
1036 WARN(_(" [%s] spob tech remove: '%s'"), target,
1037 spob_getServiceName(fail->u.data) );
1038 break;
1039 case HUNK_TYPE_FACTION_VISIBLE:
1040 WARN(_(" [%s] faction visible: '%s'"), target,
1041 fail->u.name );
1042 break;
1043 case HUNK_TYPE_FACTION_INVISIBLE:
1044 WARN(_(" [%s] faction invisible: '%s'"), target,
1045 fail->u.name );
1046 break;
1047 case HUNK_TYPE_FACTION_ALLY:
1048 WARN(_(" [%s] faction set ally: '%s'"), target,
1049 fail->u.name );
1050 break;
1051 case HUNK_TYPE_FACTION_ENEMY:
1052 WARN(_(" [%s] faction set enemy: '%s'"), target,
1053 fail->u.name );
1054 break;
1055 case HUNK_TYPE_FACTION_NEUTRAL:
1056 WARN(_(" [%s] faction set neutral: '%s'"), target,
1057 fail->u.name );
1058 break;
1059 case HUNK_TYPE_FACTION_REALIGN:
1060 WARN(_(" [%s] faction alignment reset: '%s'"), target,
1061 fail->u.name );
1062 break;
1063
1064 default:
1065 WARN(_(" unknown hunk '%d'"), fail->type);
1066 break;
1067 }
1068 }
1069 }
1070
1071 /* Update overlay map just in case. */
1072 ovr_refresh();
1073 return 0;
1074}
1075
1082static int diff_patchHunk( UniHunk_t *hunk )
1083{
1084 Spob *p;
1085 StarSystem *ssys;
1086 int a, b;
1087
1088 switch (hunk->type) {
1089
1090 /* Adding an spob. */
1091 case HUNK_TYPE_SPOB_ADD:
1092 spob_luaInit( spob_get(hunk->u.name) );
1094 return system_addSpob( system_get(hunk->target.u.name), hunk->u.name );
1095 /* Removing an spob. */
1096 case HUNK_TYPE_SPOB_REMOVE:
1098 return system_rmSpob( system_get(hunk->target.u.name), hunk->u.name );
1099
1100 /* Adding an spob. */
1101 case HUNK_TYPE_VSPOB_ADD:
1103 return system_addVirtualSpob( system_get(hunk->target.u.name), hunk->u.name );
1104 /* Removing an spob. */
1105 case HUNK_TYPE_VSPOB_REMOVE:
1107 return system_rmVirtualSpob( system_get(hunk->target.u.name), hunk->u.name );
1108
1109 /* Adding a Jump. */
1110 case HUNK_TYPE_JUMP_ADD:
1112 return system_addJumpDiff( system_get(hunk->target.u.name), hunk->node );
1113 /* Removing a jump. */
1114 case HUNK_TYPE_JUMP_REMOVE:
1116 return system_rmJump( system_get(hunk->target.u.name), hunk->u.name );
1117
1118 /* Changing system background. */
1119 case HUNK_TYPE_SSYS_BACKGROUND:
1120 ssys = system_get(hunk->target.u.name);
1121 hunk->o.name = ssys->background;
1122 ssys->background = hunk->u.name;
1123 return 0;
1124 case HUNK_TYPE_SSYS_BACKGROUND_REVERT:
1125 ssys = system_get(hunk->target.u.name);
1126 ssys->background = (char*)hunk->o.name;
1127 return 0;
1128
1129 /* Changing system features designation. */
1130 case HUNK_TYPE_SSYS_FEATURES:
1131 ssys = system_get(hunk->target.u.name);
1132 hunk->o.name = ssys->features;
1133 ssys->features = hunk->u.name;
1134 return 0;
1135 case HUNK_TYPE_SSYS_FEATURES_REVERT:
1136 ssys = system_get(hunk->target.u.name);
1137 ssys->features = (char*)hunk->o.name;
1138 return 0;
1139
1140 /* Adding a tech. */
1141 case HUNK_TYPE_TECH_ADD:
1142 return tech_addItem( hunk->target.u.name, hunk->u.name );
1143 /* Removing a tech. */
1144 case HUNK_TYPE_TECH_REMOVE:
1145 return tech_rmItem( hunk->target.u.name, hunk->u.name );
1146
1147 /* Changing spob faction. */
1148 case HUNK_TYPE_SPOB_FACTION:
1149 p = spob_get( hunk->target.u.name );
1150 if (p==NULL)
1151 return -1;
1152 if (p->presence.faction<0)
1153 hunk->o.name = NULL;
1154 else
1155 hunk->o.name = faction_name( p->presence.faction );
1157 return spob_setFaction( p, faction_get(hunk->u.name) );
1158 case HUNK_TYPE_SPOB_FACTION_REMOVE:
1159 p = spob_get( hunk->target.u.name );
1160 if (p==NULL)
1161 return -1;
1163 if (hunk->o.name==NULL)
1164 return spob_setFaction( p, -1 );
1165 else
1166 return spob_setFaction( p, faction_get(hunk->o.name) );
1167
1168 /* Changing spob population. */
1169 case HUNK_TYPE_SPOB_POPULATION:
1170 p = spob_get( hunk->target.u.name );
1171 if (p==NULL)
1172 return -1;
1173 hunk->o.data = p->population;
1174 p->population = hunk->u.data;
1175 return 0;
1176 case HUNK_TYPE_SPOB_POPULATION_REMOVE:
1177 p = spob_get( hunk->target.u.name );
1178 if (p==NULL)
1179 return -1;
1180 p->population = hunk->o.data;
1181 return 0;
1182
1183 /* Changing spob displayname. */
1184 case HUNK_TYPE_SPOB_DISPLAYNAME:
1185 p = spob_get( hunk->target.u.name );
1186 if (p==NULL)
1187 return -1;
1188 hunk->o.name = p->display;
1189 p->display = hunk->u.name;
1190 return 0;
1191 case HUNK_TYPE_SPOB_DISPLAYNAME_REVERT:
1192 p = spob_get( hunk->target.u.name );
1193 if (p==NULL)
1194 return -1;
1195 p->display = (char*)hunk->o.name;
1196 return 0;
1197
1198 /* Changing spob description. */
1199 case HUNK_TYPE_SPOB_DESCRIPTION:
1200 p = spob_get( hunk->target.u.name );
1201 if (p==NULL)
1202 return -1;
1203 hunk->o.name = p->description;
1204 p->description = hunk->u.name;
1205 return 0;
1206 case HUNK_TYPE_SPOB_DESCRIPTION_REVERT:
1207 p = spob_get( hunk->target.u.name );
1208 if (p==NULL)
1209 return -1;
1210 p->description = (char*)hunk->o.name;
1211 return 0;
1212
1213 /* Changing spob bar description. */
1214 case HUNK_TYPE_SPOB_BAR:
1215 p = spob_get( hunk->target.u.name );
1216 if (p==NULL)
1217 return -1;
1218 hunk->o.name = p->bar_description;
1219 p->bar_description = hunk->u.name;
1220 return 0;
1221 case HUNK_TYPE_SPOB_BAR_REVERT:
1222 p = spob_get( hunk->target.u.name );
1223 if (p==NULL)
1224 return -1;
1225 p->bar_description = (char*)hunk->o.name;
1226 return 0;
1227
1228 /* Modifying spob services. */
1229 case HUNK_TYPE_SPOB_SERVICE_ADD:
1230 p = spob_get( hunk->target.u.name );
1231 if (p==NULL)
1232 return -1;
1233 if (spob_hasService( p, hunk->u.data ))
1234 return -1;
1235 spob_addService( p, hunk->u.data );
1237 return 0;
1238 case HUNK_TYPE_SPOB_SERVICE_REMOVE:
1239 p = spob_get( hunk->target.u.name );
1240 if (p==NULL)
1241 return -1;
1242 if (!spob_hasService( p, hunk->u.data ))
1243 return -1;
1244 spob_rmService( p, hunk->u.data );
1246 return 0;
1247
1248 /* Modifying tech stuff. */
1249 case HUNK_TYPE_SPOB_TECH_ADD:
1250 p = spob_get( hunk->target.u.name );
1251 if (p==NULL)
1252 return -1;
1253 if (p->tech == NULL)
1254 p->tech = tech_groupCreate();
1255 tech_addItemTech( p->tech, hunk->u.name );
1256 return 0;
1257 case HUNK_TYPE_SPOB_TECH_REMOVE:
1258 p = spob_get( hunk->target.u.name );
1259 if (p==NULL)
1260 return -1;
1261 tech_rmItemTech( p->tech, hunk->u.name );
1262 return 0;
1263
1264 /* Modifying tag stuff. */
1265 case HUNK_TYPE_SPOB_TAG_ADD:
1266 p = spob_get( hunk->target.u.name );
1267 if (p==NULL)
1268 return -1;
1269 if (p->tech == NULL)
1270 p->tech = tech_groupCreate();
1271 if (p->tags==NULL)
1272 p->tags = array_create( char* );
1273 array_push_back( &p->tags, strdup( hunk->u.name ) );
1274 return 0;
1275 case HUNK_TYPE_SPOB_TAG_REMOVE:
1276 p = spob_get( hunk->target.u.name );
1277 if (p==NULL)
1278 return -1;
1279 a = -1;
1280 for (int i=0; i<array_size(p->tags); i++) {
1281 if (strcmp(p->tags[i], hunk->u.name )==0) {
1282 a = i;
1283 break;
1284 }
1285 }
1286 if (a<0)
1287 return -1; /* Didn't find tag! */
1288 free( p->tags[a] );
1289 array_erase( &p->tags, &p->tags[a], &p->tags[a+1] );
1290 return 0;
1291
1292 /* Changing spob space graphics. */
1293 case HUNK_TYPE_SPOB_SPACE:
1294 p = spob_get( hunk->target.u.name );
1295 if (p==NULL)
1296 return -1;
1297 hunk->o.name = p->gfx_spaceName;
1298 p->gfx_spaceName = hunk->u.name;
1300 return 0;
1301 case HUNK_TYPE_SPOB_SPACE_REVERT:
1302 p = spob_get( hunk->target.u.name );
1303 if (p==NULL)
1304 return -1;
1305 p->gfx_spaceName = (char*)hunk->o.name;
1307 return 0;
1308
1309 /* Changing spob exterior graphics. */
1310 case HUNK_TYPE_SPOB_EXTERIOR:
1311 p = spob_get( hunk->target.u.name );
1312 if (p==NULL)
1313 return -1;
1314 hunk->o.name = p->gfx_exterior;
1315 p->gfx_exterior = hunk->u.name;
1316 return 0;
1317 case HUNK_TYPE_SPOB_EXTERIOR_REVERT:
1318 p = spob_get( hunk->target.u.name );
1319 if (p==NULL)
1320 return -1;
1321 p->gfx_exterior = (char*)hunk->o.name;
1322 return 0;
1323
1324 /* Change Lua stuff. */
1325 case HUNK_TYPE_SPOB_LUA:
1326 p = spob_get( hunk->target.u.name );
1327 if (p==NULL)
1328 return -1;
1329 hunk->o.name = p->lua_file;
1330 p->lua_file = hunk->u.name;
1331 spob_luaInit( p );
1333 return 0;
1334 case HUNK_TYPE_SPOB_LUA_REVERT:
1335 p = spob_get( hunk->target.u.name );
1336 if (p==NULL)
1337 return -1;
1338 p->lua_file = (char*)hunk->o.name;
1339 spob_luaInit( p );
1341 return 0;
1342
1343 /* Making a faction visible. */
1344 case HUNK_TYPE_FACTION_VISIBLE:
1345 return faction_setInvisible( faction_get(hunk->target.u.name), 0 );
1346 /* Making a faction invisible. */
1347 case HUNK_TYPE_FACTION_INVISIBLE:
1348 return faction_setInvisible( faction_get(hunk->target.u.name), 1 );
1349 /* Making two factions allies. */
1350 case HUNK_TYPE_FACTION_ALLY:
1351 a = faction_get( hunk->target.u.name );
1352 b = faction_get( hunk->u.name );
1353 if (areAllies(a, b))
1354 hunk->o.data = 'A';
1355 else if (areEnemies(a, b))
1356 hunk->o.data = 'E';
1357 else
1358 hunk->o.data = 0;
1359 faction_addAlly( a, b );
1360 faction_addAlly( b, a );
1361 return 0;
1362 /* Making two factions enemies. */
1363 case HUNK_TYPE_FACTION_ENEMY:
1364 a = faction_get( hunk->target.u.name );
1365 b = faction_get( hunk->u.name );
1366 if (areAllies(a, b))
1367 hunk->o.data = 'A';
1368 else if (areEnemies(a, b))
1369 hunk->o.data = 'E';
1370 else
1371 hunk->o.data = 0;
1372 faction_addEnemy( a, b );
1373 faction_addEnemy( b, a );
1374 return 0;
1375 /* Making two factions neutral (removing enemy/ally statuses). */
1376 case HUNK_TYPE_FACTION_NEUTRAL:
1377 a = faction_get( hunk->target.u.name );
1378 b = faction_get( hunk->u.name );
1379 if (areAllies(a, b))
1380 hunk->o.data = 'A';
1381 else if (areEnemies(a, b))
1382 hunk->o.data = 'E';
1383 else
1384 hunk->o.data = 0;
1385 faction_rmAlly( a, b );
1386 faction_rmAlly( b, a );
1387 faction_rmEnemy( a, b );
1388 faction_rmEnemy( b, a );
1389 return 0;
1390 /* Resetting the alignment state of two factions. */
1391 case HUNK_TYPE_FACTION_REALIGN:
1392 a = faction_get( hunk->target.u.name );
1393 b = faction_get( hunk->u.name );
1394 if (hunk->o.data == 'A') {
1395 faction_rmEnemy(a, b);
1396 faction_rmEnemy(b, a);
1397 faction_addAlly(a, b);
1398 faction_addAlly(b, a);
1399 }
1400 else if (hunk->o.data == 'E') {
1401 faction_rmAlly(a, b);
1402 faction_rmAlly(b, a);
1403 faction_addEnemy(a, b);
1404 faction_addAlly(b, a);
1405 }
1406 else {
1407 faction_rmAlly( a, b );
1408 faction_rmAlly( b, a );
1409 faction_rmEnemy( a, b );
1410 faction_rmEnemy( b, a );
1411 }
1412 return 0;
1413
1414 default:
1415 WARN(_("Unknown hunk type '%d'."), hunk->type);
1416 break;
1417 }
1418
1419 return -1;
1420}
1421
1428static void diff_hunkFailed( UniDiff_t *diff, UniHunk_t *hunk )
1429{
1430 if (diff == NULL)
1431 return;
1432 if (diff->failed == NULL)
1433 diff->failed = array_create( UniHunk_t );
1434 array_grow( &diff->failed ) = *hunk;
1435}
1436
1443static void diff_hunkSuccess( UniDiff_t *diff, UniHunk_t *hunk )
1444{
1445 if (diff == NULL)
1446 return;
1447 if (diff->applied == NULL)
1448 diff->applied = array_create( UniHunk_t );
1449 array_grow( &diff->applied ) = *hunk;
1450}
1451
1457void diff_remove( const char *name )
1458{
1459 /* Check if already applied. */
1460 UniDiff_t *diff = diff_get(name);
1461 if (diff == NULL)
1462 return;
1463
1464 diff_removeDiff(diff);
1465
1467}
1468
1472void diff_clear (void)
1473{
1474 while (array_size(diff_stack) > 0)
1477 diff_stack = NULL;
1478
1480}
1481
1485void diff_free (void)
1486{
1487 diff_clear();
1488 for (int i = 0; i < array_size(diff_available); i++) {
1490 free( d->name );
1491 free( d->filename );
1492 }
1494 diff_available = NULL;
1495}
1496
1503{
1504 /* Check if needs initialization. */
1505 if (diff_stack == NULL)
1507 return &array_grow(&diff_stack);
1508}
1509
1516static int diff_removeDiff( UniDiff_t *diff )
1517{
1518 for (int i=0; i<array_size(diff->applied); i++) {
1519 UniHunk_t hunk = diff->applied[i];
1520 /* Invert the type for reverting. */
1521 switch (hunk.type) {
1522 case HUNK_TYPE_SPOB_ADD:
1523 hunk.type = HUNK_TYPE_SPOB_REMOVE;
1524 break;
1525 case HUNK_TYPE_SPOB_REMOVE:
1526 hunk.type = HUNK_TYPE_SPOB_ADD;
1527 break;
1528
1529 case HUNK_TYPE_VSPOB_ADD:
1530 hunk.type = HUNK_TYPE_VSPOB_REMOVE;
1531 break;
1532 case HUNK_TYPE_VSPOB_REMOVE:
1533 hunk.type = HUNK_TYPE_VSPOB_ADD;
1534 break;
1535
1536 case HUNK_TYPE_JUMP_ADD:
1537 hunk.type = HUNK_TYPE_JUMP_REMOVE;
1538 break;
1539 case HUNK_TYPE_JUMP_REMOVE:
1540 hunk.type = HUNK_TYPE_JUMP_ADD;
1541 break;
1542
1543 case HUNK_TYPE_SSYS_BACKGROUND:
1544 hunk.type = HUNK_TYPE_SSYS_BACKGROUND_REVERT;
1545 break;
1546 case HUNK_TYPE_SSYS_FEATURES:
1547 hunk.type = HUNK_TYPE_SSYS_FEATURES_REVERT;
1548 break;
1549
1550 case HUNK_TYPE_TECH_ADD:
1551 hunk.type = HUNK_TYPE_TECH_REMOVE;
1552 break;
1553 case HUNK_TYPE_TECH_REMOVE:
1554 hunk.type = HUNK_TYPE_TECH_ADD;
1555 break;
1556
1557 case HUNK_TYPE_SPOB_FACTION:
1558 hunk.type = HUNK_TYPE_SPOB_FACTION_REMOVE;
1559 break;
1560
1561 case HUNK_TYPE_SPOB_POPULATION:
1562 hunk.type = HUNK_TYPE_SPOB_POPULATION_REMOVE;
1563 break;
1564
1565 case HUNK_TYPE_SPOB_DISPLAYNAME:
1566 hunk.type = HUNK_TYPE_SPOB_DISPLAYNAME_REVERT;
1567 break;
1568
1569 case HUNK_TYPE_SPOB_DESCRIPTION:
1570 hunk.type = HUNK_TYPE_SPOB_DESCRIPTION_REVERT;
1571 break;
1572
1573 case HUNK_TYPE_SPOB_BAR:
1574 hunk.type = HUNK_TYPE_SPOB_BAR_REVERT;
1575 break;
1576
1577 case HUNK_TYPE_SPOB_SERVICE_ADD:
1578 hunk.type = HUNK_TYPE_SPOB_SERVICE_REMOVE;
1579 break;
1580 case HUNK_TYPE_SPOB_SERVICE_REMOVE:
1581 hunk.type = HUNK_TYPE_SPOB_SERVICE_ADD;
1582 break;
1583
1584 case HUNK_TYPE_SPOB_TECH_ADD:
1585 hunk.type = HUNK_TYPE_SPOB_TECH_REMOVE;
1586 break;
1587 case HUNK_TYPE_SPOB_TECH_REMOVE:
1588 hunk.type = HUNK_TYPE_SPOB_TECH_ADD;
1589 break;
1590
1591 case HUNK_TYPE_SPOB_TAG_ADD:
1592 hunk.type = HUNK_TYPE_SPOB_TAG_REMOVE;
1593 break;
1594 case HUNK_TYPE_SPOB_TAG_REMOVE:
1595 hunk.type = HUNK_TYPE_SPOB_TAG_ADD;
1596 break;
1597
1598 case HUNK_TYPE_SPOB_SPACE:
1599 hunk.type = HUNK_TYPE_SPOB_SPACE_REVERT;
1600 break;
1601
1602 case HUNK_TYPE_SPOB_EXTERIOR:
1603 hunk.type = HUNK_TYPE_SPOB_EXTERIOR_REVERT;
1604 break;
1605
1606 case HUNK_TYPE_SPOB_LUA:
1607 hunk.type = HUNK_TYPE_SPOB_LUA_REVERT;
1608 break;
1609
1610 case HUNK_TYPE_FACTION_VISIBLE:
1611 hunk.type = HUNK_TYPE_FACTION_INVISIBLE;
1612 break;
1613 case HUNK_TYPE_FACTION_INVISIBLE:
1614 hunk.type = HUNK_TYPE_FACTION_VISIBLE;
1615 break;
1616
1617 case HUNK_TYPE_FACTION_ALLY:
1618 hunk.type = HUNK_TYPE_FACTION_REALIGN;
1619 break;
1620 case HUNK_TYPE_FACTION_ENEMY:
1621 hunk.type = HUNK_TYPE_FACTION_REALIGN;
1622 break;
1623 case HUNK_TYPE_FACTION_NEUTRAL:
1624 hunk.type = HUNK_TYPE_FACTION_REALIGN;
1625 break;
1626
1627 default:
1628 WARN(_("Unknown Hunk type '%d'."), hunk.type);
1629 continue;
1630 }
1631
1632 if (diff_patchHunk(&hunk))
1633 WARN(_("Failed to remove hunk type '%d'."), hunk.type);
1634 }
1635
1636 diff_cleanup(diff);
1637 array_erase( &diff_stack, diff, &diff[1] );
1638 return 0;
1639}
1640
1646static void diff_cleanup( UniDiff_t *diff )
1647{
1648 free(diff->name);
1649 for (int i=0; i<array_size(diff->applied); i++)
1650 diff_cleanupHunk(&diff->applied[i]);
1651 array_free(diff->applied);
1652 for (int i=0; i<array_size(diff->failed); i++)
1653 diff_cleanupHunk(&diff->failed[i]);
1654 array_free(diff->failed);
1655 memset(diff, 0, sizeof(UniDiff_t));
1656}
1657
1663static void diff_cleanupHunk( UniHunk_t *hunk )
1664{
1665 free(hunk->target.u.name);
1666 hunk->target.u.name = NULL;
1667
1668 switch (hunk->type) { /* TODO: Does it really matter? */
1669 case HUNK_TYPE_SPOB_ADD:
1670 case HUNK_TYPE_SPOB_REMOVE:
1671 case HUNK_TYPE_VSPOB_ADD:
1672 case HUNK_TYPE_VSPOB_REMOVE:
1673 case HUNK_TYPE_JUMP_ADD:
1674 case HUNK_TYPE_JUMP_REMOVE:
1675 case HUNK_TYPE_SSYS_BACKGROUND:
1676 case HUNK_TYPE_SSYS_FEATURES:
1677 case HUNK_TYPE_TECH_ADD:
1678 case HUNK_TYPE_TECH_REMOVE:
1679 case HUNK_TYPE_SPOB_FACTION:
1680 case HUNK_TYPE_SPOB_FACTION_REMOVE:
1681 case HUNK_TYPE_SPOB_DISPLAYNAME:
1682 case HUNK_TYPE_SPOB_DISPLAYNAME_REVERT:
1683 case HUNK_TYPE_SPOB_DESCRIPTION:
1684 case HUNK_TYPE_SPOB_DESCRIPTION_REVERT:
1685 case HUNK_TYPE_SPOB_TECH_ADD:
1686 case HUNK_TYPE_SPOB_TECH_REMOVE:
1687 case HUNK_TYPE_SPOB_TAG_ADD:
1688 case HUNK_TYPE_SPOB_TAG_REMOVE:
1689 case HUNK_TYPE_SPOB_BAR:
1690 case HUNK_TYPE_SPOB_BAR_REVERT:
1691 case HUNK_TYPE_SPOB_SPACE:
1692 case HUNK_TYPE_SPOB_SPACE_REVERT:
1693 case HUNK_TYPE_SPOB_EXTERIOR:
1694 case HUNK_TYPE_SPOB_EXTERIOR_REVERT:
1695 case HUNK_TYPE_SPOB_LUA:
1696 case HUNK_TYPE_SPOB_LUA_REVERT:
1697 case HUNK_TYPE_FACTION_VISIBLE:
1698 case HUNK_TYPE_FACTION_INVISIBLE:
1699 case HUNK_TYPE_FACTION_ALLY:
1700 case HUNK_TYPE_FACTION_ENEMY:
1701 case HUNK_TYPE_FACTION_NEUTRAL:
1702 case HUNK_TYPE_FACTION_REALIGN:
1703 free(hunk->u.name);
1704 hunk->u.name = NULL;
1705 break;
1706
1707 default:
1708 break;
1709 }
1710 memset( hunk, 0, sizeof(UniHunk_t) );
1711}
1712
1719int diff_save( xmlTextWriterPtr writer )
1720{
1721 xmlw_startElem(writer,"diffs");
1722 if (diff_stack != NULL) {
1723 for (int i=0; i<array_size(diff_stack); i++) {
1724 UniDiff_t *diff = &diff_stack[i];
1725
1726 xmlw_elem(writer, "diff", "%s", diff->name);
1727 }
1728 }
1729 xmlw_endElem(writer); /* "diffs" */
1730 return 0;
1731
1732}
1733
1740int diff_load( xmlNodePtr parent )
1741{
1742 xmlNodePtr node;
1743 int defer = diff_universe_defer;
1744
1745 /* Don't update universe here. */
1748 diff_clear();
1749 diff_universe_defer = defer;
1750
1751 node = parent->xmlChildrenNode;
1752 do {
1753 if (xml_isNode(node,"diffs")) {
1754 xmlNodePtr cur = node->xmlChildrenNode;
1755 do {
1756 if ( xml_isNode( cur, "diff" ) ) {
1757 char *diffName = xml_get( cur );
1758 if ( diffName == NULL ) {
1759 WARN( _( "Expected node \"diff\" to contain the name of a unidiff. Was empty." ) );
1760 continue;
1761 }
1762 diff_applyInternal( diffName, 0 );
1763 }
1764 } while (xml_nextNode(cur));
1765 }
1766 } while (xml_nextNode(node));
1767
1768 /* Update as necessary. */
1770
1771 return 0;
1772}
1773
1778{
1779 Pilot *const* pilots;
1780
1782 return 0;
1783
1786
1787 /* Re-compute the economy. */
1790
1791 /* Have to update planet graphics if necessary. */
1792 if (cur_system != NULL) {
1795 }
1796
1797 /* Have to pilot targetting just in case. */
1798 pilots = pilot_getAll();
1799 for (int i=0; i<array_size(pilots); i++) {
1800 Pilot *p = pilots[i];
1801 p->nav_spob = -1;
1802 p->nav_hyperspace = -1;
1803
1804 /* Hack in case the pilot was actively jumping, this won't run the hook,
1805 * but I guess it's too much effort to properly fix for a situation that
1806 * will likely never happen. */
1807 if (!pilot_isWithPlayer(p) && pilot_isFlag( p, PILOT_HYPERSPACE ))
1808 pilot_delete(p);
1809 else
1810 pilot_rmFlag( p, PILOT_HYPERSPACE ); /* Corner case player, just have it not crash and randomly stop the jump. */
1811
1812 /* Have to reset in the case of starting. */
1813 if (pilot_isFlag( p, PILOT_HYP_BEGIN ) ||
1814 pilot_isFlag( p, PILOT_HYP_BRAKE ) ||
1815 pilot_isFlag( p, PILOT_HYP_PREP ))
1817 }
1818
1819 /* Player has to update the GUI so we send again. */
1822
1824 return 1;
1825}
1826
1832void unidiff_universeDefer( int enable )
1833{
1834 int defer = diff_universe_defer;
1835 diff_universe_defer = enable;
1836 if (defer && !enable)
1838}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition: array.h:158
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition: array.h:102
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition: array.h:140
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition: array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition: array.h:119
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
Definition: array.h:149
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition: array.h:129
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition: array.h:93
void economy_initialiseCommodityPrices(void)
Initialises commodity prices for the sinusoidal economy model.
Definition: economy.c:859
int economy_execQueued(void)
Calls economy_refresh if an economy update is queued.
Definition: economy.c:483
void faction_rmAlly(int f, int o)
Removes an ally from the faction's allies list.
Definition: faction.c:701
void faction_rmEnemy(int f, int o)
Removes an enemy from the faction's enemies list.
Definition: faction.c:608
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition: faction.c:1197
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition: faction.c:304
int faction_setInvisible(int id, int state)
Sets the faction's invisible state.
Definition: faction.c:256
void faction_addAlly(int f, int o)
Adds an ally to the faction's allies list.
Definition: faction.c:655
void faction_addEnemy(int f, int o)
Adds an enemy to the faction's enemies list.
Definition: faction.c:562
int faction_get(const char *name)
Gets a faction ID by name.
Definition: faction.c:182
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition: faction.c:1222
Header file with generic functions and naev-specifics.
#define PATH_MAX
Definition: naev.h:50
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition: ndata.c:232
static char buf[NEWS_MAX_LENGTH]
Definition: news.c:45
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition: nxml.c:75
void pilot_hyperspaceAbort(Pilot *p)
Stops the pilot from hyperspacing.
Definition: pilot.c:2772
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
Definition: pilot.c:83
void pilot_delete(Pilot *p)
Deletes a pilot.
Definition: pilot.c:2603
void player_targetHyperspaceSet(int id, int nomsg)
Sets the player's hyperspace target.
Definition: player.c:1778
void player_targetSpobSet(int id)
Sets the player's target spob.
Definition: player.c:1453
static const double a[]
Definition: rng.c:247
static const double d[]
Definition: rng.c:273
static const double b[]
Definition: rng.c:256
void safelanes_recalculate(void)
Update the safe lane locations in response to the universe changing (e.g., diff applied).
Definition: safelanes.c:249
void space_reconstructPresences(void)
Reset the presence of all systems.
Definition: space.c:4220
int system_addJumpDiff(StarSystem *sys, xmlNodePtr node)
Adds a jump point to a star system from a diff.
Definition: space.c:2531
void space_gfxUnload(StarSystem *sys)
Unloads all the graphics for a star system.
Definition: space.c:2068
int spob_luaInit(Spob *spob)
Updatse the spob's internal Lua stuff.
Definition: space.c:1942
int spob_getService(const char *name)
Converts name to spob service flag.
Definition: space.c:184
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition: space.c:1006
int system_addVirtualSpob(StarSystem *sys, const char *spobname)
Adds a virtual spob to a system.
Definition: space.c:2466
int system_rmJump(StarSystem *sys, const char *jumpname)
Removes a jump point from a star system.
Definition: space.c:2550
int spob_setFaction(Spob *p, int faction)
Changes the spobs faction.
Definition: space.c:345
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition: space.c:914
int spob_rmService(Spob *p, int service)
Removes a service from a spob.
Definition: space.c:414
StarSystem * cur_system
Definition: space.c:105
int system_addSpob(StarSystem *sys, const char *spobname)
Adds a spob to a star system.
Definition: space.c:2372
int system_rmVirtualSpob(StarSystem *sys, const char *spobname)
Removes a virtual spob from a system.
Definition: space.c:2490
int spob_addService(Spob *p, int service)
Removes a service from a spob.
Definition: space.c:372
const char * spob_getServiceName(int service)
Gets the (English) name for a service code.
Definition: space.c:165
void space_gfxLoad(StarSystem *sys)
Loads all the graphics for a star system.
Definition: space.c:2057
int system_rmSpob(StarSystem *sys, const char *spobname)
Removes a spob from a star system.
Definition: space.c:2411
The representation of an in-game pilot.
Definition: pilot.h:210
int devmode
Definition: conf.h:158
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition: space.h:88
Universe diff filepath list.
Definition: unidiff.c:36
char * name
Definition: unidiff.c:37
char * filename
Definition: unidiff.c:38
Represents each Universe Diff.
Definition: unidiff.c:145
UniHunk_t * failed
Definition: unidiff.c:148
char * name
Definition: unidiff.c:146
UniHunk_t * applied
Definition: unidiff.c:147
Represents the hunk's target.
Definition: unidiff.c:60
UniHunkTargetType_t type
Definition: unidiff.c:61
union UniHunkTarget_t::@28 u
char * name
Definition: unidiff.c:63
Represents a single hunk in the diff.
Definition: unidiff.c:125
union UniHunk_t::@29 u
UniHunkType_t type
Definition: unidiff.c:128
xmlNodePtr node
Definition: unidiff.c:129
UniHunkTarget_t target
Definition: unidiff.c:126
int tech_rmItemTech(tech_group_t *tech, const char *value)
Removes an item from a tech.
Definition: tech.c:485
tech_group_t * tech_groupCreate(void)
Creates a tech group.
Definition: tech.c:173
int tech_rmItem(const char *name, const char *value)
Removes a tech item.
Definition: tech.c:504
int tech_addItemTech(tech_group_t *tech, const char *value)
Adds an item to a tech.
Definition: tech.c:465
int tech_addItem(const char *name, const char *value)
Adds an item to a tech.
Definition: tech.c:431
static UniDiffData_t * diff_available
Definition: unidiff.c:40
static int diff_checkUpdateUniverse(void)
Checks and updates the universe if necessary.
Definition: unidiff.c:1777
UniHunkType_t
Represents the different type of hunk actions.
Definition: unidiff.c:72
static UniDiff_t * diff_get(const char *name)
Gets a diff by name.
Definition: unidiff.c:268
static UniDiff_t * diff_stack
Definition: unidiff.c:154
int diff_load(xmlNodePtr parent)
Loads the diffs.
Definition: unidiff.c:1740
void unidiff_universeDefer(int enable)
Sets whether or not to defer universe change stuff.
Definition: unidiff.c:1832
static int diff_patchTech(UniDiff_t *diff, xmlNodePtr node)
Patches a tech.
Definition: unidiff.c:490
static UniDiff_t * diff_newDiff(void)
Creates a new UniDiff_t for usage.
Definition: unidiff.c:1502
static int diff_patchHunk(UniHunk_t *hunk)
Applies a hunk and adds it to the diff.
Definition: unidiff.c:1082
int diff_apply(const char *name)
Applies a diff to the universe.
Definition: unidiff.c:282
void diff_remove(const char *name)
Removes a diff from the universe.
Definition: unidiff.c:1457
static int diff_patch(xmlNodePtr parent)
Actually applies a diff in XML node form.
Definition: unidiff.c:884
static void diff_cleanup(UniDiff_t *diff)
Cleans up a diff.
Definition: unidiff.c:1646
void diff_clear(void)
Removes all active diffs. (Call before economy_destroy().)
Definition: unidiff.c:1472
static int diff_applyInternal(const char *name, int oneshot)
Applies a diff to the universe.
Definition: unidiff.c:294
int diff_loadAvailable(void)
Loads available universe diffs.
Definition: unidiff.c:197
static void diff_cleanupHunk(UniHunk_t *hunk)
Cleans up a hunk.
Definition: unidiff.c:1663
static int diff_patchFaction(UniDiff_t *diff, xmlNodePtr node)
Patches a faction.
Definition: unidiff.c:785
static int diff_patchSpob(UniDiff_t *diff, xmlNodePtr node)
Patches a spob.
Definition: unidiff.c:559
static int diff_universe_changed
Definition: unidiff.c:157
static void diff_hunkSuccess(UniDiff_t *diff, UniHunk_t *hunk)
Adds a hunk to the applied list.
Definition: unidiff.c:1443
static int diff_patchSystem(UniDiff_t *diff, xmlNodePtr node)
Patches a system.
Definition: unidiff.c:342
static int diff_universe_defer
Definition: unidiff.c:158
void diff_free(void)
Clean up after diff_loadAvailable().
Definition: unidiff.c:1485
static int diff_removeDiff(UniDiff_t *diff)
Removes a diff.
Definition: unidiff.c:1516
int diff_save(xmlTextWriterPtr writer)
Saves the active diffs.
Definition: unidiff.c:1719
int diff_isApplied(const char *name)
Checks if a diff is currently applied.
Definition: unidiff.c:255
UniHunkTargetType_t
Represents the possible hunk targets.
Definition: unidiff.c:47
static void diff_hunkFailed(UniDiff_t *diff, UniHunk_t *hunk)
Adds a hunk to the failed list.
Definition: unidiff.c:1428