• Visit Rebornbuddy
  • Visit Panda Profiles
  • Visit LLamamMagic
  • Can Plugins use Dynamic Methods?

    Discussion in 'Community Developer Forum' started by Wheredidigo, May 14, 2015.

    1. Wheredidigo

      Wheredidigo Community Developer

      Joined:
      Dec 15, 2013
      Messages:
      417
      Likes Received:
      8
      Trophy Points:
      18
      I am currently working on my own methods for loading settings for plugins I want to use.

      Here is my LoadSettings Method:

      Code:
      private static void LoadSettings()
              {
                  var fileLocation = PluginManager.PluginDirectory + "\\FateBotManager\\FateBotManagerSettings.xml";
                  XElement xmlSettings;
                  if (File.Exists(fileLocation))
                  {
                      xmlSettings = XElement.Load(fileLocation);
                  }
                  else
                  {
                      xmlSettings = new XElement("Settings",
                          new XElement("DoBossFates", false),
                          new XElement("MinPercentCompleteForBoss", 0f),
                          new XElement("DoEscortFates", false),
                          new XElement("MaxLevelsAbove", 3),
                          new XElement("MaxLevelsBelow", 10),
                          new XElement("DoOnlyThisFate", string.Empty),
                          [B]BuildTeleportLocations()[/B]);
                      xmlSettings.Save(fileLocation);
                  }
                  var settings = new FateBotManagerSettings
                  {
                      DoBossFates = (bool) xmlSettings.Element("DoBossFates"),
                      MinPercentCompleteForBoss = (float) xmlSettings.Element("MinPercentCompleteForBoss"),
                      DoEscortFates = (bool) xmlSettings.Element("DoEscortFates"),
                      MaxLevelsAbove = (int) xmlSettings.Element("MaxLevelsAbove"),
                      MaxLevelsBelow = (int) xmlSettings.Element("MaxLevelsBelow"),
                      DoOnlyThisFate = (string) xmlSettings.Element("DoOnlyThisFate"),
                      TeleportLocations = [B]BuildTeleportLocations(xmlSettings.Element("TeleportLocations"))[/B]
                  };
                  Settings = settings;
              }
      
      Notice how I'm calling BuildTeleportLocations in 2 different ways and setting it to 2 different types.

      This is my BuildTeleportLocations method:

      Code:
      private static dynamic BuildTeleportLocations(XElement locations = null)
              {
                  if (locations == null)
                  {
                      var xmlRetval = new XElement("TeleportLocations");
                      var textInfo = CultureInfo.CurrentCulture.TextInfo;
      
                      foreach (var location in WorldManager.AvailableLocations)
                      {
                          xmlRetval.Add(new XElement("TeleportLocation",
                              new XElement("Name", textInfo.ToTitleCase(location.Name)),
                              new XElement("AetheryteId", location.AetheryteId),
                              new XElement("ZoneId", location.ZoneId),
                              new XElement("JSTAtmaHour", 0),
                              new XElement("AtmaCount", 0),
                              new XElement("AtmaName", string.Empty)));
                      }
                      return xmlRetval;
                  }
                  return locations.Descendants("TeleportLocations").Select(location => new TeleportLocation
                  {
                      AetheryteId = (uint) location.Element("AetheryteId"),
                      AtmaCount = (int) location.Element("AtmaCount"),
                      AtmaName = (string) location.Element("AtmaName"),
                      JstAtmaHour = (int) location.Element("JSTAtmaHour"),
                      Name = (string) location.Element("Name"),
                      ZoneId = (int) location.Element("ZoneId")
                  }).ToList();
              }
      
      Everything compiles just fine in Visual Studio, but when I load RB, I am getting the following error in my log:

      Is this something you can add to the compiler or do I need to create 2 different methods and then make note that RB can't handle doing dynamic methods?

      Here is my attached log:
       

      Attached Files:

    2. mastahg

      mastahg Administrator Staff Member

      Joined:
      Feb 27, 2011
      Messages:
      5,345
      Likes Received:
      383
      Trophy Points:
      83
      Post the whole plugin file so i can see what lines those errors are on.
       
    3. Wheredidigo

      Wheredidigo Community Developer

      Joined:
      Dec 15, 2013
      Messages:
      417
      Likes Received:
      8
      Trophy Points:
      18
      Here you are
       

      Attached Files:

    4. mastahg

      mastahg Administrator Staff Member

      Joined:
      Feb 27, 2011
      Messages:
      5,345
      Likes Received:
      383
      Trophy Points:
      83
      Why do you have to make everything so complicated and try and reinvent the wheel?
      Code:
              private static void LoadSettings()
              {
                  var fileLocation = PluginManager.PluginDirectory + "\\FateBotManager\\FateBotManagerSettings.xml";
                  XElement xmlSettings;
                  if (File.Exists(fileLocation))
                  {
                      xmlSettings = XElement.Load(fileLocation);
                  }
                  else
                  {
                      xmlSettings = new XElement("Settings",
                          new XElement("DoBossFates", false),
                          new XElement("MinPercentCompleteForBoss", 0f),
                          new XElement("DoEscortFates", false),
                          new XElement("MaxLevelsAbove", 3),
                          new XElement("MaxLevelsBelow", 10),
                          new XElement("DoOnlyThisFate", string.Empty),
                          BuildTeleportLocationsXml());
                      xmlSettings.Save(fileLocation);
                  }
                  var settings = new FateBotManagerSettings
                  {
                      DoBossFates = (bool) xmlSettings.Element("DoBossFates"),
                      MinPercentCompleteForBoss = (float) xmlSettings.Element("MinPercentCompleteForBoss"),
                      DoEscortFates = (bool) xmlSettings.Element("DoEscortFates"),
                      MaxLevelsAbove = (int) xmlSettings.Element("MaxLevelsAbove"),
                      MaxLevelsBelow = (int) xmlSettings.Element("MaxLevelsBelow"),
                      DoOnlyThisFate = (string) xmlSettings.Element("DoOnlyThisFate"),
                      TeleportLocations = BuildTeleportLocationsEnumerable(xmlSettings.Element("TeleportLocations"))
                  };
                  Settings = settings;
              }
      
              private static FateBotManagerSettings _settings;
      
              private static FateBotManagerSettings Settings
              {
                  get { return _settings ?? (_settings = new FateBotManagerSettings()); }
                  set { _settings = value; }
              }
      
              private static XElement BuildTeleportLocationsXml()
              {
                  var xmlRetval = new XElement("TeleportLocations");
                  var textInfo = CultureInfo.CurrentCulture.TextInfo;
      
                  foreach (var location in WorldManager.AvailableLocations)
                  {
                      xmlRetval.Add(new XElement("TeleportLocation",
                          new XElement("Name", textInfo.ToTitleCase(location.Name)),
                          new XElement("AetheryteId", location.AetheryteId),
                          new XElement("ZoneId", location.ZoneId),
                          new XElement("JSTAtmaHour", 0),
                          new XElement("AtmaCount", 0),
                          new XElement("AtmaName", string.Empty)));
                  }
                  return xmlRetval;
              }
      
              private static IEnumerable<TeleportLocation> BuildTeleportLocationsEnumerable(XContainer locations)
              {
                  return locations.Descendants("TeleportLocations").Select(location => new TeleportLocation
                  {
                      AetheryteId = (uint) location.Element("AetheryteId"),
                      AtmaCount = (int) location.Element("AtmaCount"),
                      AtmaName = (string) location.Element("AtmaName"),
                      JstAtmaHour = (int) location.Element("JSTAtmaHour"),
                      Name = (string) location.Element("Name"),
                      ZoneId = (int) location.Element("ZoneId")
                  }).ToList();
              }
      
      All this mucking about with xml elements just have a settings system? A publicly available one 1000 times less complex is already ready for people to use.
      Code:
        public class RaidBroSettings : JsonSettings
          {
      
              private static RaidBroSettings _settings;
      
              public static RaidBroSettings Instance
              {
                  get { return _settings ?? (_settings = new RaidBroSettings()); }
              }
      
              public RaidBroSettings()
                  : base(Path.Combine(CharacterSettingsDirectory, "RaidBroSettings.json"))
              {
      
              }
      
      
      
      
              private Keys _pausekey;
              [Setting]
              [Description("Changes take effect after stopping and starting the bot")]
              [DefaultSettingValue("65624")] //shift +x
              public Keys PauseKey
              {
                  get { return _pausekey; }
                  set
                  {
                      if (_pausekey != value)
                      {
                          _pausekey = value;
                          Save();
                      }
      
                  }
              }
      
      
          }
      
      Also, onenabled is poorly designed as onenabled gets called during startup of the bot if a plugin was previously enabled so unless the last bot used was fatebot its going to do nothing at startup and will require the user to disable and then reenable the plugin.
       
    5. Wheredidigo

      Wheredidigo Community Developer

      Joined:
      Dec 15, 2013
      Messages:
      417
      Likes Received:
      8
      Trophy Points:
      18
      I'm not asking you for design input on what I want to do.

      It's a very simple question.

      • Will RebornBuddy be able to handle dynamic methods?
       
    6. mastahg

      mastahg Administrator Staff Member

      Joined:
      Feb 27, 2011
      Messages:
      5,345
      Likes Received:
      383
      Trophy Points:
      83

      I don't have any issues in the plugin compiling for me so i feel like you left something out.

      And you really should ask for design help as its bad code like this that others will copy and imitate and think is ok and its really not.
      If you were to change your settings classes to structs they would be serialized and deserialized via the jsonsettings without any work on your part instead of making this big complex settings system.
       
    7. Wheredidigo

      Wheredidigo Community Developer

      Joined:
      Dec 15, 2013
      Messages:
      417
      Likes Received:
      8
      Trophy Points:
      18
      Changing my tune because I uploaded the wrong version first.

      See if you get a compiler error with this version:
       

      Attached Files:

      Last edited: May 15, 2015
    8. mastahg

      mastahg Administrator Staff Member

      Joined:
      Feb 27, 2011
      Messages:
      5,345
      Likes Received:
      383
      Trophy Points:
      83
      I'd have to manually add the reference and then import it somewhere, and that might make the executable size bloom during obfuscation.

      I still think dynamic is the wrong tool for the job.
      Also, bad and complex code are not mutually exclusive. I still think in this case your working with code that is complex for no particular reason and that there is a much simpler way to get the job done.
      Why are you storing so much data? Your storage of the TeleportLocation is more complex then it needs to be. 5/6 of the properties are static, and should be stored inside the plugin as such. The remaining field, AtmaCount could easily be stored as a Dictionary<int,int> with the Id of the zone being the key.

      Your entire settings stuff could be replaced with this:
      Code:
          public class FateManagerSettings : JsonSettings
          {
      
              private static FateManagerSettings _settings;
      
              public static FateManagerSettings Instance
              {
                  get { return _settings ?? (_settings = new FateManagerSettings()); }
              }
      
              public FateManagerSettings()  : base(Path.Combine(CharacterSettingsDirectory, "FateManagerSettings.json"))
              {
                  //Can't use defaultvalue for complex types.
                  if (AtmaCounts == null)
                  {
                      AtmaCounts = new Dictionary<int, int>();
                  }
              }
      
      //You can also use property wrappers to save the settings when they are changed.
      
              [DefaultValue(0)]
              public int MaxLevelsAbove { get; set; }
              [DefaultValue(0)]
              public int MaxLevelsBelow { get; set; }
              [DefaultValue(false)]
              public bool DoBossFates { get; set; }
              [DefaultValue(false)]
              public bool DoEscortFates { get; set; }
              [DefaultValue(0f)]
              public float MinPercentCompleteForBoss { get; set; }
              [DefaultValue("")]
              public string DoOnlyThisFate { get; set; }
      
      
              public Dictionary<int,int> AtmaCounts  { get; set; }
      
      
          }
      
      This code is very clean, and concise and easy to understand what is going on.
      I understand that your just starting the design of this but already your code is already very complex.
       
    9. Wheredidigo

      Wheredidigo Community Developer

      Joined:
      Dec 15, 2013
      Messages:
      417
      Likes Received:
      8
      Trophy Points:
      18
      I get that the current version of it is complex and that there will be better ways to do them. I've still got a ton to add to this plugin before I go about starting to refactor and make my code "clean". I was just surprised when I got the compiler error for a dynamic method and wanted to make sure I wasn't missing something. As you could see with the first upload, it was as simple as splitting it into 2 methods to get rid of the compiler error. I just wanted to confirm that it's a limitation of RB and not something I'm doing "wrong".
       

    Share This Page