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, 3 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

# User Rev Content
1 root 1.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     }