//--------------------------------------------------------------------------------------- void USkookumScriptComponent::create_sk_instance() { SK_ASSERTX(!m_instance_p, "Tried to create instance when instance already present!"); // Find the actor I belong to AActor * actor_p = GetOwner(); SK_ASSERTX(actor_p, "USkookumScriptComponent must be attached to an actor."); // Determine SkookumScript class of my actor SkClass * class_p = nullptr; FString class_name = ScriptClassName; if (!class_name.IsEmpty()) { AString class_name_ascii(*class_name, class_name.Len()); class_p = SkBrain::get_class(class_name_ascii.as_cstr()); SK_ASSERTX(class_p, a_cstr_format("Cannot find Script Class Name '%s' specified in SkookumScriptComponent of '%S'. Misspelled?", class_name_ascii.as_cstr(), *actor_p->GetName())); if (!class_p) goto set_default_class; // Recover from bad user input // Do some extra checking in non-shipping builds #if (SKOOKUM & SK_DEBUG) // Find most derived SkookumScript class known to UE4 SkClass * known_super_class_p; for (known_super_class_p = class_p; known_super_class_p; known_super_class_p = known_super_class_p->get_superclass()) { if (SkUEClassBindingHelper::get_ue_class_from_sk_class(known_super_class_p)) break; } // Find most derived UE4 class known to SkookumScript SkClass * mapped_class_p = nullptr; for (UClass * obj_uclass_p = actor_p->GetClass(); !mapped_class_p && obj_uclass_p; obj_uclass_p = obj_uclass_p->GetSuperClass()) { mapped_class_p = SkUEClassBindingHelper::get_sk_class_from_ue_class(obj_uclass_p); } SK_ASSERTX(mapped_class_p && mapped_class_p == known_super_class_p, a_cstr_format("Script Class Name '%s' in SkookumScriptComponent of '%S' is not properly related to Actor. Both the Script Class Name '%s' and the UE4 class of '%S' ('%S') must share the topmost ancestor class known to both SkookumScript and UE4. Right now these ancestor classes are different ('%s' for '%s' and '%s' for '%S').", class_name_ascii.as_cstr(), *actor_p->GetName(), class_name_ascii.as_cstr(), *actor_p->GetName(), *actor_p->GetClass()->GetName(), known_super_class_p ? known_super_class_p->get_name_cstr_dbg() : "<none>", class_name_ascii.as_cstr(), mapped_class_p ? mapped_class_p->get_name_cstr_dbg() : "<none>", *actor_p->GetClass()->GetName())); #endif } else { set_default_class: // Find most derived UE4 class known to SkookumScript class_p = nullptr; // Is already null when we get here, but set again for clarity for (UClass * obj_uclass_p = actor_p->GetClass(); !class_p && obj_uclass_p; obj_uclass_p = obj_uclass_p->GetSuperClass()) { class_p = SkUEClassBindingHelper::get_sk_class_from_ue_class(obj_uclass_p); } SK_ASSERTX(class_p, a_cstr_format("No parent class of %S is known to SkookumScript!", *actor_p->GetClass()->GetName())); if (!class_p) { class_p = SkBrain::get_class(ASymbol_Actor); // Recover from bad user input } } // Based on the desired class, create SkInstance or SkDataInstance SkInstance * instance_p = class_p->new_instance(); instance_p->construct<SkUEActor>(actor_p); // Keep track of owner actor m_instance_p = instance_p; }
static void assert_actor_has_overlap_events_enabled(AActor * actor_p) { // Check that events will properly fire TArray<UActorComponent *> components = actor_p->GetComponentsByClass(UPrimitiveComponent::StaticClass()); SK_ASSERTX(components.Num() > 0, a_cstr_format("Trying to receive overlap events on actor '%S' but it has no primitive (collision) component.", *actor_p->GetName())); bool found_enabled_overlap_event = false; for (UActorComponent * component_p : components) { if (Cast<UPrimitiveComponent>(component_p)->bGenerateOverlapEvents) { found_enabled_overlap_event = true; break; } } SK_ASSERTX(found_enabled_overlap_event, a_cstr_format("Trying to receive overlap events on actor '%S' but it has no primitive component that has overlap events turned on. To fix this, check the box 'Generate Overlap Events' for the primitive component (e.g. SkeletalMeshComponent, CapsuleComponent etc.) that you would like to trigger the overlap events. You might also simply have picked the wrong actor.", *actor_p->GetName())); }
//--------------------------------------------------------------------------------------- // Gets memory representing binary for group of classes with specified class as root. // Used as a mechanism to "demand load" scripts. // // #See Also: load_compiled_scripts(), SkCompiler::get_binary_class_group() // #Modifiers: virtual - overridden from SkookumRuntimeBase // #Author(s): Conan Reis SkBinaryHandle * SkUERuntime::get_binary_class_group(const SkClass & cls) { FString compiled_file = get_compiled_path(); // $Revisit - CReis Should use fast custom uint32_t to hex string function. compiled_file += a_cstr_format("/Class[%x].sk-bin", cls.get_name_id()); return SkBinaryHandleUE::create(*compiled_file); }
//--------------------------------------------------------------------------------------- // Get Unreal Engine class of this class static void mthdc_static_class(SkInvokedMethod * scope_p, SkInstance ** result_pp) { if (result_pp) // Do nothing if result not desired { // Determine class SkClass * sk_class_p = ((SkMetaClass *)scope_p->get_topmost_scope())->get_class_info(); UClass * ue_class_p = SkUEClassBindingHelper::get_ue_class_from_sk_class(sk_class_p); SK_ASSERTX(ue_class_p, a_cstr_format("The UE4 equivalent of class type '%s' is not known to SkookumScript. Maybe it is the class of a Blueprint that is not loaded yet?", sk_class_p->get_name_cstr_dbg())); *result_pp = ue_class_p ? SkUEEntityClass::new_instance(ue_class_p) : SkBrain::ms_nil_p; } }
//--------------------------------------------------------------------------------------- // Determines if the symbol order and symbol ids are valid. // Notes: This is a test function that should hopefully never need to be called. // It was written to discover a potential memory stomp bug. // Author(s): Conan Reis void ASymbolTable::validate() const { uint32_t length = m_sym_refs.get_length(); if (length) { ASymbolRef ** syms_pp = m_sym_refs.get_array(); // for faster than class member access ASymbolRef ** syms_end_pp = syms_pp + length; uint32_t id; uint32_t sym_id; ASymbolRef * sym_p; ASymbolRef * prev_sym_p = nullptr; for (; syms_pp < syms_end_pp; syms_pp++) { sym_p = *syms_pp; id = ASYMBOL_CSTR_TO_ID(sym_p->m_str_ref_p->m_cstr_p, sym_p->m_str_ref_p->m_length); sym_id = sym_p->m_uid; A_VERIFYX( id == sym_id, a_cstr_format( "Stored symbol '%s'#%u should have id #%u!", sym_p->m_str_ref_p->m_cstr_p, sym_id, id)); if (prev_sym_p) { A_VERIFYX( (prev_sym_p->m_uid < sym_id), a_cstr_format( "Symbol ids '%s'#%u and '%s'#%u are not in proper sequence!", prev_sym_p->m_str_ref_p->m_cstr_p, prev_sym_p->m_uid, sym_p->m_str_ref_p->m_cstr_p, sym_id)); } prev_sym_p = sym_p; } } }
//--------------------------------------------------------------------------------------- // !new constructor - creates new object void mthd_ctor_new(SkInvokedMethod * scope_p, SkInstance ** result_pp) { UObject * outer_p = scope_p->get_arg<SkUEEntity>(SkArg_1); FName name = scope_p->get_arg<SkUEName>(SkArg_2); uint32_t flags = scope_p->get_arg<SkInteger>(SkArg_3); // The scope of a constructor is always some form of an SkInstance SkInstance * receiver_p = static_cast<SkInstance *>(scope_p->m_scope_p.get_obj()); UClass * ue_class_p = SkUEClassBindingHelper::get_ue_class_from_sk_class(receiver_p->get_class()); SK_ASSERTX(ue_class_p, a_cstr_format("The UE4 equivalent of class type '%s' is not known to SkookumScript. Maybe it is the class of a Blueprint that is not loaded yet?", receiver_p->get_class()->get_name_cstr_dbg())); scope_p->get_this()->construct<SkUEEntity>(NewObject<UObject>(outer_p, ue_class_p, name, EObjectFlags(flags))); }
//--------------------------------------------------------------------------------------- // Entity@default() ThisClass_ static void mthdc_default(SkInvokedMethod * scope_p, SkInstance ** result_pp) { if (result_pp) // Do nothing if result not desired { // Determine class of object to get SkClass * sk_class_p = ((SkMetaClass *)scope_p->get_topmost_scope())->get_class_info(); UClass * ue_class_p = SkUEClassBindingHelper::get_ue_class_from_sk_class(sk_class_p); SK_ASSERTX(ue_class_p, a_cstr_format("Cannot get default instance of class '%s' as the UE4 equivalent of this class is not known to SkookumScript. Maybe it is the class of a Blueprint that is not loaded yet?", sk_class_p->get_name_cstr_dbg())); // Get default object UObject * obj_p = nullptr; if (ue_class_p) { obj_p = GetMutableDefault<UObject>(ue_class_p); } *result_pp = obj_p ? SkUEEntity::new_instance(obj_p, ue_class_p, sk_class_p) : SkBrain::ms_nil_p; } }
//--------------------------------------------------------------------------------------- // Entity@load(String name) ThisClass_ static void mthdc_load(SkInvokedMethod * scope_p, SkInstance ** result_pp) { if (result_pp) // Do nothing if result not desired { // Determine class of object to load SkClass * class_p = &((SkMetaClass *)scope_p->get_topmost_scope())->get_class_info(); UClass * uclass_p = SkUEClassBindingHelper::get_ue_class_from_sk_class(class_p); SK_ASSERTX(uclass_p, a_cstr_format("Cannot load entity '%s' as the UE4 equivalent of class type '%s' is not known to SkookumScript.", scope_p->get_arg<SkString>(SkArg_1).as_cstr(), class_p->get_name_cstr_dbg())); // Load object UObject * obj_p = nullptr; if (uclass_p) { obj_p = StaticLoadObject(uclass_p, SkUEClassBindingHelper::get_world(), *AStringToFString(scope_p->get_arg<SkString>(SkArg_1))); } *result_pp = obj_p ? SkUEEntity::new_instance(obj_p, uclass_p, class_p) : SkBrain::ms_nil_p; } }
//--------------------------------------------------------------------------------------- // Entity@load(String name) ThisClass_ static void mthdc_load(SkInvokedMethod * scope_p, SkInstance ** result_pp) { // Load it regardless if a result is desired // Determine class of object to load SkClass * sk_class_p = ((SkMetaClass *)scope_p->get_topmost_scope())->get_class_info(); UClass * ue_class_p = SkUEClassBindingHelper::get_ue_class_from_sk_class(sk_class_p); SK_ASSERTX(ue_class_p, a_cstr_format("Cannot load entity '%s' as the UE4 equivalent of class type '%s' is not known to SkookumScript. Maybe it is the class of a Blueprint that is not loaded yet?", scope_p->get_arg<SkString>(SkArg_1).as_cstr(), sk_class_p->get_name_cstr_dbg())); // Load object UObject * obj_p = nullptr; if (ue_class_p) { obj_p = StaticLoadObject(ue_class_p, SkUEClassBindingHelper::get_world(), *AStringToFString(scope_p->get_arg<SkString>(SkArg_1))); } // Set result if desired if (result_pp) { *result_pp = obj_p ? SkUEEntity::new_instance(obj_p, ue_class_p, sk_class_p) : SkBrain::ms_nil_p; } }
UProperty * SkUEBlueprintInterface::build_ue_param(UFunction * ue_function_p, SkClassDescBase * sk_parameter_class_p, const FName & param_name, ParamInfo * out_param_info_p) { // Based on Sk type, figure out the matching UProperty as well as fetcher and setter methods UProperty * property_p = nullptr; tK2ParamFetcher k2_param_fetcher_p = nullptr; tSkValueGetter sk_value_getter_p = nullptr; if (sk_parameter_class_p == SkBoolean::ms_class_p) { property_p = NewObject<UBoolProperty>(ue_function_p, param_name, RF_Public); k2_param_fetcher_p = &fetch_k2_param_boolean; sk_value_getter_p = &get_sk_value_boolean; } else if (sk_parameter_class_p == SkInteger::ms_class_p) { property_p = NewObject<UIntProperty>(ue_function_p, param_name, RF_Public); k2_param_fetcher_p = &fetch_k2_param_integer; sk_value_getter_p = &get_sk_value_integer; } else if (sk_parameter_class_p == SkReal::ms_class_p) { property_p = NewObject<UFloatProperty>(ue_function_p, param_name, RF_Public); k2_param_fetcher_p = &fetch_k2_param_real; sk_value_getter_p = &get_sk_value_real; } else if (sk_parameter_class_p == SkString::ms_class_p) { property_p = NewObject<UStrProperty>(ue_function_p, param_name, RF_Public); k2_param_fetcher_p = &fetch_k2_param_string; sk_value_getter_p = &get_sk_value_string; } else if (sk_parameter_class_p == SkVector3::ms_class_p) { UStructProperty * struct_property_p = NewObject<UStructProperty>(ue_function_p, param_name); struct_property_p->Struct = m_struct_vector3_p; property_p = struct_property_p; k2_param_fetcher_p = &fetch_k2_param_vector3; sk_value_getter_p = &get_sk_value_vector3; } else if (sk_parameter_class_p == SkRotationAngles::ms_class_p) { UStructProperty * struct_property_p = NewObject<UStructProperty>(ue_function_p, param_name); struct_property_p->Struct = m_struct_rotation_angles_p; property_p = struct_property_p; k2_param_fetcher_p = &fetch_k2_param_rotation_angles; sk_value_getter_p = &get_sk_value_rotation_angles; } else if (sk_parameter_class_p == SkTransform::ms_class_p) { UStructProperty * struct_property_p = NewObject<UStructProperty>(ue_function_p, param_name); struct_property_p->Struct = m_struct_transform_p; property_p = struct_property_p; k2_param_fetcher_p = &fetch_k2_param_transform; sk_value_getter_p = &get_sk_value_transform; } else if (sk_parameter_class_p->get_key_class()->is_class(*SkUEEntity::ms_class_p)) { UClass * uclass_p = SkUEClassBindingHelper::get_ue_class_from_sk_class(sk_parameter_class_p); SK_ASSERTX(uclass_p, a_cstr_format("Class '%s' of parameter '%s' of method '%S.%S' being exported to Blueprints is not a known engine class.", sk_parameter_class_p->get_key_class_name().as_cstr_dbg(), param_name.GetPlainANSIString(), *ue_function_p->GetOwnerClass()->GetName(), *ue_function_p->GetName())); if (uclass_p) { property_p = NewObject<UObjectProperty>(ue_function_p, param_name, RF_Public); static_cast<UObjectProperty *>(property_p)->PropertyClass = uclass_p; k2_param_fetcher_p = &fetch_k2_param_entity; sk_value_getter_p = &get_sk_value_entity; } } else { //SK_ASSERTX(false, a_cstr_format("Class '%s' of parameter '%s' of method '%S.%S' being exported to Blueprints can not be mapped to a Blueprint-compatible type.", sk_parameter_class_p->get_key_class_name().as_cstr_dbg(), param_name.GetPlainANSIString(), *ue_function_p->GetOwnerClass()->GetName(), *ue_function_p->GetName())); } // Add flags if (property_p) { property_p->PropertyFlags |= CPF_Parm; ue_function_p->LinkChild(property_p); } // Set result if (out_param_info_p) { out_param_info_p->m_ue_param_p = property_p; out_param_info_p->m_k2_param_fetcher_p = k2_param_fetcher_p; out_param_info_p->m_sk_value_getter_p = sk_value_getter_p; } return property_p; }