diff --git a/direct/src/ffi/panda3d.py b/direct/src/ffi/panda3d.py index c8dae4dc96..3e221970d9 100644 --- a/direct/src/ffi/panda3d.py +++ b/direct/src/ffi/panda3d.py @@ -124,6 +124,10 @@ class panda3d_import_manager: if (cls.os.path.exists(lib + dll_ext)): target = lib + dll_ext break + if target: + # Once we find the first match, break all the way + # out--don't keep looking for a second match. + break if target == None: message = "DLL loader cannot find %s." % name raise ImportError, message diff --git a/direct/src/p3d/HostInfo.py b/direct/src/p3d/HostInfo.py index 429253debf..39d932d294 100644 --- a/direct/src/p3d/HostInfo.py +++ b/direct/src/p3d/HostInfo.py @@ -28,13 +28,9 @@ class HostInfo: there. At the moment, mirror folders do not download old patch files from the server. - If you pass perPlatform = True, then files are unpacked into a - platform-specific directory, which is appropriate when you - might be downloading multiple platforms. The default is - perPlatform = False, which means all files are unpacked into - the host directory directly, without an intervening - platform-specific directory name. If asMirror is True, then - the default is perPlatform = True. """ + perPlatform remains for historical reasons, but it is ignored. + Nowadays, all files are always unpacked into platform-specific + directories, even on the client. """ assert appRunner or rootDir or hostDir @@ -49,9 +45,7 @@ class HostInfo: self.hostDir = hostDir self.asMirror = asMirror - self.perPlatform = perPlatform - if perPlatform is None: - self.perPlatform = asMirror + self.perPlatform = True # Initially false, this is set true when the contents file is # successfully read. @@ -583,7 +577,7 @@ class HostInfo: for pkey, package in pitems: result.append(package) else: - # If we maintain a a host for the current platform + # If we maintain a host for the current platform # only (e.g. a client copy), then return only the # current platform, or no particular platform. package = platforms.get(PandaSystem.getPlatform(), None) diff --git a/direct/src/p3d/Packager.py b/direct/src/p3d/Packager.py index 3f9b7edb9b..2d09243e75 100644 --- a/direct/src/p3d/Packager.py +++ b/direct/src/p3d/Packager.py @@ -2197,6 +2197,14 @@ class Packager: # The system PATH, for searching dll's and exe's. self.executablePath = DSearchPath() + + # By convention, we include sys.path at the front of + # self.executablePath, mainly to aid makepanda when building + # an rtdist build. + for dirname in sys.path: + self.executablePath.appendDirectory(Filename.fromOsSpecific(dirname)) + + # Now add the actual system search path. if self.platform.startswith('win'): self.addWindowsSearchPath(self.executablePath, "PATH") elif self.platform.startswith('osx'): diff --git a/direct/src/p3d/ppackage.py b/direct/src/p3d/ppackage.py index 65cca13cd4..55850e9baa 100755 --- a/direct/src/p3d/ppackage.py +++ b/direct/src/p3d/ppackage.py @@ -241,7 +241,6 @@ for platform in platforms: # Just print the error message and exit gracefully. inst = sys.exc_info()[1] print inst.args[0] - #raise sys.exit(1) # An explicit call to exit() is required to exit the program, when diff --git a/direct/src/plugin/p3dHost.cxx b/direct/src/plugin/p3dHost.cxx index 1a6e614589..dec72bcd64 100644 --- a/direct/src/plugin/p3dHost.cxx +++ b/direct/src/plugin/p3dHost.cxx @@ -62,7 +62,11 @@ P3DHost:: PackageMap &package_map = (*mi).second; PackageMap::iterator pi; for (pi = package_map.begin(); pi != package_map.end(); ++pi) { - delete (*pi).second; + PlatformPackages &ppackages = (*pi).second; + PlatformPackages::iterator ppi; + for (ppi = ppackages.begin(); ppi != ppackages.end(); ++ppi) { + delete (*ppi); + } } } _packages.clear(); @@ -356,14 +360,16 @@ read_xhost(TiXmlElement *xhost) { //////////////////////////////////////////////////////////////////// P3DPackage *P3DHost:: get_package(const string &package_name, const string &package_version, - const string &package_seq, const string &alt_host) { + const string &package_platform, const string &package_seq, + const string &alt_host) { if (!alt_host.empty()) { if (_xcontents != NULL) { // If we're asking for an alt host and we've already read our // contents.xml file, then we already know all of our hosts, and // we can start the package off with the correct host immediately. P3DHost *new_host = get_alt_host(alt_host); - return new_host->get_package(package_name, package_version, package_seq); + return new_host->get_package(package_name, package_version, + package_platform, package_seq); } // If we haven't read contents.xml yet, we need to create the @@ -371,30 +377,44 @@ get_package(const string &package_name, const string &package_version, // contents.xml, and it can migrate to its alt_host after that. } - PackageMap &package_map = _packages[alt_host]; - + string key = package_name + "_" + package_version; + PlatformPackages &ppackages = _packages[alt_host][key]; + PlatformPackages::iterator ppi; P3DPackage *package = NULL; - string key = package_name + "_" + package_version; - PackageMap::iterator pi = package_map.find(key); - if (pi != package_map.end()) { - // We've previously installed this package. - package = (*pi).second; + // First, look for an exact match of the platform. + for (ppi = ppackages.begin(); ppi != ppackages.end(); ++ppi) { + if ((*ppi)->get_package_platform() == package_platform) { + package = *ppi; + break; + } + } + // If an exact match isn't found, look for a generic platform. + if (package == NULL) { + for (ppi = ppackages.begin(); ppi != ppackages.end(); ++ppi) { + if ((*ppi)->get_package_platform().empty()) { + package = *ppi; + break; + } + } + } + + if (package != NULL) { if (package->get_failed()) { // If the package has previously failed, move it aside and try // again (maybe it just failed because the user interrupted it). nout << "Package " << key << " has previously failed; trying again.\n"; _failed_packages.push_back(package); - (*pi).second = NULL; + ppackages.erase(ppi); package = NULL; } } if (package == NULL) { package = - new P3DPackage(this, package_name, package_version, alt_host); - package_map[key] = package; + new P3DPackage(this, package_name, package_version, package_platform, alt_host); + ppackages.push_back(package); } P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); @@ -403,10 +423,10 @@ get_package(const string &package_name, const string &package_version, // believe we have a valid contents.xml file, then check the seq // value in the contents. FileSpec desc_file; - string platform, seq; + string seq; bool solo; - if (get_package_desc_file(desc_file, platform, seq, solo, - package_name, package_version)) { + if (get_package_desc_file(desc_file, seq, solo, + package_name, package_version, package_platform)) { nout << package_name << ": asked for seq " << package_seq << ", we have seq " << seq << "\n"; if (compare_seq(package_seq, seq) > 0) { @@ -421,6 +441,103 @@ get_package(const string &package_name, const string &package_version, return package; } +//////////////////////////////////////////////////////////////////// +// Function: P3DHost::choose_suitable_platform +// Access: Public +// Description: Chooses the most appropriate platform for the +// indicated package (presumably the "panda3d" package), +// based on what this hardware supports and what is +// actually available. +//////////////////////////////////////////////////////////////////// +bool P3DHost:: +choose_suitable_platform(string &selected_platform, + const string &package_name, + const string &package_version, + const string &package_platform) { + if (_xcontents == NULL) { + return false; + } + + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + + TiXmlElement *xpackage; + + // For the "panda3d" package only, we allow searching for any + // available supported platform. + if (package_name == "panda3d" && package_platform == "") { + int num_supported_platforms = inst_mgr->get_num_supported_platforms(); + for (int pi = 0; pi < num_supported_platforms; ++pi) { + string supported_platform = inst_mgr->get_supported_platform(pi); + xpackage = _xcontents->FirstChildElement("package"); + while (xpackage != NULL) { + const char *name = xpackage->Attribute("name"); + const char *platform = xpackage->Attribute("platform"); + const char *version = xpackage->Attribute("version"); + if (version == NULL) { + version = ""; + } + if (name != NULL && platform != NULL && + package_name == name && + supported_platform == platform && + package_version == version) { + // Here's the matching package definition. + selected_platform = platform; + return true; + } + + xpackage = xpackage->NextSiblingElement("package"); + } + } + } + + // Now, we look for an exact match for the current platform. + xpackage = _xcontents->FirstChildElement("package"); + while (xpackage != NULL) { + const char *name = xpackage->Attribute("name"); + const char *platform = xpackage->Attribute("platform"); + const char *version = xpackage->Attribute("version"); + if (version == NULL) { + version = ""; + } + if (name != NULL && platform != NULL && + package_name == name && + package_platform == platform && + package_version == version) { + // Here's the matching package definition. + selected_platform = platform; + return true; + } + + xpackage = xpackage->NextSiblingElement("package"); + } + + // Look again, this time looking for a non-platform-specific version. + xpackage = _xcontents->FirstChildElement("package"); + while (xpackage != NULL) { + const char *name = xpackage->Attribute("name"); + const char *platform = xpackage->Attribute("platform"); + const char *version = xpackage->Attribute("version"); + if (platform == NULL) { + platform = ""; + } + if (version == NULL) { + version = ""; + } + if (name != NULL && + package_name == name && + *platform == '\0' && + package_version == version) { + selected_platform = platform; + return true; + } + + xpackage = xpackage->NextSiblingElement("package"); + } + + // Couldn't find a suitable platform. + return false; +} + //////////////////////////////////////////////////////////////////// // Function: P3DHost::get_package_desc_file // Access: Public @@ -433,11 +550,11 @@ get_package(const string &package_name, const string &package_version, //////////////////////////////////////////////////////////////////// bool P3DHost:: get_package_desc_file(FileSpec &desc_file, // out - string &package_platform, // out string &package_seq, // out bool &package_solo, // out const string &package_name, // in - const string &package_version) { // in + const string &package_version, // in + const string &package_platform) { // in if (_xcontents == NULL) { return false; } @@ -461,12 +578,11 @@ get_package_desc_file(FileSpec &desc_file, // out } if (name != NULL && platform != NULL && package_name == name && - inst_mgr->get_platform() == platform && + package_platform == platform && package_version == version) { // Here's the matching package definition. desc_file.load_xml(xpackage); package_seq = seq; - package_platform = platform; package_solo = false; if (solo != NULL) { package_solo = (atoi(solo) != 0); @@ -501,7 +617,6 @@ get_package_desc_file(FileSpec &desc_file, // out // Here's the matching package definition. desc_file.load_xml(xpackage); package_seq = seq; - package_platform = platform; package_solo = false; if (solo != NULL) { package_solo = (atoi(solo) != 0); @@ -529,16 +644,19 @@ forget_package(P3DPackage *package, const string &alt_host) { string key = package->get_package_name() + "_" + package->get_package_version(); nout << "Forgetting package " << key << "\n"; - PackageMap &package_map = _packages[alt_host]; + PlatformPackages &ppackages = _packages[alt_host][key]; - // Hmm, this is a memory leak. But we allow it to remain, since - // it's an unusual circumstance (uninstalling), and it's safer to - // leak than to risk a floating pointer. - package_map.erase(key); + PlatformPackages::iterator ppi = find(ppackages.begin(), ppackages.end(), package); + if (ppi != ppackages.end()) { + // Hmm, this is a memory leak. But we allow it to remain, since + // it's an unusual circumstance (uninstalling), and it's safer to + // leak than to risk a floating pointer. + ppackages.erase(ppi); + } } //////////////////////////////////////////////////////////////////// -// Function: P3DHost::migrate_package +// Function: P3DHost::migrate_package_host // Access: Public // Description: This is called by P3DPackage when it migrates from // this host to its final alt_host, after downloading @@ -546,20 +664,21 @@ forget_package(P3DPackage *package, const string &alt_host) { // true URL for its target alt_host. //////////////////////////////////////////////////////////////////// void P3DHost:: -migrate_package(P3DPackage *package, const string &alt_host, P3DHost *new_host) { +migrate_package_host(P3DPackage *package, const string &alt_host, P3DHost *new_host) { assert(new_host != this); assert(new_host == get_alt_host(alt_host)); string key = package->get_package_name() + "_" + package->get_package_version(); - PackageMap &package_map = _packages[alt_host]; - PackageMap::iterator pi = package_map.find(key); - assert(pi != package_map.end()); - package_map.erase(pi); + PlatformPackages &ppackages = _packages[alt_host][key]; - PackageMap &new_package_map = new_host->_packages[""]; - bool inserted = new_package_map.insert(PackageMap::value_type(key, package)).second; - assert(inserted); + PlatformPackages::iterator ppi = find(ppackages.begin(), ppackages.end(), package); + + assert(ppi != ppackages.end()); + ppackages.erase(ppi); + + PlatformPackages &new_ppackages = new_host->_packages[""][key]; + new_ppackages.push_back(package); } //////////////////////////////////////////////////////////////////// @@ -635,8 +754,12 @@ uninstall() { PackageMap &package_map = (*mi).second; PackageMap::iterator pi; for (pi = package_map.begin(); pi != package_map.end(); ++pi) { - P3DPackage *package = (*pi).second; - package->uninstall(); + PlatformPackages &ppackages = (*pi).second; + PlatformPackages::iterator ppi; + for (ppi = ppackages.begin(); ppi != ppackages.end(); ++ppi) { + P3DPackage *package = (*ppi); + package->uninstall(); + } } } diff --git a/direct/src/plugin/p3dHost.h b/direct/src/plugin/p3dHost.h index 64bca8e17e..5a552d243f 100644 --- a/direct/src/plugin/p3dHost.h +++ b/direct/src/plugin/p3dHost.h @@ -54,17 +54,22 @@ public: P3DPackage *get_package(const string &package_name, const string &package_version, + const string &package_platform, const string &package_seq, const string &alt_host = ""); + bool choose_suitable_platform(string &selected_platform, + const string &package_name, + const string &package_version, + const string &package_platform); bool get_package_desc_file(FileSpec &desc_file, - string &package_platform, string &package_seq, bool &package_solo, const string &package_name, - const string &package_version); + const string &package_version, + const string &package_platform); void forget_package(P3DPackage *package, const string &alt_host = ""); - void migrate_package(P3DPackage *package, const string &alt_host, P3DHost *new_host); + void migrate_package_host(P3DPackage *package, const string &alt_host, P3DHost *new_host); void choose_random_mirrors(vector &result, int num_mirrors); void add_mirror(string mirror_url); @@ -97,7 +102,8 @@ private: typedef map AltHosts; AltHosts _alt_hosts; - typedef map PackageMap; + typedef vector PlatformPackages; + typedef map PackageMap; typedef map Packages; Packages _packages; typedef vector FailedPackages; diff --git a/direct/src/plugin/p3dInstance.I b/direct/src/plugin/p3dInstance.I index 8a6882dbb2..c88f10c3cf 100644 --- a/direct/src/plugin/p3dInstance.I +++ b/direct/src/plugin/p3dInstance.I @@ -60,6 +60,25 @@ get_session_key() const { return _session_key; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::get_session_platform +// Access: Public +// Description: Returns the platform of this particular session. +// Before the panda3d package has been seen, this is the +// empty string; once we have downloaded the info file +// for the panda3d package, it is filled in with +// whatever platform is provided (that we're also +// runtime-compatible with). +// +// Presumably all of the platform-specific packages that +// are downloaded subsequently must be of the exact same +// platform. +//////////////////////////////////////////////////////////////////// +inline const string &P3DInstance:: +get_session_platform() const { + return _session_platform; +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::get_session // Access: Public diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index d5adf324c2..b9ff6c20c6 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -146,7 +146,7 @@ P3DInstance(P3D_request_ready_func *func, _failed = false; _session = NULL; _auth_session = NULL; - _panda3d = NULL; + _panda3d_package = NULL; _splash_window = NULL; _instance_window_opened = false; _instance_window_attached = false; @@ -241,7 +241,7 @@ P3DInstance(P3D_request_ready_func *func, // put up a splash image (for instance, the above IT_download image) // while we download the real contents. P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url()); - _image_package = host->get_package("images", "", ""); + _image_package = host->get_package("images", "", "", ""); if (_image_package != NULL) { _image_package->add_instance(this); } @@ -774,7 +774,7 @@ get_request() { P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); P3DHost *host = inst_mgr->get_host(host_url); if (package_name != NULL) { - P3DPackage *package = host->get_package(package_name, package_version, ""); + P3DPackage *package = host->get_package(package_name, package_version, _session_platform, ""); host->forget_package(package); } else { // If a NULL package name is given, forget the whole host. @@ -1066,8 +1066,9 @@ add_package(const string &name, const string &version, const string &seq, // get its additional host information. get_host_info(host); } - - P3DPackage *package = host->get_package(name, version, seq, alt_host); + + P3DPackage *package = host->get_package(name, version, _session_platform, + seq, alt_host); add_package(package); } @@ -1087,7 +1088,7 @@ add_package(P3DPackage *package) { } if (package->get_package_name() == "panda3d") { - _panda3d = package; + _panda3d_package = package; } _packages.push_back(package); @@ -1125,6 +1126,9 @@ remove_package(P3DPackage *package) { if (package == _p3dcert_package) { _p3dcert_package = NULL; } + if (package == _panda3d_package) { + _panda3d_package = NULL; + } set_failed(); } @@ -1890,7 +1894,7 @@ check_p3d_signature() { // We have to go download this package. P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url()); - _certlist_package = host->get_package("certlist", "", ""); + _certlist_package = host->get_package("certlist", "", "", ""); if (_certlist_package != NULL) { _certlist_package->add_instance(this); } @@ -1931,7 +1935,7 @@ mark_p3d_untrusted() { // We have to go download this package. P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url()); - _p3dcert_package = host->get_package("p3dcert", "", ""); + _p3dcert_package = host->get_package("p3dcert", "", "", ""); if (_p3dcert_package != NULL) { _p3dcert_package->add_instance(this); } @@ -2009,20 +2013,10 @@ mark_p3d_trusted() { _main_object->set_bool_property("trusted", true); send_notify("onauth"); - // Now that we're all set up, start downloading the required + // Now that we're all set up, grab the panda3d package. We need to + // examine this before we can start to download the remaining // packages. - add_packages(); - - // Until we've done all of the above processing, we haven't fully - // committed to setting the trusted flag. (Setting this flag down - // here instead of a few lines above avoids starting the instance in - // add_packages(), before we've had a chance to finish processing - // this method.) - _p3d_trusted = true; - - if (get_packages_ready()) { - mark_download_complete(); - } + add_panda3d_package(); } //////////////////////////////////////////////////////////////////// @@ -2132,6 +2126,48 @@ scan_app_desc_file(TiXmlDocument *doc) { } } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::add_panda3d_package +// Access: Private +// Description: Adds the "panda3d" package only. This package must +// be downloaded first, and its desc file examined, +// before we can begin downloading the other packages. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +add_panda3d_package() { + assert(!_packages_specified); + assert(_panda3d_package == NULL); + if (_xpackage == NULL) { + return; + } + + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + + TiXmlElement *xrequires = _xpackage->FirstChildElement("requires"); + while (xrequires != NULL) { + const char *name = xrequires->Attribute("name"); + const char *host_url = xrequires->Attribute("host"); + if (name != NULL && host_url != NULL && strcmp(name, "panda3d") == 0) { + const char *version = xrequires->Attribute("version"); + if (version == NULL) { + version = ""; + } + const char *seq = xrequires->Attribute("seq"); + if (seq == NULL) { + seq = ""; + } + P3DHost *host = inst_mgr->get_host(host_url); + add_package(name, version, seq, host); + return; + } + + xrequires = xrequires->NextSiblingElement("requires"); + } + + nout << "No panda3d package found in " << _fparams.get_p3d_filename() << "\n"; + set_failed(); +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::add_packages // Access: Private @@ -2171,6 +2207,16 @@ add_packages() { _packages_specified = true; consider_start_download(); + + // Now that we've scanned the p3d file, and prepared the list of + // packages, it's safe to set the trusted flag. + _p3d_trusted = true; + + // If the packages are already downloaded, start the instance + // rolling. + if (get_packages_ready()) { + mark_download_complete(); + } } @@ -2689,8 +2735,10 @@ make_splash_window() { // Don't know where to put it yet. return; } - if (_wparams.get_window_type() == P3D_WT_hidden) { - // We're hidden, and so is the splash window. + if (_wparams.get_window_type() == P3D_WT_hidden && !is_failed()) { + // We're hidden, and so is the splash window. (But if we've got a + // failure case to report, we don't care and create the splash + // window anyway.) return; } @@ -2901,6 +2949,26 @@ report_package_info_ready(P3DPackage *package) { return; } + if (package == _panda3d_package && !_packages_specified) { + // Another special case. Once the special panda3d package is + // ready to download (and we know what platform it belongs to), we + // can begin to download the remaining required packages. + string package_platform = package->get_package_platform(); + if (!package_platform.empty() && _session_platform.empty()) { + // From now on, all platform-specific files downloaded by this + // session will be for this platform. + _session_platform = package_platform; + } + if (_session_platform != package_platform) { + nout << "Error: session is " << _session_platform + << ", but we somehow got panda3d for " << package_platform << "\n"; + set_failed(); + return; + } + + add_packages(); + } + // Now that the package's info is ready, we know its set of required // packages, and we can add these to the list. P3DPackage::Requires::const_iterator ri; diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index cf06e7b707..76d37e6522 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -88,6 +88,7 @@ public: inline int get_instance_id() const; inline const string &get_session_key() const; const string &get_log_pathname() const; + inline const string &get_session_platform() const; inline P3DSession *get_session() const; @@ -176,6 +177,7 @@ private: void mark_p3d_untrusted(); void mark_p3d_trusted(); void scan_app_desc_file(TiXmlDocument *doc); + void add_panda3d_package(); void add_packages(); string find_alt_host_url(const string &host_url, const string &alt_host); void get_host_info(P3DHost *host); @@ -286,6 +288,7 @@ private: int _instance_id; string _session_key; string _log_basename; + string _session_platform; string _prc_name; string _start_dir; bool _hidden; @@ -356,7 +359,7 @@ private: // We keep the _panda3d pointer separately because it's so // important, but it's in the above vector also. - P3DPackage *_panda3d; + P3DPackage *_panda3d_package; typedef map Downloads; Downloads _downloads; diff --git a/direct/src/plugin/p3dInstanceManager.I b/direct/src/plugin/p3dInstanceManager.I index ee644d1aed..caadc083b3 100644 --- a/direct/src/plugin/p3dInstanceManager.I +++ b/direct/src/plugin/p3dInstanceManager.I @@ -200,6 +200,38 @@ get_console_environment() const { return _console_environment; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstanceManager::get_num_supported_platforms +// Access: Public +// Description: Returns the number of different supported platforms +// available in get_supported_platform(). +//////////////////////////////////////////////////////////////////// +inline int P3DInstanceManager:: +get_num_supported_platforms() const { + return (int)_supported_platforms.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstanceManager::get_supported_platform +// Access: Public +// Description: Returns the nth supported platform, where 0 <= n < +// get_num_supported_platforms(). +// +// A given runtime environment may support multiple +// different platforms, e.g. win32 or win64, with the +// restriction that all platform-specific packages +// (beginning from panda3d), must be the same platform. +// +// This function enumerates the different platforms that +// the current runtime environment will support, in +// order of preference--preferred platforms appear first +// in the list. +//////////////////////////////////////////////////////////////////// +inline const string &P3DInstanceManager:: +get_supported_platform(int n) const { + return _supported_platforms.at(n); +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstanceManager::get_plugin_major_version // Access: Public diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index cb14c359e4..9978106ba6 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -38,6 +38,7 @@ #include #include // chmod() #include // rmdir() +#include // GetModuleHandle() etc. #else #include #include @@ -211,9 +212,32 @@ initialize(int api_version, const string &contents_filename, } if (_platform.empty()) { + // If the platform is compiled in (as opposed to passed in by the + // caller), we might in fact support multiple platforms. _platform = DTOOL_PLATFORM; + if (_platform == "win64") { + _supported_platforms.push_back("win64"); + _supported_platforms.push_back("win32"); + + } else if (_platform == "win32") { + // This is a WIN32 process, but determine if the underlying OS + // actually supports WIN64. + if (supports_win64()) { + _supported_platforms.push_back("win64"); + } + _supported_platforms.push_back("win32"); + } + + // TODO: OSX, Linux multiplatform support. Just add the + // appropriate platform strings to _supported_platforms. } + if (_supported_platforms.empty()) { + // We always support at least the specific platform on which we're + // running. + _supported_platforms.push_back(_platform); + } + #ifdef P3D_PLUGIN_LOG_DIRECTORY if (_log_directory.empty()) { _log_directory = P3D_PLUGIN_LOG_DIRECTORY; @@ -1520,3 +1544,20 @@ nt_thread_run() { _notify_ready.release(); } +#ifdef _WIN32 +bool P3DInstanceManager:: +supports_win64() { + BOOL is_win64 = false; + + typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + LPFN_ISWOW64PROCESS _IsWow64Process; + _IsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process"); + + if (_IsWow64Process != NULL) { + if (!_IsWow64Process(GetCurrentProcess(), &is_win64)) { + is_win64 = false; + } + } + return (is_win64 != 0); +} +#endif // _WIN32 diff --git a/direct/src/plugin/p3dInstanceManager.h b/direct/src/plugin/p3dInstanceManager.h index 33163fcc79..78cfcfbdce 100644 --- a/direct/src/plugin/p3dInstanceManager.h +++ b/direct/src/plugin/p3dInstanceManager.h @@ -76,6 +76,9 @@ public: inline bool get_trusted_environment() const; inline bool get_console_environment() const; + inline int get_num_supported_platforms() const; + inline const string &get_supported_platform(int n) const; + void set_plugin_version(int major, int minor, int sequence, bool official, const string &distributor, const string &coreapi_host_url, @@ -159,6 +162,10 @@ private: THREAD_CALLBACK_DECLARATION(P3DInstanceManager, nt_thread_run); void nt_thread_run(); +#ifdef _WIN32 + static bool supports_win64(); +#endif // _WIN32 + private: bool _is_initialized; bool _created_runtime_environment; @@ -185,6 +192,9 @@ private: string _coreapi_set_ver; string _super_mirror_url; + typedef vector SupportedPlatforms; + SupportedPlatforms _supported_platforms; + P3D_object *_undefined_object; P3D_object *_none_object; P3D_object *_true_object; diff --git a/direct/src/plugin/p3dPackage.I b/direct/src/plugin/p3dPackage.I index e4d09e4a5c..2ba1c24171 100755 --- a/direct/src/plugin/p3dPackage.I +++ b/direct/src/plugin/p3dPackage.I @@ -108,6 +108,16 @@ get_package_version() const { return _package_version; } +//////////////////////////////////////////////////////////////////// +// Function: P3DPackage::get_package_platform +// Access: Public +// Description: Returns the platform string of this package. +//////////////////////////////////////////////////////////////////// +inline const string &P3DPackage:: +get_package_platform() const { + return _package_platform; +} + //////////////////////////////////////////////////////////////////// // Function: P3DPackage::get_package_display_name // Access: Public diff --git a/direct/src/plugin/p3dPackage.cxx b/direct/src/plugin/p3dPackage.cxx index 5c7ff14787..1c372393d4 100755 --- a/direct/src/plugin/p3dPackage.cxx +++ b/direct/src/plugin/p3dPackage.cxx @@ -44,10 +44,12 @@ const double P3DPackage::_patch_factor = 0.01; //////////////////////////////////////////////////////////////////// P3DPackage:: P3DPackage(P3DHost *host, const string &package_name, - const string &package_version, const string &alt_host) : + const string &package_version, const string &package_platform, + const string &alt_host) : _host(host), _package_name(package_name), _package_version(package_version), + _package_platform(package_platform), _alt_host(alt_host) { _package_fullname = _package_name; @@ -611,7 +613,7 @@ host_got_contents_file() { nout << "Migrating " << get_package_name() << " to alt_host " << _alt_host << ": " << new_host->get_host_url() << "\n"; if (new_host != _host) { - _host->migrate_package(this, _alt_host, new_host); + _host->migrate_package_host(this, _alt_host, new_host); _host = new_host; } @@ -632,11 +634,30 @@ host_got_contents_file() { // instance, reloading it). _host_contents_iseq = _host->get_contents_iseq(); - // Now that we have a valid host, we can define the _package_dir. + // Now adjust the platform based on the available platforms + // provided. + assert(_alt_host.empty()); + string new_platform; + if (_host->choose_suitable_platform(new_platform, _package_name, _package_version, _package_platform)) { + if (new_platform != _package_platform) { + nout << "Migrating " << get_package_name() << " from platform \"" + << _package_platform << "\" to platform \"" + << new_platform << "\"\n"; + _package_platform = new_platform; + } + } else { + nout << "Couldn't find a platform for " << get_package_name() << ".\n"; + } + + // Now that we have a valid host and platform, we can define the + // _package_dir. _package_dir = _host->get_host_dir() + string("/") + _package_name; if (!_package_version.empty()) { _package_dir += string("/") + _package_version; } + if (!_package_platform.empty()) { + _package_dir += string("/") + _package_platform; + } // Ensure the package directory exists; create it if it does not. P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); @@ -661,11 +682,11 @@ download_desc_file() { // exists, and is consistent with the server contents file, we don't // need to re-download it. string package_seq; - if (!_host->get_package_desc_file(_desc_file, _package_platform, - package_seq, _package_solo, - _package_name, _package_version)) { + if (!_host->get_package_desc_file(_desc_file, package_seq, _package_solo, + _package_name, _package_version, + _package_platform)) { nout << "Couldn't find package " << _package_fullname - << " in contents file.\n"; + << "/" << _package_platform << " in contents file.\n"; redownload_contents_file(NULL); return; } diff --git a/direct/src/plugin/p3dPackage.h b/direct/src/plugin/p3dPackage.h index 6c938325c3..f280337b9f 100755 --- a/direct/src/plugin/p3dPackage.h +++ b/direct/src/plugin/p3dPackage.h @@ -44,6 +44,7 @@ private: P3DPackage(P3DHost *host, const string &package_name, const string &package_version, + const string &package_platform, const string &alt_host); ~P3DPackage(); @@ -58,6 +59,7 @@ public: inline const string &get_package_dir() const; inline const string &get_package_name() const; inline const string &get_package_version() const; + inline const string &get_package_platform() const; inline const string &get_package_display_name() const; string get_formatted_name() const; inline const TiXmlElement *get_xconfig() const; diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index b541411749..a299598c38 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -697,7 +697,7 @@ start_p3dpython(P3DInstance *inst) { return; } - if (inst->_panda3d == NULL) { + if (inst->_panda3d_package == NULL) { nout << "Couldn't start Python: no panda3d dependency.\n"; set_failed(); return; @@ -705,7 +705,7 @@ start_p3dpython(P3DInstance *inst) { P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - _python_root_dir = inst->_panda3d->get_package_dir(); + _python_root_dir = inst->_panda3d_package->get_package_dir(); replace_slashes(_python_root_dir); // If we're not to be preserving the user's current directory, then @@ -823,10 +823,10 @@ start_p3dpython(P3DInstance *inst) { // Allow package to override the name of the p3dpython executables. const char *p3dpython_name_xconfig = NULL; const char *p3dpythonw_name_xconfig = NULL; - const TiXmlElement *panda3d_xconfig = inst->_panda3d->get_xconfig(); + const TiXmlElement *panda3d_xconfig = inst->_panda3d_package->get_xconfig(); if (panda3d_xconfig != NULL) { - p3dpython_name_xconfig = panda3d_xconfig->Attribute("p3dpython_name"); - p3dpythonw_name_xconfig = panda3d_xconfig->Attribute("p3dpythonw_name"); + p3dpython_name_xconfig = panda3d_xconfig->Attribute("p3dpython_name"); + p3dpythonw_name_xconfig = panda3d_xconfig->Attribute("p3dpythonw_name"); } string p3dpython_name = "p3dpython"; @@ -1206,7 +1206,7 @@ start_p3dpython(P3DInstance *inst) { // Get the filename of the Panda3D multifile. We need to pass this // to p3dpython. - _mf_filename = inst->_panda3d->get_archive_file_pathname(); + _mf_filename = inst->_panda3d_package->get_archive_file_pathname(); nout << "Attempting to start python from " << _p3dpython_exe << "\n"; diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx index 97fecbc186..78bb7143e0 100644 --- a/direct/src/plugin_standalone/panda3d.cxx +++ b/direct/src/plugin_standalone/panda3d.cxx @@ -83,6 +83,7 @@ run_command_line(int argc, char *argv[]) { case 'p': _this_platform = optarg; + _coreapi_platform = optarg; break; case 'n': @@ -506,7 +507,7 @@ read_contents_file(const Filename &contents_filename, bool fresh_download) { const char *name = xpackage->Attribute("name"); if (name != NULL && strcmp(name, "coreapi") == 0) { const char *platform = xpackage->Attribute("platform"); - if (platform != NULL && _this_platform == string(platform)) { + if (platform != NULL && _coreapi_platform == string(platform)) { _coreapi_dll.load_xml(xpackage); const char *set_ver = xpackage->Attribute("set_ver"); if (set_ver != NULL) { @@ -524,7 +525,7 @@ read_contents_file(const Filename &contents_filename, bool fresh_download) { if (!found_core_package) { // Couldn't find the coreapi package description. nout << "No coreapi package defined in contents file for " - << _this_platform << "\n"; + << _coreapi_platform << "\n"; return false; } diff --git a/direct/src/plugin_standalone/panda3dBase.cxx b/direct/src/plugin_standalone/panda3dBase.cxx index 1e51631795..cb4d7e41a1 100644 --- a/direct/src/plugin_standalone/panda3dBase.cxx +++ b/direct/src/plugin_standalone/panda3dBase.cxx @@ -68,7 +68,11 @@ Panda3DBase(bool console_environment) { _exit_with_last_instance = true; _host_url = PANDA_PACKAGE_HOST_URL; - _this_platform = DTOOL_PLATFORM; + // Better to leave _this_platform set to the empty string until the + // user specifies otherwise; this allows the plugin to select a + // suitable platform at runtime. + _this_platform = ""; + _coreapi_platform = DTOOL_PLATFORM; _verify_contents = P3D_VC_none; _contents_expiration = 0; @@ -235,12 +239,17 @@ handle_request(P3D_request *request) { case P3D_RT_notify: { + //cerr << "Notify: " << request->_request._notify._message << "\n"; if (strcmp(request->_request._notify._message, "ondownloadnext") == 0) { // Tell the user we're downloading a package. report_downloading_package(request->_instance); } else if (strcmp(request->_request._notify._message, "ondownloadcomplete") == 0) { // Tell the user we're done downloading. report_download_complete(request->_instance); + } else if (strcmp(request->_request._notify._message, "onfail") == 0) { + // Failure! What else can we do? + cerr << "Failed to execute.\n"; + exit(1); } } break; diff --git a/direct/src/plugin_standalone/panda3dBase.h b/direct/src/plugin_standalone/panda3dBase.h index 0adf962f39..0f577f39fe 100755 --- a/direct/src/plugin_standalone/panda3dBase.h +++ b/direct/src/plugin_standalone/panda3dBase.h @@ -77,6 +77,7 @@ protected: string _log_dirname; string _log_basename; string _this_platform; + string _coreapi_platform; P3D_verify_contents _verify_contents; time_t _contents_expiration; diff --git a/direct/src/showutil/FreezeTool.py b/direct/src/showutil/FreezeTool.py index af7edd6997..2997747e3e 100644 --- a/direct/src/showutil/FreezeTool.py +++ b/direct/src/showutil/FreezeTool.py @@ -786,13 +786,15 @@ class Freezer: topName = parentName[:-2] newTopName = newParentName[:-2] parentNames = [] - for dirname in self.getModulePath(topName): - for basename in os.listdir(dirname): - if os.path.exists(os.path.join(dirname, basename, '__init__.py')): - parentName = '%s.%s' % (topName, basename) - newParentName = '%s.%s' % (newTopName, basename) - if self.getModulePath(parentName): - parentNames.append((parentName, newParentName)) + modulePath = self.getModulePath(topName) + if modulePath: + for dirname in modulePath: + for basename in os.listdir(dirname): + if os.path.exists(os.path.join(dirname, basename, '__init__.py')): + parentName = '%s.%s' % (topName, basename) + newParentName = '%s.%s' % (newTopName, basename) + if self.getModulePath(parentName): + parentNames.append((parentName, newParentName)) for parentName, newParentName in parentNames: modules = self.getModuleStar(parentName) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 961a74d094..508885c8c2 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -4258,7 +4258,9 @@ if (RTDIST or RUNTIME): TargetAdd('p3dcert.exe', input='plugin_wstring_encode.obj') TargetAdd('p3dcert.exe', input='plugin_p3dCert.obj') OPTS=['OPENSSL', 'FLTK', 'WINCOMCTL', 'WINSOCK'] - else: + if (sys.platform=="darwin"): OPTS += ['OPT:2'] + TargetAdd('p3dcert.exe', opts=OPTS) + elif (PkgSkip("WX")==0): OPTS.append("WX") TargetAdd('plugin_p3dCert.obj', opts=OPTS, input='p3dCert_wx.cxx') TargetAdd('p3dcert.exe', input='plugin_mkdir_complete.obj') @@ -4266,9 +4268,8 @@ if (RTDIST or RUNTIME): TargetAdd('p3dcert.exe', input='plugin_p3dCert.obj') OPTS=['NOSTRIP', 'OPENSSL', 'WX', 'CARBON', 'WINOLE', 'WINOLEAUT', 'WINUSER', 'ADVAPI', 'WINSHELL', 'WINCOMCTL', 'WINGDI', 'WINCOMDLG'] if (sys.platform=="darwin"): OPTS.append("GL") - - if (sys.platform=="darwin"): OPTS += ['OPT:2'] - TargetAdd('p3dcert.exe', opts=OPTS) + if (sys.platform=="darwin"): OPTS += ['OPT:2'] + TargetAdd('p3dcert.exe', opts=OPTS) # # DIRECTORY: direct/src/plugin_npapi/