├── .gitignore ├── Advanced Papyrus.cs ├── Advanced Papyrus.exe ├── Advanced Papyrus.ini ├── LICENSE.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.zip -------------------------------------------------------------------------------- /Advanced Papyrus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Diagnostics; 4 | using System.Collections.Generic; 5 | 6 | class Program 7 | { 8 | static string PapyrusCompilerName = "PapyrusCompiler - Original.exe"; 9 | static TextWriter twOut = Console.Out; 10 | static TextWriter twError = Console.Error; 11 | static int minimumArgumentCount = 4; 12 | 13 | static void Main(string[] args) 14 | { 15 | if (args.Length >= minimumArgumentCount) 16 | { 17 | string[] configs = new string[2]; 18 | configs[0] = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + "\\Advanced Papyrus.ini"; 19 | configs[1] = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\SublimePapyrus.ini"; 20 | foreach (string config in configs) 21 | { 22 | if (File.Exists(config)) 23 | { 24 | twError.WriteLine("Advanced Papyrus: Modifying arguments to include settings from " + config.Substring(config.LastIndexOf("\\") + 1) + "..."); 25 | args = ModifyArguments(args, config); 26 | for (int i = 1; i < args.Length; i++) 27 | { 28 | if (args[i].Substring(3).Equals("")) 29 | { 30 | twError.WriteLine("Advanced Papyrus: ERROR! Encountered an empty argument. Please check the contents of \"" + config + "\"!"); 31 | return; 32 | } 33 | } 34 | RunCompiler(args); 35 | return; 36 | } 37 | } 38 | } 39 | else 40 | { 41 | twError.WriteLine("Advanced Papyrus: ERROR! Expecting at least " + minimumArgumentCount + " arguments, but received only " + args.Length + "!"); 42 | return; 43 | } 44 | twOut.WriteLine("Advanced Papyrus: Passing unmodified arguments through to compiler..."); 45 | RunCompiler(args); 46 | } 47 | 48 | static string[] ModifyArguments(string[] args, string filepath) 49 | { 50 | string input = ""; 51 | string[] lines = File.ReadAllLines(filepath); 52 | int import = -1; 53 | int skyrim = -1; 54 | int debug = -1; 55 | for (int i = 0; i < lines.Length; i++) 56 | { 57 | if ((import == -1) && (lines[i].StartsWith("[Import]"))) 58 | { 59 | import = i + 1; 60 | } 61 | else if ((skyrim == -1) && (lines[i].StartsWith("[Skyrim]"))) 62 | { 63 | skyrim = i + 1; 64 | } 65 | else if ((debug == -1) && (lines[i].StartsWith("[Debug]"))) 66 | { 67 | debug = i + 1; 68 | } 69 | } 70 | if (import >= 0) 71 | { 72 | for (int i = import; i < lines.Length; i++) 73 | { 74 | if (lines[i].StartsWith("path")) 75 | { 76 | if (input.Length > 0) 77 | { 78 | input += ";"; 79 | } 80 | input += "\"" + lines[i].Substring(lines[i].LastIndexOf("=") + 1) + "\""; 81 | } 82 | else if (lines[i].StartsWith("[")) 83 | { 84 | break; 85 | } 86 | } 87 | } 88 | if (skyrim >= 0) 89 | { 90 | for (int i = skyrim; i < lines.Length; i++) 91 | { 92 | if (lines[i].StartsWith("scripts=")) 93 | { 94 | if (input.Length > 0) 95 | { 96 | input += ";"; 97 | } 98 | input += "\"" + lines[i].Substring(8) + "\""; 99 | } 100 | else if (lines[i].StartsWith("output=")) 101 | { 102 | args[3] = "-o=\"" + lines[i].Substring(7) + "\""; 103 | } 104 | else if (lines[i].StartsWith("flags=")) 105 | { 106 | args[1] = "-f=" + lines[i].Substring(6); 107 | } 108 | else if (lines[i].StartsWith("[")) 109 | { 110 | break; 111 | } 112 | } 113 | } 114 | args[2] = "-i=" + input; 115 | if (debug >= 0) 116 | { 117 | List arguments = new List(); 118 | arguments.AddRange(args); 119 | string[] validargs = new string[11] {"all", "a", "debug", "d", "optimize", "op", "quiet", "q", "noasm", "keepasm", "asmonly"}; 120 | for (int i = debug; i < lines.Length; i++) 121 | { 122 | if (lines[i].StartsWith("arg")) 123 | { 124 | lines[i] = lines[i].Substring(lines[i].LastIndexOf("=") + 1); 125 | foreach (string validarg in validargs) 126 | { 127 | if (validarg.Equals(lines[i])) 128 | { 129 | arguments.Add("-" + lines[i]); 130 | break; 131 | } 132 | } 133 | } 134 | else if (lines[i].StartsWith("[")) 135 | { 136 | break; 137 | } 138 | } 139 | args = arguments.ToArray(); 140 | } 141 | return args; 142 | } 143 | 144 | static void RunCompiler(string[] args) 145 | { 146 | string arguments = ""; 147 | foreach (string arg in args) 148 | { 149 | arguments += arg + " "; 150 | } 151 | string PapyrusCompilerEXE = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + "\\" + PapyrusCompilerName; 152 | if (!File.Exists(PapyrusCompilerEXE)) 153 | { 154 | twError.WriteLine("Advanced Papyrus: ERROR! Unable to find \"" + PapyrusCompilerName + "\" in \"" + PapyrusCompilerEXE.Substring(0, PapyrusCompilerEXE.LastIndexOf("\\") + 1) + "\"!"); 155 | return; 156 | } 157 | var proc = new Process { 158 | StartInfo = new ProcessStartInfo { 159 | FileName = PapyrusCompilerEXE, 160 | Arguments = arguments, 161 | UseShellExecute = false, 162 | RedirectStandardOutput = true, 163 | RedirectStandardError = true, 164 | CreateNoWindow = true 165 | } 166 | }; 167 | proc.EnableRaisingEvents = true; 168 | proc.OutputDataReceived += new DataReceivedEventHandler(OutputWriter); 169 | proc.ErrorDataReceived += new DataReceivedEventHandler(ErrorWriter); 170 | proc.Start(); 171 | proc.BeginOutputReadLine(); 172 | proc.BeginErrorReadLine(); 173 | proc.WaitForExit(); 174 | } 175 | 176 | static void OutputWriter(object sender, DataReceivedEventArgs args) 177 | { 178 | if (args.Data != null) 179 | { 180 | twOut.WriteLine(args.Data); 181 | } 182 | } 183 | 184 | static void ErrorWriter(object sender, DataReceivedEventArgs args) 185 | { 186 | if (args.Data != null) 187 | { 188 | twError.WriteLine(args.Data); 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /Advanced Papyrus.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kapiainen/Advanced-Papyrus/9c2d02cc1bdbc36d473ce03da61917cb0992484a/Advanced Papyrus.exe -------------------------------------------------------------------------------- /Advanced Papyrus.ini: -------------------------------------------------------------------------------- 1 | [Skyrim] 2 | #scripts= 3 | #output= 4 | #flags=TESV_Papyrus_Flags.flg 5 | [Import] 6 | #path0= -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Kapiainen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advanced Papyrus 2 | A wrapper program that allows for more advanced use of the Papyrus compiler from within Creation Kit. 3 | 4 | ## Installing 5 | - Copy *Advanced Papyrus.exe* to *"\Skyrim\Papyrus Compiler\"*. 6 | - Rename *PapyrusCompiler.exe* to *PapyrusCompiler - Original.exe*. 7 | - Rename *Advanced Papyrus.exe* to *PapyrusCompiler.exe*. 8 | 9 | If you've installed Advanced Papyrus correctly, then you should see the output of the Papyrus compiler in Creation Kit start with: 10 | 11 | ``` 12 | Advanced Papyrus: MESSAGE 13 | ``` 14 | 15 | *MESSAGE* will be about passing through unmodified arguments or modifying arguments to take into account an INI file. 16 | 17 | If you've forgotten to rename the old Papyrus compiler executable to *PapyrusCompiler - Original.exe*, then an error message will be printed in the output. 18 | 19 | See the Features section for information on how to use the various features of Advanced Papyrus. 20 | 21 | ## Features 22 | #### Argument modification 23 | Arguments sent by Creation Kit to the Papyrus compiler can be modified by copying *Advanced Papyrus.ini* to *"\Skyrim\Papyrus Compiler"* and modifying it to suit your needs. If you don't copy *Advanced Papyrus.ini* or use SublimePapyrus (see below for more information), then arguments sent from Creation Kit will just pass through unmodified. 24 | 25 | ``` 26 | [Skyrim] 27 | scripts= 28 | output= 29 | flags=TESV_Papyrus_Flags.flg 30 | [Import] 31 | path0= 32 | path1= 33 | path2= 34 | . 35 | . 36 | . 37 | pathN= 38 | ``` 39 | 40 | So your INI file might look something like this: 41 | ``` 42 | [Skyrim] 43 | scripts=H:\Mod Organizer\Skyrim\mods\Creation Kit - 1 - Skyrim\Scripts\Source 44 | output=H:\Mod Organizer\Skyrim\overwrite\Scripts 45 | flags=TESV_Papyrus_Flags.flg 46 | [Import] 47 | path0=H:\Mod Organizer\Skyrim\overwrite\Scripts\Source 48 | path1=H:\Mod Organizer\Skyrim\mods\FISS\scripts\source 49 | path2=H:\Mod Organizer\Skyrim\mods\JContainers\scripts\source 50 | path3=H:\Mod Organizer\Skyrim\mods\Net Immerse Override\scripts\source 51 | path4=H:\Mod Organizer\Skyrim\mods\SkyUILib\scripts\source 52 | path5=H:\Mod Organizer\Skyrim\mods\SkyUI SDK\scripts\source 53 | path6=H:\Mod Organizer\Skyrim\mods\SKSE\Scripts\Source 54 | path7=H:\Mod Organizer\Skyrim\mods\Creation Kit - 2 - Dawnguard\Scripts\Source 55 | path8=H:\Mod Organizer\Skyrim\mods\Creation Kit - 3 - Hearthfire\Scripts\Source 56 | path9=H:\Mod Organizer\Skyrim\mods\Creation Kit - 4 - Dragonborn\Scripts\Source 57 | ``` 58 | 59 | All paths specified in the INI file should be absolute. 60 | The *scripts* option should point at your copy of the vanilla Skyrim source files (.psc). 61 | The *output* option should point at the folder you want the compiled scripts (.pex) to be placed. 62 | The *path* options can point at folders containing source files. 63 | 64 | Advanced Papyrus will read through the *Import* section first and then the *Skyrim* section. *scripts* and *path* options will be parsed into a single *"-i="* argument that is passed to the Papyrus compiler so that the argument looks something like this: 65 | 66 | ``` 67 | -i=path0;path1;path2;...;pathN;scripts 68 | ``` 69 | 70 | So if you have SKSE's source files in a separate folder and put its path into option *pathN*, then the Papyrus compiler will use SKSE's sources instead of the Skyrim's source files. 71 | 72 | If you use [SublimePapyrus](https://github.com/Kapiainen/SublimePapyrus), then you might have noticed that the contents of *Advanced Papyrus.ini* look like the contents of SublimePapyrus' INI file. That is because they are the same and you can actually force Advanced Papyrus to use your copy of *SublimePapyrus.ini*, but only if it exists in *My Documents*, by not copying *Advanced Papyrus.ini* into *"\Skyrim\Papyrus Compiler"*. This way you can have the same settings for Advanced Papyrus and SublimePapyrus. 73 | 74 | **Most people will not need to use any of the arguments listed below and the arguments should only be used if you know what you are doing!** 75 | 76 | You can use arguments like *optimize*, *debug*, and *keepasm* which are intended for advanced users. These can be added to the INI file in a section labeled *Debug* and each argument should be added as the value to an option starting with *arg*: 77 | 78 | ``` 79 | [Debug] 80 | arg0=debug 81 | arg1=keepasm 82 | . 83 | . 84 | . 85 | argN=optimize 86 | ``` 87 | 88 | The full list of supported arguments is as follows: 89 | 90 | ``` 91 | // Argument = Description 92 | all = Invokes the compiler against all psc files in the specified directory. 93 | debug = Turns on compiler debugging, outputting dev information to the screen. 94 | optimize = Turns on optimization of scripts. 95 | quiet = Does not report progress or success (only failures). 96 | noasm = Does not generate an assembly file and does not run the assembler. 97 | keepasm = Keeps the assembly file after running the assembler. 98 | asmonly = Generates an assembly file but does not run the assembler. 99 | ``` 100 | 101 | 102 | ## Mod Organizer 103 | Advanced Papyrus is useful when running [Creation Kit](http://www.creationkit.com/Main_Page) via [Mod Organizer](http://www.nexusmods.com/skyrim/mods/1334/) since you don't need to modify the Papyrus compiler and you can keep all of your script source files separated. 104 | 105 | You should modify *Advanced Papyrus.ini* (or *SublimePapyrus.ini*, if you use SublimePapyrus) so that the *output* option points to the *"\Mod Organizer\overwrite\Scripts"*: 106 | 107 | ``` 108 | output=Path\To\Mod Organizer\overwrite\scripts 109 | ``` 110 | 111 | You should also have a *path* option that points to *"\Mod Organizer\Scripts\Source"*: 112 | ``` 113 | path0=Path\To\Mod Organizer\overwrite\scripts\source 114 | ``` 115 | --------------------------------------------------------------------------------