ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/swap.C
Revision: 1.7
Committed: Thu Sep 14 22:34:05 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.6: +1 -7 lines
Log Message:
indent

File Contents

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