1. This forum is obsolete and read-only. Feel free to contact us at support.keenswh.com

[Guide Request] Programmable block accessing certain methods.

Discussion in 'Programming Guides and Tools' started by erik9631, Mar 22, 2015.

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

    erik9631 Trainee Engineer

    Messages:
    60
    It is a terribly pain in the butt to browse the web with almost no results and watching 15 minutes long youtube videos just to find out how to output text on an LCD panel.

    The official guide is almost useless since there are no tutorials or no guides how to access certain properties and finding out yourself is next to impossible esspecially if you take this silly script api into the account.

    I would greatelly appreciate if someone posted and made a guide how to access properties on some blocks and change them,
     
  2. SunburstMoon

    SunburstMoon Trainee Engineer

    Messages:
    39
    Ok, this is far from a proper tutorial, but I was in the same situation as you just yesterday, and this is what I came up with (freshly updated to be more "public friendly"):

    Code:
    List<Color> colors = new List<Color>() {new Color(255, 0, 0), new Color(0, 255, 0), new Color(0, 0, 255), new Color(255, 200, 0)};
    int c = 0;
    
    void Main()
    {
        var block = GridTerminalSystem.GetBlockWithName("Test");
    
        IMyTextPanel screen = ((IMyTextPanel)GridTerminalSystem.GetBlockWithName("Code Screen"));
        List<ITerminalProperty> a = new List<ITerminalProperty>();
        List<ITerminalAction> b = new List<ITerminalAction>();
        block.GetProperties(a);
        block.GetActions(b);
        screen.WritePublicText(block.CustomName + " Properties:\n");
        if (a.Count > 0)
        {
            for (int i = 0; i < a.Count; i++) screen.WritePublicText(a[i].Id + "    " + a[i].TypeName + "\n", true);
        }
        else
        {
            screen.WritePublicText("found nothing");
        }
        screen.WritePublicText("\n" + block.CustomName + " Actions:\n", true); 
        if (b.Count > 0)
        {
            for (int i = 0; i < b.Count; i++) screen.WritePublicText(b[i].Id + "    " + b[i].Name + "\n", true); 
        }
        else
        {
            screen.WritePublicText("found nothing");
        }
        screen.ShowPublicTextOnScreen();
    
        /* ***** DELETE OR COMMENT OUT THE FOLLOWING LINES IF YOU ARE NOT USING THIS CODE
            WITH AN INTERIOR LIGHT AS YOUR TEST SUBJECT! ***** */
    
         // Getting and setting known properties of block (in this case an Interior Light)
        block.SetValue("Color", colors[c]);
        // In this case, the emitted light will change color, but not the block itself. For this we need to force the block to
        // update its physical appearance, and this is as simple as changing the light intensity.
        float f = block.GetValue<float>("Intensity");
        block.SetValue("Intensity", f + 0.1f);
        block.SetValue("Intensity", f);
        c++;
        if (c >= 4) c=0;
    
        // And similarly for actions
        block.ApplyAction("OnOff_On");
    
        // ***** DO NOT DELETE OR COMMENT OUT PAST THIS LINE! *****
    }
    
    All you have to do is place a programmable block in your world, paste this code in it, [check code] then [remember & exit]. Also place an LCD Screen and name it "Code Screen" (without the quotes). Finally, place a block that you want to know the properties and actions, and name it "Test" (just make sure it is the only block on the grid that is named "Test"). When run the code, it will output to the public text of the LCD Screen all the properties and actions available for your test block.

    You might need to chnage the last part of the code since the GetValue, SetValue and ApplyAction calls are intended for an interior light, and will likely cause a code error if called for another type of block. Just comment the lines out (by adding "//" in front of each line) at least on the first run of the code. When you know the properties/actions of your test block you may enable the lines again and change them so they match your block's properties and variable type.

    If you leave the code as is and have an Interior Light named "Test" on the grid, the light will change color on each run of the code, cycling thru red, green, blue and yellow.

    Like I said, it's far from a proper tutorial, but at least it shows how to use the code. Hope it helps a little.

    Note: to be on the safe side, set the owner of the programmable block and lcd screen to "Me", and do the same for the test block (if the option is there)
     
  3. johnwhile

    johnwhile Trainee Engineer

    Messages:
    45
    All Available Interface can be found in Space Engineers\Tools\Documentation.chm, or you can investigate in the "Sandbox.Common.dll" using a programm like dotPeek

    1. Create your script:

    go to C:\Users\***\AppData\Roaming\SpaceEngineers\IngameScripts\local\ScriptTest and create the file "Script.cs" and paste this code:

    Code:
    int Updates = 0;
    bool initialized = false;
    IMyTextPanel mypanel0;
    // this function are called when press 
    void Main()  
    {  
        Initialize();   
        // timer loops with different frequency for optimization 
        PrintOutputText();
        Updates++;
        if (Updates > 1000) Updates = 0;
    } 
    // intensive code, used to generate initial data, recall only if you insert a new block in the ship
    void Initialize() 
    { 
        if (initialized) return;
      
        List<IMyTerminalBlock> blocks = GridTerminalSystem.Blocks;     
        for (int i=0;i<blocks.Count;i++) 
        {
            IMyTerminalBlock block = blocks[i]; 
            string name = block.CustomName;
            if (block is IMyTextPanel) mypanel0 = block as IMyTextPanel ;
        }
      
        //output message, overwrite the default error message then run
        if (mypanel0==null ) throw new Exception("require one panel in the scene");
        
        initialized = true;
    } 
     
    void PrintOutputText() 
    { 
        // update every 10 frames
        if ((Updates % 10) == 0)
        {
            mypanel0.WritePublicText(string.Format("Updates : {0}\n", Updates)); 
            mypanel0.ShowPublicTextOnScreen();
        }
    }
    

    2. Create a simple Program Loop layout

    like in the image, the time block action are : Program Run -> Time Block trigger. This layout is used to generate a game loop with same frequency of game logic loop (or frame loop or physic loop, i only suppose). You can also use layout Program Run -> Time Block start and set timer to 1 second, this generate a loop of 1 second in case your code is very complex or when you don't want a precise loop.

    [​IMG]



    3. Compile the Code

    Now open you programmable block -> Edit -> Open Workshop and double clic on you script like in the screenshot

    [​IMG]

    Clicking on Check to compile, if something wrong an error message appear, if success Save and Exit
    Click on Run to start script, if something wrong an error text appear in the detailed info space, example if you don't create a text panel my script generate a exception here.

    4. Start Loop

    if all is correct start the timer, you will see this:
    [​IMG]


    5. Update the code

    use Notepad++ to edit Script.cs and set C# language, will be very usefull instead using game text editor. Or Use visual studio for a exactly editing but you need to insert the relative dll references.
    Save the file.
    Stop the timer loop
    Do step 3.
    Run script.
    Start timer loop.

    You can edit file and recompile without exit from game.

    6. About Main()

    Main() is similar to static function "https://msdn.microsoft.com/en-us/library/6wd819wh(v=vs.110).aspx". Are called every time you press ProgrammableBlock Run button. In my script i use a flag "initialized=false" to run Initialize() function only at first time, in this function i make the block scanning what is necessary only at the first run to find panel block.
    If you change something you have to re-initialize script, but this code is only my first test.
    All variable and function write outside Main() are interpreted as static, and this generate a lot of issue and error messages...
    All classes created can't have access to static values...

    Example : PrintOutputText() can have access to mypanel0 because are all interpreted as

    Code:
    public static IMyTextPanel mypanel0;
    public static void PrintOutputText();
    
    static
    but "class Motor" (that i write bellow) can't have access to mypanel0 !!! [FONT= &#39]c'mon[/FONT] Keen !!!
     
    Last edited by a moderator: Mar 22, 2015
  4. johnwhile

    johnwhile Trainee Engineer

    Messages:
    45
    Issue:

    Script use C# language but there are a lot of limitation, is a very pain, no static function, no array, no access to many block properties etc....

    example:

    1. i want create a class to manage a motor use for my turret, i investigate to the "Sandbox.Common.dll", i know that game motor block use interface: IMyMotorStator.

    2. I see that is derived interface of IMyMotorStator : IMyMotorBase, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity

    3. I go to IMyCubeBlock definition and i find the "Orientation" value...

    4. I run the script in 64 bit and return random value, run on 32 bit and game generate a System Memory Violation....

    result : pain to optain basic basic block information... it's possible what to get motor angle value i need to extract the integer in the detailedinfo string ??? not accepted, so i wait more update for modding

    Code:
    class Motor
    {    
        ToolHelper m_tool;
        IMyMotorStator m_stator; 
    
        public Motor ( IMyMotorStator stator , ToolHelper tool)   
        {   
            m_stator = stator; 
            m_tool = tool;
        }
        public int GetDegree()
        {
            int value = 0;
            m_tool.ExtractInteger(m_stator.DetailedInfo , out value);
            return value;
        }
        
        
        public string BlockInfo()
        { 
            int f = Convert.ToInt32(m_stator.Orientation.Forward);
            int l = Convert.ToInt32(m_stator.Orientation.Left);
            Vector3 left    = m_tool.ConvertDirection(l);
            Vector3 forward = m_tool.ConvertDirection(f);
            Vector3 up      = Vector3.Cross(left,forward);
            
            return string.Format("L{0} F{1} U{2}", m_tool.Vector3ToString(left), m_tool.Vector3ToString(forward),m_tool.Vector3ToString(up));
        }
        
        public override string ToString()   
        {   
            return string.Format ( "{0} {1}\n{2}" , m_stator.CustomName, GetDegree() , BlockInfo() );   
        }   
    }
    
     
  5. erik9631

    erik9631 Trainee Engineer

    Messages:
    60
    Thanks but the LCD screen was just an example.
    I am looking for a simple explanation how to for example:

    Rotor
    Interface name: IMyMotorStator
    Parent: IMyMotorBase
    Parent: IMyFunctionalBlock
    Fields:
    bool IsAttached
    float Torque
    float BrakingTorque
    float Velocity
    float LowerLimit
    float UpperLimit
    float Displacement


    How do I acess the Torque and how do I change it, how can I get the return value.
    How can I do the same with IsAttached.

    Simple IMyRotorBlock.IsAttached does not work.

    Then when I ask for help such as here: https://forum.keenswh.com/threads/depressurisation.7356933/

    Then people send me codes that make absolutely no sense and do not even compile. It is like they are programming in a totally and completely different interface.

    I am heavily confused. I thought THIS section is for IN GAME PROGRMAMING (Programmable block) not for mods.
     
  6. taikodragon

    taikodragon Trainee Engineer

    Messages:
    93
    The Orientation property is the orientation of the motor block within the grid that it was placed.. that does not give the position of the rotor. For getting the detailed information from the details section you can use the following code:
    Code:
    void ParseDetailedInfo(Dictionary<string, string> collection, string detailedInfo) {
    	string[] lines = detailedInfo.Split('\n');
    	for( int i = 0; i < lines.Length; ++i ) {
    		string line = lines[i];
    		if( string.IsNullOrEmpty(line) )
    			continue;
    		line = line.Trim();
    		if( string.IsNullOrWhiteSpace(line) )
    			continue;
    
    		string[] keyVal = line.Split(':');
    		if( keyVal.Length != 2 )
    			continue;
    		collection.Add(keyVal[0].Trim(), keyVal[1].Trim());
    	}
    }
    
    This will return a dictionary with the detailed info, the key is the stuff before the ":" and the value what is after.. you then can use the Convert.Int32 method to parse it.

    For the output of a solar panel I use this code below, I heavily commented to explain each step of the logic and what the variables are used to store.
     
Thread Status:
This last post in this thread was made more than 31 days old.