diff --git a/direct/src/p3d/AppRunner.py b/direct/src/p3d/AppRunner.py index 7a0a237243..d48f7b1c22 100644 --- a/direct/src/p3d/AppRunner.py +++ b/direct/src/p3d/AppRunner.py @@ -102,6 +102,13 @@ class AppRunner(DirectObject): # the instance starts up. self.rootDir = None + # self.superMirrorUrl, if nonempty, is the "super mirror" URL + # that should be contacted first before trying the actual + # host. This is primarily used for "downloading" from a + # locally-stored Panda3D installation. This is also filled in + # when the instance starts up. + self.superMirrorUrl = None + # A list of the Panda3D packages that have been loaded. self.installedPackages = [] @@ -430,11 +437,7 @@ class AppRunner(DirectObject): interactiveConsole = self.interactiveConsole self.interactiveConsole = False - try: - __import__(moduleName) - except ImportError: - message = "No %s found in application." % (moduleName) - raise StandardError, message + __import__(moduleName) main = sys.modules[moduleName] if hasattr(main, 'main') and callable(main.main): main.main(self) @@ -469,15 +472,17 @@ class AppRunner(DirectObject): needsResponse = False) self.deferredEvals = [] - def setInstanceInfo(self, rootDir): + def setInstanceInfo(self, rootDir, superMirrorUrl): """ Called by the browser to set some global information about the instance. """ - # At the present, this only includes rootDir, which is the - # root Panda3D install directory on the local machine. - + # rootDir is the root Panda3D install directory on the local + # machine. self.rootDir = Filename.fromOsSpecific(rootDir) + # The "super mirror" URL, generally used only by panda3d.exe. + self.superMirrorUrl = superMirrorUrl + def addPackageInfo(self, name, platform, version, hostUrl): """ Called by the browser to list all of the "required" packages that were preloaded before starting the @@ -809,7 +814,7 @@ def dummyAppRunner(tokens = [], argv = None): if AppRunnerGlobal.appRunner: print "Already have AppRunner, not creating a new one." - return + return AppRunnerGlobal.appRunner appRunner = AppRunner() appRunner.dummy = True diff --git a/direct/src/p3d/HostInfo.py b/direct/src/p3d/HostInfo.py index b856e223ab..8ed8c3cf0f 100644 --- a/direct/src/p3d/HostInfo.py +++ b/direct/src/p3d/HostInfo.py @@ -25,6 +25,7 @@ class HostInfo: assert appRunner or hostDir self.hostUrl = hostUrl + self.appRunner = appRunner self.hostDir = hostDir self.asMirror = asMirror diff --git a/direct/src/p3d/PackageInfo.py b/direct/src/p3d/PackageInfo.py index d0abb15619..75f428bafe 100644 --- a/direct/src/p3d/PackageInfo.py +++ b/direct/src/p3d/PackageInfo.py @@ -532,16 +532,24 @@ class PackageInfo: if not urlbase: urlbase = self.descFileDirname + '/' + fileSpec.filename - # Build up a list of URL's to try downloading from. + # Build up a list of URL's to try downloading from. Unlike + # the C++ implementation in P3DPackage.cxx, here we build the + # URL's in forward order. tryUrls = [] + + if self.host.appRunner and self.host.appRunner.superMirrorUrl: + # We start with the "super mirror", if it's defined. + url = self.host.appRunner.superMirrorUrl + urlbase + tryUrls.append(url) + if self.host.mirrors: - # Choose a mirror at random first, then a different - # mirror. + # Choose two mirrors at random. mirrors = self.host.mirrors[:] for i in range(2): mirror = random.choice(mirrors) mirrors.remove(mirror) - tryUrls.append(mirror + urlbase) + url = mirror + urlbase + tryUrls.append(url) if not mirrors: break diff --git a/direct/src/p3d/Packager.py b/direct/src/p3d/Packager.py index 7d057d8274..3b909607b4 100644 --- a/direct/src/p3d/Packager.py +++ b/direct/src/p3d/Packager.py @@ -458,7 +458,7 @@ class Packager: continue if mdef.exclude and mdef.implicit: - # Don't bother mentioning implicity-excluded + # Don't bother mentioning implicitly-excluded # (i.e. missing) modules. continue @@ -1529,10 +1529,8 @@ class Packager: # The following are config settings that the caller may adjust # before calling any of the command methods. - # These should each be a Filename, or None if they are not - # filled in. + # This should be set to a Filename. self.installDir = None - self.persistDir = None # The download URL at which these packages will eventually be # hosted. diff --git a/direct/src/p3d/panda3d.pdef b/direct/src/p3d/panda3d.pdef index d1d7c53145..112c1d2196 100755 --- a/direct/src/p3d/panda3d.pdef +++ b/direct/src/p3d/panda3d.pdef @@ -14,6 +14,12 @@ from pandac.PandaModules import getModelPath, Filename, ConfigVariableFilename # and then a number of smaller, optional packages, which may or may # not be needed by any one particular application. +packager.setHost('file:///home/drose/p3dstage', + mirrors = ['file:///home/drose/p3dstage_mirror1', + 'file:///home/drose/p3dstage_mirror2', + 'file:///home/drose/p3dstage_mirror3', + 'file:///home/drose/p3dstage_mirror4']) + class coreapi(solo): # The special "coreapi" package. As a "solo", this is just a # single .dll (or dylib, or whatever). @@ -102,6 +108,7 @@ class panda3d(package): 'direct.gui.*', 'direct.interval.*', 'direct.particles.*', + 'direct.p3d.*', 'direct.showbase.*', 'direct.showutil.*', 'direct.stdpy.*') diff --git a/direct/src/p3d/ppackage.py b/direct/src/p3d/ppackage.py index f99acc121a..ba43cf4b3d 100755 --- a/direct/src/p3d/ppackage.py +++ b/direct/src/p3d/ppackage.py @@ -61,15 +61,6 @@ Options: This option may be repeated as necessary. These directories may also be specified with the pdef-path Config.prc variable. - -d persist_dir - The full path to a local directory that retains persistant state - between publishes. This directory structure keeps files that are - used to build patches for future releases. You should keep this - directory structure around for as long as you plan to support - this package. If this directory structure does not exist or is - empty, patches will not be created for this publish; but the - directory structure will be populated for the next publish. - -u host_url Specifies the URL to the download server that will eventually host these packages (that is, the public URL of the install @@ -119,7 +110,7 @@ packager = Packager.Packager() buildPatches = False try: - opts, args = getopt.getopt(sys.argv[1:], 'i:ps:d:DP:u:n:h') + opts, args = getopt.getopt(sys.argv[1:], 'i:ps:DP:u:n:h') except getopt.error, msg: usage(1, msg) @@ -130,8 +121,6 @@ for opt, arg in opts: buildPatches = True elif opt == '-s': packager.installSearch.appendDirectory(Filename.fromOsSpecific(arg)) - elif opt == '-d': - packager.persistDir = Filename.fromOsSpecific(arg) elif opt == '-D': packager.allowPythonDev = True elif opt == '-P': diff --git a/direct/src/plugin/load_plugin.cxx b/direct/src/plugin/load_plugin.cxx index fc51c16e3b..0f61c045ad 100755 --- a/direct/src/plugin/load_plugin.cxx +++ b/direct/src/plugin/load_plugin.cxx @@ -36,6 +36,7 @@ static const string default_plugin_filename = "p3d_plugin"; P3D_initialize_func *P3D_initialize; P3D_finalize_func *P3D_finalize; +P3D_set_super_mirror_func *P3D_set_super_mirror; P3D_new_instance_func *P3D_new_instance; P3D_instance_start_func *P3D_instance_start; P3D_instance_finish_func *P3D_instance_finish; @@ -187,6 +188,7 @@ load_plugin(const string &p3d_plugin_filename, // Now get all of the function pointers. P3D_initialize = (P3D_initialize_func *)get_func(module, "P3D_initialize"); P3D_finalize = (P3D_finalize_func *)get_func(module, "P3D_finalize"); + P3D_set_super_mirror = (P3D_set_super_mirror_func *)get_func(module, "P3D_set_super_mirror"); P3D_new_instance = (P3D_new_instance_func *)get_func(module, "P3D_new_instance"); P3D_instance_start = (P3D_instance_start_func *)get_func(module, "P3D_instance_start"); P3D_instance_finish = (P3D_instance_finish_func *)get_func(module, "P3D_instance_finish"); @@ -226,6 +228,7 @@ load_plugin(const string &p3d_plugin_filename, // Ensure that all of the function pointers have been found. if (P3D_initialize == NULL || P3D_finalize == NULL || + P3D_set_super_mirror == NULL || P3D_new_instance == NULL || P3D_instance_start == NULL || P3D_instance_finish == NULL || @@ -265,6 +268,7 @@ load_plugin(const string &p3d_plugin_filename, << "Some function pointers not found:" << "\nP3D_initialize = " << P3D_initialize << "\nP3D_finalize = " << P3D_finalize + << "\nP3D_set_super_mirror = " << P3D_set_super_mirror << "\nP3D_new_instance = " << P3D_new_instance << "\nP3D_instance_start = " << P3D_instance_start << "\nP3D_instance_finish = " << P3D_instance_finish @@ -358,6 +362,7 @@ unload_dso() { P3D_initialize = NULL; P3D_finalize = NULL; + P3D_set_super_mirror = NULL; P3D_new_instance = NULL; P3D_instance_start = NULL; P3D_instance_finish = NULL; diff --git a/direct/src/plugin/load_plugin.h b/direct/src/plugin/load_plugin.h index 9da12b83d1..1bcfb417da 100755 --- a/direct/src/plugin/load_plugin.h +++ b/direct/src/plugin/load_plugin.h @@ -22,6 +22,7 @@ using namespace std; extern P3D_initialize_func *P3D_initialize; extern P3D_finalize_func *P3D_finalize; +extern P3D_set_super_mirror_func *P3D_set_super_mirror; extern P3D_new_instance_func *P3D_new_instance; extern P3D_instance_start_func *P3D_instance_start; extern P3D_instance_finish_func *P3D_instance_finish; diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index af800e5322..860a952791 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -847,10 +847,6 @@ start_download(P3DDownload *download) { P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - // Since we're downloading something, we might as well check all - // contents files from this point on. - inst_mgr->reset_verify_contents(); - int download_id = inst_mgr->get_unique_id(); download->set_download_id(download_id); @@ -912,6 +908,9 @@ make_xml() { P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); xinstance->SetAttribute("root_dir", inst_mgr->get_root_dir()); + if (!inst_mgr->get_super_mirror().empty()) { + xinstance->SetAttribute("super_mirror", inst_mgr->get_super_mirror()); + } TiXmlElement *xfparams = _fparams.make_xml(); xinstance->LinkEndChild(xfparams); diff --git a/direct/src/plugin/p3dInstanceManager.I b/direct/src/plugin/p3dInstanceManager.I index bc511e33f2..883f36c7ef 100644 --- a/direct/src/plugin/p3dInstanceManager.I +++ b/direct/src/plugin/p3dInstanceManager.I @@ -122,6 +122,16 @@ get_trusted_environment() const { return _trusted_environment; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstanceManager::get_super_mirror +// Access: Public +// Description: Returns the "super mirror" URL. See p3d_plugin.h. +//////////////////////////////////////////////////////////////////// +inline const string &P3DInstanceManager:: +get_super_mirror() const { + return _super_mirror_url; +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstanceManager::get_num_instances // Access: Public diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index 517780cc20..aa11eb650e 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -296,6 +296,21 @@ initialize(const string &contents_filename, const string &download_url, return true; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstanceManager::set_super_mirror +// Access: Public +// Description: Specifies the "super mirror" URL. See p3d_plugin.h. +//////////////////////////////////////////////////////////////////// +void P3DInstanceManager:: +set_super_mirror(const string &super_mirror_url) { + _super_mirror_url = super_mirror_url; + + // Make sure it ends with a slash. + if (!_super_mirror_url.empty() && _super_mirror_url[_super_mirror_url.size() - 1] != '/') { + _super_mirror_url += '/'; + } +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstanceManager::create_instance // Access: Public diff --git a/direct/src/plugin/p3dInstanceManager.h b/direct/src/plugin/p3dInstanceManager.h index 9e56b91b52..4d8bdbd09b 100644 --- a/direct/src/plugin/p3dInstanceManager.h +++ b/direct/src/plugin/p3dInstanceManager.h @@ -67,6 +67,9 @@ public: inline const string &get_log_pathname() const; inline bool get_trusted_environment() const; + void set_super_mirror(const string &super_mirror_url); + inline const string &get_super_mirror() const; + P3DInstance * create_instance(P3D_request_ready_func *func, const P3D_token tokens[], size_t num_tokens, @@ -129,6 +132,7 @@ private: string _log_pathname; string _temp_directory; bool _trusted_environment; + string _super_mirror_url; P3D_object *_undefined_object; P3D_object *_none_object; diff --git a/direct/src/plugin/p3dPackage.cxx b/direct/src/plugin/p3dPackage.cxx index 9250ecd22a..87e3d98233 100755 --- a/direct/src/plugin/p3dPackage.cxx +++ b/direct/src/plugin/p3dPackage.cxx @@ -945,6 +945,22 @@ start_download(P3DPackage::DownloadType dtype, const string &urlbase, } } + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + + if (dtype == DT_contents_file && inst_mgr->get_verify_contents()) { + // When we're dowloading the contents file with verify_contents + // true, we always go straight to the authoritative host, not even + // to the super-mirror. + + } else { + // In other cases, if the "super mirror" is enabled, we try that + // first. + if (!inst_mgr->get_super_mirror().empty()) { + string url = inst_mgr->get_super_mirror() + urlbase; + download->_try_urls.push_back(url); + } + } + // OK, start the download. assert(!download->_try_urls.empty()); url = download->_try_urls.back(); diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index 1dd92e142d..03f8a9bb29 100755 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/direct/src/plugin/p3dPythonRun.cxx @@ -1116,8 +1116,13 @@ set_instance_info(P3DCInstance *inst, TiXmlElement *xinstance) { root_dir = ""; } + const char *super_mirror = xinstance->Attribute("super_mirror"); + if (super_mirror == NULL) { + super_mirror = ""; + } + PyObject *result = PyObject_CallMethod - (_runner, (char *)"setInstanceInfo", (char *)"s", root_dir); + (_runner, (char *)"setInstanceInfo", (char *)"ss", root_dir, super_mirror); if (result == NULL) { PyErr_Print(); diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index 0b785d9202..edc832cd5c 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -850,8 +850,9 @@ start_p3dpython(P3DInstance *inst) { _env += python_path; _env += '\0'; + // Let's leave PYTHONHOME empty. Setting it adds junk to our + // carefully-constructed PYTHONPATH. _env += "PYTHONHOME="; - _env += _python_root_dir; _env += '\0'; _env += "PRC_PATH="; diff --git a/direct/src/plugin/p3d_plugin.cxx b/direct/src/plugin/p3d_plugin.cxx index e4e5c2cd3f..3221433ec4 100644 --- a/direct/src/plugin/p3d_plugin.cxx +++ b/direct/src/plugin/p3d_plugin.cxx @@ -84,11 +84,23 @@ P3D_finalize() { P3DInstanceManager::delete_global_ptr(); } +void +P3D_set_super_mirror(const char *super_mirror_url) { + assert(P3DInstanceManager::get_global_ptr()->is_initialized()); + if (super_mirror_url == NULL) { + super_mirror_url = ""; + } + + ACQUIRE_LOCK(_api_lock); + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + inst_mgr->set_super_mirror(super_mirror_url); + RELEASE_LOCK(_api_lock); +} + P3D_instance * P3D_new_instance(P3D_request_ready_func *func, const P3D_token tokens[], size_t num_tokens, int argc, const char *argv[], void *user_data) { - nout << "new_instance\n"; assert(P3DInstanceManager::get_global_ptr()->is_initialized()); ACQUIRE_LOCK(_api_lock); P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); @@ -101,7 +113,6 @@ P3D_new_instance(P3D_request_ready_func *func, bool P3D_instance_start(P3D_instance *instance, bool is_local, const char *p3d_filename) { - nout << "instance_start\n"; assert(P3DInstanceManager::get_global_ptr()->is_initialized()); if (p3d_filename == NULL) { p3d_filename = ""; @@ -138,7 +149,6 @@ P3D_instance_setup_window(P3D_instance *instance, int win_x, int win_y, int win_width, int win_height, P3D_window_handle parent_window) { - nout << "setup_window\n"; assert(P3DInstanceManager::get_global_ptr()->is_initialized()); P3DWindowParams wparams(window_type, win_x, win_y, win_width, win_height, parent_window); diff --git a/direct/src/plugin/p3d_plugin.h b/direct/src/plugin/p3d_plugin.h index 1b0af1128e..add09aaf57 100644 --- a/direct/src/plugin/p3d_plugin.h +++ b/direct/src/plugin/p3d_plugin.h @@ -145,6 +145,22 @@ P3D_initialize_func(int api_version, const char *contents_filename, typedef void P3D_finalize_func(); +/* This function defines a "super mirror" URL: a special URL that is + consulted first whenever downloading any package referenced by a + p3d file. This setting is global, and affects all package + downloads across all instances. The main purpose of this is to + facilitate local distribution of the Panda3D runtime build, to + allow applications to ship themselves totally self-contained. If + you install the appropriate Panda3D package files into a directory + on disk, and set the "super mirror" to a file:// URL that + references that directory, then users will be able to run your p3d + file without necessarily having an internet connection. + + This normally should be set only by the panda3d standalone runtime + executable, not by a web plugin. */ +typedef void +P3D_set_super_mirror_func(const char *super_mirror_url); + /********************** INSTANCE MANAGEMENT **************************/ /* The following interfaces define the API to manage individual @@ -852,6 +868,7 @@ P3D_instance_handle_event_func(P3D_instance *instance, P3D_event_data event); /* Define all of the actual prototypes for the above functions. */ EXPCL_P3D_PLUGIN P3D_initialize_func P3D_initialize; EXPCL_P3D_PLUGIN P3D_finalize_func P3D_finalize; +EXPCL_P3D_PLUGIN P3D_set_super_mirror_func P3D_set_super_mirror; EXPCL_P3D_PLUGIN P3D_new_instance_func P3D_new_instance; EXPCL_P3D_PLUGIN P3D_instance_start_func P3D_instance_start; diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx index 73efbd5ee2..f7286b5c58 100644 --- a/direct/src/plugin_standalone/panda3d.cxx +++ b/direct/src/plugin_standalone/panda3d.cxx @@ -22,6 +22,7 @@ // definition, even though we don't link with dtool. #include "dtool_platform.h" +#include #include #ifdef _WIN32 #include @@ -66,10 +67,11 @@ run(int argc, char *argv[]) { // We prefix a "+" sign to tell gnu getopt not to parse options // following the first not-option parameter. (These will be passed // into the sub-process.) - const char *optstr = "+mu:p:fw:t:s:o:l:ih"; + const char *optstr = "+mu:M:p:fw:t:s:o:l:ih"; bool allow_multiple = false; string download_url = PANDA_PACKAGE_HOST_URL; + string super_mirror_url; string this_platform = DTOOL_PLATFORM; bool verify_contents = false; @@ -89,6 +91,10 @@ run(int argc, char *argv[]) { download_url = optarg; break; + case 'M': + super_mirror_url = optarg; + break; + case 'p': this_platform = optarg; break; @@ -181,16 +187,36 @@ run(int argc, char *argv[]) { return 1; } - // Make sure it ends with a slash. + // Make sure the download URL ends with a slash. if (!download_url.empty() && download_url[download_url.length() - 1] != '/') { download_url += '/'; } + // If the "super mirror" URL is a filename, convert it to a file:// url. + if (!super_mirror_url.empty()) { + if (!is_url(super_mirror_url)) { + Filename filename = Filename::from_os_specific(super_mirror_url); + filename.make_absolute(); + string path = filename.to_os_generic(); + if (!path.empty() && path[0] != '/') { + // On Windows, a leading drive letter must be preceded by an + // additional slash. + path = "/" + path; + } + super_mirror_url = "file://" + path; + } + } + if (!get_plugin(download_url, this_platform, verify_contents)) { cerr << "Unable to load Panda3D plugin.\n"; return 1; } + // Set up the "super mirror" URL, if specified. + if (!super_mirror_url.empty()) { + P3D_set_super_mirror(super_mirror_url.c_str()); + } + int num_instance_filenames, num_instance_args; char **instance_filenames, **instance_args; @@ -682,16 +708,14 @@ P3D_instance *Panda3D:: create_instance(const string &p3d, P3D_window_type window_type, int win_x, int win_y, int win_width, int win_height, P3D_window_handle parent_window, char **args, int num_args) { - // If the supplied parameter name is a real file, pass it in on the - // parameter list. Otherwise, assume it's a URL and let the plugin - // download it. + // Check to see if the p3d filename we were given is a URL, or a + // local file. Filename p3d_filename = Filename::from_os_specific(p3d); string os_p3d_filename = p3d; - bool is_local = false; - if (p3d_filename.exists()) { + bool is_local = !is_url(p3d); + if (is_local) { p3d_filename.make_absolute(); os_p3d_filename = p3d_filename.to_os_specific(); - is_local = true; } // Build up the token list. @@ -832,8 +856,17 @@ usage() { << " code.\n\n" << " -u url\n" - << " Specify the URL of the Panda3D download server. The default is\n" - << " \"" << PANDA_PACKAGE_HOST_URL << "\" .\n\n" + + << " Specify the URL of the Panda3D download server. This is the host\n" + << " from which the plugin itself will be downloaded if necessary. The\n" + << " default is\n \"" << PANDA_PACKAGE_HOST_URL << "\" .\n\n" + + << " -M super_mirror_url\n" + << " Specifies the \"super mirror\" URL, the special URL that is consulted\n" + << " first before downloading any package file referenced by a p3d file.\n" + << " This is primarily intended to support pre-installing a downloadable\n" + << " Panda3D tree on the local machine, to allow p3d applications to\n" + << " execute without requiring an internet connection.\n\n" << " -p platform\n" << " Specify the platform to masquerade as. The default is \"" @@ -888,6 +921,39 @@ parse_int_pair(char *arg, int &x, int &y) { return false; } +//////////////////////////////////////////////////////////////////// +// Function: Panda3D::is_url +// Access: Private, Static +// Description: Returns true if the indicated string appears to be a +// URL, with a leading http:// or file:// or whatever, +// or false if it must be a local filename instead. +//////////////////////////////////////////////////////////////////// +bool Panda3D:: +is_url(const string ¶m) { + // We define a URL prefix as a sequence of at least two letters, + // followed by a colon, followed by at least one slash. + size_t p = 0; + while (p < param.size() && isalpha(param[p])) { + ++p; + } + if (p < 2) { + // Not enough letters. + return false; + } + if (p >= param.size() || param[p] != ':') { + // No colon. + return false; + } + ++p; + if (p >= param.size() || param[p] != '/') { + // No slash. + return false; + } + + // It matches the rules. + return true; +} + //////////////////////////////////////////////////////////////////// // Function: Panda3D::report_downloading_package // Access: Private diff --git a/direct/src/plugin_standalone/panda3d.h b/direct/src/plugin_standalone/panda3d.h index e113fd1bf2..4a3242453f 100755 --- a/direct/src/plugin_standalone/panda3d.h +++ b/direct/src/plugin_standalone/panda3d.h @@ -65,6 +65,7 @@ private: void usage(); bool parse_token(char *arg); bool parse_int_pair(char *arg, int &x, int &y); + static bool is_url(const string ¶m); void report_downloading_package(P3D_instance *instance); void report_download_complete(P3D_instance *instance); diff --git a/direct/src/showutil/FreezeTool.py b/direct/src/showutil/FreezeTool.py index d8af8f7258..744397f991 100644 --- a/direct/src/showutil/FreezeTool.py +++ b/direct/src/showutil/FreezeTool.py @@ -786,6 +786,8 @@ class Freezer: continue if origName in self.previousModules: continue + if origName in self.modules: + continue # This module is missing. Let it be missing in the # runtime also.