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

[Guide] Programmable Block - C# 101.5 For Space Engineers - Common Pitfalls

Discussion in 'Programming Guides and Tools' started by Textor, Jan 2, 2015.

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

    Textor Junior Engineer

    Messages:
    775
    This is a short guide to help people with common pitfalls. It is not going to go much into code, rather it will go into what might cause code to go wrong.

    Q. SE is telling me there is something wrong on line x, but I can't see anything on that line! WTF, Textor?
    A. Watch your language, sir. Anyhow, compilers (SE's in-game programming block is technically acting as a compiler. Not going to get into the complexity that is the technically here.) Usually if you see a line that doesn't have anything on it, and that's the line that is indicated as having the problem, the compiler is lying to you. What? Lying to me? Yes. The compiler tells you when it notices a problem, not when it should notice a problem. Typically this is caused by bad syntax, such as forgetting one of those pesky semicolons. If you have a mysterious error, always check the lines above it.

    Q. My IF/For/Switch statement isn't working properly!
    A. This could be caused by a lot of factors. Usually, this is either a logical fallacy on your part (trust me, it happens to every programmer, so don't worry about it.) or you made a mistake with something-- such as using = to compare rather than ==. Why is this a problem? If you read through the operators section of 101, you'd know that = is an assignment operator:

    Code:
    if(i = 10)
    {
    }
    
    This assigns the value 10 to i, it doesn't evaluate to see if i is equal to 10. For logical fallacies, just try to read it out as English (or your native tongue, I'm not picky) and see if it makes sense in a sentence (this is why I added the sentences stuff to all the logical operators in my guide).

    Q. My program is being mean and won't do what I told it to!
    A. You are wrong, actually. Computers only do what they are told to do. The actual statement you are making is, "it won't do what I think I told it to do!" Check your work-- a very common problem is order of operations. Here's a C joke that programmers have told for years, based on Order of Operations:

    Code:
    #include <iostream.h>
    #define SIX 1+5
    #define NINE 8+1
    
    int main()
    {
        printf("What do you get when you multiply {0} by {1}\n", SIX,NINE);
        printf("{0}", SIX*NINE);
    }
    
    The code prints out:
    What do you get when you multiply 6 by 9?
    42

    6*9 is 54. How did I get 42? Look at the definition:

    SIX is 1+5
    NINE is 8+1

    so, the thing the computer was asked to do was: 1+5*8+1 = 42.
    Still don't see it? PEMDAS:
    5*8 = 40
    1+40 = 41
    41+1 = 42.

    If I wanted this to give me 54, I'd have it have () around 1+5 and 8+1:
    (1+5)*(8+1)
    1+5 = 6
    8+1 = 9
    6*9 = 54.

    When you have this sort of issue, go through the code line by line and find out what it is doing. Output stuff to 100 beacons if you have to-- get data as to what your computer is doing. Comment code out after each line to isolate the problem-- once you figure out where the problem lies, you can fix it.

    Q. I have a list and/or array. I can't find the thing I'm looking for!
    A. This is usually because people new to programming forget that computers start counting at 0, not 1. If you are trying to find the first item in a list or an array, make sure you access index 0 rather than index 1. This isn't that intuitive for a lot of people, but you'll get used to it, eventually.
    (Thanks to Cuber for the question suggestion.)

    Q. Why does my code keep returning "Attempted to access an element as a type incompatible with the array." exceptions?
    A. Currently, lists and arrays are incompatible with custom classes. If you really must use a custom class, try using a struct instead (same exact structure, just "struct" instead of "class" in the declaration. Just understand that structs are not classes and are handled differently from classes, so it can cause unexpected results occasionally depending on how you are using it.

    This thread will be updated as people ask more questions that involve programming pitfalls.
     
    Last edited by a moderator: Jan 8, 2015
    • Informative Informative x 1
  2. Cuber

    Cuber Apprentice Engineer

    Messages:
    262
    You might want to add the fact that indexers are zero-based.

    List[1] will return the second element in the list, not the first.
     
  3. Textor

    Textor Junior Engineer

    Messages:
    775
    Added.
     
  4. Textor

    Textor Junior Engineer

    Messages:
    775
    Added the class array/list incompatibility to the FAQ.
     
  5. alexmbrennan

    alexmbrennan Trainee Engineer

    Messages:
    5
    I'd add an explanation for how one is to tell which methods have to be called in which way - my experience is limited to programming languages like Perl, and I confess that it took me two hours to figure out how to do anything beyond SetCustomName because it seems that all other methods have to be called in a different way:
    Code:
    void Main()
    {
    IMyGyro gyro = GridTerminalSystem.GetBlockWithName("Gyro") as IMyGyro;
    
    // This works
    //gyro.SetCustomName("Foobar");
    
    //This doesn't
    //gyro.Override();
    
    //Instead you apparently have to say
    gyro.GetActionWithName("Override").Apply(gyro);
    }
    An explanation of why this is logical and internally consistent, as well as a guide when to use which form would be appreciated.
     
    Last edited by a moderator: Feb 25, 2015
  6. Workdawg

    Workdawg Trainee Engineer

    Messages:
    4
    OMG...

    It all makes sense now. I've a software dev by trade and have been dabbling in coding for SE. I don't know C# so it's been a bit tricky sorting things out, but I finally had things working well, until I hit this error. I built a custom class to calculate total raw material amounts, i.e. GravelAmount = RefinedGravel + (Stone * refiningEfficiency).

    I tried to load up all the various types into a list and was banging my head against my keyboard for a couple of days because of this issue. I guess for the simple use I was planning a struct is probably acceptable. If I can sort it out, I'll post my code.
     
  7. johnwhile

    johnwhile Trainee Engineer

    Messages:
    45
    Someone can help me why List with Class or Struct doesn't work ???
    Code:
    List<RotatorItem> TurretRotation; 
    bool begin = true;   
    IMyTextPanel panel = null;
     
    void Main()  
    {  
        if (begin)  
        {  
            TurretRotation = new List<RotatorItem>(1);    
            Initialize();  
            begin = false;  
        }      
    } 
     
    void Initialize() 
    { 
            TurretElevation.Clear();    
            List<IMyTerminalBlock> blocks = GridTerminalSystem.Blocks; 
            
            for (int i=0;i<blocks.Count;i++) 
            { 
                IMyTerminalBlock block = blocks[i]; 
                if (block is IMyTextPanel && block.CustomName == "DebugPanel") panel = block as IMyTextPanel; 
                if (block is IMyMotorStator) 
                {
                    RotatorItem item = new RotatorItem( (IMyMotorStator)block  );
                    TurretRotation.Add ( item );
                }
            }     
     
     
            if ( panel != null ) StampDebugText ( panel ); 
    } 
     
    void StampDebugText ( IMyTextPanel panel ) 
    { 
        StringBuilder builder = new StringBuilder(); 
        builder.AppendLine("TurretRotation : "); 
        for (int i=0;i<TurretRotation.Count; i++) builder.AppendLine(TurretRotation[i].ToString()); 
        panel.WritePublicText(builder.ToString()); 
        panel.ShowPublicTextOnScreen(); 
    }
     
    private struct RotatorItem   
    {   
        IMyMotorStator m_item;   
        public RotatorItem ( IMyMotorStator item)   
        {   
            m_item = item;   
        }   
        public override string ToString()   
        {   
            return string.Format ( "{0} angle:{1}" , m_item.CustomName.ToString() , m_item.Torque.ToString() );   
        }   
    }
    
     
    Last edited by a moderator: Mar 20, 2015
  8. Burillo

    Burillo Junior Engineer

    Messages:
    648
    it's all private. declare the struct as public, and it should work. general note - it would be helpful to provide error message along with your code.
     
    Last edited by a moderator: Mar 20, 2015
  9. johnwhile

    johnwhile Trainee Engineer

    Messages:
    45
    How i will use my list implementation, but can't use generic class, tag is a "objects" so need a cast operation to optain you item:
    Code:
    class MyList 
    {
      MyNode Tail;
      public int Count;
      public MyNode Head;
      public MyList()
      {
        Head = Tail = null;
        Count = 0;
      }
      public void Add(object item)
      {
        MyNode node= new MyNode(item , Count);  
        if (Head == null) Head = node;
        else Tail.Next = node;
        Tail = node;
        Count++;
      }
      public void Clear()
      {
        Count = 0;
        Head = null;
        Tail = null;
      }
      public override string ToString()
      {
        StringBuilder strbuild = new StringBuilder();
        MyNode Current = Head;
        while ( Current != null )
        {
          strbuild.AppendLine ( Current.Tag.ToString() ); 
          Current = Current.Next;
        }
        return strbuild.ToString();
      }
      
    }
    // generic class not allowed, can only used "object", require a cast
    class MyNode
    {
        public MyNode Next;
        public int Index = -1;
      public object Tag;
        public MyNode (object tag, int index)
        {
        this.Tag = tag;
        this.Index = index;
        }
    }
    class Motor
    {
        private IMyMotorStator m_item;   
        public Motor ( IMyMotorStator item)   
        {   
            m_item = item;   
        }   
        public override string ToString()   
        {   
            return string.Format ( "{0} angle:{1}" , m_item.CustomName.ToString() , m_item.DetailedInfo.ToString() );   
        }   
    }
    

    Example:
    Code:
    
    void Main()  
    {  
    MyList mymotors = new MyList();
    List<IMyTerminalBlock> blocks = GridTerminalSystem.Blocks;
    for (int i=0;i<blocks.Count;i++) 
    { 
    IMyTerminalBlock block = blocks[i]; 
    if (block is IMyMotorStator) mymotors.Add(new Motor((IMyMotorStator)block));
    }
    }
    
     
    Last edited by a moderator: Mar 21, 2015
  10. Workdawg

    Workdawg Trainee Engineer

    Messages:
    4
    The C# implementation in space engineers does not support lists declared as containing any custom class... simple as that. List<myClass> does not work. I don't know why... someone else here might... but it does not work .
     
  11. Nairdan2

    Nairdan2 Trainee Engineer

    Messages:
    3
    Oh deer! Didn't read the last question and now i spent two days figuring out why i can't put my custom class objects in an array! A simple change to struct solved it though. :'(
     
  12. Malware

    Malware Master Engineer

    Messages:
    9,867
    @Workdawg, it doesn't work because of the security system. Types are copied from one assembly to another, and altered to contain instruction counting. In this process, generic types aren't updated to point to these new types, because that is far from a trivial thing to do. I gave a half-hearted attempt on fixing it once but it was just too much work, with too many changes and too many potential failure points.

    Why it works with structs and not with classes I have no idea, but it does.
     
Thread Status:
This last post in this thread was made more than 31 days old.