| /* |
| * ----------------------------------------------------------------------------- |
| * "THE BEER-WARE LICENSE" (Revision 42): |
| * <webmaster@flippeh.de> wrote this file. As long as you retain this notice you |
| * can do whatever you want with this stuff. If we meet some day, and you think |
| * this stuff is worth it, you can buy me a beer in return. Lukas Niederbremer. |
| * ----------------------------------------------------------------------------- |
| * |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <getopt.h> |
| #include <time.h> |
| #include <math.h> |
| |
| #include "nbt.h" |
| |
| void display_version(); |
| void display_help(); |
| void print_usage(FILE *, const char *); |
| int valid_level(nbt_tag *root); |
| |
| char *time_to_string(long); |
| |
| #define SHOW -2 |
| #define OFF -1 |
| |
| struct coord |
| { |
| int x; |
| int y; |
| int z; |
| }; |
| |
| int main(int argc, char **argv) |
| { |
| static int opt_verbose = 0; |
| static int opt_short = 0; |
| |
| long opt_time = OFF; |
| int opt_lp = OFF; |
| int opt_snow = OFF; |
| int opt_spawn = OFF; |
| |
| struct coord spawn_coords; |
| |
| /* Command line processing */ |
| for (;;) |
| { |
| static struct option long_options[] = |
| { |
| { "spawn", optional_argument, NULL, 's' }, |
| { "version", no_argument, NULL, 'v' }, |
| { "help", no_argument, NULL, 'h' }, |
| { "verbose", no_argument, &opt_verbose, 1 }, |
| { "short", no_argument, &opt_short, 1 }, |
| { "snow", optional_argument, NULL, 'S' }, |
| { "time", optional_argument, NULL, 't' }, |
| { "last-played", no_argument, NULL, 'l' }, |
| { NULL, no_argument, NULL, 0 } |
| }; |
| |
| int option_index = 0; |
| int opt; |
| |
| |
| opt = getopt_long(argc, argv, "s::vhS::t::la", long_options, &option_index); |
| |
| if (opt == -1) |
| break; |
| |
| switch (opt) |
| { |
| case 0: |
| if (long_options[option_index].flag != 0) |
| break; |
| |
| break; |
| |
| case 'v': |
| display_version(); |
| |
| return EXIT_SUCCESS; |
| |
| case 'h': |
| print_usage(stdout, argv[0]); |
| printf("\n"); |
| display_help(); |
| |
| return EXIT_SUCCESS; |
| |
| case 's': |
| opt_spawn = 0; |
| |
| if (optarg == NULL) |
| opt_spawn = SHOW; |
| else |
| { |
| opt_spawn = 0; |
| |
| /* Try parsing the string */ |
| if (sscanf(optarg, "%d,%d,%d", &spawn_coords.x, |
| &spawn_coords.y, |
| &spawn_coords.z) < 3) |
| { |
| fprintf(stderr, "Could not parse string \"%s\"\n", |
| optarg); |
| |
| opt_spawn = -1; |
| |
| break; |
| } |
| |
| } |
| |
| break; |
| |
| case 'S': |
| if (optarg != NULL) |
| { |
| if ((strcmp(optarg, "1") == 0) |
| || (strcmp(optarg, "true") == 0) |
| || (strcmp(optarg, "yes") == 0)) |
| opt_snow = 1; |
| else |
| opt_snow = 0; |
| } |
| else |
| opt_snow = SHOW; |
| |
| break; |
| |
| case 'l': |
| opt_lp = SHOW; |
| |
| break; |
| |
| case 't': |
| if (optarg != NULL) |
| { |
| /* We want to change the time */ |
| int h, m, s; |
| |
| if (sscanf(optarg, "%02d:%02d:%02d", &h, &m, &s) < 3) |
| { |
| fprintf(stderr, "Could not parse string \"%s\"\n", |
| optarg); |
| |
| } |
| else |
| { |
| opt_time = (h-6) * 3600; |
| opt_time += m * 60; |
| opt_time += s; |
| |
| opt_time = ceil(opt_time / 3.6); |
| |
| if (opt_time < 0) |
| opt_time = 24000 - abs(opt_time); |
| } |
| } |
| else |
| opt_time = SHOW; |
| |
| break; |
| |
| case 'a': |
| opt_snow = opt_snow == OFF ? SHOW : opt_snow; |
| opt_time = opt_time == OFF ? SHOW : opt_time; |
| opt_lp = opt_lp == OFF ? SHOW : opt_lp; |
| |
| break; |
| } |
| } |
| |
| if (opt_verbose) |
| { |
| printf("Settings...\n"); |
| printf(" ~> Changing spawn:\t%s\n", |
| opt_spawn < 0 ? "Unchanged" |
| : (opt_spawn ? "View" |
| : "Manual")); |
| |
| printf(" ~> Snow:\t\t%s\n", |
| opt_snow < 0 ? "Unchanged" |
| : (opt_snow ? "On" |
| : "Off")); |
| |
| printf(" ~> Set time:\t\t%s\n", |
| opt_time >= 0 ? time_to_string(opt_time) |
| : "Unchanged"); |
| |
| printf("\n"); |
| } |
| |
| /* Make sure we still have some arguments (at least one) left */ |
| if (optind < argc) |
| { |
| nbt_file *nbt; |
| |
| char *file = argv[optind]; |
| |
| if (nbt_init(&nbt) != NBT_OK) |
| { |
| fprintf(stderr, "FATAL: Couldn't initialize NBT structure... "); |
| fprintf(stderr, "do you have like... no RAM?\n"); |
| |
| return EXIT_FAILURE; |
| } |
| |
| if (opt_verbose) printf("Trying to parse \"%s\"... ", file); |
| |
| if (nbt_parse(nbt, file) != NBT_OK) |
| { |
| if (opt_verbose) printf("failure\n"); |
| |
| fprintf(stderr, "FATAL: Couldn't parse NBT file\n"); |
| |
| return EXIT_FAILURE; |
| } |
| else |
| if (opt_verbose) |
| printf("success!\n"); |
| |
| if (opt_verbose) printf("Checking file... "); |
| |
| /* Validate file */ |
| if (valid_level(nbt->root) != 0) |
| { |
| if (opt_verbose) printf("failure\n"); |
| |
| fprintf(stderr, "FATAL: This is NOT a valid level file\n"); |
| |
| return EXIT_FAILURE; |
| } |
| else |
| { |
| /* data will not be NULL, no check needed */ |
| nbt_compound *data = nbt_cast_compound(nbt_find_tag_by_name("Data", nbt_cast_compound(nbt->root))); |
| |
| if (opt_verbose) printf("success!\n\n"); |
| |
| if (opt_snow != OFF) |
| { |
| nbt_tag *snow = nbt_find_tag_by_name("SnowCovered", data); |
| |
| if (!opt_short) |
| printf("Snow is "); |
| |
| if (opt_snow == SHOW) |
| printf("%s\n", *(char *)snow->value == 1 ? "enabled" |
| : "disabled"); |
| else |
| { |
| nbt_set_byte(snow, opt_snow); |
| |
| printf("%s\n", opt_snow ? "enabled" |
| : "disabled"); |
| } |
| |
| } |
| |
| if (opt_time == SHOW || opt_time >= 0) |
| { |
| nbt_tag *time = nbt_find_tag_by_name("Time", data); |
| |
| if (!opt_short) printf("Current ingame time: "); |
| |
| if (opt_time == SHOW) |
| printf("%s\n", time_to_string(*(long *)time->value)); |
| else |
| { |
| /* Change */ |
| nbt_set_long(time, opt_time); |
| |
| printf("%s\n", time_to_string(opt_time)); |
| } |
| } |
| |
| if (opt_lp != OFF) |
| { |
| nbt_tag *lp = nbt_find_tag_by_name("LastPlayed", data); |
| time_t t = *((size_t *)lp->value) / 1000; |
| |
| if (!opt_short) printf("Last played: "); |
| |
| printf("%s", ctime(&t)); |
| } |
| |
| if (opt_spawn != OFF) |
| { |
| nbt_tag *sx = nbt_find_tag_by_name("SpawnX", data); |
| nbt_tag *sy = nbt_find_tag_by_name("SpawnY", data); |
| nbt_tag *sz = nbt_find_tag_by_name("SpawnZ", data); |
| |
| int32_t *x = nbt_cast_int(sx); |
| int32_t *y = nbt_cast_int(sy); |
| int32_t *z = nbt_cast_int(sz); |
| |
| if ((x == NULL) || (y == NULL) || (z == NULL)) |
| fprintf(stderr, "Could't cast X, Y or Z tags\n"); |
| |
| if ((sz == NULL) || (sy == NULL) || (sx == NULL)) |
| fprintf(stderr, "Couldn't find X, Y or Z tags.\n"); |
| else |
| { |
| if (opt_spawn != SHOW) |
| { |
| nbt_set_int(sx, spawn_coords.x); |
| nbt_set_int(sy, spawn_coords.y); |
| nbt_set_int(sz, spawn_coords.z); |
| } |
| |
| x = nbt_cast_int(sx); |
| y = nbt_cast_int(sy); |
| z = nbt_cast_int(sz); |
| |
| if (!opt_short) |
| printf("The spawn is at "); |
| |
| printf("X%d, Y%d, Z%d\n", *x, *y, *z); |
| } |
| } |
| } |
| |
| nbt_write(nbt, file); |
| nbt_free(nbt); |
| } |
| else |
| print_usage(stderr, argv[0]); |
| |
| return EXIT_SUCCESS; |
| } |
| |
| void display_version() |
| { |
| printf("DatLevel (level.dat) v0.2\n"); |
| return; |
| } |
| |
| void display_help() |
| { |
| printf(" -v, --version display program version\n"); |
| printf(" -h, --help display this help\n"); |
| printf(" --verbose be verbose\n"); |
| printf(" --short show less\n"); |
| printf(" -s, --spawn[=x,y,z] display or set spawn coords\n"); |
| printf(" -S, --snow[=1|0] view or toggle snow\n"); |
| printf(" -t, --time[=HH:MM:SS] display or set time\n"); |
| printf(" -l, --last-played display date of last playing\n"); |
| printf(" -a show everything\n"); |
| |
| printf("\n"); |
| |
| return; |
| } |
| |
| void print_usage(FILE *stream, const char *progname) |
| { |
| fprintf(stream, "Usage: %s [OPTION..] <file>\n", progname); |
| |
| return; |
| } |
| |
| int valid_level(nbt_tag *root) |
| { |
| if (root->type == TAG_COMPOUND) |
| { |
| nbt_tag *data = nbt_find_tag_by_name("Data", nbt_cast_compound(root)); |
| |
| if (data != NULL) |
| { |
| if (data->type == TAG_COMPOUND) |
| { |
| /* ENABLE IF YOU ONLY WANT SINGLEPLAYER MAPS |
| * nbt_tag *player = nbt_find_tag_by_name("Player", data); |
| |
| if (player != NULL)*/ |
| return 0; |
| } |
| } |
| } |
| |
| return 1; |
| } |
| |
| char *time_to_string(long time) |
| { |
| static char ret[9]; |
| |
| long real_time = (((time + 6000) % 24000) * 3.6); |
| |
| int s = real_time % 60; |
| int m = real_time / 60; |
| int h = m / 60; |
| |
| m = m % 60; |
| |
| snprintf(ret, 9, "%02d:%02d:%02d", h, m, s); |
| |
| return ret; |
| } |