ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/swap.C
Revision: 1.12
Committed: Mon Dec 18 03:49:39 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.11: +3 -1 lines
Log Message:
- generate more correct map names (/random should go, though)
- allow random maps to end up in temp.maps list

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 root 1.11 #include <sproto.h>
26 elmex 1.1 #include <object.h>
27    
28     /* This writes out information on all the temporary maps. It is called by
29     * swap_map below.
30     */
31 root 1.6 static void
32     write_map_log (void)
33 elmex 1.1 {
34 root 1.6 FILE *fp;
35 root 1.8 maptile *map;
36 root 1.6 char buf[MAX_BUF];
37     long current_time = time (NULL);
38    
39     sprintf (buf, "%s/temp.maps", settings.localdir);
40     if (!(fp = fopen (buf, "w")))
41     {
42     LOG (llevError, "Could not open %s for writing\n", buf);
43     return;
44     }
45 root 1.12
46 root 1.6 for (map = first_map; map != NULL; map = map->next)
47     {
48     /* If tmpname is null, it is probably a unique player map,
49     * so don't save information on it.
50     */
51 root 1.12 if (map->in_memory != MAP_IN_MEMORY && map->tmpname)
52 root 1.6 {
53     /* the 0 written out is a leftover from the lock number for
54     * unique items and second one is from encounter maps.
55     * Keep using it so that old temp files continue
56     * to work.
57     */
58     fprintf (fp, "%s:%s:%ld:0:0:%d:0:%d\n", map->path, map->tmpname,
59     (map->reset_time == (uint32) - 1 ? (long unsigned) -1 : map->reset_time - current_time), map->difficulty, map->darkness);
60 root 1.3 }
61 elmex 1.1 }
62 root 1.12
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 root 1.8 maptile *map;
71 root 1.6 char buf[MAX_BUF], *cp, *cp1;
72     int do_los, darkness, lock;
73 root 1.9 long sec = time (0);
74 elmex 1.1
75 root 1.6 sprintf (buf, "%s/temp.maps", settings.localdir);
76     if (!(fp = fopen (buf, "r")))
77     {
78     LOG (llevDebug, "Could not open %s for reading\n", buf);
79     return;
80 elmex 1.1 }
81 root 1.6 while (fgets (buf, MAX_BUF, fp) != NULL)
82     {
83     map = get_linked_map ();
84     /* scanf doesn't work all that great on strings, so we break
85     * out that manually. strdup is used for tmpname, since other
86     * routines will try to free that pointer.
87     */
88     cp = strchr (buf, ':');
89     *cp++ = '\0';
90     strcpy (map->path, buf);
91     cp1 = strchr (cp, ':');
92     *cp1++ = '\0';
93 root 1.10 map->tmpname = strdup (cp);
94 root 1.6
95     /* Lock is left over from the lock items - we just toss it now.
96     * We use it twice - second one is from encounter, but as we
97     * don't care about the value, this works fine
98     */
99     sscanf (cp1, "%d:%d:%d:%hd:%d:%d\n", &map->reset_time, &lock, &lock, &map->difficulty, &do_los, &darkness);
100    
101    
102     map->in_memory = MAP_SWAPPED;
103     map->darkness = darkness;
104    
105     /* When the reset time is saved out, it is adjusted so that
106     * the current time is subtracted (thus, it is saved as number
107     * of seconds from current time that it should reset). We need
108     * to add in the current seconds for this to work right.
109     * On metalforge, strange behavior was observed with really high
110     * reset times - I don't know how they got to that state,
111     * but easy enough to do some sanity checking here.
112     */
113     map->reset_time += sec;
114     if (map->reset_time > (uint32) (sec + MAP_MAXRESET))
115     map->reset_time = 0;
116    
117     }
118 root 1.11
119 root 1.6 fclose (fp);
120 elmex 1.1 }
121    
122 root 1.6 void
123 root 1.8 swap_map (maptile *map)
124 root 1.6 {
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 root 1.11
133     for (pl = first_player; pl; pl = pl->next)
134     if (!pl->ob || (!(QUERY_FLAG (pl->ob, FLAG_REMOVED)) && pl->ob->map == map))
135 root 1.6 break;
136    
137 root 1.11 if (pl)
138 root 1.6 {
139     LOG (llevDebug, "Wanted to swap out map with player.\n");
140     return;
141 elmex 1.1 }
142 root 1.11
143 root 1.6 remove_all_pets (map); /* Give them a chance to follow */
144 elmex 1.1
145 root 1.6 /* Update the reset time. Only do this is STAND_STILL is not set */
146     if (!map->fixed_resettime)
147     set_map_reset_time (map);
148    
149     /* If it is immediate reset time, don't bother saving it - just get
150     * rid of it right away.
151     */
152 root 1.9 if (map->reset_time <= (uint32) time (0))
153 root 1.6 {
154     LOG (llevDebug, "Resetting map %s.\n", map->path);
155     INVOKE_MAP (RESET, map);
156     delete_map (map);
157     return;
158     }
159    
160     if (new_save_map (map, 0) == -1)
161     {
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     }
169     else
170     {
171     INVOKE_MAP (SWAPOUT, map);
172     free_map (map, 1);
173     }
174    
175 root 1.11 write_map_log ();
176 elmex 1.1 }
177    
178 root 1.6 void
179     check_active_maps (void)
180     {
181 root 1.8 maptile *map, *next;
182 elmex 1.1
183 root 1.6 for (map = first_map; map != NULL; map = next)
184     {
185     next = map->next;
186     if (map->in_memory != MAP_IN_MEMORY)
187     continue;
188     if (!map->timeout)
189     continue;
190     if (--(map->timeout) > 0)
191     continue;
192     /* If LWM is set, we only swap maps out when we run out of objects */
193 elmex 1.1 #ifndef MAX_OBJECTS_LWM
194 root 1.6 swap_map (map);
195 elmex 1.1 #endif
196     }
197     }
198    
199     /*
200     * map_least_timeout() returns the map with the lowest timeout variable (not 0)
201     */
202    
203 root 1.8 maptile *
204 root 1.6 map_least_timeout (char *except_level)
205     {
206 root 1.8 maptile *map, *chosen = NULL;
207 elmex 1.1 int timeout = MAP_MAXTIMEOUT + 1;
208 root 1.6
209     for (map = first_map; map != NULL; map = map->next)
210     if (map->in_memory == MAP_IN_MEMORY && strcmp (map->path, except_level) && map->timeout && map->timeout < timeout)
211     chosen = map, timeout = map->timeout;
212 elmex 1.1 return chosen;
213     }
214    
215     /*
216     * players_on_map(): will be replaced by map->players when I'm satisfied
217     * that the variable is always correct.
218     * If show_all is true, we show everyone. If not, we don't show hidden
219     * players (dms)
220     */
221    
222 root 1.6 int
223 root 1.8 players_on_map (maptile *m, int show_all)
224 root 1.6 {
225 elmex 1.1 player *pl;
226 root 1.6 int nr = 0;
227    
228     for (pl = first_player; pl != NULL; pl = pl->next)
229     if (pl->ob != NULL && !QUERY_FLAG (pl->ob, FLAG_REMOVED) && pl->ob->map == m && (show_all || !pl->hidden))
230 elmex 1.1 nr++;
231     return nr;
232     }
233    
234     /*
235     * flush_old_maps():
236     * Removes tmp-files of maps which are going to be reset next time
237     * they are visited.
238     * This is very useful if the tmp-disk is very full.
239     */
240 root 1.6 void
241     flush_old_maps (void)
242     {
243    
244 root 1.8 maptile *m, *oldmap;
245 root 1.9 uint32 sec = time (0);
246 elmex 1.1
247 root 1.6 m = first_map;
248     while (m)
249     {
250     /* There can be cases (ie death) where a player leaves a map and the timeout
251     * is not set so it isn't swapped out.
252     */
253     if ((m->in_memory == MAP_IN_MEMORY) && (m->timeout == 0) && !players_on_map (m, TRUE))
254 root 1.9 set_map_timeout (m);
255 root 1.3
256 root 1.6 /* per player unique maps are never really reset. However, we do want
257     * to perdiocially remove the entries in the list of active maps - this
258     * generates a cleaner listing if a player issues the map commands, and
259     * keeping all those swapped out per player unique maps also has some
260     * memory and cpu consumption.
261     * We do the cleanup here because there are lots of places that call
262     * swap map, and doing it within swap map may cause problems as
263     * the functions calling it may not expect the map list to change
264     * underneath them.
265     */
266     if ((m->unique || m->templatemap) && m->in_memory == MAP_SWAPPED)
267     {
268     LOG (llevDebug, "Resetting map %s.\n", m->path);
269     oldmap = m;
270     m = m->next;
271     delete_map (oldmap);
272 root 1.3 }
273 root 1.6 else if (m->in_memory != MAP_SWAPPED || m->tmpname == NULL || sec < m->reset_time)
274     {
275     m = m->next;
276 root 1.3 }
277 root 1.6 else
278     {
279     LOG (llevDebug, "Resetting map %s.\n", m->path);
280     INVOKE_MAP (RESET, m);
281     clean_tmp_map (m);
282     oldmap = m;
283     m = m->next;
284     delete_map (oldmap);
285 root 1.3 }
286 elmex 1.1 }
287     }