ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/swap.C
Revision: 1.3
Committed: Tue Aug 29 08:01:38 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.2: +121 -121 lines
Log Message:
expand initial tabs to spaces

File Contents

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