Game script, api.res.constructionRep.getAll

Willkommen in der Transport Fever Community

Welcome to the fan community of Transport Fever and Train Fever, the economic simulators of Urban Games. The community is free for you to share and inform yourself about the game. We cultivate a friendly and objective interaction with each other and our team will be happy to answer any questions you may have.

 

Registration and use is of course free for you.

 

We wish you a lot of fun and hope for active participation.

The Team of the Transport-Fever Community

  • Hi


    I have downloaded the demo clock script from the Wiki, and from this working example I add my own code to see what can be done. But the first few lines I add create a headache for me.

    Code
    1. -- search for new industries
    2. local allConstructions = api.res.constructionRep.getAll()
    3. print ("allConstructions =",#allConstructions ," /UG_melectro_demo_clock")
    4. for i = 0, #allConstructions-1 do
    5. if allConstructions[i] == "industry/tools_factory.con" then
    6. print ("Construction name =",allConstructions[i] ," /UG_melectro_demo_clock")
    7. end
    8. end

    The code works so far that it can find one Tool factory and it is printed in the console.


    I was happy to see that in my new free game i got 538 constructions, but while adding more industries or f.eg. railway stations, it will not increase the number of "allConstructions".


    What is wrong?


    is this the result as the function is only run one time ?

  • ConstructionRep -> Industry types (Not build constructions, the blueprint con file data)


    Any Repository => something loaded from Model or Construction.con -> these are definition of something. Not an instance of some game element.

    Any game element is represented by some entity (referenced by entityid) and it's component. All the entities are run by the systems, they get component data from entities to run the game.


    If you have an entityid you can use api.engine.getComponent(entityId, componentTypeId)


    The componentTypeId is something from api.type.ComponentType, example: api.type.ComponentType.SIM_BUILDING


    There is a stockList,

    api.engine.system.simEntityAtStockSystem.getStockEntities(<stockListId>, <num unknown to me>) -> list of cargo entities.

    api.engine.system.simEntityAtStockSystem.getStockEntities(<stockListId>, 0) (first stock, don't ask me where to get the number)


    api.engine.system.simCargoSystem.getSimCargosForSource(<stockListId>)


    Otherwise try to see if you can get the info via Advanced Statistics


    However, sometimes it is easier to use the old game apis, maybe the needed info is already in there.



    There is api.system.stockListSystem.getCargoType2stockList2sourceAndCount too..

  • I have found in an old TpF1 code, this solution: (it seems to work even in TpF2)

    allConstructions = game.interface.getEntities({ pos = {0,0}, radius = 900000 }, { type = "CONSTRUCTION" })


    in this table I can get the EntityId for the needed factories , so the next step to find the cargo stored at these factories would be using something that you wrote.


    getStockEntities(<stockListId>, 0) (first stock, don't ask me where to get the number)

    But as I'm not allowed to ask you how to get the "StockListId", I have to continue the guessing.

    By the way earlier this year I pointed on a strange info in the Wiki list. There are two SimEntityAtBuilding

    one for "entities waiting at industries".and the second for "entities waiting at buildings". After emailing UG I got the answer that the first one (for industry) is wrong it should be named: SimEntityAtStock.

    It is still not updated.

    Anyway, by using the right name this could probably be the way to get the stockListId, or am I totally wrong?

  • I do not get any data from the script out from the factory. (The factory is producing goods and there are incoming goods in stock and products is leaving the factory to a nearby station)

    I have the Entity id (Entities[i] = 25237, #Entities = 1) and CompType= 27 ( = SIM_BUILDING)

    but after the call to local Comp = api.engine.getComponent(Entities[i], CompType)

    I get only a nil value on the Component.


    But when I test to set CompType = STOCK_LIST, I get different values for each program loop, last value was userdata = 000001C6DB72D188


    I guess that the userdata is a pointer address to a table. It doesn't feel right, that's why I write this to ask for more assistance.

  • See here, I am using my API left bottom Button -> Inspector Window. Second Tab has a "Get Entities" function, we see a Construction and SIM_BUILDING



    You want the whole UG API Madness, let's do it. You have a construction entity.

    1. Get the construction component,

    2. Use the simBuilding(s) EntityId to get component SIM_BUILDING

    3. we have a list Entity Ids of Stocks => stockList

    4. use simEntityAtStockSystem to get count.


    Dump of UG Console:



    Easy? Yeah... There are tons other apis the api.engine.systems ,so it's likely there is an easier way... but with the good documentation...


    There are some industry mods out there, maybe look what apis they use to get to a easier code path...




    -edit- More madness while we are at whole thing. Let's say, we have a SIM_BUILDING and want a construction?


    api.system.streetConnectorSystem.getConstructionEntityForSimBuilding

    https://transportfever2.com/wi…ctionEntityForSimBuilding



  • I can make you happy by telling: I have your API installed, and it is very versatile and advanced. For me this has been a huge step to pass. I and probably many others wishes some kind of manual or tutorial.


    In the post above you make it clear for me to follow this part of your API. I assume there are a lot of more functions that you have put into the package,


    Long time has passed and today I finally got the information on where to find all the names that can be used in the calls, thanks to your API !


    I can also see the data and I can see that the stocklist value in your print screen has the same value as the entity of the construction = 14088. In my game it is also the same 25237, is this a coincidence or is it always the same value?


    if I interpret the information I see in the Inspector, I do not find the file name anywhere (in SIM_BUILDING) other than under CONSTRUCTION.

    To find only the factories I am interested in, I currently see no other solution than to get this huge amount of data from CONSTRUCTION, if that is what you mean with "madness".


    I'll continue my experiments tomorrow, for now a big Thank you to you !

  • Yeah, the construction should have the stocklist. At least my inspector shows there is a stocklist.


    But as api.engine.getComponent(<constructionentityid>, api.type.ComponentType.STOCK_LIST) returns userdata.


    Damn. So still you have to use some api.system.* functions to get meaningfull data or old game.* interfaces

  • if I interpret the information I see in the Inspector, I do not find the file name anywhere (in SIM_BUILDING) other than under CONSTRUCTION.

    To find only the factories I am interested in, I currently see no other solution than to get this huge amount of data from CONSTRUCTION,

    You can get all industries with

    Code
    1. game.interface.getEntities({radius=math.huge}, { type = "SIM_BUILDING"})

    and then check the corresponding construction

  • You can get all industries with

    I can definitely see the benefit of using SIM_BUILDING as this table currently contains 69 entities against 1584 if CONSTRUCTION is used for the loop search.

    If I now use eis_os excellent API function Inspector and look at the entity value for SIM_BUILDING, I can not find a "fileName". The name shown to the right in the list above, is editable by the player and therefore it can not be used.

    If the stockList always contains the same value as CONSTRUCTION Entity as eis_os wrote "should"

    Yeah, the construction should have the stocklist.

    and I assume since previous post, then it's clear to me to use SIM_BUILING Entities followed by a second read in the CONSTRUCTION entity table and that will reduce the CPU load as it doesn't need a large search loop through all the data, but still I need the CONSTRUCTION Entites table to get "fileName", or am I wrong?


    Code
    1. local Constructions = game.interface.getEntities({ pos = {0,0}, radius = math.huge }, { type = "CONSTRUCTION" })


    VacuumTube I can not figure out what the continuation should be like to find the factory if my code below isn't what you have in your mind, The code gives me the Cargo @stock, but is it the most efficient and least system demanding? I read about "for _,id in pairs(IDs) do -- _ for unneeded variable", like Claude I have some difficulties to follow that type of setup. A question, will it do the loop more efficient? Please describe.

    FYI, I have studied the helpful thread: getEntities => type ? - Modding Allgemein - Transport Fever Community

    Here is what SIM_BUILDING reports: (the list was too long to fit in one screendump.)

  • The proper API way, if you have a sim building entity, at least from API description as mentioned earlier.

    industryEntity is a SIM_BUILDING

    streetConnectorSystem.getConstructionEntityForSimBuilding(industryEntityId) => should give you a construction entityid


    You should ask UG for a complete guide how to do it properly.

    And if you have an answer, please post them so others can learn too.

  • I am still not sure what exactly you want to achieve.

    Does your code work?


    In the SimBuilding Data, the "stockList" Property is always the construction ID right?


    Regarding Performance:

    -game.interface.getEntities is expensive, the more Ids are returned. If "includeData" is used, it takes even longer.

    -If using only a specific region (circle with pos and radius), it's faster. (applicable in your case?) See also runtimes in Advanced Statistics.

    -The new api with getComponent is very fast compared to game.interface.getEntity. But this is only relevant if this repeated many times... Like in Adv Stat. Probably doesnt matter in your case.


    I attach my timer.

    Use:

    Code
    1. local timer = require "myfolder/timer"
    2. timer.start()
    3. --do sth
    4. calctime = timer.stop()

    or

    Code
    1. local function a()
    2.     local q = 42*42
    3. end
    4. timer.timefunc(a,1000) -- timefunc(function, n, ...args)
  • Does your code work?

    Yes it works, but I'm not sure if it is the best efficient. I could see without any time measuring an enormous improvement after using SIM_BUILDING table instead of CONSTRUCTION. As I wrote the SIM_BUILDING table has less data.

    In the SimBuilding Data, the "stockList" Property is always the construction ID right?

    I hope it is so. All industries that I now have studied has the same value.



    melectro wrote (in removed post)

    Yes, true. I removed it as other parts in the text was wrong. I never came to rewrite it as you eis_os were so quick to answer:thumbup:

  • Here are the results from the Swedish test....;)


    Following part of the code has been examined and measured. It will show the difference between of using CONSTRUCTION and SIM_BUILDING table to find CARGO at stock in a selected industry. In this example I have only placed one unique industry among many vanilla industries on my test map. I have removed the logic after the industry has been found, so this is showing the time it takes just to find the industry on a small map in the beginning of a new game. It will be worse as longer the game is running, as more buildings will increase the CONSTRUCTION table.


    In this experiment I got 69 items in the SIM_BUILDING table and 1584 items in the CONSTRUCTION table


    code used time (ms)
    game.interface.getEntities "CONSTRUCTION"3 to 4
    game.interface.getEntities "SIM_BUILDING"1 to 3
    for loop using SIM_BUILDING3 to 4
    for loop using CONSTRUCTION48 to 54


    The results I got confirms what I saw earlier as each game script loop is repeated about every 200ms. Using CONSTRUCTION table has a big impact on the performance as it takes about 25% to execute. The time will also vary depending on the computer system. This was tested on a computer based on, Intel(R) Core(TM) i9-9900KF CPU @ 3.60GHz, 32.0 GB, Geforce RTX 2080, CPU is running @ 4800 MHz and GPU @ 1965 MHz.

  • Finding the industry is at the moment solved, now it's getting interesting. Reading stored items in stock works almost 100%, but when an unknown vehicle delivers items to the factory it should be read in the game script. My thought was at the first moment "easy", but no. The stored value is reduced by the production while vehicles are unloading. That means it is tricky not to miss any items as these values are increasing and decreasing at the same time. Looking on Consumption though seems to be better as this value is ending on the same value as the cargo amount was on the vehicle, but how to get it?

    I have also tested to read production by using produced = game.interface.getIndustryProduction(EntityId)

    For industries that are producing something the code works, but I get only "zero" in production on industry that doesn't produce anything, like an export industry.

    Reading Production from this Industry (that doesn't produce anything) I only get = 0, it should have been 25 like it will be if read production on a producing industry.


    Now I opened the TransportFever2.exe in Notepad++ to see if there could be something else to read and I searched for "getIndustry" This is what I found:

    Code
    1. getIndustryProduction getIndustryProductionLimit getIndustryShipping getIndustryTransportRating

    Looking around this place in the code of TransportFever2, gave nothing.


    For me it looks like the game doesn't do right when there is an only consuming industry. None of these four values are usable.


    I have spent some time to try to find how to read the Consumptions values. I used eis_os API inspector and I can't find any useful data. Is there a way to read these Consumption data?


    edit:

    In one of the vanilla campaign (03) I found a code to get itemsConsumed

    local c = game.interface.getEntity(game.interface.getEntity(params.glasgow_steelmill).simBuildings[1]).itemsConsumed

    changing the steelmill entityiD to my factory is giving me an address to a table. I wish to learn how to look into a table to get the names of the data to be read. I guess that the API will have some function in the console.

  • On the 13th Nov 2020 I got an PN answer from eis_os, writing


    I have in my game script code placed the rename function inside guiUpdate = function()

    Now I can see which lua thread runs my code. Next step I was trying is to dump some variables, but I'm not successful, it results always in "nil".


    Please don't laugh I'm still learning. What is wrong?


  • This is because a game_script is heavily running thread. As UG didn't want me to tell how to sync to it, it's not possible to reliable know the current state this lua is. maybe it's somewhere in a deep nested function (Note: the summer update made things more async, so it's even worse)


    game.interface.getEntity(<entityid sim building>) (using SIM BUILDING Entity of a construction) shows a lot of data.


    Technical internally it will use the same entity components.

    The problem with UGs api.* functions is, they really aren't finished. Every time you see userdata, UG missed a part of the puzzle.

    However, sometimes it is easier to use the old game apis, maybe the needed info is already in there.

    game.interface.getEntity and api.system.* are completely different beasts. The first does a lot of data computing to get meaningful data and are made for TPF1/2 campaigns. The api.* are more interfaces to the direct internals of the game.


    The data you get via game.interface.getEntity are the past performance of an industry.


    Internally the game normally subscribes to state changes to know if something happens via the Enity Systems, but that isn't doable from the lua side.
    So while TPF2 is a lot faster and open, the CommonAPI TPF1 was a lot more flexible because there was only one thread and the interfaces was a lot more clearer.


    The question really is. What do you want to do? What is your goal in the end. Then you can select the right "tools"


    PS: Renaming shouldn't be necessary. game_script gui* is run in "GUI Thread", the other updates are run in "Script Thread". Renaming should be only done once, otherwise you fill your log with debug info...

  • the final goal is produce tracks and every item of track delivered to the warehouse will make tracks available to be used for track build.

    I have an example from TpF1 but it is done as a campaign. I wish to get this to work in a game script in TpF2, but I struggle to read the data.


    • read number of cargo items (Standard or High speed track) delivered to the warehouse industry
    • for each delivered standard track, add numbers of items to the stock (separate variable) of available standard track
    • same for high speed track
    • when tracks in stock is emptied -> disable the track build function
    • when tracks are delivered to warehouse-> enable track build function

    Renaming should be only done once,

    I fixed that after my previous post, and I will remove it when finished. The first try was actually by selecting GUI thread, but the result of the variables where nil, so that's why I placed the rename to get a confirm on the thread name.