ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/swap.c
Revision: 1.5
Committed: Sun Aug 13 17:16:05 2006 UTC (17 years, 9 months ago) by elmex
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +0 -0 lines
State: FILE REMOVED
Log Message:
Made server compile with C++.
Removed cfanim plugin and crossedit.
C++ here we come.

File Contents

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