//--------------------------------------------------------------------------------------- // void FSkookumScriptRuntime::tick_remote() { if (!IsRunningCommandlet()) { // Request recompilation of binaries if script files changed if (m_freshen_binaries_requested) { m_remote_client.cmd_compiled_state(true); m_freshen_binaries_requested = false; } // Remote communication to and from SkookumScript IDE. // Needs to be called whether in editor or game and whether paused or not // $Revisit - CReis This is probably a hack. The remote client update should probably // live somewhere other than a tick method such as its own thread. m_remote_client.process_incoming(); // Re-load compiled binaries? if (m_remote_client.is_load_compiled_binaries_requested()) { // Load the Skookum class hierarchy scripts in compiled binary form #if WITH_EDITOR bool is_first_time = !is_skookum_initialized(); #endif bool success_b = m_runtime.load_compiled_scripts(); SK_ASSERTX(success_b, AErrMsg("Unable to load SkookumScript compiled binaries!", AErrLevel_notify)); m_remote_client.clear_load_compiled_binaries_requested(); #if WITH_EDITOR if (is_first_time && is_skookum_initialized()) { // When we load the binaries for the very first time, try regenerating all generated class script files again, // as the editor might have tried to generate them before but skipped because SkookumScript was not initialized yet m_runtime.get_editor_interface()->generate_all_class_script_files(); // Also recompile Blueprints in error state as such error state might have been due to SkookumScript not being initialized at the time of compile m_runtime.get_editor_interface()->recompile_blueprints_with_errors(); // Set world pointer now SkUEClassBindingHelper::set_world(m_game_world_p); } #endif } } }
//--------------------------------------------------------------------------------------- // This code will execute after your module is loaded into memory (but after global // variables are initialized, of course.) void FSkookumScriptRuntime::StartupModule() { A_DPRINT(A_SOURCE_STR " Starting up SkookumScript plug-in modules\n"); // Note that FWorldDelegates::OnPostWorldCreation has world_p->WorldType set to None // Note that FWorldDelegates::OnPreWorldFinishDestroy has world_p->GetName() set to "None" m_on_world_init_pre_handle = FWorldDelegates::OnPreWorldInitialization.AddRaw(this, &FSkookumScriptRuntime::on_world_init_pre); m_on_world_init_post_handle = FWorldDelegates::OnPostWorldInitialization.AddRaw(this, &FSkookumScriptRuntime::on_world_init_post); m_on_world_cleanup_handle = FWorldDelegates::OnWorldCleanup.AddRaw(this, &FSkookumScriptRuntime::on_world_cleanup); // Hook up Unreal memory allocator AMemory::override_functions(&Agog::malloc_func, &Agog::free_func, &Agog::req_byte_size_func); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Start up SkookumScript #if !WITH_EDITOR // If no editor, initialize right away // otherwise wait until map is loaded m_runtime.startup(); #ifndef SKOOKUM_REMOTE_UNREAL bool success_b = m_runtime.load_compiled_scripts(); SK_ASSERTX(success_b, AErrMsg("Unable to load SkookumScript compiled binaries!", AErrLevel_notify)); #endif #endif //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Send off connect request to IDE // Come back later to check on it #ifdef SKOOKUM_REMOTE_UNREAL if (!IsRunningCommandlet()) { m_remote_client.set_mode(SkLocale_runtime); } #endif }
//--------------------------------------------------------------------------------------- // void FSkookumScriptRuntime::on_editor_map_opened() { // When editor is present, initialize Sk here if (!m_runtime.is_initialized()) { m_runtime.startup(); #ifdef SKOOKUM_REMOTE_UNREAL // At this point, have zero patience with the IDE and launch it if not connected if (!IsRunningCommandlet()) { // At this point, wait if necessary to make sure we are connected m_remote_client.ensure_connected(0.0); // Kick off re-compilation of the binaries m_remote_client.cmd_compiled_state(true); m_freshen_binaries_requested = false; // Request satisfied } #else // If no remote connection, load binaries at this point bool success_b = m_runtime.load_compiled_scripts(); SK_ASSERTX(success_b, AErrMsg("Unable to load SkookumScript compiled binaries!", AErrLevel_notify)); #endif } }
//--------------------------------------------------------------------------------------- // Modifiers: static // Author(s): Conan Reis ASymbolRef * ASymbolTable::symbol_reference(uint32_t sym_id, const char * cstr_p, uint32_t length, eATerm term) { if (sym_id == ASymbol_id_null) { #if defined(A_SYMBOL_REF_LINK) return ASymbol::ms_null.m_ref_p; #else return const_cast<ASymbolRef *>(&ASymbolRef::get_null()); #endif } // Ensure symbol string no larger than 255 characters since only 1-byte is used to store // length in binary. A_ASSERTX( length <= UINT8_MAX, AErrMsg( a_str_format( "Tried to create symbol '%s' (0x%X) but it too long!\n" "Its length is %u and the max length is 255 characters.\n" "[Try to use a different shorter string if possible.]", cstr_p, sym_id, length), AErrLevel_notify)); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Use existing symbol reference if it is already registered. uint32_t idx; ASymbolRef * sym_ref_p = m_sym_refs.get(sym_id, 1u, &idx); if (sym_ref_p) { // Found existing symbol reference // Check for name collision A_ASSERTX( sym_ref_p->m_str_ref_p->is_equal(cstr_p, length), AErrMsg( a_str_format( "Symbol id collision! The new string '%s' and the string '%s' are different,\n" "but they both have the same id 0x%X.\n" "[Try to use a different string if possible and hope that it has a unique id.]", cstr_p, sym_ref_p->m_str_ref_p->m_cstr_p, sym_id), AErrLevel_notify)); return sym_ref_p; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Create new symbol reference AStringRef * str_ref_p = (term == ATerm_long) ? AStringRef::pool_new(cstr_p, length, length + 1u, 1u, false, true) : AStringRef::pool_new_copy(cstr_p, length); sym_ref_p = ASymbolRef::pool_new(str_ref_p, sym_id); m_sym_refs.insert(*sym_ref_p, idx); return sym_ref_p; }
//--------------------------------------------------------------------------------------- // void FSkookumScriptRuntime::tick_remote() { if (!IsRunningCommandlet()) { // Request recompilation of binaries if script files changed if (m_freshen_binaries_requested) { m_remote_client.cmd_compiled_state(true); m_freshen_binaries_requested = false; } // Remote communication to and from SkookumScript IDE. // Needs to be called whether in editor or game and whether paused or not // $Revisit - CReis This is probably a hack. The remote client update should probably // live somewhere other than a tick method such as its own thread. m_remote_client.process_incoming(); // Re-load compiled binaries? // If the game is currently running, delay until it's not if (m_remote_client.is_load_compiled_binaries_requested() && SkookumScript::get_initialization_level() < SkookumScript::InitializationLevel_gameplay) { // Makes sure the SkookumScript runtime object is initialized at this point ensure_runtime_initialized(); // Load the Skookum class hierarchy scripts in compiled binary form bool is_first_time = !is_skookum_initialized(); bool success_b = m_runtime.load_and_bind_compiled_scripts(); SK_ASSERTX(success_b, AErrMsg("Unable to load SkookumScript compiled binaries!", AErrLevel_notify)); m_remote_client.clear_load_compiled_binaries_requested(); // After reloading, re-resolve the raw data of all dynamic classes #if WITH_EDITORONLY_DATA TArray<UObject*> blueprint_array; GetObjectsOfClass(UBlueprint::StaticClass(), blueprint_array, true, RF_ClassDefaultObject); for (UObject * obj_p : blueprint_array) { UBlueprint * blueprint_p = static_cast<UBlueprint *>(obj_p); if (blueprint_p->GeneratedClass) { SkClass * sk_class_p = SkUEClassBindingHelper::get_sk_class_from_ue_class(blueprint_p->GeneratedClass); if (sk_class_p) { SkUEClassBindingHelper::resolve_raw_data(sk_class_p, blueprint_p->GeneratedClass); } } } #endif if (is_first_time && is_skookum_initialized()) { #if WITH_EDITOR // Recompile Blueprints in error state as such error state might have been due to SkookumScript not being initialized at the time of compile if (m_runtime.get_editor_interface()) { m_runtime.get_editor_interface()->recompile_blueprints_with_errors(); } #endif } } } }
void FSkookumScriptRuntime::compile_and_load_binaries() { #ifdef SKOOKUM_REMOTE_UNREAL // At this point, have zero patience with the IDE and launch it if not connected if (!IsRunningCommandlet()) { // At this point, wait if necessary to make sure we are connected m_remote_client.ensure_connected(0.0); // Alert user in case we are still not connected - and allow for corrective measures bool load_binaries = true; #if WITH_EDITOR while (!m_remote_client.is_authenticated()) { FText title = FText::FromString(TEXT("SkookumScript UE4 Plugin cannot connect to the SkookumIDE!")); EAppReturnType::Type decision = FMessageDialog::Open( EAppMsgType::CancelRetryContinue, FText::Format(FText::FromString(TEXT( "The SkookumScript UE4 Plugin cannot connect to the SkookumIDE. A connection to the SkookumIDE is required to properly work with SkookumScript.\n\n" "The connection problem could be caused by any of the following situations:\n" "- The SkookumIDE application is not running. If this is the case, your security software (Virus checker, VPN, Firewall) may have blocked or even removed it. If so, allow SkookumIDE.exe to run, then click 'Retry'. " "You can also try to launch the IDE manually. It should be located at the following path: {0}. Once running, click 'Retry'.\n" "- The SkookumIDE application is running, but stuck on an error. If so, try to resolve the error, and when the SkookumIDE is back up, click 'Retry'.\n" "- The SkookumIDE application is running and seems to be working fine. " "If so, the IP and port that the SkookumScript UE4 Plugin is trying to connect to ({1}) might be different from the IP and port that the SkookumIDE is listening to (see SkookumIDE log window), or blocked by a firewall. " "These problems could be due to your networking environment, such as a custom firewall, virtualization software such as VirtualBox, or multiple network adapters.\n\n" "For additional information including how to specify the SkookumIDE address for the runtime, please see http://skookumscript.com/docs/v3.0/ide/ip-addresses/ and ensure 'Settings'->'Remote runtimes' on the SkookumIDE is set properly.\n\n" "If you are having difficulties resolving this issue, please don't hesitate to ask us for help at the SkookumScript Forum (http://forum.skookumscript.com). We are here to make your experience skookum!\n")), FText::FromString(FPaths::ConvertRelativePathToFull(IPluginManager::Get().FindPlugin(TEXT("SkookumScript"))->GetBaseDir() / TEXT("SkookumIDE") / TEXT("SkookumIDE.exe"))), FText::FromString(m_remote_client.get_ip_address_ide()->ToString(true))), &title); if (decision != EAppReturnType::Retry) { load_binaries = (decision == EAppReturnType::Continue); break; } m_remote_client.ensure_connected(10.0); } #endif if (load_binaries && m_remote_client.is_authenticated()) { #if WITH_EDITOR RetryCompilation: #endif // Block while binaries are being recompiled m_remote_client.cmd_compiled_state(true); m_freshen_binaries_requested = false; // Request satisfied while (!m_remote_client.is_load_compiled_binaries_requested() && !m_remote_client.is_compiled_binaries_have_errors()) { m_remote_client.wait_for_update(); } #if WITH_EDITOR if (m_remote_client.is_compiled_binaries_have_errors()) { FText title = FText::FromString(TEXT("Compilation errors!")); EAppReturnType::Type decision = FMessageDialog::Open( EAppMsgType::CancelRetryContinue, FText::FromString(TEXT( "The SkookumScript compiled binaries could not be generated because errors were found in the script files.\n\n")), &title); if (decision == EAppReturnType::Retry) { m_remote_client.clear_load_compiled_binaries_requested(); goto RetryCompilation; } load_binaries = (decision == EAppReturnType::Continue); } #endif m_remote_client.clear_load_compiled_binaries_requested(); } if (load_binaries) { // Attempt to load binaries at this point bool success_b = m_runtime.load_compiled_scripts(); if (success_b) { // Inform the IDE about the version we got m_remote_client.cmd_incremental_update_reply(true, SkBrain::ms_session_guid, SkBrain::ms_revision); } else { // Something went wrong - let the user know FText title = FText::FromString(TEXT("Unable to load SkookumScript compiled binaries!")); FMessageDialog::Open( EAppMsgType::Ok, FText::FromString(TEXT( "Unable to load the compiled binaries. This is most likely caused by errors in the script files which prevented a successful compilation. The project will continue to load with SkookumScript temporarily disabled.")), &title); } } } else #endif { // If no remote connection, or commandlet mode, load binaries at this point bool success_b = m_runtime.load_compiled_scripts(); SK_ASSERTX(success_b, AErrMsg("Unable to load SkookumScript compiled binaries!", AErrLevel_notify)); } }