Editor plugin question(s) - now: SUGGESTIONS :P (3 down, ?? to go!)

Started by monkey0506, Sat 23/01/2010 20:43:34

Previous topic - Next topic

monkey0506

So against my better judgment (:P) I've been teaching myself some C# in order to be able to write an editor plugin. It's actually quite nice...although I still hate that bloody name. :=

Anyway, I've searched through the AGS DLLs using both the Object Browser and a program called Reflector that lets me see more of the internals (actual function definitions and things beyond what the Object Browser shows) and I can't seem to find anything that will allow me to write to the AGS directory.

Simply omitting the file path put the files in the project folder, which presumably is by design. However, I am looking at implementing some global items that can't be placed in the game project folders. So far this is what I've come up with:

Code: ags
                RegistryKey key = Registry.ClassesRoot.OpenSubKey(@"agf_auto_file\shell\open\command");
                string dir = "";
                try
                {
                    // value will be in format of @""C:\Adventure Game Studio\AGSEditor.exe"" ""%1"""
                    dir = key.GetValue("").ToString().Substring(1); // trim leading quote
                    dir = dir.Substring(0, dir.LastIndexOf('\\') + 1); // get editor directory
                    dir += "PluginInfo\\"; // add the new directory
                    DirectoryInfo dirinfo = new DirectoryInfo(dir);
                    if (!dirinfo.Exists) dirinfo.Create();
                }
                catch (Exception e)
                {
                    editor.GUIController.ShowMessage("Error reading AGS directory from system registry." +
                    " You must have a valid file association for AGF files to use this plugin.", MessageBoxIconType.Error);
                    return;
                }
                string fileName = dir + name + extension;
                FileInfo info = new FileInfo(fileName);
                FileStream stream = info.OpenWrite();
                // write file
                stream.Close();


All of which is working perfectly. My only concern is that it's depending on a value in the system registry which is usually registered by the installer (by default) but the key may not exist. Is there any way to write to the AGS directory without relying on this registry key?

tzachs

I don't know if there's a way.
As a workaround, though, if you don't find the key in the registry (if (key.GetValue("") == null)), you can ask the user to select the path via UI, and then save it to the registry yourself (or to xml which might be more safe)...

smiley

Code: ags

Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)

or
Code: ags

AppDomain.CurrentDomain.BaseDirectory

should return the AGS dir.

But since Vista and 7 don't like writes to 'program files', and, at least on XP, the AGS installer defaults to a subfolder of that, you should create a new folder in 'application data' and write to that folder.
E.g.:
Code: ags

dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "PluginInfo");
if (!Directory.Exists(dir))
{
  Directory.CreateDirectory(dir);
}



monkey0506

Thanks for the suggestion smiley! :D That works well enough.

I have another question for anybody who might know. I'm trying to create a new script file (both header and script files) which is working with a couple of problems:

- The script does not get saved to the Game.agf XML until the game is manually saved.
- The script list does not show the new script until the game has been saved, closed, and reloaded.

Is there anyway to 1) save the game and then 2) refresh the list of scripts using the currently exposed plugin API?

Pumaman

Currently the plugin API doens't have methods to refresh the script list in the project tree. Generally the plugin API evolves by having methods added to it as and when people need them, so is this something you would like to see added?

monkey0506

For my particular purposes I would find it very useful to be able to refresh the script list. Even if the script doesn't get saved to the Game XML automatically that would still be okay as it would then be saved when the game is saved/compiled.

I'm already having no problems creating the script file and header, the only problem is getting them loaded into the game without having to save, exit, and reload the game project.

One issue though with the Script(string fileName, string text, bool isHeader) constructor...it seems that the text parameter isn't getting used as the Script.Text? There's not really documentation on what it's supposed to do so maybe I've misinterpreted it but so far I've been doing:

Code: ags
Script script = new Script(fileName + ".asc", "", false);
script.Text = _scriptText;
_editor.CurrentGame.Scripts.AddAtTop(script);
script = new Script(fileName + ".ash", "", true);
script.Text = _headerText;
_editor.CurrentGame.Scripts.AddAtTop(script);


Because:

Code: ags
Script script = new Script(fileName + ".asc", _scriptText, false);


Is creating the script file but it's empty...

Anyway, if there's a chance we could update the script list in the project tree that would be great! :=

Pumaman

Quote from: monkey_05_06 on Mon 25/01/2010 06:24:10
For my particular purposes I would find it very useful to be able to refresh the script list.

Ok, I'll try to add this to a future version.

QuoteOne issue though with the Script(string fileName, string text, bool isHeader) constructor...it seems that the text parameter isn't getting used as the Script.Text? There's not really documentation on what it's supposed to do so maybe I've misinterpreted it but so far I've been doing:

The "text" parameter does work, what makes you think it isn't working?
The only potential gotcha is that the Script.SaveToDisk method won't do anything unless the Modified flag is set -- and the Modified flag is initially false, until you manually change the .Text property at which point it becomes true.

monkey0506

That was the problem with the text parameter. Instead of setting the text manually it's the same if I just manually set Modified to true before saving. Otherwise it doesn't save the script and the text doesn't get saved into the file.

I have another question. I have discovered that by adding a reference to the AGSEditor.exe file directly I gain access to some very useful functionality. Importing/exporting SCM files, saving the game, and even force-refreshing the project tree (through reflection).

Is there a technical reason why I shouldn't do this? I understand that using reflection like I'm doing with the project tree is not considered a "safe" procedure as the internal structure could potentially change at any time. However, I'm not really aware of any negative effects that would come from having the reference to the editor EXE. Would this perhaps be considered in violation of the current licensing of AGS? I don't want to step on any toes here, but there's some very useful functions that I can access...

Pumaman

Apart from the fact that the internal structure could change at any time, various methods may have side-effects or prerequisites which you wouldn't know about, and that could cause the editor to become unstable and/or corrupt the game files. If there's any functionality you need, it'd be much better to request it to be added to the formally supported interfaces.

monkey0506

Okay in that case I'd like to formally request/suggest the following items be exposed to the editor plugin API:

  • Import/export SCM format. Preferably with the ability to provide the full filename allowing to save to a non-SCM extension.
  • Save the game. This is useful for cases where an editor plugin may create/delete files that the editor does not detect. For example calling CurrentGame.Scripts.Add[AtTop] does not detect new files as having been added/removed so won't prompt the user a second time if they decline to save on exit.
  • Refresh the project tree. Specifically the Scripts component when scripts have been added/removed, but the ability to a) refresh the entire project tree as well as b) refresh a specific component would be very useful. (Noting of course that this one has already been suggested :P just elaborating on that)
  • A pre-compile game event. There's already one being used internally that I am aware of, but it's not exposed to the plugin API. There is the BeforeSaveGame event, but I'm actually looking for a post-save, pre-compile event (like the aforementioned internal event). The reason I would find this useful? I was actually thinking of trying to implement a custom-purpose pre-processor for the scripts. It wouldn't be useful if it overwrote the actual script files; I would just want to update the CurrentGame.Scripts collection with my necessary modifications.

    I think that's everything for now. I'm sure I'll stumble across something else though. := Thanks CJ.

SMF spam blocked by CleanTalk