Verse: FindCreativeObjectsWithTag should be able to function within modules

I create this function and works fine, need test outside of device

FindObjectsWithTag<public>(Tag:tag)<transacts>:[]creative_object_interface=
        TaggedObjects:=FindCreativeObjectsWithTag(Tag)
        var Objects:[]creative_object_interface=array{}
        for (Obj:TaggedObjects, TaggedObject:=creative_device_base[Obj]):
            set Objects += array{TaggedObject}
        return Objects
1 Like

For custom class or module maybe

oe_custom_player := class<unique>():
    Player:player
    NPCDevice:npc_spawner_device

	var Debug:oe_logger = oe_logger{}

    FindObjectsWithTag<public>(Tag:tag)<transacts>:[]creative_object_interface=
        TaggedObjects:=NPCDevice.FindCreativeObjectsWithTag(Tag)
        var Objects:[]creative_object_interface=array{}
        for (Obj:TaggedObjects, TaggedObject:=creative_device_base[Obj]):
             set Objects += array{TaggedObject}
        return Objects
1 Like

But this is redundante hehehe, because if we pass a device in editable don’t need tags anymore

FindObjectsWithTag<public>(Tag:tag,CreativeDevice:(creative_device))<transacts>:[]creative_object_interface=
        TaggedObjects:=CreativeDevice.FindCreativeObjectsWithTag(Tag)
        var Objects:[]creative_object_interface=array{}
        for (Obj:TaggedObjects, TaggedObject:=creative_device_base[Obj]):
             set Objects += array{TaggedObject}
        return Objects

in device

CustomPlayerTagged:=CustomPlayer.FindObjectsWithTag(Tag:=npc_tag{},CreativeDevice:=Self)

this works fine, and we can pass a self creative base for custom class or module

custom_tag_module := module:
    FindObjectsWithTag<public>(Tag:tag,CreativeDevice:(creative_device))<transacts>:[]creative_object_interface=
        TaggedObjects:=CreativeDevice.FindCreativeObjectsWithTag(Tag)
        var Objects:[]creative_object_interface=array{}
        for (Obj:TaggedObjects, TaggedObject:=creative_device_base[Obj]):
             set Objects += array{TaggedObject}
        return Objects
CustomPlayerTagged:=custom_tag_module.FindObjectsWithTag(Tag:=npc_tag{},CreativeDevice:=Self)
            for (CustomPlayerTaggedIndex->Obj:CustomPlayerTagged, NPC:=npc_spawner_device[Obj]):
                Debug.Log("TESTAGS::CustomPlayerTagged as CustomPlayer.FindObjectsWithTag {CustomPlayerTaggedIndex}")
1 Like

(post deleted by author)

3 Likes

I completely agree with the frustration and how it feels like Epic just pulled the rug from under us all and didn’t bother to really help give a solution.

Would love to know if anyone here knows what the solution to this is. To just wait for Epic to fix this or recode everything to an unstable state… Been looking everywhere for the past week to see if there is any solutions to which everyone seems to have either given up or resorted to said unstable/short-term fixes.

2 Likes

The most logical way in my opinion to get an active device in the world to use in different modules would be to use weak_map with the key as the session that returns the device

1 Like

I found this article by Epic about the Verse Lang Update and it explains a lot.

It says that the Update to Verse V1 is completely optional.

I quote:

This upgrade is optional; your current version of the project will always continue to work at an older Verse version. That being said, there may be a point in the future where you will need to upgrade your project to a newer Verse version if you want to upload a newer iteration of it.

We can choose our Verse version in the settings. So they did not leave us hanging.

They mentioned:

Most of the deprecations clear the way for future language improvements, and don’t yet provide any benefit to users. Two exceptions are local qualifiers and struct comparison.

Warnings will appear any time you save code that is not backwards compatible and indicate your code behavior is deprecated in newer versions of the language. For example, continuing to use coding practices that aren’t compatible with the new Verse Language version result in warnings about your code.

If anyone could upload a test project to see if publishing with the warnings is possible, it would be highly appreciated.

I was worried about why they would release this without considering the mentioned effects but it makes sense now, considering that the update is just there to clear the way for the language with the warnings, so we don’t end up building things that don’t have a solid foundation.

This gives us a map to plan ahead.

Here’s the full piece: Verse Language Version 1 Updates and Deprecations | Unreal Editor for Fortnite Documentation | Epic Developer Community

1 Like

@Mephistia Thank you for your feedback. While I cannot guarantee a response, I can confirm that this has been forwarded to the appropriate team.

I did get this working using the weak map approach with the code that Mineblo showed in Post 33/Here is the code I used for the game manager. I don’t want to say how many hours I spent on this but this thread definitely helped A LOT.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

var MyVariable:weak_map(session,creative_device_base)= map{}

game_manager := class(creative_device):
        
        @editable
        MySettings : experience_settings_device = experience_settings_device{}
         
        OnBegin<override>()<suspends>:void=
                 if(set MyVariable[GetSession()]=MySettings):
                    Print("The device reference has been set.")
###################################################################
1 Like
new_npc_behavior_basic := class(npc_behavior):

    
    #Using tags to get our Creative Device and set a reference to it in the variable Found Device.
    GetGameDevice()<decides><transacts>:my_creative_device =
        var FoundDevice : ?my_creative_device = false
        
            if(ADevice:=MyVariable[GetSession()]):
                AllCreativeObjects:generator(creative_object_interface )=ADevice.FindCreativeObjectsWithTag(device_reference{})
                for (TaggedActor: AllCreativeObjects, MyDevice := my_creative_device[TaggedActor]):
                   set FoundDevice = option{MyDevice}
            FoundDevice? 

And here’s the other section of code. NPC is now following again!!!

1 Like

I found a possible way to further simple the addition of a device to a weakmap

by just referencing the verse device itself, so it would just work by itself so long as you drop one of the verse device in the project

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

var MyVariable:weak_map(session,creative_device)= map{} # Replaced "creative_device_base" with "creative_device"

game_manager := class(creative_device):
        
        OnBegin<override>()<suspends>:void=
                 if(set MyVariable[GetSession()]=Self): #Replaced "MySettings With Self"
                    Print("The device reference has been set.")
###################################################################
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

var MyVariable:weak_map(session,creative_device)= map{}

game_manager := class(creative_device):
        
      

        @editable
        MyDevice: creative_device = creative_device{}
         
        OnBegin<override>()<suspends>:void=
                 if(set MyVariable[GetSession()]=MyDevice):
                    Print("The device reference has been set.")
new_npc_behavior_basic := class(npc_behavior):

    
    #Using tags to get our Creative Device and set a reference to it in the variable Found Device.
    GetGameDevice()<decides><transacts>:my_creative_device =
        var FoundDevice : ?my_creative_device = false
        
            if(ADevice:=MyVariable[GetSession()]):
                AllCreativeObjects:generator(creative_object_interface )=ADevice.FindCreativeObjectsWithTag(device_reference{})
                for (TaggedActor: AllCreativeObjects, ThisDevice := my_creative_device[TaggedActor]):
                   set FoundDevice = option{ThisDevice}
            FoundDevice? 

It was working, then stopped working, and I’m not sure why it worked the first time through. Maybe it cleared the overloading error / issue or something and just allowed the Find method to work. I don’t know. It is working now that I am referencing the creative_device, and not the experience_settings_device, which is of creative_device_base. The problem I see is that the function, npc behavior class, cannot take a direct reference for some reason, so it has to be fed it in a roundabout way. So it does seem a bit redundant doing it this way, but at least it works. When it gets the reference by way of the global variable, then it can see the reference and communicate. The problem is that it doesn’t seem to be able to see the other actors. The good news is it is working and making some sense to me now. In this scenario, we create a weak_map and pair the session as the key and creative device as the value. Then when we reference the global variable in the tag search, the npc behavior function can SEE the reference and everything works as expected. I will post again on this as it is definitely a wip. I am not referencing the island settings at all any more, just the creative device.

People at Epic PLEASE revert this change! I had an NPC behavior code that relied on tags to get the navigation points scattered across the map, now the code is broken and I’m trying to find a workaround.
There must be a way of getting game objects globally in verse, either a function that returns these objects or a singleton class, anything. We just need a solution to make coding with verse easier and faster

For anyone struggling with this, here is my workaround, it’s working for now but it might stop working in the future, I don’t know.

Declare this in module scope:

var WorkaroundForTaggedObjects : weak_map(session, creative_device) = map{}

FindObjectsWithTag(search_tag:tag)<transacts>:[]creative_object_interface=
    var ObjectsArray : []creative_object_interface = array{}

    if:
        Session := GetSession()
        CreativeDevice := WorkaroundForTaggedObjects[Session]
    then:
        TaggedObjects := CreativeDevice.FindCreativeObjectsWithTag(search_tag)

        for(Object:TaggedObjects):
            set ObjectsArray += array{Object}

    return ObjectsArray

And then in your game controller class add this in the OnBegin method:

game_controller := class(creative_device):
    OnBegin<override>()<suspends>:void=
        Session := GetSession()

        if:
            set WorkaroundForTaggedObjects[Session] = Self

Then, when you want to get your tagged objects you just call:

TaggedObjects := FindObjectsWithTag(my_tag{})

Good news is that we can insert creative device into our npc behavior, so we don’t need tag for that.
Tested and working for me. I just set premade variable but ofc that could be set function.

That’s cool im confused how would something like this be implemented for multiple NpcSpawners? would there need to be like a class or something where you need to make as many classes as the npc spawner devices?

I don’t know if its common knowledge ect but in the NPC class just add a editable device and ref that. That’s all i did and it works perfect without the need for all the extra workings. The device doesnt need to be connected to anything and it works.

This also works in a standard class but you need to ref any editable device and connect it to the verse device even if you are not using/needing a device just add one anyway

NPC CLASS

A Verse-authored NPC Behavior that can be used within an NPC Character Definition or a NPC Spawner device’s NPC Behavior Script Override.

Trail_Example := class(npc_behavior):

@editable
Button : button_device = button_device{}

# This function runs when the NPC is spawned in the world and ready to follow a behavior.
OnBegin<override>()<suspends>:void =
    TaggedList := Button.FindCreativeObjectsWithTag(YourTagNameHere{})

Further down in your code

for(MaybeTaggedActor : TaggedList):
if(Name :=Type[MaybeTaggedActor]):
# Do Something

NormalClass

for(FoundObject : Power_Settings.Mutator_Device.FindCreativeObjectsWithTag(YourTagNameHere{})):

uses the mutator as a relay to the creative device

          if(Name := Type[FoundObject]):

With a normal class the editable device in this case the Mutator needs to be connected to the verse device. If it isnt then it doesnt work.

Hope this helps some of you.