Welcome to Keen Software House Forums! Log in or Sign up to interact with the KSH community.
  1. You are currently browsing our forum as a guest. Create your own forum account to access all forum functionality.

Important Ingame API Issues

Discussion in 'Programming (In-game)' started by rexxar, Oct 10, 2017.

Thread Status:
This last post in this thread was made more than 31 days old.
  1. taleden Trainee Engineer

    Messages:
    48
    Here's a few bugs I still have on my list:

    1. Blocks of type IMyShipController (cockpits, flight seats, etc) have Inventories (block.GetInventory(0) works) but those inventory instances are not correctly linked back to the block (block.GetInventory(0).Owner is null). Hopefully this is already on your list since it's been reported a few times before.
      Code:
      List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>();
      GridTerminalSystem.GetBlocksOfType<IMyShipController>(blocks);
      Echo(""+blocks[0]+":");
      Echo(""+blocks[0].GetInventory(0).Owner);
      
      That should print the block name twice, but it only prints once because the Owner isn't set.
    2. There is no in-API way to discover the correct blueprint MyDefinitionId to queue into an Assembler to produce a given item; adding such a lookup would be fantastic but that is a feature request that was so far deemed impossible, so here is the related bug: calling CanUseBlueprint() with an invalid MyDefinitionId crashes the script rather than gracefully reporting failure.
      Code:
      List<IMyAssembler> asms = new List<IMyAssembler>();
      GridTerminalSystem.GetBlocksOfType<IMyAssembler>(asms);
      MyDefinitionId blueprint = MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/SteelPlate");
      Echo("?"+blueprint);
      Echo("="+asms[0].CanUseBlueprint(blueprint));
      blueprint = MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/invalid");
      Echo("?"+blueprint);
      Echo("="+asms[0].CanUseBlueprint(blueprint));
      
      The first test succeeds because SteelPlate is a valid blueprint. But in the second test, Parse() returns a MyDefinitionId object even though the definition string is wrong, which makes it impossible to know in advance that the following CanUseBlueprint() is going to throw an exception with that invalid definition object. So either Parse() needs to return null for invalid definition strings, or CanUseBlueprint() needs to gracefully return false on invalid definition objects.
    3. I haven't re-tested this in awhile, but I have in my notes that inven.TransferItemTo() gives a pretty useless return value. Transfers can report success when in fact zero items were moved because the destination was full, or the destination does not accept the item type, or possibly other errors. It seems like TransferItemTo() only reports connectivity, but there is already IsConnectedTo() for that purpose (and neither cover situations like conveyor tube size or conveyor sorter whitelist/blacklist restrictions).
    Thanks!
     
  2. Digi Senior Engineer

    Messages:
    2,384
    • IMyProjector.RemainingBlocksPerType has MyDefinitionBase keys, which means people can't use them properly as they're not whitelisted (and shouldn't be), the key should be replaced with MyDefinitionId.
     
  3. Lynnux Junior Engineer

    Messages:
    881
    On saving the game the Custom Data field seems to be written before the Save() method of a PB is called.
    At least this applies to the own Custom Data of the PB but I guess also to every terminal block which has been stored before.
     
    Last edited: Nov 13, 2017
  4. abrtn00101 Trainee Engineer

    Messages:
    59
    IMyMotorStator
    - The setters for UpperLimit and LowerLimit don't work. They always set some ridiculously high negative value, even if you pass a 0.
    - The units for the setters and getters of TargetVelocity don't match. The setters take radians per second and the getters give RPM.
     
  5. Malware Master Engineer

    Messages:
    9,600
    Well you shouldn't use CustomData for saving anyway... (95% joke, 5% serious :p )
     
  6. Digi Senior Engineer

    Messages:
    2,384
    MyResourceSinkComponent's properties that don't require a type input (CurrentInput, RequiredInput, etc) are giving values for electricity in an explicit manner.
    However, the MyResourceSourceComponent's similar properties use the first resource it can find, which can be problematic if you *assume* it's electricity when it's not.
    I see this as an issue as it's quite inconsistent.

    The MyResourceSourceComponent's properties are also not deprecated like MyResourceSinkComponent's properties, which makes it worse.

    This also affects modAPI btw but at least in modAPI we have the option to get by type, PB scripts do not as the sink/source methods that require a definition are not whitelisted.

    Changing this of course should be done carefully, those source properties could be used in the game where it expects non-electricity...

    This would be a non-issue if these would be exposed as interfaces and re-done properly in a more self-explanatory way, but the source properties should probably be deprecated regardless.
     
  7. Digi Senior Engineer

    Messages:
    2,384
    Runtime.TimeSinceLastRun is rounded to 0.016s, which means it kinda breaks accurate scheduling as a second becomes 0.96s and so on.
     
    • Agree Agree x 1
  8. Malware Master Engineer

    Messages:
    9,600
    It would be nice if we could find some way to stop Echo from clearing every tick, while still keeping it performance friendly...

    (also it really should sync only for those who have their console open...)


    Actually, I think the mechanism that's already in place should be able to deal with this nicely. I don't remember exactly how I wrote it, it might be it can be optimized a little more, but it should be fast enough. So with a little luck, all we need to do is to remove the clear...
     
    Last edited: Dec 8, 2017
  9. the1corrupted Trainee Engineer

    Messages:
    1
    Hello, everyone! So I was trying to access the rotor velocity, but it seems the pb doesn't have access to the rotor Velocity property.
     
  10. Wicorel Senior Engineer

    Messages:
    1,242
    It does, but the name changed in November.

    There are now two ways to get and set:
    imymstator.TargetVelocityRad;
    imymstator.TargetVelocityRPM;


    Please use something like MDK and it will tell you these types of things.
     
  11. Malware Master Engineer

    Messages:
    9,600
    That's not the current velocity is it?
     
    • Agree Agree x 2
  12. Burillo Junior Engineer

    Messages:
    648
    Yep, having current rotor velocity would be great.
     
  13. Lynnux Junior Engineer

    Messages:
    881
    VRageMath.Vector3D.Normalize() without parameter returns a double instead of a Vector3D.
     
  14. Digi Senior Engineer

    Messages:
    2,384
    That mutates the vector into a normalized vector and returns its old length if you wanna use it.
    It's not an issue and can be useful if you want both of those things or you just want to micro-optimize by avoiding a vector copy.
     
    • Informative Informative x 1
  15. Lynnux Junior Engineer

    Messages:
    881
    Ah, thanks for the info ! The description in Visual Studio is not clear ("the result is a..." sounds like the result of the method).
     
  16. Cranphin Trainee Engineer

    Messages:
    11
    This! It took me days to figure out what was happening.
    As a workaround, would it currently be accurate to just multiply the value with (1+1/24)?

    PS: To answer that last question, yes, that seems to work as a workaround, it's not so much rounding, each second just gets reported as 0.96 seconds exactly..
     
    Last edited: Jan 28, 2018
  17. Romanticiser Trainee Engineer

    Messages:
    2
    Guys,

    Look I'm new to programming in C#. I've been programming as part of my job in VB, VBA, SQL & Cobol and tiny bits of C for over 20 years and consider myself fairy intelligent.

    However I'm probably being an idiot but I can't seem to find a valid api call to get the inventory of a cargo container. All the tutorials either use IMyInventoryOwner which the programmable block says is obsolete or they use List&It which has type syntax errors with brackets all over the place.

    The thread "Guide] Accessing inventory from Programmable block" - in this forum is filled with code which is obsolete or so filled with syntax errors that the check code error list has scrollbars.

    I'm not after someone to write a script for me but some documentation that is valid for todays standard of programmable block would be massively helpful.

    The only up to date documentation on api's I can find for Cargo containers states there are no action list. Does this mean all methods & properties - like getitems().

    Is there some documentation for all api calls.

    So can someone please help?

    Thanks for your attention
    Dave
     
  18. Digi Senior Engineer

    Messages:
    2,384
    block.GetInventory(), returns null if the block has no inventory and has an optional index to get the one of the 2 inventories from refinery, asssembler, etc.

    Also this thread is not really the place for questions, just make a new thread next time :p or better yet the #programming-in-game channel in the keen discord server is the place for quick questions and answers.
     
    • Agree Agree x 1
  19. cheerkin Trainee Engineer

    Messages:
    62
    Can we have the PB class not instantiated if it is in turned off state?
    Using the constructor initialization raises a race problem when, for exampe, you are trying to weld the drone, and PB emerges faster than the block it needs to have refs on.
    This forces to abandon using constructor and to write custom "init" method with isInitialized check, this is kind of smelly
     
  20. Wicorel Senior Engineer

    Messages:
    1,242
    Same problem when grids are loaded. So constructor is never gonna be safe.
     
  21. EnjoyCoke Trainee Engineer

    Messages:
    72
    So, reading the GetExtraField text through PB to display on an LCD is no longer a possibility?
    All I get is 0, no matter how much oxygen is stored in the tank I attempt to get a readout from. What is happening? :(

    EDIT: This works for hydrogen tanks but NOT oxygen tanks.
     
    Last edited: Jun 11, 2018
  22. Wicorel Senior Engineer

    Messages:
    1,242
    I don't know what GetExtrafield is..

    Use the built-in properties for IMyGasTank: tank.FilledRatio
     
  23. Malware Master Engineer

    Messages:
    9,600
    @EnjoyCoke Avoid using the text for data recovery. Text parsing is slow and allocates memory. Always look for a proper API before resorting to that.

    I have also never heard of GetExtraField.
     
  24. EnjoyCoke Trainee Engineer

    Messages:
    72
    for(int i = 0; i < v0.Count; i++) {
    test += getExtraFieldFloat(v0, "Filled: (\\d+\\.?\\d*)%");

    This is the field I've always used and which has worked without many issues until now.
    What would you suggest using instead, exactly? Simply replace "getExtraFieldFloat(etc)" with "tank.FilledRatio(etc)"?
     
  25. Malware Master Engineer

    Messages:
    9,600
    @EnjoyCoke getExtraFieldFloat must be a custom function, because #1 it uses the wrong naming convention (lowercase get) and #2 it doesn't exist in the API.
     
  26. EnjoyCoke Trainee Engineer

    Messages:
    72
    Code:
    
    public Program()
    {
      Runtime.UpdateFrequency = UpdateFrequency.Update1;
    }
    
    void Main(string argument)
    {
      // block declarations
      string ERR_TXT = "";
      List<IMyTerminalBlock> v0 = new List<IMyTerminalBlock>();
      GridTerminalSystem.GetBlocksOfType<IMyOxygenTank>(v0, filterOxy);
      if(v0.Count == 0) {
    	ERR_TXT += "no Oxygen Tank blocks found\n";
      }
      List<IMyTerminalBlock> l1 = new List<IMyTerminalBlock>();
      IMyTextPanel v1 = null;
      GridTerminalSystem.GetBlocksOfType<IMyTextPanel>(l1);
      if(l1.Count == 0) {
    	ERR_TXT += "no LCD Panel blocks found\n";
      }
      else {
    	for(int i = 0; i < l1.Count; i++) {
    	  if(l1[i].CustomName == "LCD Panel 5") {
    		v1 = (IMyTextPanel)l1[i];
    		break;
    	  }
    	}
    	if(v1 == null) {
    	  ERR_TXT += "no LCD Panel block named LCD Panel 5 found\n";
    	}
      }
      // user variable declarations
      float test = 0.0f;
      // display errors
      if(ERR_TXT != "") {
    	Echo("Script Errors:\n"+ERR_TXT+"(make sure block ownership is set correctly)");
      }
      else {Echo("");}
      // logic
      for(int i = 0; i < v0.Count; i++) {
    	test += getExtraFieldFloat(v0[i], "Filled:(\\d+\\.?\\d*)%");
      }
      ((IMyTextPanel)v1).WritePublicText(""+Math.Round((test), 2)+"\n"+
    	"\n"+
    	"", false);
      ((IMyTextPanel)v1).ShowPublicTextOnScreen();
    }
    
    const string MULTIPLIERS = ".kMGTPEZY";
    
    bool filterOxy(IMyTerminalBlock block) {
      return !block.BlockDefinition.SubtypeId.Contains("Hydrogen");
    }
    
    float getExtraFieldFloat(IMyTerminalBlock block, string regexString) {
      System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(regexString, System.Text.RegularExpressions.RegexOptions.Singleline);
      float result = 0.0f;
      double parsedDouble;
      System.Text.RegularExpressions.Match match = regex.Match(block.DetailedInfo);
      if (match.Success) {
    	if (Double.TryParse(match.Groups[1].Value, out parsedDouble)) {
    	  result = (float) parsedDouble;
    	}
    	if(MULTIPLIERS.IndexOf(match.Groups[2].Value) > -1) {
    	  result = result * (float) Math.Pow(1000.0, MULTIPLIERS.IndexOf(match.Groups[2].Value));
    	}
      }
      return result;
    }
    
    EDIT: I think this should work.
     
  27. Malware Master Engineer

    Messages:
    9,600
    @EnjoyCoke Yes, there you have the custom getExtraFieldFloat function. It is terribly slow though I see, since it not only parses strings but uses regular expressions and even recompiles a regular expression every time it's run.

    I don't have access to the API here so typo/memory warning, but the tanks' `.FilledRatio` should a factor (between 0.0 and 1.0) that would be several orders of magnitude faster to use.
     
  28. EnjoyCoke Trainee Engineer

    Messages:
    72
    So rather than run it through system.text.regularexpression.regex etc etc etc, I could just run a "tank.FilledRatio" command? This is a new function, non?
    --- Automerge ---
    Also, how to disable auto-jetpack? (off-topic, I know)
     
  29. Malware Master Engineer

    Messages:
    9,600
    @EnjoyCoke It is not a new function. It's a property that's been there for quite a while now. To get percent you'd do tank.FilledRatio * 100. Or even use the built-in formatting in C#. So... you could do this:

    Code:
    for(int i = 0; i < v0.Count; i++) {
    	var tank = (IMyOxygenTank)v0;
    		test += $"Filled: {tank.FilledRatio:P0}");
    }
    
    This part:
    Code:
    $"Filled: {tank.FIlledRatio:P0]" 
    
    is called an interpolated string.

    (they really should be using markdown in this forum, not this... strange... thing... I'm having trouble formatting :p )

    Also, please don't use Update1 for this. You do not need to update this information every tick. Only the rarest scripts need to run every tick, Update10 or even Update100 should suffice. Especially with the amount of allocations you're doing in your script there which really not necessary. You should cache and reuse, not always create and fetch :)

    As for the auto jetpack, you can't, as far as I know
     
  30. EnjoyCoke Trainee Engineer

    Messages:
    72
    I normally run it with 100, just didn't bother for this example ;)
    But thanks :D
    God I hate smilies on boards like this... did you use
    Code:
    :p
    ?
     
    Last edited: Jun 12, 2018
    • Like Like x 1
Thread Status:
This last post in this thread was made more than 31 days old.