ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/swap.C
Revision: 1.1
Committed: Sun Aug 13 17:16:05 2006 UTC (17 years, 10 months ago) by elmex
Content type: text/plain
Branch: MAIN
Log Message:
Made server compile with C++.
Removed cfanim plugin and crossedit.
C++ here we come.

File Contents

# User Rev Content
1 elmex 1.1 /*
2     * static char *rcsid_swap_c =
3     * "$Id$";
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     /* Lauwenmark : Here we handle the MAPRESET global event */
157     execute_global_event(EVENT_MAPRESET, map);
158     delete_map(map);
159     return;
160     }
161    
162     if (new_save_map (map, 0) == -1) {
163     LOG(llevError, "Failed to swap map %s.\n", map->path);
164     /* need to reset the in_memory flag so that delete map will also
165     * free the objects with it.
166     */
167     map->in_memory = MAP_IN_MEMORY;
168     delete_map(map);
169     } else {
170     execute_global_event(EVENT_MAPOUT, map);
171     free_map(map,1);
172     }
173    
174     if (settings.recycle_tmp_maps == TRUE)
175     write_map_log();
176     }
177    
178     void check_active_maps(void) {
179     mapstruct *map, *next;
180    
181     for(map=first_map;map!=NULL;map=next) {
182     next = map->next;
183     if(map->in_memory != MAP_IN_MEMORY)
184     continue;
185     if(!map->timeout)
186     continue;
187     if( --(map->timeout) > 0)
188     continue;
189     /* If LWM is set, we only swap maps out when we run out of objects */
190     #ifndef MAX_OBJECTS_LWM
191     swap_map(map);
192     #endif
193     }
194     }
195    
196     /*
197     * map_least_timeout() returns the map with the lowest timeout variable (not 0)
198     */
199    
200     mapstruct *map_least_timeout(char *except_level) {
201     mapstruct *map, *chosen=NULL;
202     int timeout = MAP_MAXTIMEOUT + 1;
203     for(map = first_map;map != NULL; map = map->next)
204     if(map->in_memory == MAP_IN_MEMORY && strcmp (map->path, except_level) &&
205     map->timeout && map->timeout < timeout)
206     chosen = map, timeout = map->timeout;
207     return chosen;
208     }
209    
210     /*
211     * swap_below_max() tries to swap out maps which are still in memory because
212     * of MAP_TIMEOUT until used objects is below MAX_OBJECTS or there are
213     * no more maps to swap.
214     */
215    
216     void swap_below_max(char *except_level) {
217     mapstruct *map;
218    
219     if(nrofallocobjects - nroffreeobjects < MAX_OBJECTS)
220     return;
221     for(;;) {
222     #ifdef MAX_OBJECTS_LWM
223     if(nrofallocobjects - nroffreeobjects < MAX_OBJECTS_LWM)
224     return;
225     #else
226     if(nrofallocobjects - nroffreeobjects < MAX_OBJECTS)
227     return;
228     #endif
229     if ((map = map_least_timeout(except_level)) == NULL)
230     return;
231     LOG(llevDebug,"Trying to swap out %s before its time.\n", map->path);
232     map->timeout=0;
233     swap_map(map);
234     }
235     }
236    
237     /*
238     * players_on_map(): will be replaced by map->players when I'm satisfied
239     * that the variable is always correct.
240     * If show_all is true, we show everyone. If not, we don't show hidden
241     * players (dms)
242     */
243    
244     int players_on_map(mapstruct *m, int show_all) {
245     player *pl;
246     int nr=0;
247     for(pl=first_player;pl!=NULL;pl=pl->next)
248     if(pl->ob != NULL && !QUERY_FLAG(pl->ob,FLAG_REMOVED) && pl->ob->map==m &&
249     (show_all || !pl->hidden))
250     nr++;
251     return nr;
252     }
253    
254     /*
255     * flush_old_maps():
256     * Removes tmp-files of maps which are going to be reset next time
257     * they are visited.
258     * This is very useful if the tmp-disk is very full.
259     */
260     void flush_old_maps(void) {
261    
262     mapstruct *m, *oldmap;
263     long sec;
264     sec = seconds();
265    
266     m= first_map;
267     while (m) {
268     /* There can be cases (ie death) where a player leaves a map and the timeout
269     * is not set so it isn't swapped out.
270     */
271     if ((m->in_memory == MAP_IN_MEMORY) && (m->timeout==0) &&
272     !players_on_map(m,TRUE)) {
273     set_map_timeout(m);
274     }
275    
276     /* per player unique maps are never really reset. However, we do want
277     * to perdiocially remove the entries in the list of active maps - this
278     * generates a cleaner listing if a player issues the map commands, and
279     * keeping all those swapped out per player unique maps also has some
280     * memory and cpu consumption.
281     * We do the cleanup here because there are lots of places that call
282     * swap map, and doing it within swap map may cause problems as
283     * the functions calling it may not expect the map list to change
284     * underneath them.
285     */
286     if ((m->unique || m->templatemap) && m->in_memory == MAP_SWAPPED) {
287     LOG(llevDebug,"Resetting map %s.\n",m->path);
288     oldmap = m;
289     m = m->next;
290     delete_map(oldmap);
291     }
292     else if(m->in_memory != MAP_SWAPPED || m->tmpname == NULL ||
293     sec < m->reset_time) {
294     m = m->next;
295     }
296     else {
297     LOG(llevDebug,"Resetting map %s.\n",m->path);
298     /* Lauwenmark : Here we handle the MAPRESET global event */
299     execute_global_event(EVENT_MAPRESET, m);
300     clean_tmp_map(m);
301     oldmap = m;
302     m = m->next;
303     delete_map(oldmap);
304     }
305     }
306     }