0ad/source/lib/res/res.cpp

115 lines
2.4 KiB
C++
Raw Normal View History

#include "precompiled.h"
#include "res.h"
#include "file.h"
#include "timer.h"
#ifdef _WIN32
#include "sysdep/win/wfam.h"
#else
#include <fam.h>
#endif
#include <string.h>
int res_reload(const char* const fn)
{
return h_reload(fn);
}
static FAMConnection fc;
static bool initialized=false;
// path: portable and relative, must add current directory and convert to native
// better to use a cached string from rel_chdir - secure
int res_watch_dir(const char* const path, intptr_t* const watch)
{
if(!initialized)
{
CHECK_ERR(FAMOpen2(&fc, "lib_res"));
atexit2((void*)FAMClose, (uintptr_t)&fc);
initialized = true;
}
char n_full_path[PATH_MAX];
CHECK_ERR(file_make_native_path(path, n_full_path));
FAMRequest req;
if(FAMMonitorDirectory(&fc, n_full_path, &req, (void*)0) < 0)
{
*watch = -1;
debug_warn("res_watch_dir failed!");
return -1; // no way of getting error code?
}
*watch = (intptr_t)req.reqnum;
return 0;
}
int res_cancel_watch(const intptr_t watch)
{
if(!initialized)
{
debug_warn("res_cancel_watch before res_watch_dir");
return -1;
}
FAMRequest req;
req.reqnum = (int)watch;
return FAMCancelMonitor(&fc, &req);
}
// purpose of this routine (intended to be called once a frame):
// file notification may come at any time. by forcing the reloads
// to take place here, we don't require everything to be thread-safe.
int res_reload_changed_files()
{
if(!initialized)
return -1;
static double last_time;
static char last_fn[VFS_MAX_PATH];
FAMEvent e;
while(FAMPending(&fc) > 0)
{
if(FAMNextEvent(&fc, &e) < 0)
continue;
char path[PATH_MAX];
char vfs_path[VFS_MAX_PATH];
CHECK_ERR(file_make_portable_path(e.filename, path));
CHECK_ERR(vfs_make_vfs_path(path, vfs_path));
const char* fn = vfs_path;
// many apps save by creating a temp file, deleting the original,
// and renaming the temp file. that leads to 2 reloads, which is slow.
// so:
// .. ignore temp files,
char* ext = strrchr(fn, '.');
if(ext && !strcmp(ext, ".tmp"))
continue;
// .. directory change (more info is upcoming anyway)
if(!ext && e.code == FAMChanged) // dir changed
continue;
// .. and reloads for the same file within a small timeframe.
double cur_time = get_time();
if(cur_time - last_time < 50e-3 && !strcmp(last_fn, fn))
continue;
res_reload(fn);
debug_out("%s\n\n", fn);
last_time = get_time();
strcpy(last_fn, fn);
}
return 0;
}