/* Originally from /Source/gg2/Scripts/Plugins/loadserverplugins.gml in Gang Garrison 2 Copyright (C) 2008-2013 Faucet Software http://www.ganggarrison.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . Additional permission under GNU GPL version 3 section 7 If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library, the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries, the licensors of this Program grant you additional permission to convey the resulting work. */ // loads plugins from ganggarrison.com asked for by server // argument0 - comma separated plugin list (pluginname@md5hash) // returns true on success, false on failure var list, hashList, text, i, pluginname, pluginhash, realhash, url, handle, filesize, progress, tempfile, tempdir, failed, lastContact, isCached; failed = false; list = ds_list_create(); lastContact = 0; isCached = false; isDebug = false; hashList = ds_list_create(); // split plugin list string list = split(argument0, ','); // Split hashes from plugin names for (i = 0; i < ds_list_size(list); i += 1) { text = ds_list_find_value(list, i); pluginname = string_copy(text, 0, string_pos("@", text) - 1); pluginhash = string_copy(text, string_pos("@", text) + 1, string_length(text) - string_pos("@", text)); ds_list_replace(list, i, pluginname); ds_list_add(hashList, pluginhash); } // Check plugin names and check for duplicates for (i = 0; i < ds_list_size(list); i += 1) { pluginname = ds_list_find_value(list, i); // invalid plugin name if (!checkpluginname(pluginname)) { show_message('Error loading server-sent plugins - invalid plugin name:#"' + pluginname + '"'); return false; } // is duplicate else if (ds_list_find_index(list, pluginname) != i) { show_message('Error loading server-sent plugins - duplicate plugin:#"' + pluginname + '"'); return false; } } // Download plugins for (i = 0; i < ds_list_size(list); i += 1) { pluginname = ds_list_find_value(list, i); pluginhash = ds_list_find_value(hashList, i); isDebug = file_exists(working_directory + "\ServerPluginsDebug\" + pluginname + ".zip"); isCached = file_exists(working_directory + "\ServerPluginsCache\" + pluginname + "@" + pluginhash); tempfile = temp_directory + "\" + pluginname + ".zip.tmp"; tempdir = temp_directory + "\" + pluginname + ".tmp"; // check to see if we have a local copy for debugging if (isDebug) { file_copy(working_directory + "\ServerPluginsDebug\" + pluginname + ".zip", tempfile); // show warning if (global.isHost) { show_message( "Warning: server-sent plugin '" + pluginname + "' is being loaded from ServerPluginsDebug. Make sure clients have the same version, else they may be unable to connect." ); } else { show_message( "Warning: server-sent plugin '" + pluginname + "' is being loaded from ServerPluginsDebug. Make sure the server has the same version, else you may be unable to connect." ); } } // otherwise, check if we have it cached else if (isCached) { file_copy(working_directory + "\ServerPluginsCache\" + pluginname + "@" + pluginhash, tempfile); } // otherwise, download as usual else { // construct the URL // http://www.ganggarrison.com/plugins/$PLUGINNAME$@$PLUGINHASH$.zip) url = PLUGIN_SOURCE + pluginname + "@" + pluginhash + ".zip"; // let's make the download handle handle = httpGet(url, -1); // download it while (!httpRequestStatus(handle)) { // prevent game locking up io_handle(); httpRequestStep(handle); if (!global.isHost) { // send ping if we haven't contacted server in 20 seconds // we need to do this to keep the connection open if (current_time-lastContact > 20000) { write_byte(global.serverSocket, PING); socket_send(global.serverSocket); lastContact = current_time; } } // draw progress bar since they may be waiting a while filesize = httpRequestResponseBodySize(handle); progress = httpRequestResponseBodyProgress(handle); draw_background_ext(background_index[0], 0, 0, background_xscale[0], background_yscale[0], 0, c_white, 1); draw_set_color(c_white); draw_set_alpha(1); draw_set_halign(fa_left); draw_rectangle(50, 550, 300, 560, 2); draw_text(50, 530, "Downloading server-sent plugin " + string(i + 1) + "/" + string(ds_list_size(list)) + ' - "' + pluginname + '"'); if (filesize != -1) draw_rectangle(50, 550, 50 + progress / filesize * 250, 560, 0); screen_refresh(); } // errored if (httpRequestStatus(handle) == 2) { show_message('Error loading server-sent plugins - download failed for "' + pluginname + '":#' + httpRequestError(handle)); failed = true; break; } // request failed if (httpRequestStatusCode(handle) != 200) { show_message('Error loading server-sent plugins - download failed for "' + pluginname + '":#' + string(httpRequestStatusCode(handle)) + ' ' + httpRequestReasonPhrase(handle)); failed = true; break; } else { write_buffer_to_file(httpRequestResponseBody(handle), tempfile); if (!file_exists(tempfile)) { show_message('Error loading server-sent plugins - download failed for "' + pluginname + '":# No such file?'); failed = true; break; } } httpRequestDestroy(handle); } // check file integrity realhash = GG2DLL_compute_MD5(tempfile); if (realhash != pluginhash) { show_message('Error loading server-sent plugins - integrity check failed (MD5 hash mismatch) for:#"' + pluginname + '"'); failed = true; break; } // don't try to cache debug plugins if (!isDebug) { // add to cache if we don't already have it if (!file_exists(working_directory + "\ServerPluginsCache\" + pluginname + "@" + pluginhash)) { // make sure directory exists if (!directory_exists(working_directory + "\ServerPluginsCache")) { directory_create(working_directory + "\ServerPluginsCache"); } // store in cache file_copy(tempfile, working_directory + "\ServerPluginsCache\" + pluginname + "@" + pluginhash); } } // let's get 7-zip to extract the files extractzip(tempfile, tempdir); // if the directory doesn't exist, extracting presumably failed if (!directory_exists(tempdir)) { show_message('Error loading server-sent plugins - extracting zip failed for:#"' + pluginname + '"'); failed = true; break; } } if (!failed) { // Execute plugins for (i = 0; i < ds_list_size(list); i += 1) { pluginname = ds_list_find_value(list, i); tempdir = temp_directory + "\" + pluginname + ".tmp"; // Debugging facility, so we know *which* plugin caused compile/execute error fp = file_text_open_write(working_directory + "\last_plugin.log"); file_text_write_string(fp, pluginname); file_text_close(fp); // packetID is (i), so make queues for it ds_map_add(global.pluginPacketBuffers, i, ds_queue_create()); ds_map_add(global.pluginPacketPlayers, i, ds_queue_create()); // Execute plugin execute_file( // the plugin's main gml file must be in the root of the zip // it is called plugin.gml tempdir + "\plugin.gml", // the plugin needs to know where it is // so the temporary directory is passed as first argument tempdir, // the plugin needs to know its packetID // so it is passed as the second argument i ); } } // Delete last plugin log file_delete(working_directory + "\last_plugin.log"); // Get rid of plugin list ds_list_destroy(list); // Get rid of plugin hash list ds_list_destroy(hashList); return !failed;