home · contact · privacy
Server: Read in former "config" data as normal server god commands.
[plomrogue] / src / server / init.c
1 /* src/server/init.c */
2
3 #define _POSIX_C_SOURCE 2 /* getopt(), optarg */
4 #include "init.h"
5 #include <errno.h> /* global errno, EEXIST */
6 #include <stddef.h> /* NULL */
7 #include <stdint.h> /* uint32_t */
8 #include <stdio.h> /* FILE, sprintf(), fflush() */
9 #include <stdlib.h> /* exit(), free(), atoi() */
10 #include <string.h> /* strlen() */
11 #include <sys/stat.h> /* mkdir() */
12 #include <sys/types.h> /* defines pid_t, time_t */
13 #include <time.h> /* time() */
14 #include <unistd.h> /* optarg, getopt(), access(), getpid() */
15 #include "../common/parse_file.h" /* err_line_zero(), err_line_inc() */
16 #include "../common/readwrite.h" /* try_fopen(), try_fclose(), textfile_width(),
17                                   * try_fgets(), try_fwrite(),
18                                   * detect_atomic_leftover()
19                                   */
20 #include "../common/rexit.h" /* exit_err(), exit_trouble() */
21 #include "../common/try_malloc.h" /* try_malloc() */
22 #include "cleanup.h" /* set_cleanup_flag() */
23 #include "field_of_view.h" /* build_fov_map() */
24 #include "hardcoded_strings.h" /* s */
25 #include "map.h" /* remake_map() */
26 #include "things.h" /* Thing, ThingType, free_things(), add_things(),
27                      * get_thing_id_action_id_by_name()
28                      */
29 #include "run.h" /* obey_msg(), io_loop() */
30 #include "world.h" /* global world */
31
32
33
34
35 /* Pass to obey_msg() lines from file at "path", on "record" write to same. Do
36  * not pass lines that consist only of a newline character. Transform newline
37  * in the line passed to \0.
38  */
39 static void obey_lines_from_file(char * path, uint8_t record);
40
41 /* Replay game from record file up to the turn named in world.replay, then turn
42  * over to manual replay via io_loop().
43  */
44 static void replay_game();
45
46 /* Return 1 if the type defined by world.player_type has a .start_n of 0.
47  * Return 2 if no thing action with .name of s[S_CMD_WAIT] is defined.
48  * Else, return 0.
49  */
50 static uint8_t world_cannot_be_made();
51
52
53 static void obey_lines_from_file(char * path, uint8_t record)
54 {
55     char * f_name = "obey_lines_from_file()";
56     FILE * file = try_fopen(path, "r", f_name);
57     uint32_t linemax = textfile_width(file);
58     char * line = try_malloc(linemax + 1, f_name);
59     while (NULL != try_fgets(line, linemax + 1, file, f_name))
60     {
61         if (strlen(line))
62         {
63             if (strcmp("\n", line))
64             {
65                 char * nl = strchr(line, '\n');
66                 if (nl)
67                 {
68                     *nl = '\0';
69                 }
70                 obey_msg(line, record, 1);
71             }
72             err_line_inc();
73         }
74     }
75     free(line);
76     try_fclose(file, f_name);
77 }
78
79
80
81 static void replay_game()
82 {
83     char * f_name = "replay_game()";
84     exit_err(access(s[S_PATH_RECORD], F_OK), "No record found to replay.");
85     FILE * file = try_fopen(s[S_PATH_RECORD], "r", f_name);
86     uint32_t linemax = textfile_width(file);
87     char * line = try_malloc(linemax + 1, f_name);
88     while (   world.turn < world.replay
89            && NULL != try_fgets(line, linemax + 1, file, f_name))
90     {
91         obey_msg(line, 0, 1);
92         err_line_inc();
93     }
94     uint8_t end = 0;
95     while (!io_loop())
96     {
97         if (!end)
98         {
99             end = (NULL == try_fgets(line, linemax + 1, file, f_name));
100             if (!end)
101             {
102                 obey_msg(line, 0, 1);
103                 err_line_inc();
104             }
105         }
106     }
107     free(line);
108     try_fclose(file, f_name);
109 }
110
111
112
113 static uint8_t world_cannot_be_made()
114 {
115     uint8_t player_will_be_generated = 0;
116     struct ThingType * tt;
117     for (tt = world.thing_types; NULL != tt; tt = tt->next)
118     {
119         if (world.player_type == tt->id)
120         {
121             player_will_be_generated = 0 < tt->start_n;
122             break;
123         }
124     }
125     if (!player_will_be_generated)
126     {
127         return 1;
128     }
129     if (!get_thing_action_id_by_name(s[S_CMD_WAIT]))
130     {
131         return 2;
132     }
133     return 0;
134 }
135
136
137
138 extern void obey_argv(int argc, char * argv[])
139 {
140     int opt;
141     while (-1 != (opt = getopt(argc, argv, "vs::")))
142     {
143         if      ('v' == opt)
144         {
145             world.is_verbose = 1;
146         }
147         else if ('s' == opt)
148         {
149             world.replay = 1;
150             if (optarg)
151             {
152                 world.replay = atoi(optarg);
153             }
154         }
155         else
156         {
157             exit(EXIT_FAILURE);
158         }
159     }
160 }
161
162
163
164 extern void setup_server_io()
165 {
166     char * f_name = "setup_server_io()";
167     int test = mkdir("server", 0700);
168     exit_trouble(test && EEXIST != errno, f_name, "mkdir()");
169     world.file_out = try_fopen(s[S_PATH_OUT], "w", f_name);
170     world.server_test = try_malloc(10 + 1 + 10 + 1 + 1, f_name);
171     test = sprintf(world.server_test, "%d %d\n", getpid(), (int) time(0));
172     exit_trouble(test < 0, f_name, s[S_FCN_SPRINTF]);
173     try_fwrite(world.server_test, strlen(world.server_test), 1,
174                world.file_out, f_name);
175     fflush(world.file_out);
176     set_cleanup_flag(CLEANUP_OUT);
177     char * path_in = s[S_PATH_IN];
178     if (!access(path_in, F_OK))        /* This keeps out input from old input */
179     {                                  /* file streams of clients             */
180         unlink(path_in)   ;            /* communicating with server processes */
181     }                                  /* superseded by this current one.     */
182     world.file_in = try_fopen(path_in, "w", f_name);
183     try_fclose(world.file_in, f_name);
184     world.file_in = try_fopen(path_in, "r", f_name);
185     set_cleanup_flag(CLEANUP_IN);
186 }
187
188
189
190 extern uint8_t remake_world()
191 {
192     uint8_t test = world_cannot_be_made();
193     if (test)
194     {
195         return test;
196     }
197     free(world.log);
198     world.log = NULL;      /* thing_actions.c's update_log() checks for this. */
199     world.seed_map = world.seed;
200     free_things(world.things);
201     remake_map();
202     struct ThingType * tt;
203     for (tt = world.thing_types; NULL != tt; tt = tt->next)
204     {
205         if (world.player_type == tt->id)
206         {
207             add_things(tt->id, tt->start_n);
208             break;
209         }
210     }
211     for (tt = world.thing_types; NULL != tt; tt = tt->next)
212     {
213         if (world.player_type != tt->id)
214         {
215             add_things(tt->id, tt->start_n);
216         }
217     }
218     struct Thing * t;
219     for (t = world.things; NULL != t; t = t->next)
220     {
221         t->fov_map = t->lifepoints ? build_fov_map(t) : NULL;
222     }
223     world.turn = 1;
224     world.do_update = 1;
225     world.exists = 1;
226     return 0;
227 }
228
229
230
231 extern void run_game()
232 {
233     char * f_name = "run_game()";
234     detect_atomic_leftover(s[S_PATH_SAVE]);
235     detect_atomic_leftover(s[S_PATH_RECORD]);
236     err_line_zero();
237     if (world.replay)
238     {
239         replay_game();
240         return;
241     }
242     if (!access(s[S_PATH_SAVE], F_OK))
243     {
244         obey_lines_from_file(s[S_PATH_SAVE], 0);
245     }
246     else
247     {
248         char * err = "No world config file from which to start a new world.";
249         exit_err(access(s[S_PATH_CONFIG], F_OK), err);
250         obey_lines_from_file(s[S_PATH_CONFIG], 1);
251         err_line_zero();
252         char * command = s[S_CMD_MAKE_WORLD];
253         char * msg = try_malloc(strlen(command) + 1 + 11 + 1, f_name);
254         int test = sprintf(msg, "%s %d", command, (int) time(NULL));
255         exit_trouble(test < 0, f_name, s[S_FCN_SPRINTF]);
256         obey_msg(msg, 1, 1);
257         free(msg);
258     }
259     err_line_zero();
260     io_loop();
261 }