Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Problems using Mono.CSharp.Evaluator.Evaluate(System.String)

Discussion in 'Scripting' started by Duri, Mar 25, 2016.

  1. Duri

    Duri

    Joined:
    Dec 5, 2014
    Posts:
    29
    I've searched from yesterday ways to do some pure eval() in C#. Altough I find how (after some hours of research and trial error), I cannot resolve why I'm getting this error (as I cannot find any solutions).

    Code (CSharp):
    1. public void something() {
    2.     Mono.CSharp.Evaluator.Evaluate("Debug.Log(\"The spell name is: \");");
    3. }

    That throws the next exception:
    Code (CSharp):
    1. ArgumentException: The expression did not set a result
    2. Mono.CSharp.Evaluator.Evaluate (System.String input)

    I saw that the function returns an object, so I tried to store it... but nothing, says the same.
     
  2. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    What platform are you targeting? I personally would avoid dynamically executing code in this manner because it likely won't be supported by IL2CPP, and it won't be allowed at all on some platforms like iOS. I'm not exactly sure how Evaluator works under the hood, but my guess is that it does IL Emission which is not supported on a variety of platforms (iOS, Android, WebPlayer, WebGL, etc).

    At any rate, I think what you're looking for is "Evaluator.Run", not Evaluator.Evaluate.
     
  3. Duri

    Duri

    Joined:
    Dec 5, 2014
    Posts:
    29
    I'm targetting PC. Evaluator.Run just throws the same exception.

    But if it isn't supported in all platforms... well, I will have to do the easy way. I wanted this because I recollect the objects ("spells") from an XML file that has this structure:

    Code (XML):
    1. <card>
    2.     <tag>...</tag>
    3.     ...
    4.     <useEffect>Instructions go here</useEffect>
    5. </card>
    So I would just maintain then in the file, for not hardcoding then in the class.
     
  4. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    But the Evaluator isn't going to be supported in all platforms either. For example, Windows Phone, Windows Store, UWP actually run against .NET, not Mono so it wouldn't likely be available. It also won't be available on the other platforms I mentioned above because they:

    #1 They are AOT environments and don't support IL.Emit
    #2 Some such as iOS don't allow dynamic code execution

    You would be much better off defining a "Vocabulary" and having helpers that can execute those. Use Interfaces on your spells that supply you with the methods you need and then execute the methods on the spells. There are lots of great ways to provide functionality to objects. Plus, you get the benefit of compile time error checking which dynamic runtime compilation would not provide.
     
  5. Duri

    Duri

    Joined:
    Dec 5, 2014
    Posts:
    29
    Yeah, a vocabulary would go well ("kill" -> delegate(enemy) {..}, for example).
    But the problem is that a spell will have normal code with no vocabulary. For example a fireball, would ask you to select a target and then damage that target. So the code would be:

    Code (CSharp):
    1. delegate() {
    2.     // Don't know exactly how to find a Gameobject by name, but you can imagine.
    3.     GameObject enemy = getEnemy();
    4.     // Make damage to him/her.
    5.     enemy.setDamage(9999);
    6. }
    You know, the spells limit would just be what the programmer wants, so creating an Action property where to store that delegate and later call it with useCard() would be great. Then it was when I thinked evaluating the code from an XML, but I'll do it the other way.
     
  6. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Code (csharp):
    1.  
    2. public interface ICard
    3. {
    4.    void UseCard();
    5. }
    6.  
    7. public interface ISpell : ICard
    8. {
    9.     void Cast();
    10. }
    11.  
    Code (csharp):
    1.  
    2. public class FireBall : ISpell
    3. {
    4.     public void UseCard()
    5.     {
    6.             //Do your standard Card stuff here
    7.             Cast();
    8.     }
    9.  
    10.     public void Cast()
    11.     {
    12.             //Do fireball specific stuff here
    13.     }
    14. }
    15.  
    Code (csharp):
    1.  
    2. public class Abilities
    3. {
    4.      public IList<Card> Cards { get; set;}
    5.  
    6.      public Abilities()
    7.      {
    8.           Cards = new List<Card>();
    9.      }
    10. }
    11.  
    Code (csharp):
    1.  
    2.        var abilities = new Abilities();
    3.        abilities.Cards.Add(new FireBall());
    4.  
    5.         abilities.Cards[0].UseCard();
    6.  
    Interfaces can be your friend. You can also do fun stuff like:
    Code (csharp):
    1.  
    2. if (abilities.Cards[0] is ISpell)
    3. {
    4.     (abilities.Cards[0] as ISpell).Cast();
    5. }
    6.  
    Get all spells
    Code (csharp):
    1.  
    2. var spells = Abilities.Cards.Where(c => c is ISpell).ToArray();
    3.  
     
  7. Duri

    Duri

    Joined:
    Dec 5, 2014
    Posts:
    29
    Yeah, I'm using interfaces. I will show you my files, because I should did it before haha.

    Code (CSharp):
    1.  
    2. public interface ICard {
    3.     string getCardName();
    4.     string getCardDescription();
    5.     string getCardEffect();
    6.     void useCard();
    7. }
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3.  
    4. public class SpellCard : ICard {
    5.     /*
    6.     * -cardName: Name of the spell card.
    7.     * -cardDescription: Description of the spell card.
    8.     * -cardEffect: Effects of the spell card when used.
    9.     * -spellType: Type of the spell (Attack, Defense, Heal). The class has
    10.     *         constants predefined for it.
    11.     * -powerCost: How much Power Tokens costs the spell to be casted.
    12.     * -useEffect: What is gonna happen when you call "useCard()"
    13.     *         ("delegate() {..}" with no args or return).
    14.     */
    15.     string cardName, cardDescription, cardEffect;
    16.     Action useEffect;
    17.     int spellType, powerCost;
    18.     public const int SPELL_TYPE_ATTACK = 1;
    19.     public const int SPELL_TYPE_DEFENSE = 2;
    20.     public const int SPELL_TYPE_HEAL = 3;
    21.  
    22.  
    23.     public SpellCard(string cardName, string cardDescription, string cardEffect,
    24.                     int spellType, Action useEffect) {
    25.         if (spellType != SPELL_TYPE_ATTACK &&
    26.            spellType != SPELL_TYPE_DEFENSE &&
    27.            spellType != SPELL_TYPE_HEAL) {
    28.             throw new System.Exception("Invalid spell type selected: use one" +
    29.                 " of the spell types constants predefined in the class.");
    30.         }
    31.  
    32.         this.cardName = cardName;
    33.         this.cardDescription = cardDescription;
    34.         this.cardEffect = cardEffect;
    35.         this.spellType = spellType;
    36.         this.useEffect = useEffect;
    37.     }
    38.  
    39.     public int getSpellType() {
    40.         return this.spellType;
    41.     }
    42.  
    43.     public string getCardName ()
    44.     {
    45.         return this.cardName;
    46.     }
    47.  
    48.     public string getCardDescription ()
    49.     {
    50.         return this.cardDescription;
    51.     }
    52.  
    53.     public string getCardEffect ()
    54.     {
    55.         return this.cardEffect;
    56.     }
    57.  
    58.     public void useCard ()
    59.     {
    60.         this.useEffect();
    61.     }
    62. }
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections.Generic;
    4.  
    5.  
    6. public class SpellDeck : MonoBehaviour {
    7.  
    8.     List<SpellCard> spells = new List<SpellCard>();
    9.  
    10.  
    11.     // Use this for initialization
    12.     void Start () {
    13.         // And so on for each spell. And tough the player will only choose 3 for the rest of the gameplay, this is a little problem.
    14.         spells.Add(new SpellCard(
    15.             "Fireball",
    16.             "My fireball description.",
    17.             "My fireball effects (text).",
    18.             SpellCard.SPELL_TYPE_ATTACK,
    19.             // This is the interesting part of the spell.
    20.             delegate() {
    21.                 Debug.Log("KILL IT WITH FIREEEEEE!!!");
    22.             }
    23.         ));
    24.     }
    25.  
    26.     // Update is called once per frame
    27. //    void Update () {
    28. //  
    29. //    }
    30. }

    I think that this is similar to what you have (except for Cast(), it isn't neccesary as useCard() just does the same).
     
  8. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    I was just throwing it in as an example. For that matter you could have ISpell with no methods at all. Then it becomes really what's referred to as a "Marker Interface" as it only defines that it is a specific type and doesn't define any functionality. That way you can disseminate between "Spell" and "Ranged" for example as different card types. Or "Spell" and "Defense".
     
    Duri likes this.
  9. Duri

    Duri

    Joined:
    Dec 5, 2014
    Posts:
    29
    Ok, thanks for the help :)
     
  10. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,376
    1) don't use evaluator as Dustin Horne was saying.


    2) the reason it throws that exception is because the method 'Evaluate' expects whatever code that is evaluated to return some result.

    Really it just forwards to the method:
    Evaluator.Evaluate(string input, out object result, out bool result_set)

    And if the result is not set, it throws an exception.

    Here you can see the decompiled code for it:

    Code (csharp):
    1.  
    2.     public static object Evaluate(string input)
    3.     {
    4.       object result;
    5.       bool result_set;
    6.       if (Evaluator.Evaluate(input, out result, out result_set) != null)
    7.         throw new ArgumentException("Syntax error on input: partial input");
    8.       if (!result_set)
    9.         throw new ArgumentException("The expression did not set a result");
    10.       return result;
    11.     }
    12.  
    Why it does that? No clue... I guess the Mono team decided that because this method returned an object, that object should be accounted for in some manner.
     
    Duri likes this.