ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/swap.c
Revision: 1.1.1.1 (vendor branch)
Committed: Fri Feb 3 07:14:41 2006 UTC (18 years, 4 months ago) by root
Content type: text/plain
Branch: UPSTREAM
CVS Tags: UPSTREAM_2006_03_15, UPSTREAM_2006_02_22, UPSTREAM_2006_02_03
Changes since 1.1: +0 -0 lines
Log Message:
initial import

File Contents

# Content
1 /*
2 * static char *rcsid_swap_c =
3 * "$Id: swap.c,v 1.17 2005/12/05 23:34:04 akirschbaum 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 (map->reset_time==-1 ? -1: map->reset_time-current_time),
63 map->difficulty,
64 map->darkness);
65 }
66 }
67 fclose(fp);
68 }
69
70 void read_map_log(void)
71 {
72 FILE *fp;
73 mapstruct *map;
74 char buf[MAX_BUF],*cp,*cp1;
75 int do_los, darkness, lock;
76 long sec = seconds();
77
78
79 sprintf(buf,"%s/temp.maps", settings.localdir);
80 if (!(fp=fopen(buf,"r"))) {
81 LOG(llevDebug,"Could not open %s for reading\n", buf);
82 return;
83 }
84 while (fgets(buf, MAX_BUF, fp)!=NULL) {
85 map=get_linked_map();
86 /* scanf doesn't work all that great on strings, so we break
87 * out that manually. strdup is used for tmpname, since other
88 * routines will try to free that pointer.
89 */
90 cp=strchr(buf,':');
91 *cp++='\0';
92 strcpy(map->path, buf);
93 cp1=strchr(cp,':');
94 *cp1++='\0';
95 map->tmpname=strdup_local(cp);
96
97 /* Lock is left over from the lock items - we just toss it now.
98 * We use it twice - second one is from encounter, but as we
99 * don't care about the value, this works fine
100 */
101 sscanf(cp1,"%d:%d:%d:%hd:%d:%d\n",
102 &map->reset_time, &lock,
103 &lock, &map->difficulty, &do_los,
104 &darkness);
105
106
107 map->in_memory=MAP_SWAPPED;
108 map->darkness=darkness;
109
110 /* When the reset time is saved out, it is adjusted so that
111 * the current time is subtracted (thus, it is saved as number
112 * of seconds from current time that it should reset). We need
113 * to add in the current seconds for this to work right.
114 * On metalforge, strange behavior was observed with really high
115 * reset times - I don't know how they got to that state,
116 * but easy enough to do some sanity checking here.
117 */
118 map->reset_time += sec;
119 if (map->reset_time > (sec + MAP_MAXRESET))
120 map->reset_time = 0;
121
122 }
123 fclose(fp);
124 }
125
126 void swap_map(mapstruct *map) {
127 player *pl;
128
129 if(map->in_memory != MAP_IN_MEMORY) {
130 LOG(llevError,"Tried to swap out map which was not in memory.\n");
131 return;
132 }
133 for(pl=first_player;pl!=NULL;pl=pl->next)
134 if(pl->ob == NULL || (!(QUERY_FLAG(pl->ob,FLAG_REMOVED)) && pl->ob->map == map))
135 break;
136
137 if(pl != NULL) {
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 <= seconds()) {
151 mapstruct *oldmap = map;
152
153 LOG(llevDebug,"Resetting map %s.\n",map->path);
154 /* Lauwenmark : Here we handle the MAPRESET global event */
155 execute_global_event(EVENT_MAPRESET, map->path);
156 map = map->next;
157 delete_map(oldmap);
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 free_map(map,1);
170 }
171
172 if (settings.recycle_tmp_maps == TRUE)
173 write_map_log();
174 }
175
176 void check_active_maps(void) {
177 mapstruct *map, *next;
178
179 for(map=first_map;map!=NULL;map=next) {
180 next = map->next;
181 if(map->in_memory != MAP_IN_MEMORY)
182 continue;
183 if(!map->timeout)
184 continue;
185 if( --(map->timeout) > 0)
186 continue;
187 /* If LWM is set, we only swap maps out when we run out of objects */
188 #ifndef MAX_OBJECTS_LWM
189 swap_map(map);
190 #endif
191 }
192 }
193
194 /*
195 * map_least_timeout() returns the map with the lowest timeout variable (not 0)
196 */
197
198 mapstruct *map_least_timeout(char *except_level) {
199 mapstruct *map, *chosen=NULL;
200 int timeout = MAP_MAXTIMEOUT + 1;
201 for(map = first_map;map != NULL; map = map->next)
202 if(map->in_memory == MAP_IN_MEMORY && strcmp (map->path, except_level) &&
203 map->timeout && map->timeout < timeout)
204 chosen = map, timeout = map->timeout;
205 return chosen;
206 }
207
208 /*
209 * swap_below_max() tries to swap out maps which are still in memory because
210 * of MAP_TIMEOUT until used objects is below MAX_OBJECTS or there are
211 * no more maps to swap.
212 */
213
214 void swap_below_max(char *except_level) {
215 mapstruct *map;
216
217 if(nrofallocobjects - nroffreeobjects < MAX_OBJECTS)
218 return;
219 for(;;) {
220 #ifdef MAX_OBJECTS_LWM
221 if(nrofallocobjects - nroffreeobjects < MAX_OBJECTS_LWM)
222 return;
223 #else
224 if(nrofallocobjects - nroffreeobjects < MAX_OBJECTS)
225 return;
226 #endif
227 if ((map = map_least_timeout(except_level)) == NULL)
228 return;
229 LOG(llevDebug,"Trying to swap out %s before its time.\n", map->path);
230 map->timeout=0;
231 swap_map(map);
232 }
233 }
234
235 /*
236 * players_on_map(): will be replaced by map->players when I'm satisfied
237 * that the variable is always correct.
238 * If show_all is true, we show everyone. If not, we don't show hidden
239 * players (dms)
240 */
241
242 int players_on_map(mapstruct *m, int show_all) {
243 player *pl;
244 int nr=0;
245 for(pl=first_player;pl!=NULL;pl=pl->next)
246 if(pl->ob != NULL && !QUERY_FLAG(pl->ob,FLAG_REMOVED) && pl->ob->map==m &&
247 (show_all || !pl->hidden))
248 nr++;
249 return nr;
250 }
251
252 /*
253 * flush_old_maps():
254 * Removes tmp-files of maps which are going to be reset next time
255 * they are visited.
256 * This is very useful if the tmp-disk is very full.
257 */
258 void flush_old_maps(void) {
259
260 mapstruct *m, *oldmap;
261 long sec;
262 sec = seconds();
263
264 m= first_map;
265 while (m) {
266 /* There can be cases (ie death) where a player leaves a map and the timeout
267 * is not set so it isn't swapped out.
268 */
269 if ((m->in_memory == MAP_IN_MEMORY) && (m->timeout==0) &&
270 !players_on_map(m,TRUE)) {
271 set_map_timeout(m);
272 }
273
274 /* per player unique maps are never really reset. However, we do want
275 * to perdiocially remove the entries in the list of active maps - this
276 * generates a cleaner listing if a player issues the map commands, and
277 * keeping all those swapped out per player unique maps also has some
278 * memory and cpu consumption.
279 * We do the cleanup here because there are lots of places that call
280 * swap map, and doing it within swap map may cause problems as
281 * the functions calling it may not expect the map list to change
282 * underneath them.
283 */
284 if ((m->unique || m->template) && m->in_memory == MAP_SWAPPED) {
285 LOG(llevDebug,"Resetting map %s.\n",m->path);
286 oldmap = m;
287 m = m->next;
288 delete_map(oldmap);
289 }
290 else if(m->in_memory != MAP_SWAPPED || m->tmpname == NULL ||
291 sec < m->reset_time) {
292 m = m->next;
293 }
294 else {
295 LOG(llevDebug,"Resetting map %s.\n",m->path);
296 /* Lauwenmark : Here we handle the MAPRESET global event */
297 execute_global_event(EVENT_MAPRESET, m->path);
298 clean_tmp_map(m);
299 oldmap = m;
300 m = m->next;
301 delete_map(oldmap);
302 }
303 }
304 }