├── .gitattributes ├── DalamudPackager ├── buildMultiTargeting │ └── DalamudPackager.props ├── build │ ├── DalamudPackager.props │ └── DalamudPackager.targets ├── DalamudPackager.csproj └── DalamudPackager.cs ├── DalamudPackager.sln ├── README.org ├── .gitignore └── LICENCE /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | -------------------------------------------------------------------------------- /DalamudPackager/buildMultiTargeting/DalamudPackager.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /DalamudPackager/build/DalamudPackager.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.1 4 | net48 5 | $(MSBuildThisFileDirectory)..\tasks\$(DPTaskFolder)\DalamudPackager.dll 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /DalamudPackager.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DalamudPackager", "DalamudPackager\DalamudPackager.csproj", "{32D99B21-57F1-457B-8902-EF7325DA15A8}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {32D99B21-57F1-457B-8902-EF7325DA15A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {32D99B21-57F1-457B-8902-EF7325DA15A8}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | {32D99B21-57F1-457B-8902-EF7325DA15A8}.Release|Any CPU.ActiveCfg = Release|Any CPU 14 | {32D99B21-57F1-457B-8902-EF7325DA15A8}.Release|Any CPU.Build.0 = Release|Any CPU 15 | EndGlobalSection 16 | EndGlobal 17 | -------------------------------------------------------------------------------- /DalamudPackager/DalamudPackager.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | enable 5 | latest 6 | netstandard2.1;net48 7 | 8 | true 9 | 10 | true 11 | 12 | tasks 13 | true 14 | DalamudPackager 15 | An MSBuild task that simplifies making Dalamud plugins by generating a manifest and packing the build output into a release-ready zip. 16 | EUPL-1.2 17 | 14.0.1 18 | Anna Clemens, goatcorp contributors 19 | https://github.com/goatcorp/DalamudPackager 20 | https://github.com/goatcorp/DalamudPackager 21 | 22 | 23 | 24 | 25 | build\ 26 | 27 | 28 | buildMultiTargeting\ 29 | 30 | 31 | 32 | build\ 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 53 | 54 | <_PackageFiles Include="bin\$(Configuration)\*\Newtonsoft.Json.dll;bin\$(Configuration)\*\YamlDotNet.dll"> 55 | tasks\%(RecursiveDir) 56 | false 57 | Content 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /DalamudPackager/build/DalamudPackager.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(ProjectDir)DalamudPackager.targets 5 | 6 | 7 | 8 | 9 | 12 | 37 | 38 | 39 | 42 | 67 | 68 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+title: DalamudPackager 2 | #+options: ^:{} 3 | #+options: toc:nil 4 | 5 | This is an MSBuild task that is designed to simplify creating plugins 6 | for [[https://github.com/goatcorp/Dalamud][Dalamud]]. 7 | 8 | Install the NuGet package ~DalamudPackager~. When you build in release 9 | mode, a folder will be placed in your output directory containing your 10 | plugin manifest and ~latest.zip~. 11 | 12 | * Table of contents :TOC: 13 | - [[#configuration][Configuration]] 14 | - [[#manifest-generation][Manifest generation]] 15 | - [[#yaml-manifests][YAML manifests]] 16 | - [[#zip-file-generation][~.zip~ file generation]] 17 | - [[#task-attributes][Task attributes]] 18 | 19 | * Configuration 20 | 21 | If you need to additionally configure the task, create a file called 22 | ~DalamudPackager.targets~ in your project and use the template below. 23 | 24 | #+begin_src xml 25 | 26 | 27 | 28 | 33 | 34 | 35 | #+end_src 36 | 37 | * Manifest generation 38 | 39 | DalamudPackager reduces the amount of keys you need to include in your 40 | manifest, filling in the rest from sane defaults or your assembly. You 41 | can, of course, specify everything manually. 42 | 43 | #+begin_src json5 44 | { 45 | "Name": "Test Plugin", 46 | "Author": "You", 47 | "Description": "This is a test plugin", 48 | "RepoUrl": "https://example.com/" 49 | } 50 | #+end_src 51 | 52 | Notice how keys like ~AssemblyVersion~ and ~DalamudApiLevel~ are 53 | missing. You can include these if you'd like, but DalamudPackager will 54 | automatically do it for you when you build your project. If you build 55 | a project with this manifest in Release mode, you will find the 56 | following JSON file in your output directory. 57 | 58 | #+begin_src json5 59 | { 60 | "Author": "You", 61 | "Name": "Test Plugin", 62 | // this will be set to your AssemblyName automatically 63 | "InternalName": "TestPlugin", 64 | // this will be set to your assembly's version automatically 65 | "AssemblyVersion": "1.0.0.0", 66 | "Description": "This is a test plugin - this first line is a summary.\n\nDown here is a more detailed explanation of what the plugin\ndoes, manually wrapped to make sure it stays visible in the\ninstaller.", 67 | // this will be set to "any" automatically 68 | "ApplicableVersion": "any", 69 | "RepoUrl": "https://example.com/", 70 | // this will be set to 2 automatically 71 | "DalamudApiLevel": 2, 72 | // this will be set to 0 automatically 73 | "LoadPriority": 0 74 | } 75 | #+end_src 76 | 77 | * YAML manifests 78 | 79 | In addition, DalamudPackager allows you to use YAML, a more 80 | human-friendly format, for your manifest instead of JSON. YAML uses 81 | *snake_case* for keys instead of PascalCase like JSON. All the 82 | features of DalamudPackager work with YAML manifests. Just end your 83 | manifest's file name with ~.yaml~ instead of ~.json~ to make use of 84 | it. 85 | 86 | #+begin_src yaml 87 | name: Test Plugin 88 | author: You 89 | description: |- 90 | This is a test plugin - this first line is a summary. 91 | 92 | Down here is a more detailed explanation of what the plugin 93 | does, manually wrapped to make sure it stays visible in the 94 | installer. 95 | repo_url: https://example.com/ 96 | #+end_src 97 | 98 | * ~.zip~ file generation 99 | 100 | DalamudPackager will also create a folder with ~latest.zip~ for you if 101 | ~MakeZip~ is ~true~. Check your output directory for a folder with the 102 | name of your assembly. Inside will be your manifest and ~latest.zip~, 103 | ready for distribution or PRs. 104 | 105 | Note that the entire contents of your output directory will be zipped 106 | by default. Either turn off copy local for Dalamud references, set up 107 | a task to clean your output directory, or use ~Exclude~ or ~Include~ 108 | if you want to change this. 109 | 110 | * Task attributes 111 | 112 | | Attribute | Description | Required | Default | 113 | |---------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------+-----------------------------------| 114 | | ~ProjectDir~ | This is the path where your ~csproj~ is located. You must set this to ~$(ProjectDir)~. | *Yes* | /None/ - set to ~$(ProjectDir)~ | 115 | | ~OutputPath~ | This is the path that your assemblies are output to after build. You must set this to ~$(OutputPath)~. | *Yes* | /None/ - set to ~$(OutputPath)~ | 116 | | ~AssemblyName~ | This is the name of the assembly that Dalamud will be loading. You used to need to specify this in your manifest as ~InternalName~. | *Yes* | /None/ - set to ~$(AssemblyName)~ | 117 | | ~ManifestType~ | You can choose between ~auto~, ~json~, and ~yaml~ for your manifest file. ~auto~ will use ~json~ first, then fall back on ~yaml~. | No | ~auto~ | 118 | | ~VersionComponents~ | How many components of the assembly's version to include in the generated manifest. If you use semantic versioning, set this to ~3~. | No | ~4~ | 119 | | ~MakeZip~ | If this is ~true~, a folder will be created in your ~OutputPath~ that contains your generated manifest and ~latest.zip~, reading for PRing. | No | ~false~ | 120 | | ~Exclude~ | Files to exclude from the zip if ~MakeZip~ is ~true~. Mutually exclusive with ~Include~. Files should be separated by a semicolon (~;~) and be relative to ~OutputPath~. Files do not need to exist. | No | /None/ | 121 | | ~Include~ | Files to include in the zip if ~MakeZip~ is ~true~. Mutually exclusive with ~Exclude~. Files should be separated by a semicolon (~;~) and be relative to ~OutputPath~. Files must exist. | No | /None/ | 122 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Rider 38 | .idea/ 39 | # Uncomment if you have tasks that create the project's static files in wwwroot 40 | #wwwroot/ 41 | 42 | # Visual Studio 2017 auto generated files 43 | Generated\ Files/ 44 | 45 | # MSTest test Results 46 | [Tt]est[Rr]esult*/ 47 | [Bb]uild[Ll]og.* 48 | 49 | # NUnit 50 | *.VisualState.xml 51 | TestResult.xml 52 | nunit-*.xml 53 | 54 | # Build Results of an ATL Project 55 | [Dd]ebugPS/ 56 | [Rr]eleasePS/ 57 | dlldata.c 58 | 59 | # Benchmark Results 60 | BenchmarkDotNet.Artifacts/ 61 | 62 | # .NET Core 63 | project.lock.json 64 | project.fragment.lock.json 65 | artifacts/ 66 | 67 | # ASP.NET Scaffolding 68 | ScaffoldingReadMe.txt 69 | 70 | # StyleCop 71 | StyleCopReport.xml 72 | 73 | # Files built by Visual Studio 74 | *_i.c 75 | *_p.c 76 | *_h.h 77 | *.ilk 78 | *.meta 79 | *.obj 80 | *.iobj 81 | *.pch 82 | *.pdb 83 | *.ipdb 84 | *.pgc 85 | *.pgd 86 | *.rsp 87 | *.sbr 88 | *.tlb 89 | *.tli 90 | *.tlh 91 | *.tmp 92 | *.tmp_proj 93 | *_wpftmp.csproj 94 | *.log 95 | *.vspscc 96 | *.vssscc 97 | .builds 98 | *.pidb 99 | *.svclog 100 | *.scc 101 | 102 | # Chutzpah Test files 103 | _Chutzpah* 104 | 105 | # Visual C++ cache files 106 | ipch/ 107 | *.aps 108 | *.ncb 109 | *.opendb 110 | *.opensdf 111 | *.sdf 112 | *.cachefile 113 | *.VC.db 114 | *.VC.VC.opendb 115 | 116 | # Visual Studio profiler 117 | *.psess 118 | *.vsp 119 | *.vspx 120 | *.sap 121 | 122 | # Visual Studio Trace Files 123 | *.e2e 124 | 125 | # TFS 2012 Local Workspace 126 | $tf/ 127 | 128 | # Guidance Automation Toolkit 129 | *.gpState 130 | 131 | # ReSharper is a .NET coding add-in 132 | _ReSharper*/ 133 | *.[Rr]e[Ss]harper 134 | *.DotSettings.user 135 | 136 | # TeamCity is a build add-in 137 | _TeamCity* 138 | 139 | # DotCover is a Code Coverage Tool 140 | *.dotCover 141 | 142 | # AxoCover is a Code Coverage Tool 143 | .axoCover/* 144 | !.axoCover/settings.json 145 | 146 | # Coverlet is a free, cross platform Code Coverage Tool 147 | coverage*.json 148 | coverage*.xml 149 | coverage*.info 150 | 151 | # Visual Studio code coverage results 152 | *.coverage 153 | *.coveragexml 154 | 155 | # NCrunch 156 | _NCrunch_* 157 | .*crunch*.local.xml 158 | nCrunchTemp_* 159 | 160 | # MightyMoose 161 | *.mm.* 162 | AutoTest.Net/ 163 | 164 | # Web workbench (sass) 165 | .sass-cache/ 166 | 167 | # Installshield output folder 168 | [Ee]xpress/ 169 | 170 | # DocProject is a documentation generator add-in 171 | DocProject/buildhelp/ 172 | DocProject/Help/*.HxT 173 | DocProject/Help/*.HxC 174 | DocProject/Help/*.hhc 175 | DocProject/Help/*.hhk 176 | DocProject/Help/*.hhp 177 | DocProject/Help/Html2 178 | DocProject/Help/html 179 | 180 | # Click-Once directory 181 | publish/ 182 | 183 | # Publish Web Output 184 | *.[Pp]ublish.xml 185 | *.azurePubxml 186 | # Note: Comment the next line if you want to checkin your web deploy settings, 187 | # but database connection strings (with potential passwords) will be unencrypted 188 | *.pubxml 189 | *.publishproj 190 | 191 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 192 | # checkin your Azure Web App publish settings, but sensitive information contained 193 | # in these scripts will be unencrypted 194 | PublishScripts/ 195 | 196 | # NuGet Packages 197 | *.nupkg 198 | # NuGet Symbol Packages 199 | *.snupkg 200 | # The packages folder can be ignored because of Package Restore 201 | **/[Pp]ackages/* 202 | # except build/, which is used as an MSBuild target. 203 | !**/[Pp]ackages/build/ 204 | # Uncomment if necessary however generally it will be regenerated when needed 205 | #!**/[Pp]ackages/repositories.config 206 | # NuGet v3's project.json files produces more ignorable files 207 | *.nuget.props 208 | *.nuget.targets 209 | 210 | # Microsoft Azure Build Output 211 | csx/ 212 | *.build.csdef 213 | 214 | # Microsoft Azure Emulator 215 | ecf/ 216 | rcf/ 217 | 218 | # Windows Store app package directories and files 219 | AppPackages/ 220 | BundleArtifacts/ 221 | Package.StoreAssociation.xml 222 | _pkginfo.txt 223 | *.appx 224 | *.appxbundle 225 | *.appxupload 226 | 227 | # Visual Studio cache files 228 | # files ending in .cache can be ignored 229 | *.[Cc]ache 230 | # but keep track of directories ending in .cache 231 | !?*.[Cc]ache/ 232 | 233 | # Others 234 | ClientBin/ 235 | ~$* 236 | *~ 237 | *.dbmdl 238 | *.dbproj.schemaview 239 | *.jfm 240 | *.pfx 241 | *.publishsettings 242 | orleans.codegen.cs 243 | 244 | # Including strong name files can present a security risk 245 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 246 | #*.snk 247 | 248 | # Since there are multiple workflows, uncomment next line to ignore bower_components 249 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 250 | #bower_components/ 251 | 252 | # RIA/Silverlight projects 253 | Generated_Code/ 254 | 255 | # Backup & report files from converting an old project file 256 | # to a newer Visual Studio version. Backup files are not needed, 257 | # because we have git ;-) 258 | _UpgradeReport_Files/ 259 | Backup*/ 260 | UpgradeLog*.XML 261 | UpgradeLog*.htm 262 | ServiceFabricBackup/ 263 | *.rptproj.bak 264 | 265 | # SQL Server files 266 | *.mdf 267 | *.ldf 268 | *.ndf 269 | 270 | # Business Intelligence projects 271 | *.rdl.data 272 | *.bim.layout 273 | *.bim_*.settings 274 | *.rptproj.rsuser 275 | *- [Bb]ackup.rdl 276 | *- [Bb]ackup ([0-9]).rdl 277 | *- [Bb]ackup ([0-9][0-9]).rdl 278 | 279 | # Microsoft Fakes 280 | FakesAssemblies/ 281 | 282 | # GhostDoc plugin setting file 283 | *.GhostDoc.xml 284 | 285 | # Node.js Tools for Visual Studio 286 | .ntvs_analysis.dat 287 | node_modules/ 288 | 289 | # Visual Studio 6 build log 290 | *.plg 291 | 292 | # Visual Studio 6 workspace options file 293 | *.opt 294 | 295 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 296 | *.vbw 297 | 298 | # Visual Studio LightSwitch build output 299 | **/*.HTMLClient/GeneratedArtifacts 300 | **/*.DesktopClient/GeneratedArtifacts 301 | **/*.DesktopClient/ModelManifest.xml 302 | **/*.Server/GeneratedArtifacts 303 | **/*.Server/ModelManifest.xml 304 | _Pvt_Extensions 305 | 306 | # Paket dependency manager 307 | .paket/paket.exe 308 | paket-files/ 309 | 310 | # FAKE - F# Make 311 | .fake/ 312 | 313 | # CodeRush personal settings 314 | .cr/personal 315 | 316 | # Python Tools for Visual Studio (PTVS) 317 | __pycache__/ 318 | *.pyc 319 | 320 | # Cake - Uncomment if you are using it 321 | # tools/** 322 | # !tools/packages.config 323 | 324 | # Tabs Studio 325 | *.tss 326 | 327 | # Telerik's JustMock configuration file 328 | *.jmconfig 329 | 330 | # BizTalk build output 331 | *.btp.cs 332 | *.btm.cs 333 | *.odx.cs 334 | *.xsd.cs 335 | 336 | # OpenCover UI analysis results 337 | OpenCover/ 338 | 339 | # Azure Stream Analytics local run output 340 | ASALocalRun/ 341 | 342 | # MSBuild Binary and Structured Log 343 | *.binlog 344 | 345 | # NVidia Nsight GPU debugger configuration file 346 | *.nvuser 347 | 348 | # MFractors (Xamarin productivity tool) working folder 349 | .mfractor/ 350 | 351 | # Local History for Visual Studio 352 | .localhistory/ 353 | 354 | # BeatPulse healthcheck temp database 355 | healthchecksdb 356 | 357 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 358 | MigrationBackup/ 359 | 360 | # Ionide (cross platform F# VS Code tools) working folder 361 | .ionide/ 362 | 363 | # Fody - auto-generated XML schema 364 | FodyWeavers.xsd 365 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | EUROPEAN UNION PUBLIC LICENCE v. 1.2 2 | EUPL © the European Union 2007, 2016 3 | 4 | This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined 5 | below) which is provided under the terms of this Licence. Any use of the Work, 6 | other than as authorised under this Licence is prohibited (to the extent such 7 | use is covered by a right of the copyright holder of the Work). 8 | 9 | The Work is provided under the terms of this Licence when the Licensor (as 10 | defined below) has placed the following notice immediately following the 11 | copyright notice for the Work: 12 | 13 | Licensed under the EUPL 14 | 15 | or has expressed by any other means his willingness to license under the EUPL. 16 | 17 | 1. Definitions 18 | 19 | In this Licence, the following terms have the following meaning: 20 | 21 | - ‘The Licence’: this Licence. 22 | 23 | - ‘The Original Work’: the work or software distributed or communicated by the 24 | Licensor under this Licence, available as Source Code and also as Executable 25 | Code as the case may be. 26 | 27 | - ‘Derivative Works’: the works or software that could be created by the 28 | Licensee, based upon the Original Work or modifications thereof. This Licence 29 | does not define the extent of modification or dependence on the Original Work 30 | required in order to classify a work as a Derivative Work; this extent is 31 | determined by copyright law applicable in the country mentioned in Article 15. 32 | 33 | - ‘The Work’: the Original Work or its Derivative Works. 34 | 35 | - ‘The Source Code’: the human-readable form of the Work which is the most 36 | convenient for people to study and modify. 37 | 38 | - ‘The Executable Code’: any code which has generally been compiled and which is 39 | meant to be interpreted by a computer as a program. 40 | 41 | - ‘The Licensor’: the natural or legal person that distributes or communicates 42 | the Work under the Licence. 43 | 44 | - ‘Contributor(s)’: any natural or legal person who modifies the Work under the 45 | Licence, or otherwise contributes to the creation of a Derivative Work. 46 | 47 | - ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of 48 | the Work under the terms of the Licence. 49 | 50 | - ‘Distribution’ or ‘Communication’: any act of selling, giving, lending, 51 | renting, distributing, communicating, transmitting, or otherwise making 52 | available, online or offline, copies of the Work or providing access to its 53 | essential functionalities at the disposal of any other natural or legal 54 | person. 55 | 56 | 2. Scope of the rights granted by the Licence 57 | 58 | The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, 59 | sublicensable licence to do the following, for the duration of copyright vested 60 | in the Original Work: 61 | 62 | - use the Work in any circumstance and for all usage, 63 | - reproduce the Work, 64 | - modify the Work, and make Derivative Works based upon the Work, 65 | - communicate to the public, including the right to make available or display 66 | the Work or copies thereof to the public and perform publicly, as the case may 67 | be, the Work, 68 | - distribute the Work or copies thereof, 69 | - lend and rent the Work or copies thereof, 70 | - sublicense rights in the Work or copies thereof. 71 | 72 | Those rights can be exercised on any media, supports and formats, whether now 73 | known or later invented, as far as the applicable law permits so. 74 | 75 | In the countries where moral rights apply, the Licensor waives his right to 76 | exercise his moral right to the extent allowed by law in order to make effective 77 | the licence of the economic rights here above listed. 78 | 79 | The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to 80 | any patents held by the Licensor, to the extent necessary to make use of the 81 | rights granted on the Work under this Licence. 82 | 83 | 3. Communication of the Source Code 84 | 85 | The Licensor may provide the Work either in its Source Code form, or as 86 | Executable Code. If the Work is provided as Executable Code, the Licensor 87 | provides in addition a machine-readable copy of the Source Code of the Work 88 | along with each copy of the Work that the Licensor distributes or indicates, in 89 | a notice following the copyright notice attached to the Work, a repository where 90 | the Source Code is easily and freely accessible for as long as the Licensor 91 | continues to distribute or communicate the Work. 92 | 93 | 4. Limitations on copyright 94 | 95 | Nothing in this Licence is intended to deprive the Licensee of the benefits from 96 | any exception or limitation to the exclusive rights of the rights owners in the 97 | Work, of the exhaustion of those rights or of other applicable limitations 98 | thereto. 99 | 100 | 5. Obligations of the Licensee 101 | 102 | The grant of the rights mentioned above is subject to some restrictions and 103 | obligations imposed on the Licensee. Those obligations are the following: 104 | 105 | Attribution right: The Licensee shall keep intact all copyright, patent or 106 | trademarks notices and all notices that refer to the Licence and to the 107 | disclaimer of warranties. The Licensee must include a copy of such notices and a 108 | copy of the Licence with every copy of the Work he/she distributes or 109 | communicates. The Licensee must cause any Derivative Work to carry prominent 110 | notices stating that the Work has been modified and the date of modification. 111 | 112 | Copyleft clause: If the Licensee distributes or communicates copies of the 113 | Original Works or Derivative Works, this Distribution or Communication will be 114 | done under the terms of this Licence or of a later version of this Licence 115 | unless the Original Work is expressly distributed only under this version of the 116 | Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee 117 | (becoming Licensor) cannot offer or impose any additional terms or conditions on 118 | the Work or Derivative Work that alter or restrict the terms of the Licence. 119 | 120 | Compatibility clause: If the Licensee Distributes or Communicates Derivative 121 | Works or copies thereof based upon both the Work and another work licensed under 122 | a Compatible Licence, this Distribution or Communication can be done under the 123 | terms of this Compatible Licence. For the sake of this clause, ‘Compatible 124 | Licence’ refers to the licences listed in the appendix attached to this Licence. 125 | Should the Licensee's obligations under the Compatible Licence conflict with 126 | his/her obligations under this Licence, the obligations of the Compatible 127 | Licence shall prevail. 128 | 129 | Provision of Source Code: When distributing or communicating copies of the Work, 130 | the Licensee will provide a machine-readable copy of the Source Code or indicate 131 | a repository where this Source will be easily and freely available for as long 132 | as the Licensee continues to distribute or communicate the Work. 133 | 134 | Legal Protection: This Licence does not grant permission to use the trade names, 135 | trademarks, service marks, or names of the Licensor, except as required for 136 | reasonable and customary use in describing the origin of the Work and 137 | reproducing the content of the copyright notice. 138 | 139 | 6. Chain of Authorship 140 | 141 | The original Licensor warrants that the copyright in the Original Work granted 142 | hereunder is owned by him/her or licensed to him/her and that he/she has the 143 | power and authority to grant the Licence. 144 | 145 | Each Contributor warrants that the copyright in the modifications he/she brings 146 | to the Work are owned by him/her or licensed to him/her and that he/she has the 147 | power and authority to grant the Licence. 148 | 149 | Each time You accept the Licence, the original Licensor and subsequent 150 | Contributors grant You a licence to their contributions to the Work, under the 151 | terms of this Licence. 152 | 153 | 7. Disclaimer of Warranty 154 | 155 | The Work is a work in progress, which is continuously improved by numerous 156 | Contributors. It is not a finished work and may therefore contain defects or 157 | ‘bugs’ inherent to this type of development. 158 | 159 | For the above reason, the Work is provided under the Licence on an ‘as is’ basis 160 | and without warranties of any kind concerning the Work, including without 161 | limitation merchantability, fitness for a particular purpose, absence of defects 162 | or errors, accuracy, non-infringement of intellectual property rights other than 163 | copyright as stated in Article 6 of this Licence. 164 | 165 | This disclaimer of warranty is an essential part of the Licence and a condition 166 | for the grant of any rights to the Work. 167 | 168 | 8. Disclaimer of Liability 169 | 170 | Except in the cases of wilful misconduct or damages directly caused to natural 171 | persons, the Licensor will in no event be liable for any direct or indirect, 172 | material or moral, damages of any kind, arising out of the Licence or of the use 173 | of the Work, including without limitation, damages for loss of goodwill, work 174 | stoppage, computer failure or malfunction, loss of data or any commercial 175 | damage, even if the Licensor has been advised of the possibility of such damage. 176 | However, the Licensor will be liable under statutory product liability laws as 177 | far such laws apply to the Work. 178 | 179 | 9. Additional agreements 180 | 181 | While distributing the Work, You may choose to conclude an additional agreement, 182 | defining obligations or services consistent with this Licence. However, if 183 | accepting obligations, You may act only on your own behalf and on your sole 184 | responsibility, not on behalf of the original Licensor or any other Contributor, 185 | and only if You agree to indemnify, defend, and hold each Contributor harmless 186 | for any liability incurred by, or claims asserted against such Contributor by 187 | the fact You have accepted any warranty or additional liability. 188 | 189 | 10. Acceptance of the Licence 190 | 191 | The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ 192 | placed under the bottom of a window displaying the text of this Licence or by 193 | affirming consent in any other similar way, in accordance with the rules of 194 | applicable law. Clicking on that icon indicates your clear and irrevocable 195 | acceptance of this Licence and all of its terms and conditions. 196 | 197 | Similarly, you irrevocably accept this Licence and all of its terms and 198 | conditions by exercising any rights granted to You by Article 2 of this Licence, 199 | such as the use of the Work, the creation by You of a Derivative Work or the 200 | Distribution or Communication by You of the Work or copies thereof. 201 | 202 | 11. Information to the public 203 | 204 | In case of any Distribution or Communication of the Work by means of electronic 205 | communication by You (for example, by offering to download the Work from a 206 | remote location) the distribution channel or media (for example, a website) must 207 | at least provide to the public the information requested by the applicable law 208 | regarding the Licensor, the Licence and the way it may be accessible, concluded, 209 | stored and reproduced by the Licensee. 210 | 211 | 12. Termination of the Licence 212 | 213 | The Licence and the rights granted hereunder will terminate automatically upon 214 | any breach by the Licensee of the terms of the Licence. 215 | 216 | Such a termination will not terminate the licences of any person who has 217 | received the Work from the Licensee under the Licence, provided such persons 218 | remain in full compliance with the Licence. 219 | 220 | 13. Miscellaneous 221 | 222 | Without prejudice of Article 9 above, the Licence represents the complete 223 | agreement between the Parties as to the Work. 224 | 225 | If any provision of the Licence is invalid or unenforceable under applicable 226 | law, this will not affect the validity or enforceability of the Licence as a 227 | whole. Such provision will be construed or reformed so as necessary to make it 228 | valid and enforceable. 229 | 230 | The European Commission may publish other linguistic versions or new versions of 231 | this Licence or updated versions of the Appendix, so far this is required and 232 | reasonable, without reducing the scope of the rights granted by the Licence. New 233 | versions of the Licence will be published with a unique version number. 234 | 235 | All linguistic versions of this Licence, approved by the European Commission, 236 | have identical value. Parties can take advantage of the linguistic version of 237 | their choice. 238 | 239 | 14. Jurisdiction 240 | 241 | Without prejudice to specific agreement between parties, 242 | 243 | - any litigation resulting from the interpretation of this License, arising 244 | between the European Union institutions, bodies, offices or agencies, as a 245 | Licensor, and any Licensee, will be subject to the jurisdiction of the Court 246 | of Justice of the European Union, as laid down in article 272 of the Treaty on 247 | the Functioning of the European Union, 248 | 249 | - any litigation arising between other parties and resulting from the 250 | interpretation of this License, will be subject to the exclusive jurisdiction 251 | of the competent court where the Licensor resides or conducts its primary 252 | business. 253 | 254 | 15. Applicable Law 255 | 256 | Without prejudice to specific agreement between parties, 257 | 258 | - this Licence shall be governed by the law of the European Union Member State 259 | where the Licensor has his seat, resides or has his registered office, 260 | 261 | - this licence shall be governed by Belgian law if the Licensor has no seat, 262 | residence or registered office inside a European Union Member State. 263 | 264 | Appendix 265 | 266 | ‘Compatible Licences’ according to Article 5 EUPL are: 267 | 268 | - GNU General Public License (GPL) v. 2, v. 3 269 | - GNU Affero General Public License (AGPL) v. 3 270 | - Open Software License (OSL) v. 2.1, v. 3.0 271 | - Eclipse Public License (EPL) v. 1.0 272 | - CeCILL v. 2.0, v. 2.1 273 | - Mozilla Public Licence (MPL) v. 2 274 | - GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 275 | - Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for 276 | works other than software 277 | - European Union Public Licence (EUPL) v. 1.1, v. 1.2 278 | - Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong 279 | Reciprocity (LiLiQ-R+). 280 | 281 | The European Commission may update this Appendix to later versions of the above 282 | licences without producing a new version of the EUPL, as long as they provide 283 | the rights granted in Article 2 of this Licence and protect the covered Source 284 | Code from exclusive appropriation. 285 | 286 | All other changes or additions to this Appendix require the production of a new 287 | EUPL version. 288 | -------------------------------------------------------------------------------- /DalamudPackager/DalamudPackager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.IO; 5 | using System.IO.Compression; 6 | using System.Linq; 7 | using System.Reflection; 8 | using Microsoft.Build.Framework; 9 | using Microsoft.Build.Utilities; 10 | using Newtonsoft.Json; 11 | using YamlDotNet.Serialization; 12 | using YamlDotNet.Serialization.NamingConventions; 13 | 14 | namespace DalamudPackager { 15 | [SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global")] 16 | [SuppressMessage("ReSharper", "UnusedType.Global")] 17 | [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] 18 | [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")] 19 | public class DalamudPackager : Task { 20 | private static readonly string[] ImagePaths = { 21 | "icon.png", 22 | "image1.png", 23 | "image2.png", 24 | "image3.png", 25 | "image4.png", 26 | "image5.png", 27 | }; 28 | 29 | /// 30 | /// Set this to $(AssemblyName) 31 | /// 32 | [Required] 33 | public string AssemblyName { get; set; } = null!; 34 | 35 | /// 36 | /// Set this to $(ProjectDir) 37 | /// 38 | [Required] 39 | public string ProjectDir { get; set; } = null!; 40 | 41 | /// 42 | /// Set this to $(OutputPath) 43 | /// 44 | [Required] 45 | public string OutputPath { get; set; } = null!; 46 | 47 | /// 48 | /// This can be either "auto", "json", or "yaml" 49 | /// 50 | public string ManifestType { get; set; } = "auto"; 51 | 52 | private ManifestKind RealManifestType => this.ManifestType switch { 53 | "auto" => ManifestKind.Auto, 54 | "json" => ManifestKind.Json, 55 | "yaml" => ManifestKind.Yaml, 56 | _ => throw new ArgumentException("Invalid manifest type: expected either 'auto', 'json', or 'yaml'", nameof(this.ManifestType)), 57 | }; 58 | 59 | public byte VersionComponents { get; set; } = 4; 60 | 61 | public bool MakeZip { get; set; } = false; 62 | 63 | public bool HandleImages { get; set; } = true; 64 | 65 | /// 66 | /// Path to images relative to . 67 | /// 68 | public string ImagesPath { get; set; } = "images"; 69 | 70 | public string? Exclude { get; set; } 71 | 72 | public string? Include { get; set; } 73 | 74 | #region Packager Manifest Properties 75 | 76 | public string? Author { get; set; } 77 | 78 | public string? Name { get; set; } 79 | 80 | public string? InternalName { get; set; } 81 | 82 | public string? AssemblyVersion { get; set; } 83 | 84 | public string? MinimumDalamudVersion { get; set; } 85 | 86 | public string? Description { get; set; } 87 | 88 | public string? ApplicableVersion { get; set; } 89 | 90 | public string? RepoUrl { get; set; } 91 | 92 | public string? Tags { get; set; } 93 | 94 | public string? CategoryTags { get; set; } 95 | 96 | public string? DalamudApiLevel { get; set; } 97 | 98 | public string? LoadRequiredState { get; set; } 99 | 100 | public string? LoadSync { get; set; } 101 | 102 | public string? CanUnloadAsync { get; set; } 103 | 104 | public string? LoadPriority { get; set; } 105 | 106 | public string? ImageUrls { get; set; } 107 | 108 | public string? IconUrl { get; set; } 109 | 110 | public string? Punchline { get; set; } 111 | 112 | public string? Changelog { get; set; } 113 | 114 | public string? AcceptsFeedback { get; set; } 115 | 116 | public string? FeedbackMessage { get; set; } 117 | 118 | #endregion 119 | 120 | private Lazy> ExcludeFiles => new(() => this.StringToList(this.Exclude)); 121 | 122 | private Lazy> IncludeFiles => new(() => this.StringToList(this.Include)); 123 | 124 | private void NormalizePaths() { 125 | this.ProjectDir = this.NormalizePath(this.ProjectDir); 126 | this.OutputPath = this.NormalizePath(this.OutputPath); 127 | this.ImagesPath = this.NormalizePath(this.ImagesPath); 128 | } 129 | 130 | private string NormalizePath(string path) { 131 | return path 132 | .Replace('/', Path.DirectorySeparatorChar) 133 | .Replace('\\', Path.DirectorySeparatorChar) 134 | .TrimEnd(Path.DirectorySeparatorChar); 135 | } 136 | 137 | public override bool Execute() { 138 | // normalise path attributes 139 | this.NormalizePaths(); 140 | 141 | // load the manifest 142 | var manifest = this.LoadManifest(); 143 | 144 | // verify required fields on the manifest 145 | if (manifest.LogMissing(this.Log)) { 146 | return false; 147 | } 148 | 149 | // set some things automatically from the assembly 150 | var assemblyName = this.LoadAssemblyInfo(); 151 | manifest.SetProperties(assemblyName, this.VersionComponents); 152 | 153 | // save the json manifest in the output 154 | this.SaveManifest(manifest); 155 | 156 | // make a zip if specified 157 | return !this.MakeZip || this.CreateZip(); 158 | } 159 | 160 | private bool CreateZip() { 161 | // get path of the folder called the assembly name where we'll have the manifest and latest.zip 162 | var zipOutput = Path.Combine(this.OutputPath, this.AssemblyName); 163 | 164 | // remove the output folder if it exists 165 | if (Directory.Exists(zipOutput)) { 166 | Directory.Delete(zipOutput, true); 167 | } 168 | 169 | // determine file names to zip 170 | var includeLen = this.IncludeFiles.Value.Count; 171 | var excludeLen = this.ExcludeFiles.Value.Count; 172 | 173 | if (includeLen > 0 && excludeLen > 0) { 174 | this.Log.LogError("Specify either Include or Exclude on your DalamudPackager task, not both."); 175 | return false; 176 | } 177 | 178 | // File names all using \ as separator 179 | string[] fileNames; 180 | 181 | if (includeLen == 0 && excludeLen == 0) { 182 | fileNames = Directory.EnumerateFiles(this.OutputPath, "*", SearchOption.AllDirectories) 183 | .Select(file => this.NormalizePath(file.Substring(this.OutputPath.Length + 1))) 184 | .ToArray(); 185 | } else if (includeLen > 0) { 186 | fileNames = this.IncludeFiles.Value.ToArray(); 187 | } else { 188 | fileNames = Directory.EnumerateFiles(this.OutputPath, "*", SearchOption.AllDirectories) 189 | .Select(file => this.NormalizePath(file.Substring(this.OutputPath.Length + 1))) 190 | .Where(file => !this.ExcludeFiles.Value.Contains(file)) 191 | .ToArray(); 192 | } 193 | 194 | // remove any images that will be handled 195 | if (this.HandleImages) { 196 | var badPaths = ImagePaths.Select(p => Path.Combine(this.ImagesPath, p)).ToArray(); 197 | 198 | fileNames = fileNames 199 | .Where(file => !badPaths.Contains(file)) 200 | .ToArray(); 201 | } 202 | 203 | // create zip of files in the output path 204 | var zipPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); 205 | using (var zipFile = File.Create(zipPath)) { 206 | using (var zip = new ZipArchive(zipFile, ZipArchiveMode.Create)) { 207 | foreach (var file in fileNames) { 208 | var filePath = Path.Combine(this.OutputPath, file); 209 | zip.CreateEntryFromFile(filePath, file); 210 | } 211 | } 212 | } 213 | 214 | // create the output folder 215 | Directory.CreateDirectory(zipOutput); 216 | 217 | // copy manifest to output 218 | File.Copy( 219 | Path.Combine(this.OutputPath, $"{this.AssemblyName}.json"), 220 | Path.Combine(zipOutput, $"{this.AssemblyName}.json") 221 | ); 222 | 223 | // copy images to output 224 | if (this.HandleImages) { 225 | var outputImagesPath = Path.Combine(zipOutput, "images"); 226 | 227 | foreach (var path in ImagePaths) { 228 | var actualPath = Path.Combine(this.OutputPath, this.ImagesPath, path); 229 | if (File.Exists(actualPath)) { 230 | if (!Directory.Exists(outputImagesPath)) { 231 | Directory.CreateDirectory(outputImagesPath); 232 | } 233 | 234 | File.Copy( 235 | actualPath, 236 | Path.Combine(outputImagesPath, path) 237 | ); 238 | } 239 | } 240 | } 241 | 242 | // move zip to output 243 | File.Move( 244 | zipPath, 245 | Path.Combine(zipOutput, "latest.zip") 246 | ); 247 | 248 | return true; 249 | } 250 | 251 | private AssemblyName LoadAssemblyInfo() { 252 | var assemblyPath = Path.Combine(this.OutputPath, $"{this.AssemblyName}.dll"); 253 | var fullPath = Path.GetFullPath(assemblyPath); 254 | 255 | return System.Reflection.AssemblyName.GetAssemblyName(fullPath); 256 | } 257 | 258 | private Manifest LoadManifest() { 259 | var exts = this.RealManifestType switch { 260 | ManifestKind.Auto => new[] { "json", "yaml" }, 261 | ManifestKind.Json => new[] { "json" }, 262 | ManifestKind.Yaml => new[] { "yaml" }, 263 | _ => throw new ArgumentOutOfRangeException(nameof(this.RealManifestType), $"extension doesn't exist for {this.RealManifestType}"), 264 | }; 265 | 266 | Manifest? manifest = null; 267 | 268 | foreach (var ext in exts) { 269 | var manifestPath = Path.Combine(this.ProjectDir, $"{this.AssemblyName}.{ext}"); 270 | 271 | if (!File.Exists(manifestPath)) { 272 | continue; 273 | } 274 | 275 | using var manifestFile = File.Open(manifestPath, FileMode.Open); 276 | using var manifestStream = new StreamReader(manifestFile); 277 | 278 | manifest = ext switch { 279 | "json" => LoadJsonManifest(manifestStream), 280 | "yaml" => LoadYamlManifest(manifestStream), 281 | _ => throw new Exception("unreachable"), 282 | }; 283 | } 284 | 285 | manifest ??= new(); 286 | return ApplyManifestProperties(manifest); 287 | } 288 | 289 | private static Manifest LoadYamlManifest(TextReader reader) { 290 | var yamlDeserialiser = new DeserializerBuilder() 291 | .IgnoreUnmatchedProperties() 292 | .WithNamingConvention(UnderscoredNamingConvention.Instance) 293 | .Build(); 294 | 295 | return yamlDeserialiser.Deserialize(reader); 296 | } 297 | 298 | private static Manifest LoadJsonManifest(TextReader reader) { 299 | return JsonSerializer.CreateDefault().Deserialize(new JsonTextReader(reader))!; 300 | } 301 | 302 | private void SaveManifest(Manifest manifest) { 303 | var jsonPath = Path.Combine(this.OutputPath, $"{this.AssemblyName}.json"); 304 | 305 | var jsonSerialiser = JsonSerializer.Create(new JsonSerializerSettings { 306 | Formatting = Formatting.Indented, 307 | NullValueHandling = NullValueHandling.Ignore, 308 | }); 309 | 310 | using var jsonFile = File.Open(jsonPath, FileMode.Create); 311 | using var jsonStream = new StreamWriter(jsonFile) { 312 | NewLine = "\n", 313 | }; 314 | jsonSerialiser.Serialize(jsonStream, manifest); 315 | } 316 | 317 | private List StringToList(string? s, bool normalizePaths = true) { 318 | if (s == null) { 319 | return new List(); 320 | } 321 | 322 | return s.Split(';') 323 | .Select(name => normalizePaths ? this.NormalizePath(name.Trim()) : name.Trim()) 324 | .ToList(); 325 | } 326 | 327 | private Manifest ApplyManifestProperties(Manifest manifest) { 328 | if (!string.IsNullOrEmpty(Author)) 329 | manifest.Author = Author; 330 | 331 | if (!string.IsNullOrEmpty(Name)) 332 | manifest.Name = Name; 333 | 334 | if (!string.IsNullOrEmpty(InternalName)) 335 | manifest.InternalName = InternalName; 336 | 337 | if (!string.IsNullOrEmpty(AssemblyVersion)) 338 | manifest.AssemblyVersion = AssemblyVersion; 339 | 340 | if (!string.IsNullOrEmpty(MinimumDalamudVersion)) 341 | manifest.MinimumDalamudVersion = MinimumDalamudVersion; 342 | 343 | if (!string.IsNullOrEmpty(Description)) 344 | manifest.Description = Description; 345 | 346 | if (!string.IsNullOrEmpty(ApplicableVersion)) 347 | manifest.ApplicableVersion = ApplicableVersion!; 348 | 349 | if (!string.IsNullOrEmpty(RepoUrl)) 350 | manifest.RepoUrl = RepoUrl; 351 | 352 | if (!string.IsNullOrEmpty(Tags)) 353 | manifest.Tags = StringToList(Tags, false); 354 | 355 | if (!string.IsNullOrEmpty(CategoryTags)) 356 | manifest.CategoryTags = StringToList(CategoryTags, false); 357 | 358 | if (!string.IsNullOrEmpty(DalamudApiLevel) && int.TryParse(DalamudApiLevel, out var dalamudApiLevel)) 359 | manifest.DalamudApiLevel = dalamudApiLevel; 360 | 361 | if (!string.IsNullOrEmpty(LoadRequiredState) && int.TryParse(LoadRequiredState, out var loadRequiredState)) 362 | manifest.LoadRequiredState = loadRequiredState; 363 | 364 | if (!string.IsNullOrEmpty(LoadSync) && bool.TryParse(LoadSync, out var loadSync)) 365 | manifest.LoadSync = loadSync; 366 | 367 | if (!string.IsNullOrEmpty(CanUnloadAsync) && bool.TryParse(CanUnloadAsync, out var canUnloadAsync)) 368 | manifest.CanUnloadAsync = canUnloadAsync; 369 | 370 | if (!string.IsNullOrEmpty(LoadPriority) && int.TryParse(LoadPriority, out var loadPriority)) 371 | manifest.LoadPriority = loadPriority; 372 | 373 | if (!string.IsNullOrEmpty(ImageUrls)) 374 | manifest.ImageUrls = StringToList(ImageUrls, false); 375 | 376 | if (!string.IsNullOrEmpty(IconUrl)) 377 | manifest.IconUrl = IconUrl; 378 | 379 | if (!string.IsNullOrEmpty(Punchline)) 380 | manifest.Punchline = Punchline; 381 | 382 | if (!string.IsNullOrEmpty(Changelog)) 383 | manifest.Changelog = Changelog; 384 | 385 | if (!string.IsNullOrEmpty(AcceptsFeedback) && bool.TryParse(AcceptsFeedback, out var acceptsFeedback)) 386 | manifest.AcceptsFeedback = acceptsFeedback; 387 | 388 | if (!string.IsNullOrEmpty(FeedbackMessage)) 389 | manifest.FeedbackMessage = FeedbackMessage; 390 | 391 | return manifest; 392 | } 393 | } 394 | 395 | public enum ManifestKind { 396 | /// 397 | /// Automatically searches for JSON manifests, then searches for YAML manifests if no JSON could be found. 398 | /// 399 | Auto, 400 | 401 | /// 402 | /// Superior manifest type. Easier for human consumption. Will be converted into JSON for machine consumption 403 | /// during the build process. 404 | /// 405 | Yaml, 406 | 407 | /// 408 | /// Inferior manifest type. Not meant for human consumption. 409 | /// 410 | Json, 411 | } 412 | 413 | [Serializable] 414 | public class Manifest { 415 | /// 416 | /// The author/s of the plugin. 417 | /// 418 | public string? Author { get; set; } 419 | 420 | /// 421 | /// The public name of the plugin. 422 | /// 423 | public string? Name { get; set; } 424 | 425 | /// 426 | /// The internal name of the plugin, which should match the assembly name of the plugin. 427 | /// 428 | public string? InternalName { get; set; } 429 | 430 | /// 431 | /// The current assembly version of the plugin. 432 | /// 433 | public string? AssemblyVersion { get; set; } 434 | 435 | /// 436 | /// Gets the minimum Dalamud assembly version this plugin requires. 437 | /// 438 | public string? MinimumDalamudVersion { get; set; } 439 | 440 | /// 441 | /// A description of the plugins functions. 442 | /// 443 | public string? Description { get; set; } 444 | 445 | /// 446 | /// The version of the game this plugin works with. 447 | /// 448 | public string ApplicableVersion { get; set; } = "any"; 449 | 450 | /// 451 | /// An URL to the website or source code of the plugin. 452 | /// 453 | public string? RepoUrl { get; set; } 454 | 455 | /// 456 | /// List of tags defined on the plugin. 457 | /// 458 | public List? Tags { get; set; } 459 | 460 | /// 461 | /// List of the category tags defined on the plugin. 462 | /// 463 | public List? CategoryTags { get; set; } 464 | 465 | /// 466 | /// The API level of this plugin. 467 | /// 468 | public int DalamudApiLevel { get; set; } = 14; 469 | 470 | /// 471 | /// Gets the required Dalamud load step for this plugin to load. Takes precedence over LoadPriority. 472 | /// Valid values are: 473 | /// 0. During Framework.Tick, when drawing facilities are available. 474 | /// 1. During Framework.Tick. 475 | /// 2. No requirement. 476 | /// 477 | public int LoadRequiredState { get; set; } 478 | 479 | /// 480 | /// Gets a value indicating whether Dalamud must load this plugin not at the same time with other plugins and the game. 481 | /// 482 | public bool LoadSync { get; set; } 483 | 484 | /// 485 | /// Gets a value indicating whether Dalamud can unload the plugin outside of the Framework thread. 486 | /// 487 | public bool CanUnloadAsync { get; set; } 488 | 489 | /// 490 | /// Load priority for this plugin. Higher values means higher priority. 0 is default priority. 491 | /// 492 | public int LoadPriority { get; set; } 493 | 494 | /// 495 | /// Array of links to screenshots/other images that will be displayed. These images must be 730x380 resolution, with a maximum of 5 images. 496 | /// 497 | public List? ImageUrls { get; set; } 498 | 499 | /// 500 | /// Link to a 512x512 icon for your plugin. 501 | /// 502 | public string? IconUrl { get; set; } 503 | 504 | /// 505 | /// One-sentence description of your plugin. 506 | /// 507 | public string? Punchline { get; set; } 508 | 509 | /// 510 | /// Small description of recent changes to your plugin, only shown for people who have the plugin installed. 511 | /// 512 | public string? Changelog { get; set; } 513 | 514 | /// 515 | /// Gets a value indicating whether this plugin accepts feedback. 516 | /// 517 | public bool AcceptsFeedback { get; set; } = true; 518 | 519 | /// 520 | /// Gets a message that is shown to users when sending feedback. 521 | /// 522 | public string? FeedbackMessage { get; set; } 523 | 524 | internal bool LogMissing(TaskLoggingHelper log) { 525 | var anyNull = this.Name == null || this.Author == null || this.Description == null || this.Punchline == null; 526 | 527 | if (this.Name == null) { 528 | log.LogError("Plugin name is required in your manifest."); 529 | } 530 | 531 | if (this.Author == null) { 532 | log.LogError("Author name is required in your plugin manifest."); 533 | } 534 | 535 | if (this.Description == null) { 536 | log.LogError("Description is required in your plugin manifest."); 537 | } 538 | 539 | if (this.Punchline == null) { 540 | log.LogError("Punchline is required in your plugin manifest."); 541 | } 542 | 543 | return anyNull; 544 | } 545 | 546 | internal void SetProperties(AssemblyName assembly, byte components) { 547 | this.AssemblyVersion = assembly.Version!.ToString(components); 548 | this.InternalName = assembly.Name; 549 | } 550 | } 551 | } 552 | --------------------------------------------------------------------------------