ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/swap.C
Revision: 1.4
Committed: Mon Sep 4 11:08:00 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.3: +1 -28 lines
Log Message:
Changes...

- alternative shstr representation, saves code
- use glibs splice memory allocator (seems slower)
- use simpler memory/lifetime management for objects, no recycling

File Contents

# Content
1 /*
2 * static char *rcsid_swap_c =
3 * "$Id: swap.C,v 1.3 2006-08-29 08:01:38 root 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 (
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 INVOKE_MAP (RESET, map);
157 delete_map(map);
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 INVOKE_MAP (SWAPOUT, map);
170 free_map(map,1);
171 }
172
173 if (settings.recycle_tmp_maps == TRUE)
174 write_map_log();
175 }
176
177 void check_active_maps(void) {
178 mapstruct *map, *next;
179
180 for(map=first_map;map!=NULL;map=next) {
181 next = map->next;
182 if(map->in_memory != MAP_IN_MEMORY)
183 continue;
184 if(!map->timeout)
185 continue;
186 if( --(map->timeout) > 0)
187 continue;
188 /* If LWM is set, we only swap maps out when we run out of objects */
189 #ifndef MAX_OBJECTS_LWM
190 swap_map(map);
191 #endif
192 }
193 }
194
195 /*
196 * map_least_timeout() returns the map with the lowest timeout variable (not 0)
197 */
198
199 mapstruct *map_least_timeout(char *except_level) {
200 mapstruct *map, *chosen=NULL;
201 int timeout = MAP_MAXTIMEOUT + 1;
202 for(map = first_map;map != NULL; map = map->next)
203 if(map->in_memory == MAP_IN_MEMORY && strcmp (map->path, except_level) &&
204 map->timeout && map->timeout < timeout)
205 chosen = map, timeout = map->timeout;
206 return chosen;
207 }
208
209 /*
210 * players_on_map(): will be replaced by map->players when I'm satisfied
211 * that the variable is always correct.
212 * If show_all is true, we show everyone. If not, we don't show hidden
213 * players (dms)
214 */
215
216 int players_on_map(mapstruct *m, int show_all) {
217 player *pl;
218 int nr=0;
219 for(pl=first_player;pl!=NULL;pl=pl->next)
220 if(pl->ob != NULL && !QUERY_FLAG(pl->ob,FLAG_REMOVED) && pl->ob->map==m &&
221 (show_all || !pl->hidden))
222 nr++;
223 return nr;
224 }
225
226 /*
227 * flush_old_maps():
228 * Removes tmp-files of maps which are going to be reset next time
229 * they are visited.
230 * This is very useful if the tmp-disk is very full.
231 */
232 void flush_old_maps(void) {
233
234 mapstruct *m, *oldmap;
235 long sec;
236 sec = seconds();
237
238 m= first_map;
239 while (m) {
240 /* There can be cases (ie death) where a player leaves a map and the timeout
241 * is not set so it isn't swapped out.
242 */
243 if ((m->in_memory == MAP_IN_MEMORY) && (m->timeout==0) &&
244 !players_on_map(m,TRUE)) {
245 set_map_timeout(m);
246 }
247
248 /* per player unique maps are never really reset. However, we do want
249 * to perdiocially remove the entries in the list of active maps - this
250 * generates a cleaner listing if a player issues the map commands, and
251 * keeping all those swapped out per player unique maps also has some
252 * memory and cpu consumption.
253 * We do the cleanup here because there are lots of places that call
254 * swap map, and doing it within swap map may cause problems as
255 * the functions calling it may not expect the map list to change
256 * underneath them.
257 */
258 if ((m->unique || m->templatemap) && m->in_memory == MAP_SWAPPED) {
259 LOG(llevDebug,"Resetting map %s.\n",m->path);
260 oldmap = m;
261 m = m->next;
262 delete_map(oldmap);
263 }
264 else if(m->in_memory != MAP_SWAPPED || m->tmpname == NULL ||
265 sec < m->reset_time) {
266 m = m->next;
267 }
268 else {
269 LOG(llevDebug,"Resetting map %s.\n",m->path);
270 INVOKE_MAP (RESET, m);
271 clean_tmp_map(m);
272 oldmap = m;
273 m = m->next;
274 delete_map(oldmap);
275 }
276 }
277 }