Jump to content

How to get room/task an entity is located?


Recommended Posts

Is it possible to get the room/task an entity is located?

I mean if you select your character with c_select() and hit backspace, you enable the DebugRender.
And this is showing you besides other information, also the room and task you are currently located.

But what is the function to get this room/task name?

Link to comment
Share on other sites

33 minutes ago, ZupaleX said:

I would use GetClosestNodeToPlayer()

This returns you a node which have a field "data" containing all the info you are asking about.

thank you :)
The goal is to connect wormholes depending on the task they are located in.

So I used GetClosestNode(x,y) instead, but this does not contain "data". It does contain this:

neighbours    table: 5D1D4268    
type    0    
c    7    
tags    table: 0C20C030    
cent    table: 0C20C648    
y    -19    
poly    table: 0C20C300    
validedges    table: 5D18C428    
x    42    
area    323  

 
So what now? =/
My Code:
 

AddPrefabPostInit("wormhole",function(inst)
    if inst.components.teleporter then
        inst:DoTaskInTime(0,function(inst)
            local x, y, z = inst.Transform:GetWorldPosition() 
            local n = GLOBAL.GetClosestNode(x,y)
            -- ...
        end)
    end
end)

Why I'm asking:

Spoiler

I'm working on the Adventure Mod, which will allow playing the DS adventure. There is a world "Archipelago", which has 5 islands and a start island.
Unfortunately islands do not work by default and it is too complicated to rewrite the worldgeneration code.
Therefore I made them half-islands linked with a small path, but this path is blocked by undestroyable basalt.
But the game is not generating wormholes by itself. So I added 5 wormholes to the start-task and 1 wormhole for each of the other island tasks.
In map/network the wormholes are randomly connected.

The only solution I can imagine so far, is to iterate after world generation over all exisiting wormholes and make them connect correctly, depending on their task they are located.

 

Edited by Serpens
Link to comment
Share on other sites

I was expecting this function to return a table of this type

Spoiler

Node = Class(function(self, id, data)
	self.id = id
	self.graph = nil
	self.delta_graph = nil
	
    -- Graph properties
    self.edges = {}
    
    -- Data
    self.data = data
    
    -- Search
    self.visited = false
    
    self.colour = data.colour or {r=255,g=255,b=0,a=55}


    self.ents = nil
    self.populateFn = nil
    self.tileFn = nil
    self.populated = false
    self.children_populated = false


    if self.data.custom_tiles ~= nil then
 		self:SetTilesFunction(self.data.custom_tiles)    	
    	self.data.custom_tiles = nil
    end
    if self.data.custom_objects ~= nil then
 		self:SetPopulateFunction(self.data.custom_objects)    	
    	self.data.custom_objects = nil
    end

end)

 

but obviously it does not. Well there is a bit more research to do then, sorry about that.

Link to comment
Share on other sites

I believe this is what you want. It is based on the 'GetClosestNode'.  A small change was made to make it more precise for edges.

function GetRoom(entity)
    local closestdist = math.huge
    local closestid = nil
    x,_,y=entity.Transform:GetWorldPosition()
    for i,v in pairs(GLOBAL.TheWorld.topology.nodes) do
        if #v.neighbours > 0 then
            local dx = math.floor((math.abs(v.x - x)+2)/4)
            local dy = math.floor((math.abs(v.y - y)+2)/4)
            local distsq = dx*dx + dy*dy
            if distsq < closestdist then
                closestdist = distsq
                closestid = i
            end
        end
    end
    return GLOBAL.TheWorld.topology.ids[closestid]
end

Link to comment
Share on other sites

51 minutes ago, ptr said:

I believe this is what you want. It is based on the 'GetClosestNode'.  A small change was made to make it more precise for edges.

O.ô brilliant it works ! :)
eg returning "IslandHop_Start:2:SpiderMarsh" (task and room)

By the way I just implemented another solution :D
I created a new room which includes countstaticlayout. And made a new layout that includes a wormhole with a scenario. The scenario is adding the Tag "wormholeX". (while X is a number from 1 to 10). Then I added those rooms to the the island tasks. Now in modmain I was able to connect the wormhole with Tag "wormhole1" with the wormhole with tag "wormhole2" (FindFirstEntityWithTag).

But with your solution it is much better :D:)
(just have to think about how to find the other wormholes... hmm.. only solution is a worldwide FindEntities and then checking their Task/Room ? ... or better adding the Tags from above in AddPrefabPostInit depending on their room and then do a DoTaskInTime and connect them via FindFirstEntityWithTag)

ok, this is my solution now in modmain:
 

Spoiler

AddPrefabPostInit("wormhole",function(inst)
    if inst.components.teleporter then
        inst:DoTaskInTime(0,function(inst)
            taskandroom = GetRoom(inst) -- eg "IslandHop_Start:2:SpiderMarsh"
            if string.find(taskandroom,"IslandHop_Start") then
                if not GLOBAL.TheSim:FindFirstEntityWithTag("wormhole1") then
                    inst:AddTag("wormhole1")
                elseif not GLOBAL.TheSim:FindFirstEntityWithTag("wormhole2") then
                    inst:AddTag("wormhole2")
                elseif not GLOBAL.TheSim:FindFirstEntityWithTag("wormhole3") then
                    inst:AddTag("wormhole3")
                elseif not GLOBAL.TheSim:FindFirstEntityWithTag("wormhole4") then
                    inst:AddTag("wormhole4")
                elseif not GLOBAL.TheSim:FindFirstEntityWithTag("wormhole5") then
                    inst:AddTag("wormhole5")
                end
            elseif string.find(taskandroom,"IslandHop_Hounds") then
                inst:AddTag("wormhole6")
            elseif string.find(taskandroom,"IslandHop_Forest") then
                inst:AddTag("wormhole7")
            elseif string.find(taskandroom,"IslandHop_Savanna") then
                inst:AddTag("wormhole8")
            elseif string.find(taskandroom,"IslandHop_Rocky") then
                inst:AddTag("wormhole9")
            elseif string.find(taskandroom,"IslandHop_Merm") then
                inst:AddTag("wormhole10")
            end
            inst:DoTaskInTime(0.1,function(inst)
                if inst:HasTag("wormhole1") then
                    local worm6 = GLOBAL.TheSim:FindFirstEntityWithTag("wormhole6")
                    inst.components.teleporter.targetTeleporter = worm6
                elseif inst:HasTag("wormhole2") then
                    local worm7 = GLOBAL.TheSim:FindFirstEntityWithTag("wormhole7")
                    inst.components.teleporter.targetTeleporter = worm7
                elseif inst:HasTag("wormhole3") then
                    local worm8 = GLOBAL.TheSim:FindFirstEntityWithTag("wormhole8")
                    inst.components.teleporter.targetTeleporter = worm8
                elseif inst:HasTag("wormhole4") then
                    local worm9 = GLOBAL.TheSim:FindFirstEntityWithTag("wormhole9")
                    inst.components.teleporter.targetTeleporter = worm9
                elseif inst:HasTag("wormhole5") then
                    local worm10 = GLOBAL.TheSim:FindFirstEntityWithTag("wormhole10")
                    inst.components.teleporter.targetTeleporter = worm10
                elseif inst:HasTag("wormhole6") then
                    local worm1 = GLOBAL.TheSim:FindFirstEntityWithTag("wormhole1")
                    inst.components.teleporter.targetTeleporter = worm1
                elseif inst:HasTag("wormhole7") then
                    local worm2 = GLOBAL.TheSim:FindFirstEntityWithTag("wormhole2")
                    inst.components.teleporter.targetTeleporter = worm2
                elseif inst:HasTag("wormhole8") then
                    local worm3 = GLOBAL.TheSim:FindFirstEntityWithTag("wormhole3")
                    inst.components.teleporter.targetTeleporter = worm3
                elseif inst:HasTag("wormhole9") then
                    local worm4 = GLOBAL.TheSim:FindFirstEntityWithTag("wormhole4")
                    inst.components.teleporter.targetTeleporter = worm4
                elseif inst:HasTag("wormhole10") then
                    local worm5 = GLOBAL.TheSim:FindFirstEntityWithTag("wormhole5")
                    inst.components.teleporter.targetTeleporter = worm5
                end
            end)
        end)
    end
end)

 

 

Edited by Serpens
Link to comment
Share on other sites

14 hours ago, ptr said:

Why not save all the wormholes in a global table like the sinkholes do in addprefabpostinit?

Then you can connect them in a function once all wormholes are saved.

Are you interested in helping me to improve the code from the adventure mod?
https://github.com/Serpens66/DST-Adventure-Mod/tree/master/Adventure-Mod

Especially the level code is very poor..
It works like this:
In Adventure we have a "Chapter" from 0 to 6. And a Level (I call it Overridelevel, currently 1 to 8). The levels are all designed worlds we have, egl Archipelago, King of Winter and so on.  From those worlds not all are selected (only so many to fill the available chapters).

So basic problem is now, that when we complete the first chapter, the game has to "restart", but load the next world now, instead of the old one again.
DarkXero solved that by basically writing the next world in a file located in modfolder when doing the "adventurejump". When next world is loaded it reads that file, loads the correct world, and empties that file again.
In modworldgenmain I save this actual level (and chapter) in GLOBAL.CHAPTER_GEN and GLOBAL.OVERRIDELEVEL_GEN.
The problem is now, that modworldgenmain runs ~ 2 or 3 times at gamestart, and also when world is not generating 1 or 2 times.
Also modmain is running several times each gamestart.

But the file where the actual level is saved, does only exist directly when doing the worldjump. That means that GLOBAL.OVERRIDELEVEL_GEN is not usable each time we load the game (without generating a new world). Therefore a component attached to the world is saving that information instead. So now I have a cluttered system to get the actual world/chapter, which is only known after the world added and started their components.

The problem now is, that I don't 100% know when this component is successfully loaded.
Eg. for the AddPrefabPostInit with the wormholes, I did a "AddTaskPostInit" with DoTaskInTime of 0.05 seconds. Cause I thought the world and their components are initilaiied before all the prefabs. But obviously this is not true, cause level was unknown.  So now I do wait 0.5 seconds instead, wich is working. But in the PostInit of the world I now have to connect those wormholes I saved in GLOBAL variable in PostInit of wormholes. But I have to do it after I saved the wormholes, so I use DoTaskInTime of 1 second now.

The result is, everywhere were I need to know the actual level, has a "DoTaskInTime" with some seconds to wait. But what if for some reason the game takes longer to load the world components? And it really sucks to make sure that everywhere the seconds are increased if it depends on each other. I this is very error prone, cause I can also miss to increase the time for depending things (like the wormhole code) and not always an error is thrown.

All in all I don't like this and I hope there is a btter way of doing it...




 

Edited by Serpens
Link to comment
Share on other sites

3 hours ago, Serpens said:

Are you interested in helping me to improve the code from the adventure mod?
https://github.com/Serpens66/DST-Adventure-Mod/tree/master/Adventure-Mod

Especially the level code is very poor..
It works like this:
In Adventure we have a "Chapter" from 0 to 6. And a Level (I call it Overridelevel, currently 1 to 8). The levels are all designed worlds we have, egl Archipelago, King of Winter and so on.  From those worlds not all are selected (only so many to fill the available chapters).

So basic problem is now, that when we complete the first chapter, the game has to "restart", but load the next world now, instead of the old one again.
DarkXero solved that by basically writing the next world in a file located in modfolder when doing the "adventurejump". When next world is loaded it reads that file, loads the correct world, and empties that file again.
In modworldgenmain I save this actual level (and chapter) in GLOBAL.CHAPTER_GEN and GLOBAL.OVERRIDELEVEL_GEN.
The problem is now, that modworldgenmain runs ~ 2 or 3 times at gamestart, and also when world is not generating 1 or 2 times.
Also modmain is running several times each gamestart.

But the file where the actual level is saved, does only exist directly when doing the worldjump. That means that GLOBAL.OVERRIDELEVEL_GEN is not usable each time we load the game (without generating a new world). Therefore a component attached to the world is saving that information instead. So now I have a cluttered system to get the actual world/chapter, which is only known after the world added and started their components.

The problem now is, that I don't 100% know when this component is successfully loaded.
Eg. for the AddPrefabPostInit with the wormholes, I did a "AddTaskPostInit" with DoTaskInTime of 0.05 seconds. Cause I thought the world and their components are initilaiied before all the prefabs. But obviously this is not true, cause level was unknown.  So now I do wait 0.5 seconds instead, wich is working. But in the PostInit of the world I now have to connect those wormholes I saved in GLOBAL variable in PostInit of wormholes. But I have to do it after I saved the wormholes, so I use DoTaskInTime of 1 second now.

The result is, everywhere were I need to know the actual level, has a "DoTaskInTime" with some seconds to wait. But what if for some reason the game takes longer to load the world components? And it really sucks to make sure that everywhere the seconds are increased if it depends on each other. I this is very error prone, cause I can also miss to increase the time for depending things (like the wormhole code) and not always an error is thrown.

All in all I don't like this and I hope there is a btter way of doing it...




 

Well, I will look into that when I get time.

Link to comment
Share on other sites

After endless trial and error, I finally found a way to disconnect the islands. However, it is quite a rough solution...

By the way, maybe you can save the next world into a file only when jumping to the next world, and read it in worldgenmain but do not delete it. the file will be better to be in the shard folder to prevent affecting other save slots.

Link to comment
Share on other sites

6 hours ago, ptr said:

After endless trial and error, I finally found a way to disconnect the islands. However, it is quite a rough solution...

By the way, maybe you can save the next world into a file only when jumping to the next world, and read it in worldgenmain but do not delete it. the file will be better to be in the shard folder to prevent affecting other save slots.

nice :) I did not expected anyone to find a solution for the island generation O.ô

Yes, only reason for deleting is to not affect other save slots. But is it save/possible to save in the shard folder? I would think if this would be possible DarkXero would have done this (sry egnlish is not my native, absolutely unsure if tense is correct :D) ... but of course even DarkXero may not think about every kind of solutions :D

Feel free to also contact me via PM with details or if you want to discuss public, maybe we should start a new thread, to better fit the topic :)

edit: Of course you can also participate directly at github with code improvements:
https://github.com/Serpens66/DST-Adventure-Mod

Edited by Serpens
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
  • Create New...