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.

Ingame Programming missing API and functions and known issues

Discussion in 'Programming (In-game)' started by mexmer, Apr 23, 2015.

Thread Status:
Not open for further replies.
This last post in this thread was made more than 31 days old.
  1. Wicorel Senior Engineer

    Messages:
    1,243
    You'll need a MOD for that, not in-game script.
     
  2. Saphi Trainee Engineer

    Messages:
    33
    why I need a mod for such a simple thing?
     
  3. Phoera Senior Engineer

    Messages:
    1,713
    cuz grid can't send messages.
     
    • Agree Agree x 1
  4. Wicorel Senior Engineer

    Messages:
    1,243
    Nor receive.
     
  5. EnjoyCoke Trainee Engineer

    Messages:
    72
    Suggesting API controls for text panels/ LCDs so that programmable blocks can set textures to be displayed and swap between them (so that when my hangar doors open, the LCD switches to "DANGER", and upon being fully opened switches to "ENTER" - and in between that has a big, red "DO NOT ENTER" and "DANGER" sign swapping every 1 second).
    Am I making any sense?
    Also, same goes for sound block. Programmable block switching which sound to play would make for some awesome opportunities.
     
  6. Phoera Senior Engineer

    Messages:
    1,713
    @EnjoyCoke , and who forbids you to do that?
    Code:
      public interface IMyTextPanel : IMyFunctionalBlock
        {
            bool WritePublicText(string value, bool append = false);
            string GetPublicText();
    
            bool WritePublicTitle(string value, bool append = false);
            string GetPublicTitle();
    
            [Obsolete("LCD private text is deprecated")]
            bool WritePrivateText(string value, bool append = false);
            [Obsolete("LCD private text is deprecated")]
            string GetPrivateText();
    
            [Obsolete("LCD private text is deprecated")]
            bool WritePrivateTitle(string value, bool append = false);
            [Obsolete("LCD private text is deprecated")]
            string GetPrivateTitle();
    
            void AddImageToSelection(string id, bool checkExistence = false);
            void AddImagesToSelection(List<string> ids, bool checkExistence = false);
    
            void RemoveImageFromSelection(string id, bool removeDuplicates = false);
            void RemoveImagesFromSelection(List<string> ids, bool removeDuplicates = false);
    
            void ClearImagesFromSelection();
    
            /// <summary>
            /// Outputs the selected image ids to the specified list.
            ///
            /// NOTE: List is not cleared internally.
            /// </summary>
            /// <param name="output"></param>
            void GetSelectedImages(List<string> output);
    
            /// <summary>
            /// The image that is currently shown on the screen.
            ///
            /// Returns NULL if there are no images selected OR the screen is in text mode.
            /// </summary>
            string CurrentlyShownImage { get; }
    
            void ShowPublicTextOnScreen();
            [Obsolete("LCD private text is deprecated")]
            void ShowPrivateTextOnScreen();
            void ShowTextureOnScreen();
            void SetShowOnScreen(ShowTextOnScreenFlag set);
    
            /// <summary>
            /// Indicates what should be shown on the screen, none being an image.
            /// </summary>
            ShowTextOnScreenFlag ShowOnScreen { get; }
    
            /// <summary>
            /// Returns true if the ShowOnScreen flag is set to either PUBLIC or PRIVATE
            /// </summary>
            bool ShowText { get; }
        }
     
    • Agree Agree x 1
  7. XkyDiver Apprentice Engineer

    Messages:
    360
    I feel like the Programming Block sandbox should protect against moving negative amounts of inventory between containers. I realize I'm a horrible programmer, and anyone with half a brain won't have this issue, but if you do a cargo.GetInventory(0).TransferItemFrom(othercargo.GetInventory(0), 0, 0, true, -x); you'll end up with a potential crash as a negative value is placed in the target container, which then depletes the grid of that item type before imploding the cargo container. :\
     
    • Agree Agree x 3
  8. Jzuken Apprentice Engineer

    Messages:
    127
    Is there an API for wheels/rotors safety lock override?

    Like .ApplyAction("SafetyLock_On"); ?
     
  9. Wicorel Senior Engineer

    Messages:
    1,243
  10. Jzuken Apprentice Engineer

    Messages:
    127
  11. Wicorel Senior Engineer

    Messages:
    1,243
    Not yet. That's in Dev 1.172 (current). Stable update will probably be Friday.
     
    • Agree Agree x 1
  12. Inflex Developer Staff

    Messages:
    397
    Next stable update will most probably not contain last batch of API updates
     
  13. Equinox Trainee Engineer

    Messages:
    18
    I've been recently mucking around with smarter piloting scripts and one limitation I've found is that you can't read definition values for blocks (and items). This information is directly exposed in game most of the time, and allowing scripts read only access would likely be a fairly minor change in most cases. This primarily came up when trying to determine the maximum thrust of thrusters, and the maximum torque of gyros -- two things that essentially became a copy of portions of the published source code with a lookup table for relevant definition values.
    This could possibly be implemented in a "GetValue(string name)" type method that is backed by reflection.
    Some places this would be useful:
    - Scripted organization of oxygen and hydrogen bottles (fill value is stored in the definition)
    - Determining power consumption of blocks that don't list it in detailed info
    - Figuring out how many components in takes to assemble something

    In addition to accessing a grid's center of mass being able to access it's inertial tensor and angular momentum would be useful as well. Inertial tensor so you can get an idea of how the gyros will perform, angular momentum/velocity so you know how fast it's turning (without gimbal locking yaw/pitch/roll)

    You can actually get the orientation of a grid quite easily using something like Quaternion.fromMatrix(grid.WorldPositon). In theory you could implement angular velocity by computing the minimum angle rotation between two orientation samples, however this may not be accurate, as it might not have been minimum angle.
     
  14. Phoera Senior Engineer

    Messages:
    1,713
    i am not sure, but i saw that power source and sink is exposed now.
    no thanks.
     
  15. Regn Trainee Engineer

    Messages:
    74
    Dev 1.172
    IMyAssember.Status - null
    IMyAssember.Status.ToString() - null
    IMyAssember.GetValueString("Status") - null
    IMyAssember.NotWorking - null

    IMyAssember.MissingItems - null
    IMyAssember.GetValueBool("MissingItems") - null
    IMyAssembler.DisassembleEnabled - obsolete (refers to 'Mode' 'property', case sensitive)
    IMyAssembler.property - null (don't know how to utilize this)
    IMyAssembler.Property - null (don't know how to utilize this)

    Works with a bit of tweaking:
    IMyAirvent.Status.ToString() -
    unexpectedly influenced by bool CanPressurize = false
    if (IMyDoor.Status == "Open") - expected to be able to write it like this, but result cannot convert type/string
    if (IMyDoor.Status.ToString() == "Open") - solution, feels a bit derpy, but then again I'm not used to C#.

    Ps. I don't know where to post this. Up to several threads are touching this topic.
     
    Last edited: Jan 30, 2017
  16. Digi Senior Engineer

    Messages:
    2,384
    @Regn
    You should use Visual Studio or some other IDE to help you autocomplete valid types and check syntax and all that.

    The IMyAssember parts seem so random, none of those are in the interface or the ones that exist are used improperly...
    Where are you even getting these things from ?

    Obsolete tags are intentional, it means you should not use the thing, it's left there however to not break existing scripts.
    Use something like this instead:
    Code:
    if(assembler.Mode == MyAssemblerMode.Disassembly)
    {
        // ...
    }
    IMyDoor.Status is type DoorStatus which is an enum (just like MyAssemblerMode), not a string. Don't convert it to a string when you can simply compare it to the proper enum.
     
    Last edited: Jan 30, 2017
    • Agree Agree x 1
  17. Regn Trainee Engineer

    Messages:
    74
    http://forum.keenswh.com/threads/modapi-changes-jan-26.7392280/
    If you click on the "Ingame PB" tab below, you'll find what I'm after.

    So, how do I get to MissingItems?

    MyAssembler.cs
    Line: 47-55
    PHP:
            public enum StateEnum
            
    {
                
    Ok,
                
    Disabled,
                
    NotWorking,
                
    NotEnoughPower,
                
    MissingItems,
                
    InventoryFull,
            }
    All I want is to do this

    PHP:
    if (thisAssembler.Status == "MissingItems") {
        
    sb_cic.AppendLine("An item is missing.");
    } else {
        
    sb_cic.AppendLine("An item is not missing.");
    }
    or this (if I have to)

    PHP:
    if (thisAssembler.Status.ToString() == "MissingItems") {
        
    sb_cic.AppendLine("An item is missing.");
    } else {
        
    sb_cic.AppendLine("An item is not missing.");
    }
    or this

    PHP:
    if (thisAssembler.GetValue("Status") == "MissingItems") {
        
    sb_cic.AppendLine("An item is missing.");
    } else {
        
    sb_cic.AppendLine("An item is not missing.");
    }
    or this (if I have to)

    PHP:
    if (thisAssembler.GetValueString("Status") == "MissingItems") {
        
    sb_cic.AppendLine("An item is missing.");
    } else {
        
    sb_cic.AppendLine("An item is not missing.");
    }
    or this (if I have to)

    PHP:
    if (thisAssembler.GetValueBool("MissingItems") == true) {
        
    sb_cic.AppendLine("An item is missing.");
    } else {
        
    sb_cic.AppendLine("An item is not missing.");
    }
    or this (if I have to)

    PHP:
    if (thisAssembler.GetValue("MissingItems") == true) {
        
    sb_cic.AppendLine("An item is missing.");
    } else {
        
    sb_cic.AppendLine("An item is not missing.");
    }
    or this (if I have to)

    PHP:
    if (thisAssembler.MissingItems == true) {
        
    sb_cic.AppendLine("An item is missing.");
    } else {
        
    sb_cic.AppendLine("An item is not missing.");
    }
    or, if MissingItems is a set of items I can even look for that.

    or this

    if (assembler.Status == AssemblerStatus.MissingItems)

    But, none of these work, even though some of them work for IMyDoor and IMyAirVent (as an example), and some of them are said to work in the stylesheet found here http://forum.keenswh.com/threads/modapi-changes-jan-26.7392280/ under "Ingame PB".

    And you're telling me that I'm doing it incorrectly, so, how do I do it? Can you give me an example using the assembler?
     
    Last edited: Jan 30, 2017
  18. Digi Senior Engineer

    Messages:
    2,384
    I dunno why State is noted there because it doesn't exist in the interfaces =)

    I already gave you an example how to compare enums properly with the Mode field... I edited to encapsulate it with code tags to make it more obvious :}

    GetValue<Type>("name") are only used for properties.
    You can see the properties of a block using GetProperties() on it.

    You should join the discord chat if you want to ask for help in a more quickfire way, you can find the link on the main page of the forum on the right side.
     
    Last edited: Jan 30, 2017
  19. Blargmode Trainee Engineer

    Messages:
    21
    Two minor things:
    IMySolarPanel.Enabled doesn't work. "'IMySolarPanel' dosen't contain a definition of 'Enabled' ..."
    The solar panel and reactor has a .MaxOutput, but the battery doesn't. "'IMyBatteryBlock' dosen't contain a definition of 'MaxOutput' ..."
     
  20. taleden Trainee Engineer

    Messages:
    48
    How is one intended to make use of the new IMyProductionBlock.CanUseBlueprint() or AddQueueItem() ? Both require a MyDefinitionId for the blueprint, but I can find no way to enumerate the available blueprints or even to look one up given the desired output item. These are all prohibited:
    • Sandbox.Definitions.MyBlueprintDefinition
    • Sandbox.Definitions.MyBlueprintDefinitionBase
    • Sandbox.Definitions.MyDefinitionManager
    • VRage.Game.MyObjectBuilder_BlueprintDefinition
    and so the only method I can find so far is to call for example MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/SteelPlate"). However this is not reliable, since the blueprint subtypes do not always match the produced item; for example the subtype of a Motor component is simply "Motor" but the corresponding blueprint subtype is actually "MotorComponent", and there seems to be no way to learn this without inspecting the Blueprints.sbc XML file and hardcoding the mappings into the script, which will of course break if any of those names are ever changed, nor can it support items and blueprints added by other mods.

    Even worse, MyDefinitionId.Parse() does not validate the subtype and CanUseBlueprint() does not handle invalid inputs, so if you attempt an incorrect name such as "MyObjectBuilder_BlueprintDefinition/Motor", the returned struct *appears* functional but throws an exception if you pass it to CanUseBlueprint():
    Code:
    public void Main(string argument) {
    	List<IMyTerminalBlock> blocks;
    	IMyAssembler assembler;
    	MyDefinitionId blueprint;
    	
    	blocks = new List<IMyTerminalBlock>();
    	GridTerminalSystem.GetBlocksOfType<IMyAssembler>(blocks);
    	assembler = blocks[0] as IMyAssembler;
    	Echo("" + assembler);
    	
    	blueprint = MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/Motor");
    	Echo("" + blueprint);
    	Echo("" + assembler.CanUseBlueprint(blueprint));
    }
    If we're going to make intelligent use of these fantastic new production queue management methods, we really need a more reliable way to fetch available blueprints and/or look them up according to the desired output item; bonus points if this can be dynamic so that it automatically supports any items, production blocks or blueprints added by other mods.
     
  21. rexxar Senior Engineer

    Messages:
    1,530
    @taleden The problem is the blueprints and definitions simply are not accessible from the ingame namespace. We can't add access because it would cause a circular dependency in the source. What you have now is pretty much the only thing we could give you. This is because the refactor away from the Sandbox namespaces was never finished, so some important bits got left behind. The refactor might be finished in the future, it's hard to say.

    For now your only option is to find some way to hardcode an ID for each component type. It really sucks, but it's at least possible.
     
    • Informative Informative x 1
  22. taleden Trainee Engineer

    Messages:
    48
    That's too bad, but thanks for the explanation. Would it be possible to at least offer more robust validation or error handling so that CanUseBlueprint(MyDefinitionId.Parse(wrongtext)) will simply return false rather than throwing an exception and crashing the PB script? That would make it feasible to let users provide blueprint mappings for their modded items, for example, but as it stands I wouldn't want to allow that because so many users would make a typo and then complain that my script is broken.

    Also, is there any chance of raising the 100kb PB code length limit? Please? If I send you beer? I don't think it adds much protection on top of the "complexity" limits that are already enforced, and I have been riding that line for a long time now. I'm at the point of having to remove comments and use confusing variable names and code structures just to free up a few bytes; development of TIM is basically halted now because there's no room in that code size limit to add any more features.
     
    • Like Like x 1
    • Agree Agree x 1
  23. twotwinbrothers Trainee Engineer

    Messages:
    25
    IMylandinggear

    bool is different then string
    bool = Autolock
    string =AutoLock
    gear.ApplyAction("Autolock"); only works whit small L for Lock

    IMyShipController

    horizon inducator in space
    i now that the horizon inducator wil not be show on hud in space
    but this only thing i want to do is tu uncheck/check the checkbox for horizon in the terminal menu whit the programmeble block.
    Get it to show the status on the lcd whit my menu script but wen i toggle it it will crash the script

    internal dampeners on asteroid station
    check box in the terminal menu wil not be uncheck/ check whit the programmable block.
    pit.ApplyAction("DampenersOverride");

    Also wen you uncheck HorizonIndicator in terminal menu internal Dampeners will be uncheck as well on space station

    string MainCockpit don't work
    check box in the terminal menu wil be uncheck/ check whit the programmable block.
    but i can get it status
    if (pit.MainCockpit){
    return "Status: On";
    else
    return "Status: Off";
    }
    IMyCargoContainer

    Can not be rename whit IMyTerminalBlock and IMyFunctionalBlock.

    like: term.CustomName =(itemname + term.CustomName);
    i use this to add a tag to all terminalblocks
     
    Last edited: Feb 27, 2017
  24. krypt-lynx Apprentice Engineer

    Messages:
    175
    Once more time with extra argument:
    It cannot be worked around: since you creating your own NotImplementedException class VS starting to insert this:

    Code:
            private void Test()
            {
                throw new System.NotImplementedException();
            }
    And you still need to fix it manually.
     
  25. krypt-lynx Apprentice Engineer

    Messages:
    175
    'bool string.Contains(string testSequence, StringComparison comparison)' is prohibited

    In same time:
    bool Equals(String value, StringComparison comparisonType);
    bool StartsWith(String value, StringComparison comparisonType);

    are allowed
    ----
    string.Contains is VRage string extension:

    Code:
    public static bool Contains(this String text, string testSequence, StringComparison comparison)
    {
        return text.IndexOf(testSequence, comparison) != -1;
    }
    Quite misleading, I need to admit.
     
    Last edited: Jul 6, 2017
    • Like Like x 1
  26. krypt-lynx Apprentice Engineer

    Messages:
    175
    There is no way to recover Timer Block related logic after saved game load anymore.
    Reasons:
    - there is no way to get passed time since last run in Save() method
    - there is no way to calculate time passed since Program() called
    - there is no way to get current countdown value from Timer
    - there is no way to start timer from constructor anymore (few versions ago it was possible, it was the last workaround)

    As result, after game load and until run I don't know that is happenning: Was script called by user or Timer ticked?
    There is three ways to resolve this situation (implementation of any of them will fix situation):
    - Allow access to "ingame time since world creation" variable;
    - Allow to read countdown value of timer;
    - Allow to start actions from constructor (Program());

    I will prefer to see second one, but all of them is preferable.

    @rexxar, please, write something there. I need to know, if issue is processed, even if it will not solved.
     
    Last edited: Jul 12, 2017
  27. Malware Master Engineer

    Messages:
    9,633
    This at least I can't understand, since all my scripts do this...

    [edit] Come to think of it, I think I've heard others complain about this problem

    We're probably gonna need a proper reproduction...
     
    • Agree Agree x 1
  28. krypt-lynx Apprentice Engineer

    Messages:
    175
    Real live example: <no example, because of forum engine>
    I need to handle starting PB, started with parameter, while timer block already started
    I can take TimeSinceLastRun, check it is too early for timer block and process user request.

    It works fine until game is loaded. Now I have zero instead of TimeSinceLastRun.
    I can save current TimeSinceLastRun value in Save() method, it is not available in Save(). So, now I need to spam TriggerNow without any another reason except to count passed time.
    Ok, game loaded, I have passed part of time before savegame, but now I need to calculate time passed since game load. First script call will return 0 in TimeSinceLastRun. So, I need to force it to update somehow. The only way - trigger or start timer in constructor (Program()).
    back then it was exactly that I done. Now it is impossible.

    The best thing I can do now is to ask user to configure Timer Block to start PB *and* itself (again, with no another reason), and hope nothing will happen while script awaiting to be called by timer and add 0.5 (0.56) to passed time, because I don't know, exact time passed since game load (it must be something in 0..1 sec (0..1.12, due bug in timer scheduling code).
     
  29. Malware Master Engineer

    Messages:
    9,633
    The TimeSinceLastRun, as I already explained to you, is runtime/diagnostic information. It's content is not saved, so there simply is no measurement available the first frame. This is by design.

    Starting timers in the constructor is something I've done many times. However I have heard people state that this sometimes don't work. I can't understand why, as the constructor is run at the first real update. Everything, including the timers, should be ready by now.
     
  30. krypt-lynx Apprentice Engineer

    Messages:
    175
    Or, may be, it will actually called by TriggerNow immediately. because this issue: https://forums.keenswh.com/threads/...triggernow-action-and-game-save-load.7395956/
    --- Automerge ---
    Actually, i'm ok with actions not calling from constructor or Save(). There is no real reason to do it. But we need a way to recover script logic.
    --- Automerge ---
    > Everything, including the timers, should be ready by now.
    Game optimizations. They broke pretty many things. One of them was timers:
    link
    --- Automerge ---
    It is pretty simple: grid with pb, timer and something else;
    Make timer to change some property of something else or start itself.
    Start or Trigger timer in constructor (probably other actions of other objects does not work also).
    Save gave, load game. Timer is not triggered.

    It just always not work, with no exceptions.
     
Thread Status:
Not open for further replies.
This last post in this thread was made more than 31 days old.