bool HandleRconCommands(AMX *amx, cell *params, cell *retval) { char buf[64]; cell* addr; amx_GetAddr(amx, params[1], &addr); amx_GetString(buf, addr, 0, 64); if (!strcmp(buf, "sampsharpstop")) { if (!GameMode::IsLoaded()) { logprintf("A gamemode must be loaded in order to stop."); return false; } logprintf("Stopping SampSharp..."); run_signal = -1; signal_amx = amx; return false; } if (!strcmp(buf, "sampsharpstart")) { if (!initial_load) { logprintf("OnGameModeInit needs to be called first."); return false; } if (GameMode::IsLoaded()) { logprintf("You need to stop the gamemode before you can start it."); return false; } logprintf("Starting SampSharp..."); run_signal = 1; signal_amx = amx; return false; } }
PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) { if (!sampgdk::Load(ppData)) return false; pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS]; logprintf(""); logprintf("SampSharp Plugin"); logprintf("----------------"); logprintf("v%s, (C)2014-2015 Tim Potze", PLUGIN_VERSION); logprintf(""); Config::Read(); return true; }
void unloadGamemode() { if (!GameMode::IsLoaded()) return; string namespase = Config::GetGameModeNameSpace(); string klass = Config::GetGameModeClass(); logprintf(""); logprintf("---------------"); logprintf("Unloading gamemode: %s:%s", namespase.c_str(), klass.c_str()); GameMode::Unload(); logprintf(" Unloaded."); logprintf(""); }
void convertSymbols() { string symbols = Config::GetSymbolFiles(); if (symbols.length() > 0) { logprintf("Symbol file generation"); logprintf("----------------------"); stringstream symbols_stream(symbols); string file; int successes = 0; while (std::getline(symbols_stream, file, ' ')) { logprintf("Converting: %s", file.c_str()); std::ifstream ifile(file.c_str()); if (file.empty() || !ifile) { logprintf(" Failed."); continue; } mono_convert_symbols(file.c_str()); successes++; logprintf(" Converted."); } logprintf(" Converted %d files.", successes); logprintf(""); } }
void loadGamemode() { if (GameMode::IsLoaded()) return; // Load empty filterscript. if (!filterscript_loaded) { SendRconCommand("loadfs empty"); filterscript_loaded = true; } // Load mono. if (!MonoRuntime::IsLoaded()) { MonoRuntime::Load(Config::GetMonoAssemblyDir(), Config::GetMonoConfigDir(), Config::GetTraceLevel(), PathUtil::GetPathInBin("gamemode/") .append(Config::GetGameModeNameSpace()).append(".dll")); } // Load game mode. string namespaceName = Config::GetGameModeNameSpace(); string className = Config::GetGameModeClass(); logprintf("Gamemode"); logprintf("---------------"); logprintf("Loading gamemode: %s:%s", namespaceName.c_str(), className.c_str()); if (GameMode::Load(Config::GetGameModeNameSpace(), Config::GetGameModeClass())) logprintf(" Loaded."); else logprintf(" Failed."); logprintf(""); }
void ProcessSignals() { // Process run signals. if (run_signal == -1) { cell noParams[1]; noParams[0] = 0; cell unhandledRetval; GameMode::ProcessPublicCall(signal_amx, "OnGameModeExit", noParams, &unhandledRetval); unloadGamemode(); logprintf(""); logprintf("================================="); logprintf("> SampSharp gamemode has stopped!"); logprintf("> Replace your gamemode files and run `sampsharp start`"); logprintf("================================="); logprintf(""); run_signal = 0; } else if (run_signal == 1) { loadGamemode(); cell noParams[1]; noParams[0] = 0; cell unhandledRetval; GameMode::ProcessPublicCall(signal_amx, "OnGameModeInit", noParams, &unhandledRetval); run_signal = 0; } }
void loadGamemode() { if (GameMode::IsLoaded()) return; /* Load empty filterscript */ if (!filterscript_loaded) { SendRconCommand("loadfs empty"); filterscript_loaded = true; } /* Load mono */ if (!MonoRuntime::IsLoaded()) { MonoRuntime::Load(Config::GetMonoAssemblyDir(), Config::GetMonoConfigDir(), Config::GetTraceLevel(), PathUtil::GetPathInBin("gamemode/") .append(Config::GetGameModeNameSpace()).append(".dll")); } /* Set initial codepage to the configured one. */ int codepage = Config::GetCodepage(); set_codepage(codepage); convertSymbols(); /* Load game mode */ string namespaceName = Config::GetGameModeNameSpace(); string className = Config::GetGameModeClass(); logprintf("Gamemode"); logprintf("---------------"); logprintf("Loading gamemode: %s:%s", namespaceName.c_str(), className.c_str()); if (GameMode::Load(Config::GetGameModeNameSpace(), Config::GetGameModeClass())) logprintf(" Loaded."); else logprintf(" Failed."); logprintf(""); }
void samphp_error_handler(char *str) { logprintf(str); }
int samphp_output_handler(const char *str, unsigned int str_length) { logprintf(str); return str_length; }
PLUGIN_EXPORT bool PLUGIN_CALL OnPublicCall(AMX *amx, const char *name, cell *params, cell *retval) { if (!GameMode::IsLoaded() && !strcmp(name, "OnGameModeInit")) { /* Load empty filterscript */ if (!filterscript_loaded) { SendRconCommand("loadfs empty"); filterscript_loaded = true; } /* Load mono */ if (!MonoRuntime::IsLoaded()) { MonoRuntime::Load(Config::GetMonoAssemblyDir(), Config::GetMonoConfigDir(), Config::GetTraceLevel(), PathUtil::GetPathInBin("gamemode/") .append(Config::GetGameModeNameSpace()).append(".dll")); } /* Set initial codepage to the configured one. */ int codepage = Config::GetCodepage(); set_codepage(codepage); convertSymbols(); /* Load game mode */ string namespaceName = Config::GetGameModeNameSpace(); string className = Config::GetGameModeClass(); logprintf("Gamemode"); logprintf("---------------"); logprintf("Loading gamemode: %s:%s", namespaceName.c_str(), className.c_str()); if(GameMode::Load(Config::GetGameModeNameSpace(), Config::GetGameModeClass())) logprintf(" Loaded."); else logprintf(" Failed."); logprintf(""); } else if (GameMode::IsLoaded() && !strcmp(name, "OnGameModeExit")) { GameMode::ProcessPublicCall(amx, name, params, retval); string namespaceName = Config::GetGameModeNameSpace(); string className = Config::GetGameModeClass(); logprintf(""); logprintf("---------------"); logprintf("Unloading gamemode: %s:%s", namespaceName.c_str(), className.c_str()); GameMode::Unload(); logprintf(" Unloaded."); logprintf(""); } if (GameMode::IsLoaded()) { GameMode::ProcessPublicCall(amx, name, params, retval); } return true; }
void GameMode::ProcessPublicCall(AMX *amx, const char *name, cell *params, cell *retval) { CallbackSignature *signature; if (!isLoaded_) { return; } int param_count = params[0] / sizeof(cell); if (strlen(name) == 0 || param_count > MAX_CALLBACK_PARAM_COUNT) { logprintf("[SampSharp] WARNING: Skipped callback with %d parameters.", param_count); return; } /* OnRconCommand can sometimes end up on different theads? * Just to make sure, attach the current thread to the domain. */ mono_thread_attach(domain_); /* If the callback not known in the callbacks_ map, find the callback in * the game mode or one of the registered extensions. */ if (callbacks_.find(name) == callbacks_.end()) { signature = new CallbackSignature; signature->method = FindMethodForCallback(name, param_count, signature->handle); if (!signature->method) { callbacks_[name] = NULL; return; } MonoImage *image = mono_class_get_image( mono_method_get_class(signature->method)); void *iter = NULL; int iter_idx = 0; MonoMethodSignature *sig = mono_method_get_signature(signature->method, image, mono_method_get_token(signature->method)); MonoType* type = NULL; while (type = mono_signature_get_params(sig, &iter)) { ParameterSignature parameter_signature; parameter_signature.type = GetParameterType(type); if (parameter_signature.type == PARAM_INT_ARRAY || parameter_signature.type == PARAM_FLOAT_ARRAY || parameter_signature.type == PARAM_BOOL_ARRAY) { parameter_signature.length_idx = GetParamLengthIndex( signature->method, iter_idx); if (parameter_signature.length_idx == -1) { callbacks_[name] = NULL; return; } } signature->params[iter_idx++] = parameter_signature; } callbacks_[name] = signature; } if (signature = callbacks_[name]) { /* Handle calls without parameters. */ if (!param_count) { int retint = CallEvent(signature->method, signature->handle, NULL, NULL); /* If there's a cell allocated for the return value and * the callback was executed successfuly, fill the cell with * the returned value. */ if (retval != NULL && retint != -1) { *retval = retint; } return; } /* Handle calls with parameters. */ void *args[MAX_CALLBACK_PARAM_COUNT]; int len = 0; cell *addr = NULL; MonoArray *arr; if (signature->params.size() != param_count) { logprintf("[SampSharp] ERROR: Parameters of callback %s " "does not match signature (called: %d, signature: %d)", name, param_count, signature->params.size()); return; } for (int i = 0; i < param_count; i++) { switch (signature->params[i].type) { case PARAM_INT: case PARAM_FLOAT: case PARAM_BOOL: { args[i] = ¶ms[i + 1]; break; } case PARAM_STRING: { amx_GetAddr(amx, params[i + 1], &addr); amx_StrLen(addr, &len); if (len) { len++; char* text = new char[len]; amx_GetString(text, addr, 0, len); args[i] = string_to_monostring(text, len); } else { args[i] = mono_string_new(mono_domain_get(), ""); } break; } case PARAM_INT_ARRAY: { len = params[signature->params[i].length_idx]; arr = mono_array_new(mono_domain_get(), mono_get_int32_class(), len); if (len > 0) { cell* addr = NULL; amx_GetAddr(amx, params[i + 1], &addr); for (int i = 0; i < len; i++) { mono_array_set(arr, int, i, *(addr + i)); } } args[i] = arr; break; } case PARAM_FLOAT_ARRAY: { len = params[signature->params[i].length_idx]; arr = mono_array_new(mono_domain_get(), mono_get_int32_class(), len); if (len > 0) { cell* addr = NULL; amx_GetAddr(amx, params[i + 1], &addr); for (int i = 0; i < len; i++) { mono_array_set(arr, float, i, amx_ctof(*(addr + i))); } } args[i] = arr; break; } case PARAM_BOOL_ARRAY: { len = params[signature->params[i].length_idx]; arr = mono_array_new(mono_domain_get(), mono_get_int32_class(), len); if (len > 0) { cell* addr = NULL; amx_GetAddr(amx, params[i + 1], &addr); for (int i = 0; i < len; i++) { mono_array_set(arr, bool, i, !!*(addr + i)); } } args[i] = arr; break; } default: logprintf("[SampSharp] ERROR: Signature of %s contains " "unsupported parameters.", name); return; }
bool GameMode::Load(std::string namespaceName, std::string className) { if (isLoaded_) { return false; } assert(MonoRuntime::IsLoaded()); /* Build paths based on the specified namespace and class names. */ string dirPath = PathUtil::GetPathInBin("gamemode/"); string libraryPath = PathUtil::GetPathInBin("gamemode/") .append(namespaceName).append(".dll"); string configPath = PathUtil::GetPathInBin("gamemode/") .append(namespaceName).append(".dll.config"); /* Check for existance of game mode */ std::ifstream ifile(libraryPath.c_str()); if (!ifile) { logprintf("ERROR: library does not exist!"); return false; } mono_domain_set_config(mono_domain_get(), dirPath.c_str(), configPath.c_str()); domain_ = mono_domain_get(); gameMode_.image = mono_assembly_get_image( mono_assembly_open(libraryPath.c_str(), NULL)); if (!gameMode_.image) { logprintf("ERROR: Couldn't open image!"); return false; } gameMode_.klass = mono_class_from_name(gameMode_.image, namespaceName.c_str(), className.c_str()); if (!gameMode_.klass) { logprintf("ERROR: Couldn't find class %s:%s!", namespaceName.c_str(), className.c_str()); return false; } baseMode_.klass = mono_class_get_parent(gameMode_.klass); if (!baseMode_.klass || strcmp("BaseMode", mono_class_get_name(baseMode_.klass)) != 0) { logprintf("ERROR: Parent type of %s::%s is not BaseMode!", namespaceName.c_str(), className.c_str()); return false; } baseMode_.image = mono_class_get_image(baseMode_.klass); /* Add all internal calls. */ AddInternalCall("RegisterExtension", (void *)RegisterExtension); AddInternalCall("SetTimer", (void *)SetRefTimer); AddInternalCall("KillTimer", (void *)KillRefTimer); AddInternalCall("NativeExists", (void *)NativeExists); AddInternalCall("LoadNative", (void *)LoadNative); AddInternalCall("InvokeNative", (void *)InvokeNative); AddInternalCall("Print", (void *)Print); AddInternalCall("SetCodepage", (void *)set_codepage); MonoObject *gamemode_obj = mono_object_new (mono_domain_get(), gameMode_.klass); gameModeHandle_ = mono_gchandle_new(gamemode_obj, false); mono_runtime_object_init(gamemode_obj); MonoMethod *method = LoadEvent("Initialize", 0); if (method) { MonoObject *exception = NULL; CallEvent(method, gameModeHandle_, NULL, &exception); return isLoaded_ = !exception; } else { isLoaded_ = true; return true; } }
bool GameMode::Unload() { if (!isLoaded_) { return false; } /* Clear found methods. */ tickMethod_ = NULL; paramLengthClass_ = NULL; paramLengthGetMethod_ = NULL; onCallbackException_ = NULL; /* Clear timers. */ logprintf("Stopping timers..."); for (TimerMap::iterator iter = timers_.begin(); iter != timers_.end(); iter++) { int id = iter->first; RefTimer timer = (iter->second); mono_gchandle_free(timer.handle); KillTimer(id); } timers_.clear(); /* Clear extensions. */ logprintf("Unloading extensions..."); for (ExtensionList::iterator iter = extensions_.begin(); iter != extensions_.end(); iter++) { mono_gchandle_free(*iter); } extensions_.clear(); /* Clear callbacks. */ logprintf("Clearing callbacks table..."); for (CallbackMap::iterator iter = callbacks_.begin(); iter != callbacks_.end(); iter++) { iter->second->params.clear(); delete iter->second; } callbacks_.clear(); /* Dispose of game mode. */ mono_thread_attach(domain_); MonoMethod *method = LoadEvent("Dispose", 0); if (method) { logprintf("Disposing gamemode..."); CallEvent(method, gameModeHandle_, NULL, NULL); } /* Release game mode. */ mono_gchandle_free(gameModeHandle_); gameModeHandle_ = NULL; /* TODO: For now, I see no way of unloading and reloading images without problems. * Best to look at this again in the future. */ //mono_image_close(gameMode_.image); //mono_image_close(baseMode_.image); //mono_images_cleanup(); gameMode_.image = NULL; gameMode_.klass = NULL; baseMode_.image = NULL; baseMode_.klass = NULL; domain_ = NULL; isLoaded_ = false; return true; }