ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/swap.C
Revision: 1.6
Committed: Sun Sep 10 15:59:58 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.5: +206 -187 lines
Log Message:
indent

File Contents

# Content
1
2 /*
3 * static char *rcsid_swap_c =
4 * "$Id: swap.C,v 1.5 2006-09-07 10:01:58 pippijn Exp $";
5 */
6
7 /*
8 CrossFire, A Multiplayer game for X-windows
9
10 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
11 Copyright (C) 1992 Frank Tore Johansen
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
27 The author can be reached via e-mail to crossfire-devel@real-time.com
28 */
29
30 #include <global.h>
31 #ifndef __CEXTRACT__
32 # include <sproto.h>
33 #endif
34 #include <object.h>
35
36 /* This writes out information on all the temporary maps. It is called by
37 * swap_map below.
38 */
39 static void
40 write_map_log (void)
41 {
42 FILE *fp;
43 mapstruct *map;
44 char buf[MAX_BUF];
45 long current_time = time (NULL);
46
47 sprintf (buf, "%s/temp.maps", settings.localdir);
48 if (!(fp = fopen (buf, "w")))
49 {
50 LOG (llevError, "Could not open %s for writing\n", buf);
51 return;
52 }
53 for (map = first_map; map != NULL; map = map->next)
54 {
55 /* If tmpname is null, it is probably a unique player map,
56 * so don't save information on it.
57 */
58 if (map->in_memory != MAP_IN_MEMORY && (map->tmpname != NULL) && (strncmp (map->path, "/random", 7)))
59 {
60 /* the 0 written out is a leftover from the lock number for
61 * unique items and second one is from encounter maps.
62 * Keep using it so that old temp files continue
63 * to work.
64 */
65 fprintf (fp, "%s:%s:%ld:0:0:%d:0:%d\n", map->path, map->tmpname,
66 (map->reset_time == (uint32) - 1 ? (long unsigned) -1 : map->reset_time - current_time), map->difficulty, map->darkness);
67 }
68 }
69 fclose (fp);
70 }
71
72 void
73 read_map_log (void)
74 {
75 FILE *fp;
76 mapstruct *map;
77 char buf[MAX_BUF], *cp, *cp1;
78 int do_los, darkness, lock;
79 long sec = seconds ();
80
81
82 sprintf (buf, "%s/temp.maps", settings.localdir);
83 if (!(fp = fopen (buf, "r")))
84 {
85 LOG (llevDebug, "Could not open %s for reading\n", buf);
86 return;
87 }
88 while (fgets (buf, MAX_BUF, fp) != NULL)
89 {
90 map = get_linked_map ();
91 /* scanf doesn't work all that great on strings, so we break
92 * out that manually. strdup is used for tmpname, since other
93 * routines will try to free that pointer.
94 */
95 cp = strchr (buf, ':');
96 *cp++ = '\0';
97 strcpy (map->path, buf);
98 cp1 = strchr (cp, ':');
99 *cp1++ = '\0';
100 map->tmpname = strdup_local (cp);
101
102 /* Lock is left over from the lock items - we just toss it now.
103 * We use it twice - second one is from encounter, but as we
104 * don't care about the value, this works fine
105 */
106 sscanf (cp1, "%d:%d:%d:%hd:%d:%d\n", &map->reset_time, &lock, &lock, &map->difficulty, &do_los, &darkness);
107
108
109 map->in_memory = MAP_SWAPPED;
110 map->darkness = darkness;
111
112 /* When the reset time is saved out, it is adjusted so that
113 * the current time is subtracted (thus, it is saved as number
114 * of seconds from current time that it should reset). We need
115 * to add in the current seconds for this to work right.
116 * On metalforge, strange behavior was observed with really high
117 * reset times - I don't know how they got to that state,
118 * but easy enough to do some sanity checking here.
119 */
120 map->reset_time += sec;
121 if (map->reset_time > (uint32) (sec + MAP_MAXRESET))
122 map->reset_time = 0;
123
124 }
125 fclose (fp);
126 }
127
128 void
129 swap_map (mapstruct *map)
130 {
131 player *pl;
132
133 if (map->in_memory != MAP_IN_MEMORY)
134 {
135 LOG (llevError, "Tried to swap out map which was not in memory.\n");
136 return;
137 }
138 for (pl = first_player; pl != NULL; pl = pl->next)
139 if (pl->ob == NULL || (!(QUERY_FLAG (pl->ob, FLAG_REMOVED)) && pl->ob->map == map))
140 break;
141
142 if (pl != NULL)
143 {
144 LOG (llevDebug, "Wanted to swap out map with player.\n");
145 return;
146 }
147 remove_all_pets (map); /* Give them a chance to follow */
148
149 /* Update the reset time. Only do this is STAND_STILL is not set */
150 if (!map->fixed_resettime)
151 set_map_reset_time (map);
152
153 /* If it is immediate reset time, don't bother saving it - just get
154 * rid of it right away.
155 */
156 if (map->reset_time <= (uint32) seconds ())
157 {
158 LOG (llevDebug, "Resetting map %s.\n", map->path);
159 INVOKE_MAP (RESET, map);
160 delete_map (map);
161 return;
162 }
163
164 if (new_save_map (map, 0) == -1)
165 {
166 LOG (llevError, "Failed to swap map %s.\n", map->path);
167 /* need to reset the in_memory flag so that delete map will also
168 * free the objects with it.
169 */
170 map->in_memory = MAP_IN_MEMORY;
171 delete_map (map);
172 }
173 else
174 {
175 INVOKE_MAP (SWAPOUT, map);
176 free_map (map, 1);
177 }
178
179 if (settings.recycle_tmp_maps == TRUE)
180 write_map_log ();
181 }
182
183 void
184 check_active_maps (void)
185 {
186 mapstruct *map, *next;
187
188 for (map = first_map; map != NULL; map = next)
189 {
190 next = map->next;
191 if (map->in_memory != MAP_IN_MEMORY)
192 continue;
193 if (!map->timeout)
194 continue;
195 if (--(map->timeout) > 0)
196 continue;
197 /* If LWM is set, we only swap maps out when we run out of objects */
198 #ifndef MAX_OBJECTS_LWM
199 swap_map (map);
200 #endif
201 }
202 }
203
204 /*
205 * map_least_timeout() returns the map with the lowest timeout variable (not 0)
206 */
207
208 mapstruct *
209 map_least_timeout (char *except_level)
210 {
211 mapstruct *map, *chosen = NULL;
212 int timeout = MAP_MAXTIMEOUT + 1;
213
214 for (map = first_map; map != NULL; map = map->next)
215 if (map->in_memory == MAP_IN_MEMORY && strcmp (map->path, except_level) && map->timeout && map->timeout < timeout)
216 chosen = map, timeout = map->timeout;
217 return chosen;
218 }
219
220 /*
221 * players_on_map(): will be replaced by map->players when I'm satisfied
222 * that the variable is always correct.
223 * If show_all is true, we show everyone. If not, we don't show hidden
224 * players (dms)
225 */
226
227 int
228 players_on_map (mapstruct *m, int show_all)
229 {
230 player *pl;
231 int nr = 0;
232
233 for (pl = first_player; pl != NULL; pl = pl->next)
234 if (pl->ob != NULL && !QUERY_FLAG (pl->ob, FLAG_REMOVED) && pl->ob->map == m && (show_all || !pl->hidden))
235 nr++;
236 return nr;
237 }
238
239 /*
240 * flush_old_maps():
241 * Removes tmp-files of maps which are going to be reset next time
242 * they are visited.
243 * This is very useful if the tmp-disk is very full.
244 */
245 void
246 flush_old_maps (void)
247 {
248
249 mapstruct *m, *oldmap;
250 uint32 sec;
251
252 sec = seconds ();
253
254 m = first_map;
255 while (m)
256 {
257 /* There can be cases (ie death) where a player leaves a map and the timeout
258 * is not set so it isn't swapped out.
259 */
260 if ((m->in_memory == MAP_IN_MEMORY) && (m->timeout == 0) && !players_on_map (m, TRUE))
261 {
262 set_map_timeout (m);
263 }
264
265 /* per player unique maps are never really reset. However, we do want
266 * to perdiocially remove the entries in the list of active maps - this
267 * generates a cleaner listing if a player issues the map commands, and
268 * keeping all those swapped out per player unique maps also has some
269 * memory and cpu consumption.
270 * We do the cleanup here because there are lots of places that call
271 * swap map, and doing it within swap map may cause problems as
272 * the functions calling it may not expect the map list to change
273 * underneath them.
274 */
275 if ((m->unique || m->templatemap) && m->in_memory == MAP_SWAPPED)
276 {
277 LOG (llevDebug, "Resetting map %s.\n", m->path);
278 oldmap = m;
279 m = m->next;
280 delete_map (oldmap);
281 }
282 else if (m->in_memory != MAP_SWAPPED || m->tmpname == NULL || sec < m->reset_time)
283 {
284 m = m->next;
285 }
286 else
287 {
288 LOG (llevDebug, "Resetting map %s.\n", m->path);
289 INVOKE_MAP (RESET, m);
290 clean_tmp_map (m);
291 oldmap = m;
292 m = m->next;
293 delete_map (oldmap);
294 }
295 }
296 }