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

# User Rev Content
1 elmex 1.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 root 1.7 The author can be reached via e-mail to <crossfire@schmorp.de>
22 elmex 1.1 */
23    
24     #include <global.h>
25     #ifndef __CEXTRACT__
26 root 1.6 # include <sproto.h>
27 elmex 1.1 #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 root 1.6 static void
34     write_map_log (void)
35 elmex 1.1 {
36 root 1.6 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 root 1.3 }
62 elmex 1.1 }
63 root 1.6 fclose (fp);
64 elmex 1.1 }
65    
66 root 1.6 void
67     read_map_log (void)
68 elmex 1.1 {
69 root 1.6 FILE *fp;
70     mapstruct *map;
71     char buf[MAX_BUF], *cp, *cp1;
72     int do_los, darkness, lock;
73     long sec = seconds ();
74    
75 elmex 1.1
76 root 1.6 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 elmex 1.1 }
82 root 1.6 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 elmex 1.1 }
121    
122 root 1.6 void
123     swap_map (mapstruct *map)
124     {
125     player *pl;
126 elmex 1.1
127 root 1.6 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 elmex 1.1 }
141 root 1.6 remove_all_pets (map); /* Give them a chance to follow */
142 elmex 1.1
143 root 1.6 /* 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 elmex 1.1 }
176    
177 root 1.6 void
178     check_active_maps (void)
179     {
180     mapstruct *map, *next;
181 elmex 1.1
182 root 1.6 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 elmex 1.1 #ifndef MAX_OBJECTS_LWM
193 root 1.6 swap_map (map);
194 elmex 1.1 #endif
195     }
196     }
197    
198     /*
199     * map_least_timeout() returns the map with the lowest timeout variable (not 0)
200     */
201    
202 root 1.6 mapstruct *
203     map_least_timeout (char *except_level)
204     {
205     mapstruct *map, *chosen = NULL;
206 elmex 1.1 int timeout = MAP_MAXTIMEOUT + 1;
207 root 1.6
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 elmex 1.1 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 root 1.6 int
222     players_on_map (mapstruct *m, int show_all)
223     {
224 elmex 1.1 player *pl;
225 root 1.6 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 elmex 1.1 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 root 1.6 void
240     flush_old_maps (void)
241     {
242    
243     mapstruct *m, *oldmap;
244     uint32 sec;
245    
246     sec = seconds ();
247 elmex 1.1
248 root 1.6 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 root 1.3 }
258    
259 root 1.6 /* 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 root 1.3 }
276 root 1.6 else if (m->in_memory != MAP_SWAPPED || m->tmpname == NULL || sec < m->reset_time)
277     {
278     m = m->next;
279 root 1.3 }
280 root 1.6 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 root 1.3 }
289 elmex 1.1 }
290     }