Simple Wood Logger

Place to get help with not working mods / modding interface.
User avatar
Animar
Long Handed Inserter
Long Handed Inserter
Posts: 53
Joined: Sat Dec 21, 2013 8:06 am
Contact:

Simple Wood Logger

Post by Animar »

Hi there

After playing arround with some selfmade turrets and rockets, wich is basically copy and paste with some litle changes to the original code. I feel it's kinda next step to do this. Even some other mods did this already aka treefarm, blueprint ... So please dont blame me for reinventing the wheel. It's just my way to getting used to all that stuff because i learned programming only in C/C++ and of course Basic. So Lua didn't apear that much different to me but sometimes i get stuck with the syntax.

I got this so far, maybe already cluttered with potential errors ?

Code: Select all

local var1 = game.findentities{{-5,-5}{5,5}}								     --get entitys in a 10*10 area
local var2 = math.random(#var1)									               --pic a random entity
if (var1[var2].type == "tree") then									           --if it's a tree
	var1[var2].destroy()											                 --destroy it
	if (game.canplaceentity{name="raw-wood", position = {-2, 0}}) then	 --check outpotside
		game.createentity{name="raw-wood", position = {-0.5, -1.3}}        --drop ""raw-wood" on ground
	end						
end
will that work as i suppose ?
and how on earth get i this code to work with an placeable entity in the world. I thought about changing the miner to harvest wood instead of ore, at least for now.
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: Simple Wood Logger

Post by FreeER »

a couple issues :) 3 is the big one
1) Since this is searching for a single entity (of the same kind), it'd be a bit faster, and you'd be able to remove the check for if it was a tree, to use

Code: Select all

game.findentitiesfiltered{type="tree", area={{-5,-5}{5,5}}} --c++ rather than lua looping
2) You might want to check if you can place the raw wood before destroying the tree, otherwise you'll be losing production (possible bug, could be intended)
3) you can not drop items (like wood, raw-wood, electronic circuits, etc.) directly using createentity because it's not an entity, slightly confusing since most entities have the same name as the item. The way to drop items on the ground is with an item-on-ground entity wrapper with

Code: Select all

game.createentity{position={-1.7,-12.2}, name="item-stack", stack={name="raw-wood", count=1}}  --note, see 4
or you can search for a container/inventory (treefarm does this, but the container is the stored entity, see below, so it doesn't have to search) and inserting the item into that.
4) I'm sure you probably did this as an example, but for completeness: you'd want to use the mining entity's position +/- an offset to drop items, not a constant position. (store a reference to an entity and use entity_var_name.position)

Opinions:
Unless you use var2 for something later, or intend to, I'd just use var1[math.random(#var1)]
I like to create a boundingbox function that takes a single integer and creates these square areas for me, it looks a bit neater imo, and was much easier to type when the area was in the format of area={topleft={}, bottomright={}}, or was it lefttop and rightbottom?

as to getting it to work with a placeable entity, the best (at least known) approach is to hook the onentityplaced event and watch for the entity being placed, then add the newly placed entity to a table and in ontick (and using game.tick % something, so it's not literally every tick) loop through that table and check each entity if it's still valid, and for nearby trees. As to the table that you store the entities in, make sure it's inside of glob (because it gets saved and loaded with the player's game).
<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
User avatar
Animar
Long Handed Inserter
Long Handed Inserter
Posts: 53
Joined: Sat Dec 21, 2013 8:06 am
Contact:

Re: Simple Wood Logger

Post by Animar »

initially i had used

Code: Select all

if (var1[math.random(#var1)].type == "tree") then                   --check for tree
    var1[math.random(#var1)].destroy()                              --delete possibly someting else
    if (game.canplaceentity{name="raw-wood", position = {-2, 0}}) then
        game.createentity{name="raw-wood", position = {-0.5, -1.3}}
    end						
end
wich ended up in 2 different entitys, that was the reason for var2 ^^ (ya i shouldn't name them alphanumeric like)
i want a static drop position to put it on belts, like the miner. I will make it as a fueled machine, so storing it its internal inventory might end up in some trouble with its fuelslot. Maybe i will change my mind about that who knows.

I now end up with this

Code: Select all

	if (game.canplaceentity{name="raw-wood", position = {-2, 0}}) then		--check for free space
		local var1 = game.findentitiesfiltered{type="tree"{
			topleft = {x = -5,y = -5},       
			bottomright = {x = 5,y = 5}}}									    --geting trees in a 10*10 area
			var1[math.random(#var1)].destroy()								    --pic a random tree and destroy it
			game.createentity{position={-2, 0}, name="item-stack", stack={name="raw-wood", count=5}}
		end						  --drop "raw-wood" on ground / Belt ^^
	end
FreeER wrote: as to getting it to work with a placeable entity, the best (at least known) approach is to hook the onentityplaced event and watch for the entity being placed, then add the newly placed entity to a table and in ontick (and using game.tick % something, so it's not literally every tick) loop through that table and check each entity if it's still valid, and for nearby trees. As to the table that you store the entities in, make sure it's inside of glob (because it gets saved and loaded with the player's game).
ya thats the point where my knowledge fades out

i gues i need something like

Code: Select all

 
require "defines"
 
 game.onevent(defines.events, function(event)
   if event.name == defines.events.onentityplaced then
        ???
   elsif event.name == defines.events.ontick then
        ???
 end)
it's a shame that cursing on the monitor did not solve any problems.
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: Simple Wood Logger

Post by FreeER »

Animar wrote:initially i had used
Yeah, I thought it was something like that, again more personal opinion that anything else when you don't use it later.
i want a static drop position to put it on belts, like the miner.
But the problem with the 'static' drop position is that {-0.5, -1.3} specifies those exact positions in the world, not relative to any machine. So every single tree miner would be creating their output at exactly {-0.5, -1.3}, no matter how far away they might be from that position. And if that position happened to be in a lake, no output for anything. To place it relative to the miner you would need a reference to the miner and use that miner's postion like so, {miner.position.x-0.5, miner.position.y-1.3}. That makes every single miner place their results exactly .5 to the left of that specific miner and 1.3 above that drill, well relative to the center of the miner I believe.
I will make it as a fueled machine, so storing it its internal inventory might end up in some trouble with its fuelslot.
Ah, well, that could be an issue. defines does not list a mining drills' buffer (though it does the fuel), but maybe you could still use miner_inv=miner.getinventory(1) then miner_inv.insert. Simply dropping it on the ground does seem easier though, and more in line with the other miners.
topleft = {x = -5,y = -5},
bottomright = {x = 5,y = 5}}}
oops, probably my fault here :) but topleft and bottomright are the old methods and, though 'supported' can cause random issues.
oh, just noticed one other issue, if there are no trees then var1 will be empty or nil, I'd have to check to be sure which, but either way passing #var1 to math.random in such a state would give an error (empty interval range I believe is the text).
oh, well wow, apparently I made a typo when responding about the item-stack, it should be item-on-ground instead. :oops: (why didn't I copy and paste from console? I'd tested it...sigh)

so what you should actually have is this:

Code: Select all

if (game.canplaceentity{name="raw-wood", position = {miner.position.x-2, miner.position.y}}) then      --check for free space
  local var1 = game.findentitiesfiltered{type="tree", area={{miner.position.x-5,miner.position.y-5},{miner.position.x+5,miner.position.y+5}}} --getting trees in a 10*10 area relative to the miner
  if (#var1 > 0) then
     var1[math.random(#var1)].destroy() --pic a random tree and destroy it
     game.createentity{position={miner.position.x-2, miner.position.y}, name="item-on-ground", stack={name="raw-wood", count=5}}
  end --drop "raw-wood" on ground / Belt ^^
end
This code would allow you to also fill a chest, I believe

Code: Select all

if (game.canplaceentity{position={miner.position.x-2, miner.position.y}, name="item-on-ground"}) then      --check for free space
  local var1 = game.findentitiesfiltered{type="tree", area={{miner.position.x-5,miner.position.y-5},{miner.position.x+5,miner.position.y+5}}} --getting trees in a 10*10 area relative to the miner
  if (#var1 > 0) then
     var1[math.random(#var1)].destroy() --pic a random tree and destroy it
     game.createentity{position={miner.position.x-2, miner.position.y}, name="item-on-ground", stack={name="raw-wood", count=5}}
  end --drop "raw-wood" on ground / Belt ^^
elseif game.findentitiesfiltered{type=="container", area={{miner.position.x-5,miner.position.y-5},{miner.position.x+5,miner.position.y+5}}}~=nil then -- if there is a chest in the drop location
  local chest=game.findentitiesfiltered{type=="container", area={{miner.position.x-5,miner.position.y-5},{miner.position.x+5,miner.position.y+5}}}[1] --get reference, this may look ugly with getting a table AND storing the first element to the variable in the same line
  if chest.caninsert{name="raw-wood", count=5} then chest.insert{name="raw-wood", count=5} end --insert if possible
end
as for the events, that or each individually like so

Code: Select all

game.onevent(defines.events.onbuiltentity, function(event) --miner is placed
  if event.createdentity.name == "tree_miner" then table.insert(glob.miners, event.createdentity) end --code
end)

game.onevent(defines.events.ontick, function(event) --
  if game.tick%60==1 then --do once per second
    for index, miner in ipairs(glob.miners) do --loop table
      if miner.valid then --check miner still exists
        --code from above
      else
        table.remove(glob.miners, index) -- remove from table if it no longer exists
      end
    end
  end
end)
ok, now I think everything should work :)

edit wow: I started working on this post just a few minutes after your last post...Took me about an hour to write it all, and test a tiny bit in the console...
edit, and still fixed a mistake where I didn't replace item-stack with item-on-ground in code block....
edit, and another from where I copied a findentitiesfiltered and forgot to edit the search parameter
<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
User avatar
Dysoch
Filter Inserter
Filter Inserter
Posts: 445
Joined: Fri Oct 18, 2013 2:27 pm
Contact:

Re: Simple Wood Logger

Post by Dysoch »

I think it easier to just make a new mining drill, and make a resource called dense forest. That way you can mine it with the mining drills, and its less memory intensive :)
Creator of:
- DyTech
- DyWorld
- DyWorld-Dynamics
- DyWorld-Dynamics 2
Active since Factorio 0.6
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: Simple Wood Logger

Post by FreeER »

Dysoch wrote:I think it easier to just make a new mining drill, and make a resource called dense forest. That way you can mine it with the mining drills, and its less memory intensive :)
OH nice idea. Never thought of that, would work though not sure how you'd get the same visual effect of mining trees :) Beyond that I think this was more of a project for Animar to become more used to the lua language, and how it's used in Factorio, than to actually create a new logging machine. Of course since (s)he mention knowing C++ maybe s(he) will eventually end up with access to the source and be able to help implement new ways of doing this :)
<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
User avatar
Animar
Long Handed Inserter
Long Handed Inserter
Posts: 53
Joined: Sat Dec 21, 2013 8:06 am
Contact:

Re: Simple Wood Logger

Post by Animar »

Thanks for all the advise, it seems you did more for the code than me.
@Dysoch would it be realy that much of an impact at the memory to use such a device on regular trees instead of replacing them all with selfmade dense-trees ?


edit:
aw i dont get it, there is somwhere arround a index global 'game' (a nil value) error
i tried to initialize, but so far noc success.

ready for ugly code, here it comes

Code: Select all

{
  game.oninit(function()
	if glob.loggers == nil then
		glob.loggers = {}
	end
  end)
},
{
  game.onload(function()
	if glob.loggers == nil then
		glob.loggers = {}
	end
  end)
},
{
  game.onevent(defines.events.onbuiltentity, function(event) --logger is placed
    if event.createdentity.name == "logger" then 
		table.insert(glob.loggers, event.createdentity)
	end
  end)
},
{
    game.onevent(defines.events.ontick, function(event) --
      if game.tick%120==1 then --tick / modulo = action
        for index, logger in ipairs(glob.loggers) do --loop table
			if logger.valid then --check logger still exists    
				if (game.canplaceentity{position={logger.position.x-2, logger.position.y}, name="item-on-ground"}) then      --check for free space
					local var1 = game.findentitiesfiltered{type="tree", area={{logger.position.x-5,logger.position.y-5},{logger.position.x+5,logger.position.y+5}}} --getting trees in a 10*10 area relative to the logger
					if (#var1 > 0) then
						var1[math.random(#var1)].destroy() --pic a random tree and destroy it
						game.createentity{position={logger.position.x-2, logger.position.y}, name="item-on-ground", stack={name="raw-wood", count=5}}
					elseif game.findentitiesfiltered{type=="container", area={{logger.position.x-5,logger.position.y-5},{logger.position.x+5,logger.position.y+5}}}~=nil then -- if there is a chest in the drop location
					end
					local chest=game.findentitiesfiltered{type=="container", area={{logger.position.x-5,logger.position.y-5},{logger.position.x+5,logger.position.y+5}}}[1]
					if chest.caninsert{name="raw-wood", count=5} then 
						chest.insert{name="raw-wood", count=5} 
					end --insert if possible
				end
			else
				table.remove(glob.loggers, index) -- remove from table if it no longer exists
			end
        end
	  end	
    end)
}
User avatar
Dysoch
Filter Inserter
Filter Inserter
Posts: 445
Joined: Fri Oct 18, 2013 2:27 pm
Contact:

Re: Simple Wood Logger

Post by Dysoch »

@Dysoch would it be realy that much of an impact at the memory to use such a device on regular trees instead of replacing them all with selfmade dense-trees ?
only when generating the terrain, after that it would require next to nothing for memory, since its static.

as for the event, it would use memory for every building placed. and i know from knowledge that some people create a ton of buildings to get alot of trees fast. so if your releasing it, state that i could lag your system when used in large numbers
Creator of:
- DyTech
- DyWorld
- DyWorld-Dynamics
- DyWorld-Dynamics 2
Active since Factorio 0.6
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: Simple Wood Logger

Post by FreeER »

Dysoch wrote:
@Dysoch would it be realy that much of an impact at the memory to use such a device on regular trees instead of replacing them all with selfmade dense-trees ?
only when generating the terrain, after that it would require next to nothing for memory, since its static.

as for the event, it would use memory for every building placed. and i know from knowledge that some people create a ton of buildings to get alot of trees fast. so if your releasing it, state that i could lag your system when used in large numbers
I'm not sure it's the memory usage, I think it's more the looping through and checking the entity is still valid, then finding the entities in the area, then selecting a random one, etc. for each entity in the loop. It could be curbed by only 'running' a few of the entities each loop (breaking after x loggers). I think, I haven't really tested it.
Animar wrote:it seems you did more for the code than me.
(bad?) habit, I guess. Ask pretty much anyone I've helped. It's seems easier to show the code than try to explain it without proper examples..
Animar wrote:ready for ugly code, here it comes
This looks really weird to me...why are they each in tables?

Code: Select all

require "defines" --needed for the event variables, defines.events.onbuiltentity, etc.
game.oninit(function()
  if glob.loggers == nil then
    glob.loggers = {}
  end
end)

game.onload(function()
  if glob.loggers == nil then
    glob.loggers = {}
  end
end)

game.onevent(defines.events.onbuiltentity, function(event) --logger is placed
  if event.createdentity.name == "logger" then
    table.insert(glob.loggers, event.createdentity)
  end
end)

game.onevent(defines.events.ontick, function(event) --
  if game.tick%120==1 then --tick / modulo = action
    for index, logger in ipairs(glob.loggers) do --loop table
      if logger.valid then --check logger still exists   
        if (game.canplaceentity{position={logger.position.x-2, logger.position.y}, name="item-on-ground"}) then      --check for free space
          local var1 = game.findentitiesfiltered{type="tree", area={{logger.position.x-5,logger.position.y-5},{logger.position.x+5,logger.position.y+5}}} --getting trees in a 10*10 area relative to the logger
          if (#var1 > 0) then
            var1[math.random(#var1)].destroy() --pic a random tree and destroy it
            game.createentity{position={logger.position.x-2, logger.position.y}, name="item-on-ground", stack={name="raw-wood", count=5}}
          elseif game.findentitiesfiltered{type=="container", area={{logger.position.x-5,logger.position.y-5},{logger.position.x+5,logger.position.y+5}}}~=nil then -- if there is a chest in the drop location
          end
          local chest=game.findentitiesfiltered{type=="container", area={{logger.position.x-5,logger.position.y-5},{logger.position.x+5,logger.position.y+5}}}[1]
          if chest.caninsert{name="raw-wood", count=5} then
          chest.insert{name="raw-wood", count=5}
          end --insert if possible
        end
      else
      table.remove(glob.loggers, index) -- remove from table if it no longer exists
      end
    end
  end   
end)
<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
User avatar
Animar
Long Handed Inserter
Long Handed Inserter
Posts: 53
Joined: Sat Dec 21, 2013 8:06 am
Contact:

Re: Simple Wood Logger

Post by Animar »

because i tought it has to be ?

don't get me wrong i prefer code examples rather more than explanations because code always speaks for itself, i only fear that i end up in coping your code one by one instead of developing it self.
User avatar
Dysoch
Filter Inserter
Filter Inserter
Posts: 445
Joined: Fri Oct 18, 2013 2:27 pm
Contact:

Re: Simple Wood Logger

Post by Dysoch »

Animar wrote:because i tought it has to be ?

don't get me wrong i prefer code examples rather more than explanations, i only fear that i end up in coping your code one by one instead of developing it self
i know what you mean :P he has helped me more then 1 time, and most of the time i use his code and modify it slighty to my wises :P
But FreeER doesnt mind, he is here to help us, and he enjoys it (at least, he said that xD)
Creator of:
- DyTech
- DyWorld
- DyWorld-Dynamics
- DyWorld-Dynamics 2
Active since Factorio 0.6
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: Simple Wood Logger

Post by FreeER »

Animar wrote:because i tought it has to be ?
Nope. Try checking out some of the control.lua files from other mods or from the base campaign (or freeplay). The base files are in factorio\data\base\campaigns\, there are two directories one for the demo campaign and one for the full 'beta' campaign. Each of those has individual directories for each level (which has the locale, map data and control.lua for the level). The freeplay is in scenarios instead of campaigns. In lua tables are mostly used to store multiple variables together (think of structures) and if combined with metatables to approach object oriented programming (classes and polymorphism etc.), if you get into the metatables I won't be able to help much (I haven't used them lol).

When you use game.onevent you are calling a Factorio function that passes a function (by reference) to run whenever the event you specified as the first argument is called. You wouldn't try to run a function in c++ by saying (warning, this may be incredibly horrible c++ code, I've relatively little experience with it and I tried to do that off the top of my head. I apologize in advance.)

Code: Select all

struct ontick {[] function () {return "Hello"}}
You do not do so in lua either. That's the issue with using an unfamiliar programming language though, sometimes you get the wrong idea about something :) but there is always someone willing to say "that doesn't make sense" and try to help you out :)
<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
Post Reply

Return to “Modding help”