Atrinik Server 2.5
server/swap.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 
00032 #if RECYCLE_TMP_MAPS
00033 
00035 static void write_map_log()
00036 {
00037     FILE *fp;
00038     mapstruct *map;
00039     char buf[MAX_BUF];
00040     long current_time = time(NULL);
00041 
00042     snprintf(buf, sizeof(buf), "%s/temp.maps", settings.localdir);
00043 
00044     if (!(fp = fopen(buf, "w")))
00045     {
00046         LOG(llevBug, "Could not open %s for writing\n", buf);
00047         return;
00048     }
00049 
00050     for (map = first_map; map; map = map->next)
00051     {
00052         /* If tmpname is null, it is probably a unique player map,
00053          * so don't save information on it. */
00054         if (map->in_memory != MAP_IN_MEMORY && map->tmpname && strncmp(map->path, "/random", 7))
00055         {
00056             /* the 0 written out is a leftover from the lock number for
00057              * unique items and second one is from encounter maps.
00058              * Keep using it so that old temp files continue
00059              * to work. */
00060             fprintf(fp, "%s:%s:%ld:%d:%d\n", map->path, map->tmpname, (map->reset_time == -1 ? -1: map->reset_time - current_time), map->difficulty, map->darkness);
00061         }
00062     }
00063 
00064     fclose(fp);
00065 }
00066 #endif
00067 
00070 void read_map_log()
00071 {
00072     FILE *fp;
00073     mapstruct *map;
00074     char buf[MAX_BUF];
00075     int darkness;
00076 
00077     snprintf(buf, sizeof(buf), "%s/temp.maps", settings.localdir);
00078 
00079     if (!(fp = fopen(buf, "r")))
00080     {
00081         LOG(llevDebug, "Could not open %s for reading\n", buf);
00082         return;
00083     }
00084 
00085     while (fgets(buf, sizeof(buf), fp))
00086     {
00087         char *tmp[3];
00088 
00089         map = get_linked_map();
00090 
00091         if (split_string(buf, tmp, sizeof(tmp) / sizeof(*tmp), ':') != 3)
00092         {
00093             LOG(llevDebug, "%s/temp.maps: ignoring invalid line: %s\n", settings.localdir, buf);
00094             continue;
00095         }
00096 
00097         FREE_AND_COPY_HASH(map->path, tmp[0]);
00098         map->tmpname = strdup_local(tmp[1]);
00099 
00100         sscanf(tmp[2], "%ud:%d:%d\n", &map->reset_time, &map->difficulty, &darkness);
00101 
00102         map->in_memory = MAP_SWAPPED;
00103         map->darkness = darkness;
00104 
00105         if (darkness == -1)
00106         {
00107             darkness = MAX_DARKNESS;
00108         }
00109 
00110         map->light_value = global_darkness_table[MAX_DARKNESS];
00111     }
00112 
00113     fclose(fp);
00114 }
00115 
00120 void swap_map(mapstruct *map, int force_flag)
00121 {
00122     int i;
00123 
00124     if (map->in_memory != MAP_IN_MEMORY)
00125     {
00126         LOG(llevBug, "Tried to swap out map which was not in memory (%s).\n", map->path);
00127         return;
00128     }
00129 
00130     /* Test for players. */
00131     if (!force_flag)
00132     {
00133         if (map->player_first)
00134         {
00135             return;
00136         }
00137 
00138         for (i = 0; i < TILED_MAPS; i++)
00139         {
00140             /* If there is a map, is loaded and in memory, has players, then no swap */
00141             if (map->tile_map[i] && map->tile_map[i]->in_memory == MAP_IN_MEMORY && map->tile_map[i]->player_first)
00142             {
00143                 return;
00144             }
00145         }
00146     }
00147 
00148     /* Update the reset time. */
00149     if (!MAP_FIXED_RESETTIME(map))
00150     {
00151         set_map_reset_time(map);
00152     }
00153 
00154     /* If it is immediate reset time, don't bother saving it - just get
00155      * rid of it right away. */
00156     if (map->reset_time <= (uint32) seconds())
00157     {
00158         mapstruct *oldmap = map;
00159 
00160         LOG(llevDebug, "Resetting1 map %s.\n", map->path);
00161 
00162         if (map->events)
00163         {
00164             /* Trigger the map reset event */
00165             trigger_map_event(MEVENT_RESET, map, NULL, NULL, NULL, map->path, 0);
00166         }
00167 
00168         map = map->next;
00169         delete_map(oldmap);
00170         return;
00171     }
00172 
00173     if (new_save_map(map, 0) == -1)
00174     {
00175         LOG(llevBug, "Failed to swap map %s.\n", map->path);
00176         /* Need to reset the in_memory flag so that delete map will also
00177          * free the objects with it. */
00178         map->in_memory = MAP_IN_MEMORY;
00179         delete_map(map);
00180     }
00181     else
00182     {
00183         free_map(map, 1);
00184     }
00185 
00186 #if RECYCLE_TMP_MAPS
00187     write_map_log();
00188 #endif
00189 }
00190 
00193 void check_active_maps()
00194 {
00195     mapstruct *map, *next;
00196 
00197     for (map = first_map; map != NULL; map = next)
00198     {
00199         next = map->next;
00200 
00201         if (map->in_memory != MAP_IN_MEMORY)
00202         {
00203             continue;
00204         }
00205 
00206         if (!map->timeout)
00207         {
00208             if (!map->player_first)
00209             {
00210                 set_map_timeout(map);
00211             }
00212 
00213             continue;
00214         }
00215 
00216         if (--(map->timeout) > 0)
00217         {
00218             continue;
00219         }
00220 
00221         swap_map(map, 0);
00222     }
00223 }
00224 
00230 void flush_old_maps()
00231 {
00232     mapstruct *m = first_map, *oldmap;
00233     long sec = seconds();
00234 
00235     while (m)
00236     {
00237         /* There can be cases (ie death) where a player leaves a map and
00238          * the timeout is not set so it isn't swapped out. */
00239         if ((m->in_memory == MAP_IN_MEMORY) && (m->timeout == 0) && !m->player_first)
00240         {
00241             set_map_timeout(m);
00242         }
00243 
00244         /* Per player unique maps are never really reset. */
00245         if (MAP_UNIQUE(m) && m->in_memory == MAP_SWAPPED)
00246         {
00247             LOG(llevDebug, "Resetting2 map %s.\n", m->path);
00248             oldmap = m;
00249             m = m->next;
00250             delete_map(oldmap);
00251         }
00252         /* No need to flush them if there are no resets */
00253         else if (m->in_memory != MAP_SWAPPED || m->tmpname == NULL || (uint32) sec < m->reset_time)
00254         {
00255             m = m->next;
00256         }
00257         else
00258         {
00259             LOG(llevDebug, "Resetting3 map %s.\n", m->path);
00260 
00261             if (m->events)
00262             {
00263                 /* Trigger the map reset event */
00264                 trigger_map_event(MEVENT_RESET, m, NULL, NULL, NULL, m->path, 0);
00265             }
00266 
00267             clean_tmp_map(m);
00268             oldmap = m;
00269             m = m->next;
00270             delete_map(oldmap);
00271         }
00272     }
00273 }