Implement extracted files for packp3d and pdeploy (only when used together)

This also changes start_dir for pdeployed applications to point to the application directory, no longer to ~/.panda3d/start
This commit is contained in:
rdb 2015-08-14 15:57:56 +02:00
parent 9b93b8a030
commit 3e34233b1c
19 changed files with 271 additions and 118 deletions

View File

@ -444,6 +444,7 @@ class Installer:
notify = directNotify.newCategory("Installer")
def __init__(self, p3dfile, shortname, fullname, version, tokens = {}):
self.p3dFilename = p3dfile
if not shortname:
shortname = p3dfile.getBasenameWoExtension()
self.shortname = shortname
@ -477,22 +478,16 @@ class Installer:
if not self.authoremail and ' ' not in uname:
self.authoremail = "%s@%s" % (uname, socket.gethostname())
self.standalone = Standalone(p3dfile, tokens)
self.tempDir = Filename.temporary("", self.shortname, "") + "/"
self.tempDir.makeDir()
self.__tempRoots = {}
# Load the p3d file to read out the required packages
mf = Multifile()
if not mf.openRead(p3dfile):
if not mf.openRead(self.p3dFilename):
Installer.notify.error("Not a Panda3D application: %s" % (p3dfile))
return
# Now load the p3dInfo file.
self.hostUrl = PandaSystem.getPackageHostUrl()
if not self.hostUrl:
self.hostUrl = self.standalone.host.hostUrl
self.hostUrl = None
self.requires = []
self.extracts = []
i = mf.findSubfile('p3d_info.xml')
if i >= 0:
stream = mf.openReadSubfile(i)
@ -511,14 +506,54 @@ class Installer:
p3dRequires.Attribute('host')))
p3dRequires = p3dRequires.NextSiblingElement('requires')
p3dExtract = p3dPackage.FirstChildElement('extract')
while p3dExtract:
filename = p3dExtract.Attribute('filename')
self.extracts.append(filename)
p3dExtract = p3dExtract.NextSiblingElement('extract')
if not self.fullname:
p3dConfig = p3dPackage.FirstChildElement('config')
if p3dConfig:
self.fullname = p3dConfig.Attribute('display_name')
else:
Installer.notify.warning("No p3d_info.xml was found in .p3d archive.")
mf.close()
if not self.hostUrl:
self.hostUrl = PandaSystem.getPackageHostUrl()
if not self.hostUrl:
self.hostUrl = self.standalone.host.hostUrl
Installer.notify.warning("No host URL was specified by .p3d archive. Falling back to %s" % (self.hostUrl))
if not self.fullname:
self.fullname = self.shortname
self.tempDir = Filename.temporary("", self.shortname, "") + "/"
self.tempDir.makeDir()
self.__tempRoots = {}
if self.extracts:
# Copy .p3d to a temporary file so we can remove the extracts.
p3dfile = Filename(self.tempDir, self.p3dFilename.getBasename())
shutil.copyfile(self.p3dFilename.toOsSpecific(), p3dfile.toOsSpecific())
mf = Multifile()
if not mf.openReadWrite(p3dfile):
Installer.notify.error("Failure to open %s for writing." % (p3dfile))
# We don't really need this silly thing when embedding, anyway.
mf.setHeaderPrefix("")
for fn in self.extracts:
if not mf.removeSubfile(fn):
Installer.notify.error("Failure to remove %s from multifile." % (p3dfile))
mf.repack()
mf.close()
self.standalone = Standalone(p3dfile, tokens)
def __del__(self):
try:
appRunner.rmtree(self.tempDir)
@ -533,6 +568,22 @@ class Installer:
if not self.includeRequires:
return
# Write out the extracts from the original .p3d.
if self.extracts:
mf = Multifile()
if not mf.openRead(self.p3dFilename):
Installer.notify.error("Failed to open .p3d archive: %s" % (filename))
for filename in self.extracts:
i = mf.findSubfile(filename)
if i < 0:
Installer.notify.error("Cannot find extract in .p3d archive: %s" % (filename))
continue
if not mf.extractSubfile(i, Filename(hostDir, filename)):
Installer.notify.error("Failed to extract file from .p3d archive: %s" % (filename))
mf.close()
pkgTree = PackageTree(platform, hostDir, self.hostUrl)
pkgTree.installPackage("images", None, self.standalone.host.hostUrl)
@ -660,7 +711,8 @@ class Installer:
Filename(tempdir, "usr/bin/").makeDir()
if self.includeRequires:
extraTokens = {"host_dir" : "/usr/lib/" + self.shortname.lower()}
extraTokens = {"host_dir" : "/usr/lib/" + self.shortname.lower(),
"start_dir" : "/usr/lib/" + self.shortname.lower()}
else:
extraTokens = {}
self.standalone.build(Filename(tempdir, "usr/bin/" + self.shortname.lower()), platform, extraTokens)
@ -712,7 +764,7 @@ class Installer:
print >>desktop, "Type=Application"
desktop.close()
if self.includeRequires:
if self.includeRequires or self.extracts:
hostDir = Filename(tempdir, "usr/lib/%s/" % self.shortname.lower())
hostDir.makeDir()
self.installPackagesInto(hostDir, platform)
@ -853,7 +905,7 @@ class Installer:
exefile = Filename(output, "Contents/MacOS/" + self.shortname)
exefile.makeDir()
if self.includeRequires:
extraTokens = {"host_dir" : "../Resources"}
extraTokens = {"host_dir": "../Resources", "start_dir": "../Resources"}
else:
extraTokens = {}
self.standalone.build(exefile, platform, extraTokens)
@ -1064,7 +1116,7 @@ class Installer:
exefile = Filename(Filename.getTempDirectory(), self.shortname + ".exe")
exefile.unlink()
if self.includeRequires:
extraTokens = {"host_dir" : "."}
extraTokens = {"host_dir": ".", "start_dir": "."}
else:
extraTokens = {}
self.standalone.build(exefile, platform, extraTokens)

View File

@ -1496,6 +1496,10 @@ class Packager:
xhost = he.makeXml(packager = self.packager)
xpackage.InsertEndChild(xhost)
self.extracts.sort()
for name, xextract in self.extracts:
xpackage.InsertEndChild(xextract)
doc.InsertEndChild(xpackage)
# Write the xml file to a temporary file on disk, so we

View File

@ -57,6 +57,14 @@ Options:
instead of -e for files that are uncompressible by their nature
(e.g. mpg files). This option may be repeated as necessary.
-x ext
Marks files with the given extensions of needing to be physically
extracted to disk before they can be loaded. This is used for
file types that cannot be loaded via the virtual file system,
such as .ico files on Windows.
This option is currently only implemented when deploying the
application with pdeploy.
-p python_lib_dir
Adds a directory to search for additional Python modules. You
can use this to add your system's Python path, to allow packp3d
@ -134,6 +142,8 @@ def makePackedApp(args):
packager.binaryExtensions.append(value)
elif option == '-n':
packager.uncompressibleExtensions.append(value)
elif option == '-x':
packager.extractExtensions.append(value)
elif option == '-p':
sys.path.append(value)
elif option == '-c':

View File

@ -140,7 +140,7 @@ load_plugin(const string &p3d_plugin_filename,
const string &log_directory, const string &log_basename,
bool trusted_environment, bool console_environment,
const string &root_dir, const string &host_dir,
ostream &logfile) {
const string &start_dir, ostream &logfile) {
if (plugin_loaded) {
return true;
}
@ -259,7 +259,7 @@ load_plugin(const string &p3d_plugin_filename,
verify_contents, platform,
log_directory, log_basename,
trusted_environment, console_environment,
root_dir, host_dir, logfile)) {
root_dir, host_dir, start_dir, logfile)) {
unload_dso();
return false;
}
@ -283,7 +283,7 @@ init_plugin(const string &contents_filename, const string &host_url,
const string &log_directory, const string &log_basename,
bool trusted_environment, bool console_environment,
const string &root_dir, const string &host_dir,
ostream &logfile) {
const string &start_dir, ostream &logfile) {
// Ensure that all of the function pointers have been found.
if (P3D_initialize_ptr == NULL ||
@ -371,15 +371,26 @@ init_plugin(const string &contents_filename, const string &host_url,
return false;
}
if (!P3D_initialize_ptr(P3D_API_VERSION, contents_filename.c_str(),
// A bit of extra hand-hacked compatibility for using newer plug-ins
// with an older version of the core API.
int api_version = P3D_API_VERSION;
if (api_version == 17 && start_dir.empty()) {
api_version = 16;
if (host_dir.empty()) {
api_version = 15;
}
}
if (!P3D_initialize_ptr(api_version, contents_filename.c_str(),
host_url.c_str(), verify_contents, platform.c_str(),
log_directory.c_str(), log_basename.c_str(),
trusted_environment, console_environment,
root_dir.c_str(), host_dir.c_str())) {
root_dir.c_str(), host_dir.c_str(),
start_dir.c_str())) {
// Oops, failure to initialize.
logfile
<< "Failed to initialize plugin (passed API version "
<< P3D_API_VERSION << ")\n";
<< api_version << ")\n";
return false;
}

View File

@ -67,13 +67,15 @@ load_plugin(const string &p3d_plugin_filename,
P3D_verify_contents verify_contents, const string &platform,
const string &log_directory, const string &log_basename,
bool trusted_environment, bool console_environment,
const string &root_dir, const string &host_dir, ostream &logfile);
const string &root_dir, const string &host_dir,
const string &start_dir, ostream &logfile);
bool
init_plugin(const string &contents_filename, const string &host_url,
P3D_verify_contents verify_contents, const string &platform,
const string &log_directory, const string &log_basename,
bool trusted_environment, bool console_environment,
const string &root_dir, const string &host_dir, ostream &logfile);
const string &root_dir, const string &host_dir,
const string &start_dir, ostream &logfile);
void unload_plugin(ostream &logfile);
bool is_plugin_loaded();

View File

@ -163,7 +163,7 @@ start_p3dcert() {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_start_dir = inst_mgr->get_root_dir() + "/start";
_start_dir = inst_mgr->get_start_dir();
string root_dir = _inst->_p3dcert_package->get_package_dir();
mkdir_complete(_start_dir, nout);

View File

@ -1564,7 +1564,7 @@ uninstall_packages() {
if (inst_mgr->get_verify_contents() != P3D_VC_never) {
string start_dir_suffix = get_start_dir_suffix();
if (!start_dir_suffix.empty()) {
string start_dir = inst_mgr->get_root_dir() + "/start" + start_dir_suffix;
string start_dir = inst_mgr->get_start_dir() + start_dir_suffix;
nout << "Cleaning up start directory " << start_dir << "\n";
inst_mgr->delete_directory_recursively(start_dir);
}

View File

@ -111,6 +111,18 @@ get_root_dir() const {
return _root_dir;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_start_dir
// Access: Public
// Description: Returns the directory that the .p3d file should be
// mounted to and run from. This is usually the
// "start" subdirectory of the root_dir.
////////////////////////////////////////////////////////////////////
inline const string &P3DInstanceManager::
get_start_dir() const {
return _start_dir;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_platform
// Access: Public

View File

@ -201,7 +201,8 @@ initialize(int api_version, const string &contents_filename,
const string &platform, const string &log_directory,
const string &log_basename, bool trusted_environment,
bool console_environment,
const string &root_dir, const string &host_dir) {
const string &root_dir, const string &host_dir,
const string &start_dir) {
_api_version = api_version;
_host_url = host_url;
_verify_contents = verify_contents;
@ -298,12 +299,18 @@ initialize(int api_version, const string &contents_filename,
} else {
_root_dir = root_dir;
}
_host_dir = host_dir;
if (start_dir.empty()) {
_start_dir = _root_dir + "/start";
} else {
_start_dir = start_dir;
}
// Allow the caller (e.g. panda3d.exe) to specify a log directory.
// Or, allow the developer to compile one in.
//
// Failing that, we write logfiles to Panda3D/log.
if (_log_directory.empty()) {
_log_directory = _root_dir + "/log";
@ -1515,8 +1522,10 @@ create_runtime_environment() {
// Make the certificate directory.
_certs_dir = _root_dir + "/certs";
if (!mkdir_complete(_certs_dir, nout)) {
nout << "Couldn't mkdir " << _certs_dir << "\n";
if (!get_trusted_environment()) {
if (!mkdir_complete(_certs_dir, nout)) {
nout << "Couldn't mkdir " << _certs_dir << "\n";
}
}
_created_runtime_environment = true;

View File

@ -59,7 +59,8 @@ public:
bool trusted_environment,
bool console_environment,
const string &root_dir = "",
const string &host_dir = "");
const string &host_dir = "",
const string &start_dir = "");
inline bool is_initialized() const;
inline void reconsider_runtime_environment();
@ -69,6 +70,7 @@ public:
inline int get_api_version() const;
inline const string &get_host_url() const;
inline const string &get_root_dir() const;
inline const string &get_start_dir() const;
inline const string &get_platform() const;
inline const string &get_temp_directory() const;
inline const string &get_log_directory() const;
@ -173,6 +175,7 @@ private:
string _host_url;
string _root_dir;
string _host_dir;
string _start_dir;
string _certs_dir;
P3D_verify_contents _verify_contents;
string _platform;

View File

@ -717,7 +717,7 @@ start_p3dpython(P3DInstance *inst) {
_keep_user_env = true;
}
if (!_keep_user_env) {
_start_dir = inst_mgr->get_root_dir() + "/start" + inst->get_start_dir_suffix();
_start_dir = inst_mgr->get_start_dir() + inst->get_start_dir_suffix();
mkdir_complete(_start_dir, nout);
}
replace_slashes(_start_dir);

View File

@ -39,7 +39,8 @@ P3D_initialize(int api_version, const char *contents_filename,
const char *platform, const char *log_directory,
const char *log_basename, bool trusted_environment,
bool console_environment,
const char *root_dir, const char *host_dir) {
const char *root_dir, const char *host_dir,
const char *start_dir) {
if (api_version < 10 || api_version > P3D_API_VERSION) {
// Can't accept an incompatible version.
return false;
@ -89,12 +90,16 @@ P3D_initialize(int api_version, const char *contents_filename,
host_dir = "";
}
if (api_version < 17 || start_dir == NULL) {
start_dir = "";
}
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
bool result = inst_mgr->initialize(api_version, contents_filename, host_url,
verify_contents, platform,
log_directory, log_basename,
trusted_environment, console_environment,
root_dir, host_dir);
root_dir, host_dir, start_dir);
RELEASE_LOCK(_api_lock);
return result;
}

View File

@ -79,7 +79,7 @@ extern "C" {
(below). This number will be incremented whenever there are changes
to any of the interface specifications defined in this header
file. */
#define P3D_API_VERSION 16
#define P3D_API_VERSION 17
/************************ GLOBAL FUNCTIONS **************************/
@ -161,7 +161,8 @@ P3D_initialize_func(int api_version, const char *contents_filename,
const char *platform,
const char *log_directory, const char *log_basename,
bool trusted_environment, bool console_environment,
const char *root_dir, const char *host_dir);
const char *root_dir, const char *host_dir,
const char *start_dir);
/* This function should be called to unload the core API. It will
release all internally-allocated memory and return the core API to

View File

@ -581,12 +581,12 @@ int PPInstance::LoadPlugin( const std::string& dllFilename )
pathname = override_filename;
}
#endif // P3D_PLUGIN_P3D_PLUGIN
nout << "Attempting to load core API from " << pathname << "\n";
string contents_filename = m_rootDir + "/contents.xml";
if (!load_plugin(pathname, contents_filename, PANDA_PACKAGE_HOST_URL,
P3D_VC_normal, "", "", "", false, false,
m_rootDir, "", nout)) {
P3D_VC_normal, "", "", "", false, false,
m_rootDir, "", "", nout)) {
nout << "Unable to launch core API in " << pathname << "\n";
error = 1;
} else {

View File

@ -1738,8 +1738,8 @@ do_load_plugin() {
nout << "Attempting to load core API from " << pathname << "\n";
string contents_filename = _root_dir + "/contents.xml";
if (!load_plugin(pathname, contents_filename, PANDA_PACKAGE_HOST_URL,
P3D_VC_normal, "", "", "", false, false,
_root_dir, "", nout)) {
P3D_VC_normal, "", "", "", false, false,
_root_dir, "", "", nout)) {
nout << "Unable to launch core API in " << pathname << "\n";
set_failed();
return;

View File

@ -53,7 +53,8 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
// the + 1 from the test.
_read_offset_check = read_offset + (streampos)1;
if (_read_offset_check == (streampos)0xFF3D3D01) {
cerr << "This program is not intended to be run directly.\nIt is used by pdeploy to construct an embedded Panda3D application.\n";
cerr << "This program is not intended to be run directly.\nIt is used "
"by pdeploy to construct an embedded Panda3D application.\n";
return 1;
}
@ -86,22 +87,30 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
string value;
string root_dir;
string host_dir;
string start_dir;
while (true) {
if (curchr == EOF) {
cerr << "Truncated stream\n";
return(1);
return 1;
} else if (curchr == 0) {
// Two null bytes in a row means we've reached the end of the data.
if (havenull) {
break;
}
// This means we haven't seen an '=' character yet.
if (keyword == "") {
if (curstr != "") {
cerr << "Ignoring token '" << curstr << "' without value\n";
}
} else if (keyword == "start_dir") {
// Don't pass this on as a token, since it has slightly different
// semantics when used as an HTML token.
start_dir = curstr;
} else {
value.assign(curstr);
P3D_token token;
@ -118,6 +127,8 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
_got_win_size = true;
} else if (keyword == "log_basename") {
_log_basename = value;
} else if (keyword == "log_directory") {
_log_dirname = value;
} else if (keyword == "root_dir") {
root_dir = value;
} else if (keyword == "host_dir") {
@ -168,6 +179,13 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
_host_dir = host_dir_f.to_os_specific();
}
// Make the start directory absolute
if (!start_dir.empty()) {
Filename start_dir_f(start_dir);
start_dir_f.make_absolute(f.get_dirname());
_start_dir = start_dir_f.to_os_specific();
}
// Initialize the core API by directly assigning all of the function
// pointers.
P3D_initialize_ptr = &P3D_initialize;
@ -229,18 +247,17 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
// function pointers. This will also call P3D_initialize().
if (!init_plugin("", _host_url, _verify_contents, _this_platform,
_log_dirname, _log_basename, true, _console_environment,
_root_dir, _host_dir, cerr)) {
_root_dir, _host_dir, _start_dir, cerr)) {
cerr << "Unable to launch core API\n";
return 1;
}
// Create a plugin instance and run the program
P3D_instance *inst = create_instance(f, true, argv, argc, read_offset);
_instances.insert(inst);
run_main_loop();
unload_plugin(cerr);
return 0;
}

View File

@ -690,7 +690,6 @@ choose_random_mirrors(vector_string &result, int num_mirrors) {
}
}
////////////////////////////////////////////////////////////////////
// Function: Panda3D::get_core_api
// Access: Protected
@ -700,78 +699,12 @@ choose_random_mirrors(vector_string &result, int num_mirrors) {
////////////////////////////////////////////////////////////////////
bool Panda3D::
get_core_api() {
bool is_fresh = false;
if (!_coreapi_dll.quick_verify(_root_dir)) {
// The DLL file needs to be downloaded. Build up our list of
// URL's to attempt to download it from, in reverse order.
string url;
vector_string core_urls;
// Our last act of desperation: hit the original host, with a
// query uniquifier, to break through any caches.
ostringstream strm;
strm << _download_url_prefix << _coreapi_dll.get_filename()
<< "?" << time(NULL);
url = strm.str();
core_urls.push_back(url);
// Before we try that, we'll hit the original host, without a
// uniquifier.
url = _download_url_prefix;
url += _coreapi_dll.get_filename();
core_urls.push_back(url);
// And before we try that, we'll try two mirrors, at random.
vector_string mirrors;
choose_random_mirrors(mirrors, 2);
for (vector_string::iterator si = mirrors.begin();
si != mirrors.end();
++si) {
url = (*si) + _coreapi_dll.get_filename();
core_urls.push_back(url);
}
// The very first thing we'll try is the super_mirror, if we have
// one.
if (!_super_mirror_url_prefix.empty()) {
url = _super_mirror_url_prefix + _coreapi_dll.get_filename();
core_urls.push_back(url);
}
// Now pick URL's off the list, and try them, until we have
// success.
Filename pathname = Filename::from_os_specific(_coreapi_dll.get_pathname(_root_dir));
pathname.make_dir();
HTTPClient *http = HTTPClient::get_global_ptr();
bool success = false;
while (!core_urls.empty()) {
url = core_urls.back();
core_urls.pop_back();
PT(HTTPChannel) channel = http->get_document(url);
if (!channel->download_to_file(pathname)) {
cerr << "Unable to download " << url << "\n";
} else if (!_coreapi_dll.full_verify(_root_dir)) {
cerr << "Mismatched download for " << url << "\n";
} else {
// successfully downloaded!
success = true;
break;
}
}
if (!success) {
cerr << "Couldn't download core API.\n";
if (!download_core_api()) {
return false;
}
// Since we had to download some of it, might as well ask the core
// API to check all of it.
if (_verify_contents == P3D_VC_none) {
_verify_contents = P3D_VC_normal;
}
is_fresh = true;
}
// Now we've got the DLL. Load it.
@ -795,9 +728,19 @@ get_core_api() {
if (!load_plugin(pathname, contents_filename.to_os_specific(),
_host_url, _verify_contents, _this_platform, _log_dirname,
_log_basename, trusted_environment, _console_environment,
_root_dir, "", cerr)) {
cerr << "Unable to launch core API in " << pathname << "\n";
return false;
_root_dir, _host_dir, _start_dir, cerr)) {
// If we're not sure this is the latest version, make sure it is
// up-to-date, and then try again.
if (is_fresh || !download_core_api() ||
!load_plugin(pathname, contents_filename.to_os_specific(),
_host_url, _verify_contents, _this_platform, _log_dirname,
_log_basename, trusted_environment, _console_environment,
_root_dir, _host_dir, _start_dir, cerr)) {
cerr << "Unable to launch core API in " << pathname << "\n";
return false;
}
}
// Successfully loaded.
@ -822,6 +765,88 @@ get_core_api() {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Panda3D::download_core_api
// Access: Protected
// Description: Downloads the latest version of the core API from
// the plug-in server.
////////////////////////////////////////////////////////////////////
bool Panda3D::
download_core_api() {
// The DLL file needs to be downloaded. Build up our list of
// URL's to attempt to download it from, in reverse order.
string url;
vector_string core_urls;
// Our last act of desperation: hit the original host, with a
// query uniquifier, to break through any caches.
ostringstream strm;
strm << _download_url_prefix << _coreapi_dll.get_filename()
<< "?" << time(NULL);
url = strm.str();
core_urls.push_back(url);
// Before we try that, we'll hit the original host, without a
// uniquifier.
url = _download_url_prefix;
url += _coreapi_dll.get_filename();
core_urls.push_back(url);
// And before we try that, we'll try two mirrors, at random.
vector_string mirrors;
choose_random_mirrors(mirrors, 2);
for (vector_string::iterator si = mirrors.begin();
si != mirrors.end();
++si) {
url = (*si) + _coreapi_dll.get_filename();
core_urls.push_back(url);
}
// The very first thing we'll try is the super_mirror, if we have
// one.
if (!_super_mirror_url_prefix.empty()) {
url = _super_mirror_url_prefix + _coreapi_dll.get_filename();
core_urls.push_back(url);
}
// Now pick URL's off the list, and try them, until we have
// success.
Filename pathname = Filename::from_os_specific(_coreapi_dll.get_pathname(_root_dir));
pathname.make_dir();
HTTPClient *http = HTTPClient::get_global_ptr();
bool success = false;
while (!core_urls.empty()) {
url = core_urls.back();
core_urls.pop_back();
PT(HTTPChannel) channel = http->get_document(url);
if (!channel->download_to_file(pathname)) {
cerr << "Unable to download " << url << "\n";
} else if (!_coreapi_dll.full_verify(_root_dir)) {
cerr << "Mismatched download for " << url << "\n";
} else {
// successfully downloaded!
success = true;
break;
}
}
if (!success) {
cerr << "Couldn't download core API.\n";
return false;
}
// Since we had to download some of it, might as well ask the core
// API to check all of it.
if (_verify_contents == P3D_VC_none) {
_verify_contents = P3D_VC_normal;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Panda3D::usage
// Access: Protected

View File

@ -48,6 +48,7 @@ protected:
void add_mirror(string mirror_url);
void choose_random_mirrors(vector_string &result, int num_mirrors);
bool get_core_api();
bool download_core_api();
void usage();

View File

@ -74,6 +74,7 @@ protected:
string _host_url;
string _root_dir;
string _host_dir;
string _start_dir;
string _log_dirname;
string _log_basename;
string _this_platform;