From 7ec0f0c0d0ba47e23f87d83e4848cd0f4973abff Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 4 Mar 2008 21:55:29 +0100 Subject: [PATCH] New utility program empdump empdump exports and imports game state as plain text. Limitations: it currently can't export player bmaps, power report, telegrams, announcements, message of the day, no-login message and log files. Exported floating-point values may be inexact. Importing an exported game state may not result in identical data files; besides the loss of floating-point precision just mentioned, coordinates are normalized, and characters beyond a string's terminating zero in a character array are lost. Bug: importing resets timestamps to zero. It should set them to the current time. --- Make.mk | 2 +- man/empdump.6 | 59 ++++++++ src/util/empdump.c | 336 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 396 insertions(+), 1 deletion(-) create mode 100644 man/empdump.6 create mode 100644 src/util/empdump.c diff --git a/Make.mk b/Make.mk index 5a97d3f33..caa55c811 100644 --- a/Make.mk +++ b/Make.mk @@ -104,7 +104,7 @@ deps := $(obj:.o=.d) # Library archives: libs := $(addprefix lib/, libcommon.a libas.a libgen.a libglobal.a) # Programs: -util := $(addprefix src/util/, $(addsuffix $(EXEEXT), empsched fairland files pconfig)) +util := $(addprefix src/util/, $(addsuffix $(EXEEXT), empdump empsched fairland files pconfig)) client := src/client/empire$(EXEEXT) server := src/server/emp_server$(EXEEXT) # Info subjects: diff --git a/man/empdump.6 b/man/empdump.6 new file mode 100644 index 000000000..3e16c93e7 --- /dev/null +++ b/man/empdump.6 @@ -0,0 +1,59 @@ +.TH EMPDUMP 6 +.SH NAME +empdump \- Export/import Empire game state +.SH SYNOPSIS +.B empdump +[ +.B \-mtxhv +] +[ +.BI \-e " configfile" +] +[ +.I dump-file +] +.br +.SH DESCRIPTION +.B empdump +exports and imports game state as plain text. +.SH OPTIONS +.TP +.BI \-e " configfile" +Use game configuration in \fIconfigfile\fR. +.TP +.B \-h +Help. Print brief usage information and exit. +.TP +.TP +.B \-m +Use machine-readable format for export. Import always recognizes both +machine-readable and human-readable format. +.TP +.B \-t +Test import, don't update game state. +.TP +.B \-v +Print version information and exit. +.TP +.B \-x +Export game state to standard output. +.SH OPERANDS +.TP +.I dump-file +The file to import. +.SH "LIMITATIONS" +.B empdump +can't export player bmaps, power report, telegrams, announcements, +message of the day, no-login message and log files. Exported +floating-point values may be inexact. Importing an exported game +state may not result in identical data files; besides the loss of +floating-point precision just mentioned, coordinates are normalized, +and characters beyond a string's terminating zero in a character array +are lost. +.SH "BUGS" +Importing resets timestamps to zero. It should set them to the +current time. +.SH "SEE ALSO" +\fIemp_server\fR(6). +.SH AUTHOR +Markus Armbruster diff --git a/src/util/empdump.c b/src/util/empdump.c new file mode 100644 index 000000000..344c26e3b --- /dev/null +++ b/src/util/empdump.c @@ -0,0 +1,336 @@ +/* + * Empire - A multi-player, client/server Internet based war game. + * Copyright (C) 1986-2008, Dave Pare, Jeff Bailey, Thomas Ruschak, + * Ken Stevens, Steve McClure + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * --- + * + * See files README, COPYING and CREDITS in the root of the source + * tree for related information and legal notices. It is expected + * that future projects/authors will amend these files as needed. + * + * --- + * + * empdump.c: Export/import Empire game state + * + * Known contributors to this file: + * Markus Armbruster, 2008 + */ + +#include + +#include +#include +#include +#include +#include +#include "file.h" +#include "optlist.h" +#include "prototypes.h" +#include "version.h" +#include "xdump.h" + +static void dump_table(int, int); +static void pln_fixup(void); +static void lnd_fixup(void); +static void nuk_fixup(void); + +int +main(int argc, char *argv[]) +{ + char *config_file = NULL; + char *import = NULL; + int export = 0; + int private = 0; + int human = 1; + int opt, i, lineno, type; + FILE *impf = NULL; + int dirty[EF_MAX]; + + while ((opt = getopt(argc, argv, "e:mtxhv")) != EOF) { + switch (opt) { + case 'e': + config_file = optarg; + break; + case 'h': + printf("Usage: %s [OPTION]... [DUMP-FILE]\n" + " -e CONFIG-FILE configuration file\n" + " (default %s)\n" + " -m use machine-readable format\n" + " -t test import, don't update game state\n" + " -x export to standard output\n" + " -h display this help and exit\n" + " -v display version information and exit\n", + argv[0], dflt_econfig); + exit(0); + case 'm': + human = 0; + break; + case 't': + private = EFF_PRIVATE; + break; + case 'x': + export = 1; + break; + case 'v': + printf("%s\n\n%s", version, legal); + exit(0); + default: + fprintf(stderr, "Try -h for help.\n"); + exit(1); + } + } + + if (argv[optind]) + import = argv[optind++]; + + if (import) { + impf = fopen(import, "r"); + if (!impf) { + fprintf(stderr, "Cant open %s for reading (%s)\n", + import, strerror(errno)); + exit(1); + } + } else + private = EFF_PRIVATE; + + /* read configuration & initialize */ + empfile_init(); + if (emp_config(config_file) < 0) + exit(1); + empfile_fixup(); + nsc_init(); + if (read_builtin_tables() < 0) + exit(1); + if (read_custom_tables() < 0) + exit(1); + if (chdir(gamedir)) { + fprintf(stderr, "Can't chdir to %s (%s)\n", + gamedir, strerror(errno)); + exit(1); + } + global_init(); + + for (i = 0; i < EF_MAX; i++) { + if (!EF_IS_GAME_STATE(i)) + continue; + if (!ef_open(i, EFF_MEM | private)) + exit(1); + } + + /* import from IMPORT */ + memset(dirty, 0, sizeof(dirty)); + if (import) { + lineno = 1; + while ((type = xundump(impf, import, &lineno, EF_BAD)) >= 0) + dirty[type] = 1; + if (type == EF_BAD) + exit(1); + pln_fixup(); + lnd_fixup(); + nuk_fixup(); + } + + if (ef_verify() < 0) + exit(1); + + /* export to stdout */ + if (export) { + for (i = 0; i < EF_MAX; i++) { + if (!EF_IS_GAME_STATE(i)) + continue; + dump_table(i, human); + } + } + + /* write out imported data */ + for (i = 0; i < EF_MAX; i++) { + if (!EF_IS_GAME_STATE(i)) + continue; + if (!private && dirty[i]) { + if (!ef_close(i)) + exit(1); + } + } + + return 0; +} + +static void +printf_wrapper(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +static void +dump_table(int type, int human) +{ + struct xdstr xd; + struct castr *ca; + int i; + void *p; + + ca = ef_cadef(type); + if (!ca) + return; + + xdinit(&xd, 0, human, printf_wrapper); + xdhdr(&xd, ef_nameof(type), 0); + xdcolhdr(&xd, ca); + for (i = 0; (p = ef_ptr(type, i)); i++) { + xdflds(&xd, ca, p); + printf("\n"); + } + xdftr(&xd, i); +} + + +/* TODO remove need for this */ + +#include +#include "ship.h" +#include "plane.h" +#include "land.h" +#include "nuke.h" + +static int fit_plane_on_ship(struct plnstr *, struct shpstr *); +static int fit_plane_on_land(struct plnstr *, struct lndstr *); + +static void +pln_fixup(void) +{ + int i; + struct plnstr *pp; + struct shpstr *csp; + struct lndstr *clp; + + for (i = 0; (pp = ef_ptr(EF_PLANE, i)); i++) { + if (!pp->pln_own) + continue; + csp = ef_ptr(EF_SHIP, pp->pln_ship); + clp = ef_ptr(EF_LAND, pp->pln_land); + if (csp) + fit_plane_on_ship(pp, csp); + else if (clp) + fit_plane_on_land(pp, clp); + } +} + +static void +lnd_fixup(void) +{ + int i; + struct lndstr *lp; + struct shpstr *csp; + struct lndstr *clp; + + for (i = 0; (lp = ef_ptr(EF_LAND, i)); i++) { + if (!lp->lnd_own) + continue; + csp = ef_ptr(EF_SHIP, lp->lnd_ship); + clp = ef_ptr(EF_LAND, lp->lnd_land); + if (csp) + csp->shp_nland++; + else if (clp) + clp->lnd_nland++; + } +} + +static void +nuk_fixup(void) +{ + int i; + struct nukstr *np; + struct plnstr *cpp; + + for (i = 0; (np = ef_ptr(EF_NUKE, i)); i++) { + if (!np->nuk_own) + continue; + cpp = ef_ptr(EF_PLANE, np->nuk_plane); + if (cpp) + cpp->pln_nuketype = np->nuk_type; + } +} + +/* Temporarily copied from src/lib/subs/???sub.c */ + +/* + * Fit a plane of PP's type on ship SP. + * Adjust SP's plane counters. + * Updating the plane accordingly is the caller's job. + * Return whether it fits. + */ +static int +fit_plane_on_ship(struct plnstr *pp, struct shpstr *sp) +{ + struct plchrstr *pcp = plchr + pp->pln_type; + struct mchrstr *mcp = mchr + sp->shp_type; + int wanted; + + if (pcp->pl_flags & P_K) { + /* chopper, try chopper slot first */ + if (sp->shp_nchoppers < mcp->m_nchoppers) + return ++sp->shp_nchoppers; + /* else try plane slot */ + wanted = M_FLY; + } else if (pcp->pl_flags & P_E) { + /* x-light, try x-light slot first */ + if (sp->shp_nxlight < mcp->m_nxlight) + return ++sp->shp_nxlight; + /* else try plane slot */ + wanted = M_MSL | M_FLY; + } else if (!(pcp->pl_flags & P_L)) { + /* not light, no go */ + wanted = 0; + } else if (pcp->pl_flags & P_M) { + /* missile, use plane slot */ + wanted = M_MSL | M_FLY; + } else { + /* fixed-wing plane, use plane slot */ + wanted = M_FLY; + } + + if ((mcp->m_flags & wanted) == 0) + return 0; /* ship not capable */ + + if (sp->shp_nplane < mcp->m_nplanes) + return ++sp->shp_nplane; + + return 0; +} + +/* + * Fit a plane of PP's type on land unit LP. + * Adjust LP's plane counters. + * Updating the plane accordingly is the caller's job. + * Return whether it fits. + */ +static int +fit_plane_on_land(struct plnstr *pp, struct lndstr *lp) +{ + struct plchrstr *pcp = plchr + pp->pln_type; + struct lchrstr *lcp = lchr + lp->lnd_type; + + if ((pcp->pl_flags & P_E) && lp->lnd_nxlight < lcp->l_nxlight) + return ++lp->lnd_nxlight; + + return 0; +} -- 2.43.0