Find entity

Place to get help with not working mods / modding interface.
Post Reply
CarpeDiem
Burner Inserter
Burner Inserter
Posts: 5
Joined: Mon May 19, 2014 11:35 am
Contact:

Find entity

Post by CarpeDiem »

Hi all.

I'm a programmer, but it's my first time with LUA. I've looked through the documentation and other mods, but haven't found the solution for these scenários.
Could anyone help please?

There are three questions here:
1 - Is there any way to find the nearest entity of some kind without using the game.findentities or findentitiesfiltered? They are very slow if we use a large area (100 or 1000 for instance).
Example of use that I need: find the nearest spawner from a roboport or find the nearest ore of some type from a certain position.

2 - Is there any way to move an entity from point A to point B without "teleporting" it?
Example of use that I need: Move a custom robot from point A to B. (Mechs :D)

3 - As a player/bitter moves, they do not have damage from colision on trees, but a car has.
How does it work? Is it possible to remove/customize these settings? (I don't want my bots killing themselves on trees or destroying the base. I could remove the colision box, but they would fly and that's not the initial idea).

Thanks a lot.

User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: Find entity

Post by FreeER »

Hello CarpeDiem, glad you chose to seize the day and work with LUA :P (couldn't resist, I apologize if that seemed quite silly)
CarpeDiem wrote:Is there any way to find the nearest entity
Not that I'm aware of...I've thought about that a couple times but haven't needed to actually implement it yet... my thought plan for that case has been findentities(filtered) with a small-ish radius that increased until it found one...assuming of course that game.player.force.getentitycount("entity-name") says there is at least one. The other idea I've had is to keep track of all entities of that type that have been placed and loop through them...but that may have even more related issues than findentities. Of course if these do not work (efficiently) for you then you're free to make an interface request.
CarpeDiem wrote:Is there any way to move an entity from point A to point B without "teleporting" it?
not unless that entity is a 'unit' (which can be given commands), which kind of makes sense since most entities are stationary "buildings"
CarpeDiem wrote:As a player/bitter moves, they do not have damage from colision on trees, but a car has.
This one I don't know, but I'm going to guess that it's the speed at which the entity is moving that determines whether it is damaged when it collides...perhaps also affected by the weight since the wiki says that is " used for physics calculation when car hits something" (default value of 1).

P.S. sorry for late reply...apparently I didn't get an email for this (or it sent me a generic "new topics created" email and I only saw one topic when I read it...).
<I'm really not active any more so these may not be up to date>
~FreeER=Factorio Modding
- Factorio Wiki
- My Factorio Modding Guide
- Wiki Modding Guide
Feel free to pm me :)
Or drop into #factorio on irc.esper.net

CarpeDiem
Burner Inserter
Burner Inserter
Posts: 5
Joined: Mon May 19, 2014 11:35 am
Contact:

Re: Find entity

Post by CarpeDiem »

Lol, you don't need to apologize. First, thank you for the answers.

I'll try to create a glob table to control it with the coordinates and use the current position to check the nearest one (X, Y, entity). No idea yet on how to do it, I will learn a little more with the tutorials first since I'm losing hours to make a method call. This will create some problems as I'll have to periodically check if the entity is still "alive".

Great idea with the "unit". This solves all problems (it already has methods to move, does not have collision problems and attack). I've made some tests yesterday and it worked. Unit was created, is player friendly and attack bitters. It's still a little stubborn as I couldn’t find a sample on how to use gotolocation or atackarea methods from Lua/Command and it keeps wandering. Do you have one of these? :)

Abusing your good will… I’ve seen the event “ontick”, but doing some controls or periodical checks like 1 every minute, I had to implement a counter, but I’m not sure if this is the best way to do it. Is there a better one?

game.onevent(defines.events.ontick, function(event)
if game.tick%60==0 then
glob.second = glob. second + 1
end.
If glob.second==60 then
glob.second = 0
game.showmessagedialog("Test")
end.
end)

User avatar
rk84
Filter Inserter
Filter Inserter
Posts: 556
Joined: Wed Feb 13, 2013 9:15 am
Contact:

Re: Find entity

Post by rk84 »

Modulo seems to be popular option, but I dislike it. In my mind, its unnecessary calculation done on "every" tick.

Code: Select all

game.onevent(defines.events.ontick, function(event)
  if event.tick > glob.tick then
    glob.tick = event.tick + 3600
    game.showmessagedialog("Test")
  end
end)
Test mode
Searching Flashlight
[WIP]Fluid handling expansion
[WIP]PvP gamescript
[WIP]Rocket Express
Autofill: The torch has been pass to Nexela

CarpeDiem
Burner Inserter
Burner Inserter
Posts: 5
Joined: Mon May 19, 2014 11:35 am
Contact:

Re: Find entity

Post by CarpeDiem »

I liked this idea since it avoid an unnecessary calculation every tick. I didn't knew about this variable.
Is there a list of all variables available like the wiki or is there any way that I can use to find then?

Best Regards.

User avatar
rk84
Filter Inserter
Filter Inserter
Posts: 556
Joined: Wed Feb 13, 2013 9:15 am
Contact:

Re: Find entity

Post by rk84 »

CarpeDiem wrote:I liked this idea since it avoid an unnecessary calculation every tick. I didn't knew about this variable.
Is there a list of all variables available like the wiki or is there any way that I can use to find then?

Best Regards.
you mean event variable? Lua/Events#Game_events
I decided to use event.tick over game.tick, because the event variable is local (we both name it as function's parameter in first line) and locals are faster than globals. It might not be big gain, but it is there. So why not.
Test mode
Searching Flashlight
[WIP]Fluid handling expansion
[WIP]PvP gamescript
[WIP]Rocket Express
Autofill: The torch has been pass to Nexela

User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: Find entity

Post by FreeER »

CarpeDiem wrote:It's still a little stubborn as I couldn’t find a sample on how to use gotolocation or atackarea methods from Lua/Command and it keeps wandering. Do you have one of these? :)
hm...Personally, no. However, you can find two or three in the ccmod (wip section), it's a bit outdated in some respects but the majority of it and the setcommand methods specifically should be the same.
here's one from it which tells a single 'trooper' to move to a (player targeted) location and set's the trooper's distraction level to 'byenemy' (the command will be interrupted when it's 'distracted'):

Code: Select all

trooper.setcommand({ type=defines.command.gotolocation, destination=npos, distraction=defines.distraction.byenemy })
From the wiki's list of parameters, I believe the attackarea command would be given like so

Code: Select all

trooper.setcommand({ type=defines.command.attackarea, destination={x=20, y=30}, radius=50, distraction=defines.distraction.byenemy })
as for wandering...i think the wander command takes effect when no other commands are active...I'm not sure how to solve that one (would be nice if you could give the wander command with a radius limit but I'm not sure that's possible, probably easy enough to make an interface request for it though).
edit: I suppose one method would be to make the unit.active = false...but that has obvious problems associated with it (and may not work at all for what you want)
rk84 wrote:Modulo seems to be popular option, but I dislike it. In my mind, its unnecessary calculation done on "every" tick.
I've used Modulo mostly because that's how I learned, I would however think that a division would have fairly equal overhead to assigning an incremented value...I haven't tested at all though so no idea how similar the overhead truly is (or not)

User avatar
rk84
Filter Inserter
Filter Inserter
Posts: 556
Joined: Wed Feb 13, 2013 9:15 am
Contact:

Re: Find entity

Post by rk84 »

FreeER wrote:I've used Modulo mostly because that's how I learned, I would however think that a division would have fairly equal overhead to assigning an incremented value...I haven't tested at all though so no idea how similar the overhead truly is (or not)
Yea me too. Lately I have become more performance driven. Mayby I'm splitting hairs here, but small things tends to add up. Mayby its because my pc is on it's last leg :)

When looking past the syntax sugar, modulo is more than just division.

Code: Select all

a % b == a - math.floor(a/b)*b
Test mode
Searching Flashlight
[WIP]Fluid handling expansion
[WIP]PvP gamescript
[WIP]Rocket Express
Autofill: The torch has been pass to Nexela

User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: Find entity

Post by FreeER »

rk84 wrote:When looking past the syntax sugar, modulo is more than just division.
Oh! Interesting, I wonder if that's due to lua using doubles... in assembly (with ints at least, I've never used floats/doubles in asm) modulo really is just division that returns the remainder rather than the quotient...at least from my understanding of how it works, which could be wrong :lol:

User avatar
rk84
Filter Inserter
Filter Inserter
Posts: 556
Joined: Wed Feb 13, 2013 9:15 am
Contact:

Re: Find entity

Post by rk84 »

FreeER wrote:
rk84 wrote:When looking past the syntax sugar, modulo is more than just division.
Oh! Interesting, I wonder if that's due to lua using doubles... in assembly (with ints at least, I've never used floats/doubles in asm) modulo really is just division that returns the remainder rather than the quotient...at least from my understanding of how it works, which could be wrong :lol:
Actually I might have been too fast to post that. (reference manual and some article/post let me assume things)
I made crude test and % was visually faster than a-floor(a/b)*b (looping over 10mil times)
Test mode
Searching Flashlight
[WIP]Fluid handling expansion
[WIP]PvP gamescript
[WIP]Rocket Express
Autofill: The torch has been pass to Nexela

User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: Find entity

Post by FreeER »

rk84 wrote:Actually I might have been too fast to post that. (reference manual and some article/post let me assume things)
I made crude test and % was visually faster than a-floor(a/b)*b (looping over 10mil times)
Well I'm sure the % operator would be optimized enough to at least take out the overhead of a function call so that would account for some of the speed difference, however the real difference/test we care about here is between % and modifying a global table (regardless of how efficient % is compared to other remainder retrieving methods)...

CarpeDiem
Burner Inserter
Burner Inserter
Posts: 5
Joined: Mon May 19, 2014 11:35 am
Contact:

Re: Find entity

Post by CarpeDiem »

Thanks all, It's nice to see an active comunity.

I've found a mod called "Cobra Commander". It has several calls on "unit" that I could use as example to learn these "unit control commands".

The basic idea that I initially had was to create two automatons.
1º kind is the combat mech. Moves to a position after an order, kills anything on the way and returns. (more than one type here. Probably 1 for each weapon type as a mech, maybe a tank and an aircraft).
To test the limits, I will probably insert some return to base conditions (25, 50, 75% damage) or less than X friendly mech units in a certain radius
2º kind is the support mech. Moves to a position and retrieves every alien artifact in their way and returns. (The find entity would be used for this guy to find that destination position without intervention).
The best Idea that I had up to now was to create a logic in the event at "Lua/Events.onentitydied" and log in a glob.array it's coordinates (only for those that could drop the alien artifacts). If this unity finds anything in this array, it moves through there and check the area. (additional control would be necessary at "Lua/Events.onpickedupitem" )
As I'm a complete beginner in LUA and it's veeery diferent from the language that I knoll (ABAP), I'm having some problems with these arrays. I have to study more first hehehe.
Example: In order to store the coordinates I need to create a matrix with "keyValue, position X, position Y, droppedItem". The only way that I've found to do it was using for. Something like this:

Code: Select all

 mt = {}          -- create the matrix
    for i=1,N do
      mt[i] = {}     -- create a new row
      for j=1,M do
        mt[i][j] = 0
      end
    end
source http://www.lua.org/pil/11.2.html
This is slow if I have to loop through the entire table every time that I want to find the nearest entity from my mech-base position. The table can became huge deppending of the resource type that I'm controlling(not limited to alien artifacts).
Probable solution found for this was to create another array related to the first one. {mech-base, Distance in the cartesian plane, keyValue
What do you guys think about my workarounds?

User avatar
rk84
Filter Inserter
Filter Inserter
Posts: 556
Joined: Wed Feb 13, 2013 9:15 am
Contact:

Re: Find entity

Post by rk84 »

FreeER wrote:Well I'm sure the % operator would be optimized enough to at least take out the overhead of a function call so that would account for some of the speed difference, however the real difference/test we care about here is between % and modifying a global table (regardless of how efficient % is compared to other remainder retrieving methods)...
You were right. Accessing/modifing global had more impact than I though. Also % is quite same level as division. Below is some test values. Values have bit of fluctuation.
Performance.png
Test setup codes
Notes:
  • Usage of local variables had the biggest impact. event.tick is faster then game.tick. Also tick (global) is bit faster then glob.tick.
  • I also had loop test setup and assigning every value and function to local variable before loop can improve speed. Example "local floor = math.floor"
Test mode
Searching Flashlight
[WIP]Fluid handling expansion
[WIP]PvP gamescript
[WIP]Rocket Express
Autofill: The torch has been pass to Nexela

User avatar
rk84
Filter Inserter
Filter Inserter
Posts: 556
Joined: Wed Feb 13, 2013 9:15 am
Contact:

Re: Find entity

Post by rk84 »

CarpeDiem wrote:What do you guys think about my workarounds?
I'm not quite sure of your plan yet. What are you planning to do with the matrix? do you use x and y coord as keys?

onpickedupitem works only in case of player. You could monitor your units command execution with "hascommand" possibly and store some value to tell what was it doing?

Code: Select all

 if going_after_artifacts and not unit.hascommand then scanArea(unit.position) end
I'm not sure if wandering kicks in and count as command?

Also I have not fully tested, but you should be able to create groups, add units to group and command them as group. It might be worth exploring. I'm not sure about the behavior, but atleast during gathering units don't wander.

Code: Select all

group = game.createunitgroup(position)
group.addmember(unit)
group.setcommand(command)
Test mode
Searching Flashlight
[WIP]Fluid handling expansion
[WIP]PvP gamescript
[WIP]Rocket Express
Autofill: The torch has been pass to Nexela

User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: Find entity

Post by FreeER »

CarpeDiem wrote:What do you guys think about my workarounds?
sounds pretty good. Also note rk84's comments of course :)
CarpeDiem wrote: I need to create a matrix with "keyValue, position X, position Y, droppedItem"
Do you need an actual matrix or would a regular associative array (table) work? I personally find associative arrays easier to work with (and there's practically no additional overhead for them in lua, at least from my understanding...). note: a lot of this is pseudo code

Code: Select all

dropped_items = {}
on_item_dropped do -- pseudo event handler
  -- note: I'm not sure what your keyValue is used for...
  -- where position will be a typical table of {x=x_coord, y=y_coord}
  table.insert(dropped_items, {keyValue=whatever, position=dropped_item.position, name=dropped_item.stack.name})
end

-- example use

on_retrieve_items do -- pseudo event handler (assuming distance from individual collector mech, not from a base)
  local closest = {dist = math.huge, position=nil, name=nil}
  for _, item in ipairs(dropped_items) do
    -- function to calculate distance, assuming 'mech' is the entity that will pick it up, and require "util" (provided by Factorio)
    local distance = util.distance(item.position, mech.position)
    -- technically a bit of waste here since you create a new table instead of modifying closest's values...you're free to do that instead.
    if distance < closest.dist then closest = {dist=distance, position=item.position, name=item.name} end
  end
  send_robot_to_collect(closest.position, closest.name) -- function (setcommand goto call?)
end
if the distance is from a base rather than individual mech collectors it'd probably be possible to have dropped_items store the distance as well (to avoid recalculating an unchanging value) and be sorted (occasionally) and then just use it like a queue (push/insert items onto the end and pop them off the top for collection, assuming it was sorted in least to greatest distance).
rk84 wrote:Values have bit of fluctuation.
Now there's some interesting test result :D of course how much is 'a bit', mod-a and mod-tick have a difference of .9% and if it only fluctuates by .2% that's a decent difference (overall), though possibly only a small optimization when compared with any redundant for loops or multiple function calls that often return quickly (without doing anything)...

CarpeDiem
Burner Inserter
Burner Inserter
Posts: 5
Joined: Mon May 19, 2014 11:35 am
Contact:

Re: Find entity

Post by CarpeDiem »

Both did a lot more than I hoped for. I will do some thinkering in the weekend when some spare time will be available.
As soon as I have something minimaly usefull I will post here.

Again, thank you.

Post Reply

Return to “Modding help”