├── .github ├── FUNDING.yml └── workflows │ └── publish.yml ├── .gitignore ├── .gitmodules ├── CathodeLib ├── CathodeLib.csproj ├── CathodeLib.sln ├── Properties │ ├── Resources.Designer.cs │ └── Resources.resx ├── Resources │ ├── NodeDBs │ │ ├── cathode_entity_lut.bin │ │ ├── cathode_enum_lut.bin │ │ ├── cathode_shortguid_lut.bin │ │ ├── composite_entity_names.bin │ │ ├── composite_parameter_info.bin │ │ └── composite_paths.bin │ └── sound_names.bin └── Scripts │ ├── Base Classes │ └── CathodeFile.cs │ ├── CATHODE │ ├── AlphaLightLevel.cs │ ├── AnimClipDB.cs │ ├── AnimationStrings.cs │ ├── CharacterAccessorySets.cs │ ├── CollisionMaps.cs │ ├── Collisions.cs │ ├── Commands.cs │ ├── CommandsPAK │ │ ├── Components │ │ │ ├── Composite.cs │ │ │ ├── Entity.cs │ │ │ ├── Parameter.cs │ │ │ ├── ParameterData.cs │ │ │ ├── ResourceReference.cs │ │ │ ├── ShortGuid.cs │ │ │ └── TypeEnums.cs │ │ └── Helpers │ │ │ ├── CommandsUtils.cs │ │ │ ├── CompositeUtils.cs │ │ │ ├── CustomTable.cs │ │ │ ├── EntityUtils.cs │ │ │ ├── EnumUtils.cs │ │ │ ├── ParameterUtils.cs │ │ │ └── ShortGuidUtils.cs │ ├── CustomCharacterConstrainedComponents.cs │ ├── CustomCharacterInfo.cs │ ├── EnvironmentAnimations.cs │ ├── EnvironmentMaps.cs │ ├── Helpers │ │ └── SoundUtils.cs │ ├── Lights.cs │ ├── MaterialMappings.cs │ ├── Materials.cs │ ├── MissionSave.cs │ ├── Models.cs │ ├── Movers.cs │ ├── NavigationMesh.cs │ ├── PAK1.cs │ ├── PAK2.cs │ ├── PathBarrierResources.cs │ ├── PhysicsMaps.cs │ ├── ProgressionSave.cs │ ├── RenderableElements.cs │ ├── Resources.cs │ ├── Shaders.cs │ ├── SkeleDB.cs │ ├── SoundBankData.cs │ ├── SoundDialogueLookups.cs │ ├── SoundEnvironmentData.cs │ ├── SoundEventData.cs │ ├── SoundFlashModels.cs │ ├── SoundLoadZones.cs │ ├── SoundNodeNetwork.cs │ ├── TextDB.cs │ ├── Textures.cs │ └── Traversals.cs │ ├── LEGACY_DAN │ ├── CathodePAK.cs │ ├── IDXRemap.cs │ ├── ShadersBIN.cs │ └── ShadersPAK.cs │ ├── Level.cs │ └── Utilities.cs ├── LICENSE ├── README.md ├── icon.png └── release.bat /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: MattFiler 2 | ko_fi: MattFiler 3 | custom: https://www.paypal.me/mattfiler 4 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish to nuget 2 | on: 3 | push: 4 | branches: 5 | - master # Default release branch 6 | jobs: 7 | publish: 8 | name: build, pack & publish 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | submodules: recursive 14 | 15 | # - name: Setup dotnet 16 | # uses: actions/setup-dotnet@v1 17 | # with: 18 | # dotnet-version: 3.1.200 19 | 20 | # Publish 21 | - name: publish on version change 22 | id: publish_nuget 23 | uses: rohith/publish-nuget@v2 24 | with: 25 | # Filepath of the project to be packaged, relative to root of repository 26 | PROJECT_FILE_PATH: CathodeLib/CathodeLib.csproj 27 | 28 | # NuGet package id, used for version detection & defaults to project name 29 | # PACKAGE_NAME: Core 30 | 31 | # Filepath with version info, relative to root of repository & defaults to PROJECT_FILE_PATH 32 | # VERSION_FILE_PATH: Directory.Build.props 33 | 34 | # Regex pattern to extract version info in a capturing group 35 | # VERSION_REGEX: ^\s*(.*)<\/Version>\s*$ 36 | 37 | # Useful with external providers like Nerdbank.GitVersioning, ignores VERSION_FILE_PATH & VERSION_REGEX 38 | # VERSION_STATIC: 1.0.0 39 | 40 | # Flag to toggle git tagging, enabled by default 41 | # TAG_COMMIT: true 42 | 43 | # Format of the git tag, [*] gets replaced with actual version 44 | # TAG_FORMAT: v* 45 | 46 | # API key to authenticate with NuGet server 47 | NUGET_KEY: ${{secrets.NUGET_API_KEY}} 48 | 49 | # NuGet server uri hosting the packages, defaults to https://api.nuget.org 50 | # NUGET_SOURCE: https://api.nuget.org 51 | 52 | # Flag to toggle pushing symbols along with nuget package to the server, disabled by default 53 | # INCLUDE_SYMBOLS: false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | testapp/* 2 | 3 | ## Ignore Visual Studio temporary files, build results, and 4 | ## files generated by popular Visual Studio add-ons. 5 | ## 6 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 7 | 8 | # User-specific files 9 | *.rsuser 10 | *.suo 11 | *.user 12 | *.userosscache 13 | *.sln.docstates 14 | 15 | # User-specific files (MonoDevelop/Xamarin Studio) 16 | *.userprefs 17 | 18 | # Mono auto generated files 19 | mono_crash.* 20 | 21 | # Build results 22 | [Dd]ebug/ 23 | [Dd]ebugPublic/ 24 | [Rr]elease/ 25 | [Rr]eleases/ 26 | x64/ 27 | x86/ 28 | [Ww][Ii][Nn]32/ 29 | [Aa][Rr][Mm]/ 30 | [Aa][Rr][Mm]64/ 31 | bld/ 32 | [Bb]in/ 33 | [Oo]bj/ 34 | [Ll]og/ 35 | [Ll]ogs/ 36 | 37 | # Visual Studio 2015/2017 cache/options directory 38 | .vs/ 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 | nuget.config 210 | 211 | # Microsoft Azure Build Output 212 | csx/ 213 | *.build.csdef 214 | 215 | # Microsoft Azure Emulator 216 | ecf/ 217 | rcf/ 218 | 219 | # Windows Store app package directories and files 220 | AppPackages/ 221 | BundleArtifacts/ 222 | Package.StoreAssociation.xml 223 | _pkginfo.txt 224 | *.appx 225 | *.appxbundle 226 | *.appxupload 227 | 228 | # Visual Studio cache files 229 | # files ending in .cache can be ignored 230 | *.[Cc]ache 231 | # but keep track of directories ending in .cache 232 | !?*.[Cc]ache/ 233 | 234 | # Others 235 | ClientBin/ 236 | ~$* 237 | *~ 238 | *.dbmdl 239 | *.dbproj.schemaview 240 | *.jfm 241 | *.pfx 242 | *.publishsettings 243 | orleans.codegen.cs 244 | 245 | # Including strong name files can present a security risk 246 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 247 | #*.snk 248 | 249 | # Since there are multiple workflows, uncomment next line to ignore bower_components 250 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 251 | #bower_components/ 252 | 253 | # RIA/Silverlight projects 254 | Generated_Code/ 255 | 256 | # Backup & report files from converting an old project file 257 | # to a newer Visual Studio version. Backup files are not needed, 258 | # because we have git ;-) 259 | _UpgradeReport_Files/ 260 | Backup*/ 261 | UpgradeLog*.XML 262 | UpgradeLog*.htm 263 | ServiceFabricBackup/ 264 | *.rptproj.bak 265 | 266 | # SQL Server files 267 | *.mdf 268 | *.ldf 269 | *.ndf 270 | 271 | # Business Intelligence projects 272 | *.rdl.data 273 | *.bim.layout 274 | *.bim_*.settings 275 | *.rptproj.rsuser 276 | *- [Bb]ackup.rdl 277 | *- [Bb]ackup ([0-9]).rdl 278 | *- [Bb]ackup ([0-9][0-9]).rdl 279 | 280 | # Microsoft Fakes 281 | FakesAssemblies/ 282 | 283 | # GhostDoc plugin setting file 284 | *.GhostDoc.xml 285 | 286 | # Node.js Tools for Visual Studio 287 | .ntvs_analysis.dat 288 | node_modules/ 289 | 290 | # Visual Studio 6 build log 291 | *.plg 292 | 293 | # Visual Studio 6 workspace options file 294 | *.opt 295 | 296 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 297 | *.vbw 298 | 299 | # Visual Studio LightSwitch build output 300 | **/*.HTMLClient/GeneratedArtifacts 301 | **/*.DesktopClient/GeneratedArtifacts 302 | **/*.DesktopClient/ModelManifest.xml 303 | **/*.Server/GeneratedArtifacts 304 | **/*.Server/ModelManifest.xml 305 | _Pvt_Extensions 306 | 307 | # Paket dependency manager 308 | .paket/paket.exe 309 | paket-files/ 310 | 311 | # FAKE - F# Make 312 | .fake/ 313 | 314 | # CodeRush personal settings 315 | .cr/personal 316 | 317 | # Python Tools for Visual Studio (PTVS) 318 | __pycache__/ 319 | *.pyc 320 | 321 | # Cake - Uncomment if you are using it 322 | # tools/** 323 | # !tools/packages.config 324 | 325 | # Tabs Studio 326 | *.tss 327 | 328 | # Telerik's JustMock configuration file 329 | *.jmconfig 330 | 331 | # BizTalk build output 332 | *.btp.cs 333 | *.btm.cs 334 | *.odx.cs 335 | *.xsd.cs 336 | 337 | # OpenCover UI analysis results 338 | OpenCover/ 339 | 340 | # Azure Stream Analytics local run output 341 | ASALocalRun/ 342 | 343 | # MSBuild Binary and Structured Log 344 | *.binlog 345 | 346 | # NVidia Nsight GPU debugger configuration file 347 | *.nvuser 348 | 349 | # MFractors (Xamarin productivity tool) working folder 350 | .mfractor/ 351 | 352 | # Local History for Visual Studio 353 | .localhistory/ 354 | 355 | # BeatPulse healthcheck temp database 356 | healthchecksdb 357 | 358 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 359 | MigrationBackup/ 360 | 361 | # Ionide (cross platform F# VS Code tools) working folder 362 | .ionide/ 363 | 364 | # Fody - auto-generated XML schema 365 | FodyWeavers.xsd -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "AlienBML"] 2 | path = AlienBML 3 | url = https://github.com/OpenCAGE/AlienBML 4 | -------------------------------------------------------------------------------- /CathodeLib/CathodeLib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | true 6 | https://github.com/OpenCAGE/CathodeLib 7 | https://github.com/MattFiler/OpenCAGE/ 8 | icon.png 9 | CathodeLib 10 | Matt Filer 11 | Provides support for parsing and writing common Alien: Isolation formats from the Cathode engine. 12 | Matt Filer 2025 13 | 0.8.3 14 | Library 15 | 0.7.8.3 16 | 0.7.8.2 17 | False 18 | README.md 19 | alien, modding, alien isolation, mod tool, file utility 20 | CathodeLib 21 | 22 | 23 | 24 | $(DefineConstants)TRACE;CATHODE_FAIL_HARD 25 | 26 | 27 | 28 | $(DefineConstants)TRACE 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | True 37 | 38 | 39 | 40 | True 41 | \ 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\PresentationCore.dll 67 | 68 | 69 | 70 | 71 | 72 | True 73 | True 74 | Resources.resx 75 | 76 | 77 | 78 | 79 | 80 | ResXFileCodeGenerator 81 | Resources.Designer.cs 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /CathodeLib/CathodeLib.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30128.74 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CathodeLib", "CathodeLib.csproj", "{E559EA84-0D43-4F5D-87FE-0259EEDFDC9C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {E559EA84-0D43-4F5D-87FE-0259EEDFDC9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {E559EA84-0D43-4F5D-87FE-0259EEDFDC9C}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {E559EA84-0D43-4F5D-87FE-0259EEDFDC9C}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {E559EA84-0D43-4F5D-87FE-0259EEDFDC9C}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {5B0B27F2-FBA2-4FD5-B1FC-C15C3568949A} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /CathodeLib/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CathodeLib.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CathodeLib.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Byte[]. 65 | /// 66 | internal static byte[] cathode_enum_lut { 67 | get { 68 | object obj = ResourceManager.GetObject("cathode_enum_lut", resourceCulture); 69 | return ((byte[])(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized resource of type System.Byte[]. 75 | /// 76 | internal static byte[] composite_entity_names { 77 | get { 78 | object obj = ResourceManager.GetObject("composite_entity_names", resourceCulture); 79 | return ((byte[])(obj)); 80 | } 81 | } 82 | 83 | /// 84 | /// Looks up a localized resource of type System.Byte[]. 85 | /// 86 | internal static byte[] composite_parameter_info { 87 | get { 88 | object obj = ResourceManager.GetObject("composite_parameter_info", resourceCulture); 89 | return ((byte[])(obj)); 90 | } 91 | } 92 | 93 | /// 94 | /// Looks up a localized resource of type System.Byte[]. 95 | /// 96 | internal static byte[] composite_paths { 97 | get { 98 | object obj = ResourceManager.GetObject("composite_paths", resourceCulture); 99 | return ((byte[])(obj)); 100 | } 101 | } 102 | 103 | /// 104 | /// Looks up a localized resource of type System.Byte[]. 105 | /// 106 | internal static byte[] cathode_shortguid_lut { 107 | get { 108 | object obj = ResourceManager.GetObject("cathode_shortguid_lut", resourceCulture); 109 | return ((byte[])(obj)); 110 | } 111 | } 112 | 113 | /// 114 | /// Looks up a localized resource of type System.Byte[]. 115 | /// 116 | internal static byte[] sound_names { 117 | get { 118 | object obj = ResourceManager.GetObject("sound_names", resourceCulture); 119 | return ((byte[])(obj)); 120 | } 121 | } 122 | 123 | /// 124 | /// Looks up a localized resource of type System.Byte[]. 125 | /// 126 | internal static byte[] cathode_entity_lut { 127 | get { 128 | object obj = ResourceManager.GetObject("cathode_entity_lut", resourceCulture); 129 | return ((byte[])(obj)); 130 | } 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /CathodeLib/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\NodeDBs\cathode_enum_lut.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 123 | 124 | 125 | ..\Resources\NodeDBs\composite_entity_names.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 126 | 127 | 128 | ..\Resources\NodeDBs\composite_parameter_info.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 129 | 130 | 131 | ..\Resources\NodeDBs\composite_paths.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 132 | 133 | 134 | ..\Resources\NodeDBs\cathode_shortguid_lut.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 135 | 136 | 137 | ..\Resources\sound_names.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 138 | 139 | 140 | ..\Resources\NodeDBs\cathode_entity_lut.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 141 | 142 | -------------------------------------------------------------------------------- /CathodeLib/Resources/NodeDBs/cathode_entity_lut.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCAGE/CathodeLib/64aa438afd9bcca5badff4d029a09ffe1fd9976f/CathodeLib/Resources/NodeDBs/cathode_entity_lut.bin -------------------------------------------------------------------------------- /CathodeLib/Resources/NodeDBs/cathode_enum_lut.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCAGE/CathodeLib/64aa438afd9bcca5badff4d029a09ffe1fd9976f/CathodeLib/Resources/NodeDBs/cathode_enum_lut.bin -------------------------------------------------------------------------------- /CathodeLib/Resources/NodeDBs/cathode_shortguid_lut.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCAGE/CathodeLib/64aa438afd9bcca5badff4d029a09ffe1fd9976f/CathodeLib/Resources/NodeDBs/cathode_shortguid_lut.bin -------------------------------------------------------------------------------- /CathodeLib/Resources/NodeDBs/composite_entity_names.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCAGE/CathodeLib/64aa438afd9bcca5badff4d029a09ffe1fd9976f/CathodeLib/Resources/NodeDBs/composite_entity_names.bin -------------------------------------------------------------------------------- /CathodeLib/Resources/NodeDBs/composite_parameter_info.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCAGE/CathodeLib/64aa438afd9bcca5badff4d029a09ffe1fd9976f/CathodeLib/Resources/NodeDBs/composite_parameter_info.bin -------------------------------------------------------------------------------- /CathodeLib/Resources/NodeDBs/composite_paths.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCAGE/CathodeLib/64aa438afd9bcca5badff4d029a09ffe1fd9976f/CathodeLib/Resources/NodeDBs/composite_paths.bin -------------------------------------------------------------------------------- /CathodeLib/Resources/sound_names.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCAGE/CathodeLib/64aa438afd9bcca5badff4d029a09ffe1fd9976f/CathodeLib/Resources/sound_names.bin -------------------------------------------------------------------------------- /CathodeLib/Scripts/Base Classes/CathodeFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | 6 | namespace CathodeLib 7 | { 8 | public class CathodeFile 9 | { 10 | public Action OnLoadBegin; 11 | public Action OnLoadSuccess; 12 | 13 | public Action OnSaveBegin; 14 | public Action OnSaveSuccess; 15 | 16 | public string Filepath { get { return _filepath; } } 17 | protected string _filepath = ""; 18 | 19 | public bool Loaded { get { return _loaded; } } 20 | protected bool _loaded = false; 21 | 22 | public static Implementation Implementation = Implementation.NONE; 23 | 24 | public CathodeFile(string filepath) 25 | { 26 | _filepath = filepath; 27 | _loaded = Load(); 28 | } 29 | 30 | #region EXTERNAL_FUNCS 31 | /* Try and load the file, if it exists */ 32 | private bool Load() 33 | { 34 | OnLoadBegin?.Invoke(_filepath); 35 | if (!File.Exists(_filepath)) return false; 36 | 37 | #if !CATHODE_FAIL_HARD 38 | try 39 | { 40 | #endif 41 | if (LoadInternal()) 42 | { 43 | OnLoadSuccess?.Invoke(_filepath); 44 | return true; 45 | } 46 | else return false; 47 | #if !CATHODE_FAIL_HARD 48 | } 49 | catch 50 | { 51 | return false; 52 | } 53 | #endif 54 | } 55 | 56 | /* Save the file back to its original filepath */ 57 | public bool Save() 58 | { 59 | OnSaveBegin?.Invoke(_filepath); 60 | 61 | #if !CATHODE_FAIL_HARD 62 | try 63 | { 64 | #endif 65 | if (SaveInternal()) 66 | { 67 | OnSaveSuccess?.Invoke(_filepath); 68 | return true; 69 | } 70 | else return false; 71 | #if !CATHODE_FAIL_HARD 72 | } 73 | catch 74 | { 75 | return false; 76 | } 77 | #endif 78 | } 79 | 80 | /* Save the file to a new path, and optionally remember it for future saves */ 81 | public bool Save(string path = "", bool updatePath = true) 82 | { 83 | string origFilepath = updatePath && path != "" ? path : _filepath; 84 | if (path != "") _filepath = path; 85 | bool saved = Save(); 86 | if (!updatePath) _filepath = origFilepath; 87 | return saved; 88 | } 89 | #endregion 90 | 91 | #region TO_OVERRIDE 92 | /* Virtual function to override in inherited classes for loading the file */ 93 | protected virtual bool LoadInternal() 94 | { 95 | Console.WriteLine("WARNING: This class does not implement loading functionality!"); 96 | return false; 97 | } 98 | 99 | /* Virtual function to override in inherited classes for saving the file */ 100 | protected virtual bool SaveInternal() 101 | { 102 | Console.WriteLine("WARNING: This class does not implement saving functionality!"); 103 | return false; 104 | } 105 | #endregion 106 | } 107 | 108 | [Flags] 109 | public enum Implementation 110 | { 111 | NONE = 1, 112 | CREATE = 2, 113 | LOAD = 4, 114 | SAVE = 8, 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/AlphaLightLevel.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace CATHODE.EXPERIMENTAL 8 | { 9 | /* DATA/ENV/PRODUCTION/x/WORLD/ALPHALIGHT_LEVEL.BIN */ 10 | public class AlphaLightLevel : CathodeFile 11 | { 12 | public List Entries = new List(); 13 | public static new Implementation Implementation = Implementation.NONE; 14 | public AlphaLightLevel(string path) : base(path) { } 15 | 16 | // Lighting information for objects with alpha (e.g. glass). Levels can load without this file, but look worse. 17 | 18 | #region FILE_IO 19 | override protected bool LoadInternal() 20 | { 21 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 22 | { 23 | reader.BaseStream.Position += 8; 24 | 25 | //NOTE: these values are always 64/128/256 i think 26 | int count = reader.ReadInt32(); 27 | int length = reader.ReadInt32() * 8; 28 | 29 | for (int i = 0; i < count; i++) 30 | { 31 | Entries.Add(new Entry() 32 | { 33 | content = reader.ReadBytes(length) 34 | }); 35 | } 36 | } 37 | return true; 38 | } 39 | 40 | override protected bool SaveInternal() 41 | { 42 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 43 | { 44 | writer.BaseStream.SetLength(0); 45 | Utilities.WriteString("alph", writer); 46 | writer.Write(0); 47 | writer.Write(Entries.Count); 48 | writer.Write(Entries.Count); 49 | for (int i = 0; i < Entries.Count; i++) 50 | { 51 | writer.Write(Entries[i].content); 52 | } 53 | } 54 | return true; 55 | } 56 | #endregion 57 | 58 | #region STRUCTURES 59 | public class Entry 60 | { 61 | public byte[] content; 62 | }; 63 | #endregion 64 | } 65 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/AnimClipDB.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Numerics; 6 | using System.Runtime.InteropServices; 7 | using System.Runtime.InteropServices.ComTypes; 8 | using System.Text; 9 | using CATHODE.Scripting; 10 | using CathodeLib; 11 | 12 | namespace CATHODE 13 | { 14 | /* DATA/GLOBAL/ANIMATION.PAK -> ANIM_CLIP_DB.BIN */ 15 | public class AnimClipDB : CathodeFile 16 | { 17 | public Dictionary Entries = new Dictionary(); 18 | public static new Implementation Implementation = Implementation.LOAD; 19 | public AnimClipDB(string path) : base(path) { } 20 | 21 | #region FILE_IO 22 | override protected bool LoadInternal() 23 | { 24 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 25 | { 26 | int EntryCount1 = reader.ReadInt32(); 27 | int EntryCount2 = reader.ReadInt32(); 28 | IndexPair[] Entries1 = Utilities.ConsumeArray(reader, EntryCount1); 29 | IndexPair[] Entries2 = Utilities.ConsumeArray(reader, EntryCount2); 30 | 31 | int Count0 = reader.ReadInt32(); 32 | int Count1 = reader.ReadInt32(); 33 | IndexPair[] Stuff0 = Utilities.ConsumeArray(reader, Count0); 34 | OffsetPair[] Stuff1 = Utilities.ConsumeArray(reader, Count1); 35 | 36 | int Count2 = reader.ReadInt32(); 37 | int[] Stuff2 = Utilities.ConsumeArray(reader, Count2); 38 | 39 | int Count4 = reader.ReadInt32(); 40 | int Count5 = reader.ReadInt32(); 41 | int Count6 = reader.ReadInt32(); 42 | IndexPair[] Stuff5 = Utilities.ConsumeArray(reader, Count5); 43 | int[] Stuff6 = Utilities.ConsumeArray(reader, Count6); 44 | 45 | int Count7 = reader.ReadInt32(); 46 | int[] Stuff7 = Utilities.ConsumeArray(reader, Count7); 47 | 48 | byte[] HeaderCounts0 = Utilities.ConsumeArray(reader, 5); 49 | float[] HeaderFloats0 = Utilities.ConsumeArray(reader, 6); // TODO: Is this HKX min/max floats for compression? 50 | int[] HeaderStuff0 = Utilities.ConsumeArray(reader, 4); 51 | 52 | int[] ContentStuff0 = Utilities.ConsumeArray(reader, HeaderCounts0[1] * 4); 53 | Vector2[] ContentStuff1 = Utilities.ConsumeArray(reader, HeaderCounts0[2]); 54 | 55 | bone_entry[] BoneEntries = Utilities.ConsumeArray(reader, HeaderCounts0[3]); 56 | 57 | // NOTE: Following content seems to be 4 unknown u8s followed by 4 u8s of which the 0th is ff and 1, 2 and 3 seem to 58 | // sum to 255. I would guess those are bone weights? Bone weights tend to sum to 1. 59 | } 60 | return true; 61 | } 62 | 63 | override protected bool SaveInternal() 64 | { 65 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 66 | { 67 | writer.BaseStream.SetLength(0); 68 | } 69 | return true; 70 | } 71 | #endregion 72 | 73 | #region STRUCTURES 74 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 75 | private struct IndexPair 76 | { 77 | public uint id; 78 | public int index; 79 | } 80 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 81 | private struct bone_entry 82 | { 83 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 84 | byte[] Joints; 85 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 86 | byte[] Weights; 87 | }; 88 | #endregion 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/AnimationStrings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using CATHODE.Scripting; 8 | using CathodeLib; 9 | 10 | namespace CATHODE 11 | { 12 | /* DATA/GLOBAL/ANIMATION.PAK -> ANIM_STRING_DB.BIN, ANIM_STRING_DB_DEBUG.BIN */ 13 | public class AnimationStrings : CathodeFile 14 | { 15 | public Dictionary Entries = new Dictionary(); 16 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 17 | public AnimationStrings(string path) : base(path) { } 18 | 19 | #region FILE_IO 20 | override protected bool LoadInternal() 21 | { 22 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 23 | { 24 | //Read all data in 25 | int EntryCount = reader.ReadInt32(); 26 | int StringCount = reader.ReadInt32(); 27 | Entry[] entries = Utilities.ConsumeArray(reader, EntryCount); 28 | int[] stringOffsets = Utilities.ConsumeArray(reader, StringCount); 29 | List strings = new List(); 30 | for (int i = 0; i < StringCount; i++) strings.Add(Utilities.ReadString(reader)); 31 | 32 | //Parse 33 | for (int i = 0; i < entries.Length; i++) Entries.Add(entries[i].StringID, strings[entries[i].StringIndex]); 34 | //TODO: encoding on a couple strings here is wrong 35 | } 36 | return true; 37 | } 38 | 39 | override protected bool SaveInternal() 40 | { 41 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 42 | { 43 | writer.BaseStream.SetLength(0); 44 | writer.Write(Entries.Count); 45 | writer.Write(Entries.Count); 46 | int count = 0; 47 | foreach (KeyValuePair value in Entries) 48 | { 49 | writer.Write(value.Key); 50 | writer.Write(count); 51 | count++; 52 | } 53 | int baseline = (Entries.Count * 4 * 2) + 8 + (Entries.Count * 4); 54 | writer.BaseStream.Position = baseline; 55 | List stringOffsets = new List(); 56 | foreach (KeyValuePair value in Entries) 57 | { 58 | stringOffsets.Add((int)writer.BaseStream.Position - baseline); 59 | Utilities.WriteString(value.Value, writer, true); 60 | } 61 | writer.BaseStream.Position = (Entries.Count * 4 * 2) + 8; 62 | for (int i = 0; i < stringOffsets.Count; i++) 63 | { 64 | writer.Write(stringOffsets[i]); 65 | } 66 | } 67 | return true; 68 | } 69 | #endregion 70 | 71 | #region ACCESSORS 72 | /* Add a string to the DB */ 73 | public void AddString(string str) 74 | { 75 | uint id = Utilities.AnimationHashedString(str); 76 | if (Entries.ContainsKey(id)) return; 77 | Entries.Add(id, str); 78 | } 79 | 80 | /* Remove a string from the DB */ 81 | public void RemoveString(string str) 82 | { 83 | uint id = Utilities.AnimationHashedString(str); 84 | Entries.Remove(id); 85 | } 86 | #endregion 87 | 88 | #region STRUCTURES 89 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 90 | private struct Entry 91 | { 92 | public uint StringID; 93 | public int StringIndex; 94 | }; 95 | #endregion 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/CharacterAccessorySets.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using CathodeLib; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Runtime.InteropServices; 8 | 9 | namespace CATHODE 10 | { 11 | /* DATA/ENV/PRODUCTION/x/WORLD/CHARACTERACCESSORYSETS.BIN */ 12 | public class CharacterAccessorySets : CathodeFile 13 | { 14 | public List Entries = new List(); 15 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 16 | public CharacterAccessorySets(string path) : base(path) { } 17 | 18 | #region FILE_IO 19 | override protected bool LoadInternal() 20 | { 21 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 22 | { 23 | reader.BaseStream.Position = 4; 24 | int entryCount = reader.ReadInt32(); 25 | for (int i = 0; i < entryCount; i++) 26 | { 27 | Entry entry = new Entry(); 28 | entry.character = Utilities.Consume(reader); 29 | 30 | entry.shirt_composite = Utilities.Consume(reader); 31 | entry.trousers_composite = Utilities.Consume(reader); 32 | entry.shoes_composite = Utilities.Consume(reader); 33 | entry.head_composite = Utilities.Consume(reader); 34 | entry.arms_composite = Utilities.Consume(reader); 35 | entry.collision_composite = Utilities.Consume(reader); 36 | 37 | entry.unk1 = reader.ReadInt32(); 38 | 39 | entry.unk2 = reader.ReadInt32(); 40 | entry.unk3 = reader.ReadInt32(); 41 | entry.unk4 = reader.ReadInt32(); 42 | entry.unk5 = reader.ReadInt32(); 43 | entry.unk6 = reader.ReadInt32(); 44 | entry.decal = (Entry.Decal)reader.ReadInt32(); 45 | entry.unk8 = reader.ReadInt32(); 46 | entry.unk9 = reader.ReadInt32(); 47 | entry.unk10 = reader.ReadInt32(); 48 | entry.unk11 = reader.ReadInt32(); 49 | 50 | byte[] stringBlock = reader.ReadBytes(260); 51 | entry.face_skeleton = Utilities.ReadString(stringBlock); 52 | stringBlock = reader.ReadBytes(260); 53 | entry.body_skeleton = Utilities.ReadString(stringBlock); 54 | 55 | entry.unk12 = reader.ReadInt32(); 56 | entry.unk13 = reader.ReadInt32(); 57 | entry.unk14 = reader.ReadInt32(); 58 | Entries.Add(entry); 59 | } 60 | } 61 | return true; 62 | } 63 | 64 | override protected bool SaveInternal() 65 | { 66 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 67 | { 68 | writer.BaseStream.SetLength(0); 69 | writer.Write(20); 70 | writer.Write(Entries.Count); 71 | for (int i = 0; i < Entries.Count; i++) 72 | { 73 | Utilities.Write(writer, Entries[i].character); 74 | 75 | Utilities.Write(writer, Entries[i].shirt_composite); 76 | Utilities.Write(writer, Entries[i].trousers_composite); 77 | Utilities.Write(writer, Entries[i].shoes_composite); 78 | Utilities.Write(writer, Entries[i].head_composite); 79 | Utilities.Write(writer, Entries[i].arms_composite); 80 | Utilities.Write(writer, Entries[i].collision_composite); 81 | 82 | writer.Write(Entries[i].unk1); 83 | writer.Write(Entries[i].unk2); 84 | writer.Write(Entries[i].unk3); 85 | writer.Write(Entries[i].unk4); 86 | writer.Write(Entries[i].unk5); 87 | writer.Write(Entries[i].unk6); 88 | writer.Write((Int32)Entries[i].decal); 89 | writer.Write(Entries[i].unk8); 90 | writer.Write(Entries[i].unk9); 91 | writer.Write(Entries[i].unk10); 92 | writer.Write(Entries[i].unk11); 93 | 94 | writer.Write(new byte[260]); 95 | writer.BaseStream.Position -= 260; 96 | Utilities.WriteString(Entries[i].face_skeleton, writer, false); 97 | writer.BaseStream.Position += 260 - Entries[i].face_skeleton.Length; 98 | writer.Write(new byte[260]); 99 | writer.BaseStream.Position -= 260; 100 | Utilities.WriteString(Entries[i].body_skeleton, writer, false); 101 | writer.BaseStream.Position += 260 - Entries[i].body_skeleton.Length; 102 | 103 | writer.Write(Entries[i].unk12); 104 | writer.Write(Entries[i].unk13); 105 | writer.Write(Entries[i].unk14); 106 | } 107 | } 108 | return true; 109 | } 110 | #endregion 111 | 112 | #region STRUCTURES 113 | public class Entry 114 | { 115 | public EntityHandle character = new EntityHandle(); 116 | 117 | public ShortGuid shirt_composite = ShortGuid.Invalid; 118 | public ShortGuid trousers_composite = ShortGuid.Invalid; 119 | public ShortGuid shoes_composite = ShortGuid.Invalid; 120 | public ShortGuid head_composite = ShortGuid.Invalid; 121 | public ShortGuid arms_composite = ShortGuid.Invalid; 122 | public ShortGuid collision_composite = ShortGuid.Invalid; 123 | 124 | public int unk1 = 0; 125 | public int unk2 = 1; 126 | public int unk3 = 2; 127 | public int unk4 = 3; //This is often odd values 128 | public int unk5 = 4; 129 | public int unk6 = 5; 130 | 131 | public Decal decal = Decal.MEDICAL; //TODO: Is this decal texture defined by CUSTOMCHARACTERASSETDATA.BIN? 132 | 133 | public int unk8 = 0; 134 | public int unk9 = 0; 135 | public int unk10 = 1; 136 | public int unk11 = 0; 137 | 138 | public string face_skeleton = "AL"; 139 | public string body_skeleton = "MALE"; 140 | 141 | public int unk12 = 3; 142 | public int unk13 = 6; 143 | public int unk14 = 9; 144 | 145 | public enum Decal 146 | { 147 | MEDICAL, 148 | ENGINEERING, 149 | GENERIC, 150 | TECHNICAL, 151 | } 152 | }; 153 | #endregion 154 | } 155 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/CollisionMaps.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using CathodeLib; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Runtime.InteropServices; 8 | 9 | namespace CATHODE 10 | { 11 | //This file defines additional info for entities with COLLISION_MAPPING resources. 12 | 13 | /* DATA/ENV/PRODUCTION/x/WORLD/COLLISION.MAP */ 14 | public class CollisionMaps : CathodeFile 15 | { 16 | public List Entries = new List(); 17 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 18 | public CollisionMaps(string path) : base(path) { } 19 | 20 | #region FILE_IO 21 | override protected bool LoadInternal() 22 | { 23 | int minUnk1 = 0; 24 | int minUnk2 = 0; 25 | int minColIn = 0; 26 | 27 | List flags = new List(); 28 | Dictionary> dictest = new Dictionary>(); 29 | 30 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 31 | { 32 | //The way this works: 33 | // - First 18 entries are empty 34 | // - Next set of entries are all the COLLISION_MAPPING resources referenced by COMMANDS.PAK (hence they have no composite_instance_id, as the composites aren't instanced - but they do have entity_ids) 35 | // - There are then a few entries that have composite_instance_ids set but I can't resolve them - perhaps these are things from GLOBAL? 36 | // - Then there's all the instanced entities with resolvable composite_instance_ids 37 | 38 | reader.BaseStream.Position = 4; 39 | int entryCount = reader.ReadInt32(); 40 | for (int i = 0; i < entryCount; i++) 41 | { 42 | Entry entry = new Entry(); 43 | 44 | entry.UnknownFlag = reader.ReadInt32(); //NOTE: if you filter by this value, all the UnknownIndex1s increment, UnknownIndex2s/collision_index don't increment but are grouped by -1s and non -1s, 45 | 46 | //todo: compare flag value across levels 47 | 48 | entry.UnknownIndex1= reader.ReadInt32(); 49 | entry.id = Utilities.Consume(reader); 50 | entry.entity = Utilities.Consume(reader); 51 | entry.UnknownIndex2 = reader.ReadInt32(); 52 | entry.collision_index = reader.ReadInt16(); 53 | entry.UnknownValue = reader.ReadInt16(); 54 | entry.zone_id = Utilities.Consume(reader); 55 | reader.BaseStream.Position += 16; 56 | Entries.Add(entry); 57 | 58 | if (minUnk1 < entry.UnknownIndex1) 59 | minUnk1 = entry.UnknownIndex1; 60 | if (minUnk2 < entry.UnknownIndex2) 61 | minUnk2 = entry.UnknownIndex2; 62 | if (minColIn < entry.collision_index) 63 | minColIn = entry.collision_index; 64 | 65 | if (!flags.Contains(entry.UnknownFlag)) 66 | flags.Add(entry.UnknownFlag); 67 | 68 | if (entry.collision_index != -1 && entry.UnknownIndex1 == -1 && entry.UnknownIndex2 == -1 && entry.UnknownValue == -1) 69 | { 70 | string sdfsdf = ""; 71 | } 72 | 73 | if (entry.UnknownIndex1 == -1 && entry.UnknownIndex2 == -1 && entry.UnknownValue == -1) 74 | { 75 | string sdfsdf = ""; 76 | } 77 | 78 | string flagBin = BitConverter.ToString(BitConverter.GetBytes(entry.UnknownFlag)); 79 | if (!dictest.ContainsKey(flagBin)) 80 | dictest.Add(flagBin, new List()); 81 | 82 | dictest[flagBin].Add(entry.UnknownIndex1 + " -> " + entry.UnknownIndex2 + " -> " + entry.collision_index); 83 | 84 | //if (entry.UnknownFlag == -1073737335) 85 | // Console.WriteLine(entry.UnknownIndex1); 86 | 87 | //if (entry.UnknownFlag == 4429) 88 | // Console.WriteLine(entry.UnknownIndex1); 89 | 90 | //if (entry.UnknownFlag == -1073737405) 91 | // Console.WriteLine(entry.UnknownIndex1); 92 | 93 | //Console.WriteLine(entry.UnknownFlag + " -> " + entry.UnknownIndex1 + " -> " + entry.UnknownIndex2 + " -> " + entry.collision_index + " -> " + entry.UnknownValue); 94 | } 95 | } 96 | 97 | 98 | return true; 99 | } 100 | 101 | override protected bool SaveInternal() 102 | { 103 | //composite_instance_id defo has something to do with the ordering as all the zeros are first 104 | 105 | 106 | //Entries = Entries.OrderBy(o => o.entity.entity_id.ToUInt32() + o.id.ToUInt32()).ThenBy(o => o.entity.composite_instance_id.ToUInt32()).ThenBy(o => o.zone_id.ToUInt32()).ToList(); 107 | 108 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 109 | { 110 | writer.BaseStream.SetLength(0); 111 | writer.Write((Entries.Count) * 48); 112 | writer.Write(Entries.Count); 113 | 114 | for (int i = 0; i < Entries.Count; i++) 115 | { 116 | //writer.Write(-268427008); 117 | //writer.Write(-1); 118 | 119 | writer.Write(Entries[i].UnknownFlag); 120 | writer.Write(Entries[i].UnknownIndex1); 121 | 122 | Utilities.Write(writer, Entries[i].id); 123 | Utilities.Write(writer, Entries[i].entity); 124 | 125 | writer.Write(-1); 126 | //writer.Write(Entries[i].UnknownIndex2); 127 | 128 | writer.Write((Int16)Entries[i].collision_index); 129 | 130 | writer.Write((short)-1); 131 | //writer.Write((Int16)Entries[i].UnknownValue); 132 | 133 | Utilities.Write(writer, Entries[i].zone_id); 134 | writer.Write(new byte[16]); 135 | } 136 | } 137 | return true; 138 | } 139 | #endregion 140 | 141 | #region STRUCTURES 142 | public class Entry 143 | { 144 | public ShortGuid id = ShortGuid.Invalid; //This is the name of the entity hashed via ShortGuid 145 | public EntityHandle entity = new EntityHandle(); 146 | public ShortGuid zone_id = ShortGuid.Invalid; //this maps the entity to a zone ID. interestingly, this seems to be the point of truth for the zone rendering 147 | 148 | public int collision_index = -1; //maps to havok hkx entry 149 | 150 | public int UnknownFlag = 0; 151 | public int UnknownIndex1 = -1; 152 | public int UnknownIndex2 = -1; 153 | public int UnknownValue = -1; 154 | 155 | public static bool operator ==(Entry x, Entry y) 156 | { 157 | if (ReferenceEquals(x, null)) return ReferenceEquals(y, null); 158 | if (ReferenceEquals(y, null)) return ReferenceEquals(x, null); 159 | if (x.id != y.id) return false; 160 | if (x.zone_id != y.zone_id) return false; 161 | if (x.entity != y.entity) return false; 162 | return true; 163 | } 164 | public static bool operator !=(Entry x, Entry y) 165 | { 166 | return !(x == y); 167 | } 168 | 169 | public override bool Equals(object obj) 170 | { 171 | return obj is Entry entry && 172 | EqualityComparer.Default.Equals(id, entry.id) && 173 | EqualityComparer.Default.Equals(entity, entry.entity) && 174 | EqualityComparer.Default.Equals(zone_id, entry.zone_id); 175 | } 176 | 177 | public override int GetHashCode() 178 | { 179 | int hashCode = 1001543423; 180 | hashCode = hashCode * -1521134295 + id.GetHashCode(); 181 | hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(entity); 182 | hashCode = hashCode * -1521134295 + zone_id.GetHashCode(); 183 | return hashCode; 184 | } 185 | }; 186 | #endregion 187 | } 188 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/Collisions.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | #if UNITY_EDITOR || UNITY_STANDALONE_WIN 7 | using UnityEngine; 8 | #else 9 | using System.Numerics; 10 | #endif 11 | 12 | namespace CATHODE.EXPERIMENTAL 13 | { 14 | /* DATA/ENV/PRODUCTION/x/WORLD/COLLISION.BIN */ 15 | public class Collisions : CathodeFile 16 | { 17 | public List Entries = new List(); 18 | public static new Implementation Implementation = Implementation.NONE; 19 | public Collisions(string path) : base(path) { } 20 | 21 | #region FILE_IO 22 | override protected bool LoadInternal() 23 | { 24 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 25 | { 26 | //remove these if exceptions dont throw 27 | byte[] magic = reader.ReadBytes(4); 28 | if (!magic.SequenceEqual(new byte[4] { 0x0C, 0xA0, 0xFE, 0xEF })) throw new Exception(); 29 | int ver = reader.ReadInt32(); 30 | if (ver != 2) throw new Exception(); 31 | int zer = reader.ReadInt32(); 32 | if (zer != 0) throw new Exception(); 33 | 34 | int dataSize = reader.ReadInt32(); 35 | int entryCount = reader.ReadInt32(); 36 | int objectCount = reader.ReadInt32(); 37 | int vertexCount = reader.ReadInt32(); 38 | int indexCount = reader.ReadInt32(); 39 | 40 | for (int i = 0; i < entryCount; i++) 41 | { 42 | alien_collision_bin_entry entry = new alien_collision_bin_entry(); 43 | entry.VertexCount = reader.ReadInt32(); 44 | entry.ObjectCount = reader.ReadInt32(); 45 | entry.UnknownFloat = reader.ReadSingle(); 46 | entry.UnknownBoolean = reader.ReadInt32(); 47 | Entries.Add(entry); 48 | } 49 | 50 | List objects = new List(); 51 | for (int i = 0; i < objectCount; i++) 52 | { 53 | alien_collision_bin_object obj = new alien_collision_bin_object(); 54 | obj.Transform = Utilities.Consume(reader); 55 | obj.UnknownFloat = reader.ReadSingle(); 56 | obj.UnknownIndex0 = reader.ReadInt32(); 57 | obj.IndexCount = reader.ReadInt32(); 58 | obj.VertexCount = reader.ReadInt32(); 59 | objects.Add(obj); 60 | } 61 | 62 | List vertexes = new List(); 63 | for (int i = 0; i < vertexCount; i++) 64 | { 65 | alien_collision_bin_vertex vertex = new alien_collision_bin_vertex(); 66 | byte[] bytes = reader.ReadBytes(6); //vec3 s16 67 | vertex.UnknownBytes = reader.ReadBytes(10); 68 | vertexes.Add(vertex); 69 | } 70 | 71 | List indicies = new List(); 72 | for (int i = 0; i < indexCount; i++) 73 | { 74 | indicies.Add(reader.ReadInt16()); 75 | } 76 | 77 | int verIndex = 0; 78 | int objIndex = 0; 79 | int indIndex = 0; 80 | for (int i = 0; i < entryCount; ++i) 81 | { 82 | alien_collision_bin_entry Entry = Entries[i]; 83 | 84 | Entry.Vertices = vertexes.GetRange(verIndex, verIndex + Entry.VertexCount); 85 | Entry.Objects = objects.GetRange(objIndex, objIndex + Entry.ObjectCount); 86 | 87 | for (int x = 0; x < Entry.ObjectCount; ++x) 88 | { 89 | alien_collision_bin_object Entry1 = Entry.Objects[x]; 90 | //Assert(Entry1->UnknownFloat == 4); 91 | 92 | Entry1.Indices = indicies.GetRange(indIndex, indIndex + Entry1.IndexCount); 93 | Entry1.Vertices = vertexes.GetRange(verIndex, verIndex + Entry1.VertexCount); 94 | } 95 | } 96 | } 97 | return true; 98 | } 99 | 100 | override protected bool SaveInternal() 101 | { 102 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 103 | { 104 | writer.BaseStream.SetLength(0); 105 | writer.Write(new byte[4] { 0x0C, 0xA0, 0xFE, 0xEF }); 106 | writer.Write(2); 107 | writer.Write(0); 108 | 109 | } 110 | return true; 111 | } 112 | #endregion 113 | 114 | #region STRUCTURES 115 | public class alien_collision_bin_object 116 | { 117 | public Matrix4x4 Transform; // NOTE: Transpose me! 118 | public float UnknownFloat; 119 | public int UnknownIndex0; 120 | public int IndexCount; 121 | public int VertexCount; 122 | public List Indices = new List(); 123 | public List Vertices = new List(); 124 | }; 125 | public class alien_collision_bin_vertex 126 | { 127 | public Vector3 point; //int16[3] 128 | public byte[] UnknownBytes = new byte[10]; 129 | }; 130 | public class alien_collision_bin_entry 131 | { 132 | public int VertexCount; 133 | public int ObjectCount; 134 | public List Vertices = new List(); 135 | public List Objects = new List(); 136 | public float UnknownFloat; 137 | public int UnknownBoolean; // NOTE: Only saw either zero or one here so far. 138 | }; 139 | #endregion 140 | } 141 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Composite.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting.Internal; 2 | using System; 3 | using System.Collections.Generic; 4 | #if UNITY_EDITOR || UNITY_STANDALONE 5 | using UnityEngine; 6 | #else 7 | #endif 8 | 9 | namespace CATHODE.Scripting 10 | { 11 | /* A script composite containing entities */ 12 | [Serializable] 13 | public class Composite 14 | { 15 | public Composite() { } 16 | public Composite(string name) 17 | { 18 | shortGUID = ShortGuidUtils.GenerateRandom(); 19 | this.name = name; 20 | } 21 | 22 | ~Composite() 23 | { 24 | variables.Clear(); 25 | functions.Clear(); 26 | aliases.Clear(); 27 | proxies.Clear(); 28 | } 29 | 30 | public ShortGuid shortGUID; //The id when this composite is used as an entity in another composite 31 | public string name = ""; //The string name of the composite 32 | 33 | public List variables = new List(); //Variables which can be accessed outside of this composite as parameters, and connected to entities internally 34 | public List functions = new List(); //Functional nodes, including hard-coded functions and references to other composites 35 | 36 | public List aliases = new List(); //Aliases of entities in child composites 37 | public List proxies = new List(); //Entites acting as entities from other composites 38 | 39 | /* If an entity exists in the composite, return it */ 40 | public Entity GetEntityByID(ShortGuid id) 41 | { 42 | foreach (Entity entity in variables) if (entity.shortGUID == id) return entity; 43 | foreach (Entity entity in functions) if (entity.shortGUID == id) return entity; 44 | foreach (Entity entity in aliases) if (entity.shortGUID == id) return entity; 45 | foreach (Entity entity in proxies) if (entity.shortGUID == id) return entity; 46 | return null; 47 | } 48 | 49 | /* Returns a collection of all entities in the composite */ 50 | public List GetEntities() 51 | { 52 | List toReturn = new List(variables.Count + functions.Count + aliases.Count + proxies.Count); 53 | toReturn.AddRange(variables); 54 | toReturn.AddRange(functions); 55 | toReturn.AddRange(aliases); 56 | toReturn.AddRange(proxies); 57 | return toReturn; 58 | } 59 | 60 | /* Returns a collection of function entities in the composite matching the given type */ 61 | public List GetFunctionEntitiesOfType(FunctionType type) 62 | { 63 | ShortGuid guid = CommandsUtils.GetFunctionTypeGUID(type); 64 | return functions.FindAll(o => o.function == guid); 65 | } 66 | 67 | /* Removes all function entities in the composite matching the given type */ 68 | public void RemoveAllFunctionEntitiesOfType(FunctionType type) 69 | { 70 | ShortGuid guid = CommandsUtils.GetFunctionTypeGUID(type); 71 | functions.RemoveAll(o => o.function == guid); 72 | } 73 | 74 | /* Add a new function entity */ 75 | public FunctionEntity AddFunction(FunctionType function) 76 | { 77 | FunctionEntity func = null; 78 | switch (function) { 79 | case FunctionType.CAGEAnimation: 80 | func = new CAGEAnimation(); 81 | break; 82 | case FunctionType.TriggerSequence: 83 | func = new TriggerSequence(); 84 | break; 85 | default: 86 | func = new FunctionEntity(function); 87 | break; 88 | } 89 | functions.Add(func); 90 | return func; 91 | } 92 | public FunctionEntity AddFunction(Composite composite) 93 | { 94 | FunctionEntity func = new FunctionEntity(composite); 95 | functions.Add(func); 96 | return func; 97 | } 98 | 99 | /* Add a new variable entity */ 100 | public VariableEntity AddVariable(string parameter, DataType type) 101 | { 102 | VariableEntity vari = new VariableEntity(parameter, type); 103 | variables.Add(vari); 104 | return vari; 105 | } 106 | 107 | /* Add a new proxy entity */ 108 | public ProxyEntity AddProxy(Commands commands, ShortGuid[] hierarchy) 109 | { 110 | CommandsUtils.ResolveHierarchy(commands, this, hierarchy, out Composite targetComposite, out string str); 111 | Entity ent = targetComposite.GetEntityByID(hierarchy[hierarchy.Length - 2]); 112 | if (ent.variant != EntityVariant.FUNCTION) return null; 113 | 114 | ProxyEntity proxy = new ProxyEntity(hierarchy, ((FunctionEntity)ent).function); 115 | proxies.Add(proxy); 116 | return proxy; 117 | } 118 | 119 | /* Add a new alias entity */ 120 | public AliasEntity AddAlias(ShortGuid[] hierarchy) 121 | { 122 | AliasEntity alias = new AliasEntity(hierarchy); 123 | aliases.Add(alias); 124 | return alias; 125 | } 126 | 127 | public override string ToString() 128 | { 129 | return name; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Parameter.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting.Internal; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace CATHODE.Scripting 7 | { 8 | /* A parameter which consists of a name and data, with a variant for how it is used */ 9 | [Serializable] 10 | public class Parameter 11 | { 12 | public Parameter(string name, ParameterData data, ParameterVariant var = ParameterVariant.PARAMETER) 13 | { 14 | this.name = ShortGuidUtils.Generate(name); 15 | content = data; 16 | variant = var; 17 | } 18 | public Parameter(ShortGuid id, ParameterData data, ParameterVariant var = ParameterVariant.PARAMETER) 19 | { 20 | name = id; 21 | content = data; 22 | variant = var; 23 | } 24 | 25 | public ShortGuid name; 26 | public ParameterData content = null; 27 | public ParameterVariant variant = ParameterVariant.PARAMETER; 28 | 29 | ~Parameter() 30 | { 31 | content = null; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/CommandsPAK/Components/ResourceReference.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System; 3 | using System.Collections.Generic; 4 | #if UNITY_EDITOR || UNITY_STANDALONE_WIN 5 | using UnityEngine; 6 | #else 7 | using System.Numerics; 8 | #endif 9 | 10 | namespace CATHODE.Scripting 11 | { 12 | /* A reference to a game resource (E.G. a renderable element, a collision mapping, etc) */ 13 | [Serializable] 14 | public class ResourceReference : ICloneable 15 | { 16 | public ResourceReference() 17 | { 18 | 19 | } 20 | public ResourceReference(ResourceType type) 21 | { 22 | switch (type) 23 | { 24 | case ResourceType.DYNAMIC_PHYSICS_SYSTEM: 25 | case ResourceType.RENDERABLE_INSTANCE: 26 | case ResourceType.ANIMATED_MODEL: 27 | index = 0; 28 | break; 29 | } 30 | resource_type = type; 31 | } 32 | 33 | public static bool operator ==(ResourceReference x, ResourceReference y) 34 | { 35 | if (ReferenceEquals(x, null)) return ReferenceEquals(y, null); 36 | if (ReferenceEquals(y, null)) return ReferenceEquals(x, null); 37 | 38 | if (x.position != y.position) return false; 39 | if (x.rotation != y.rotation) return false; 40 | if (x.resource_id != y.resource_id) return false; 41 | if (x.resource_type != y.resource_type) return false; 42 | if (x.index != y.index) return false; 43 | if (x.count != y.count) return false; 44 | if (x.entityID != y.entityID) return false; 45 | 46 | return true; 47 | } 48 | public static bool operator !=(ResourceReference x, ResourceReference y) 49 | { 50 | return !(x == y); 51 | } 52 | 53 | public object Clone() 54 | { 55 | return this.MemberwiseClone(); 56 | } 57 | 58 | public override bool Equals(object obj) 59 | { 60 | return obj is ResourceReference reference && 61 | EqualityComparer.Default.Equals(position, reference.position) && 62 | EqualityComparer.Default.Equals(rotation, reference.rotation) && 63 | EqualityComparer.Default.Equals(resource_id, reference.resource_id) && 64 | resource_type == reference.resource_type && 65 | index == reference.index && 66 | count == reference.count && 67 | EqualityComparer.Default.Equals(entityID, reference.entityID); 68 | } 69 | 70 | public override int GetHashCode() 71 | { 72 | int hashCode = -1286985782; 73 | hashCode = hashCode * -1521134295 + position.GetHashCode(); 74 | hashCode = hashCode * -1521134295 + rotation.GetHashCode(); 75 | hashCode = hashCode * -1521134295 + resource_id.GetHashCode(); 76 | hashCode = hashCode * -1521134295 + resource_type.GetHashCode(); 77 | hashCode = hashCode * -1521134295 + index.GetHashCode(); 78 | hashCode = hashCode * -1521134295 + count.GetHashCode(); 79 | hashCode = hashCode * -1521134295 + entityID.GetHashCode(); 80 | return hashCode; 81 | } 82 | 83 | public Vector3 position = new Vector3(0, 0, 0); 84 | public Vector3 rotation = new Vector3(0, 0, 0); 85 | 86 | public ShortGuid resource_id; //this can be translated to a string sometimes, like DYNAMIC_PHYSICS_SYSTEM 87 | public ResourceType resource_type; 88 | 89 | public int index = -1; 90 | public int count = 1; 91 | 92 | public ShortGuid entityID = new ShortGuid("FF-FF-FF-FF"); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/CommandsPAK/Components/ShortGuid.cs: -------------------------------------------------------------------------------- 1 | #if DEBUG 2 | using Newtonsoft.Json; 3 | #endif 4 | using System; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Runtime.InteropServices; 8 | 9 | namespace CATHODE.Scripting 10 | { 11 | /* A unique id assigned to CATHODE objects */ 12 | [Serializable] 13 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 14 | #if DEBUG 15 | [JsonConverter(typeof(ShortGuidConverter))] 16 | #endif 17 | public struct ShortGuid : IComparable 18 | { 19 | public static readonly ShortGuid Invalid = new ShortGuid(0); 20 | public static readonly ShortGuid InitialiserBase = new ShortGuid(1257266174); //"FE-5B-F0-4A" 21 | public static readonly ShortGuid Max = new ShortGuid(4294967295); //"FF-FF-FF-FF" 22 | 23 | public bool IsInvalid => val == Invalid.val; 24 | 25 | private UInt32 val; 26 | 27 | public ShortGuid(BinaryReader reader) 28 | { 29 | val = reader.ReadUInt32(); 30 | } 31 | public ShortGuid(float num) 32 | { 33 | val = Convert.ToUInt32(num); 34 | } 35 | public ShortGuid(uint num) 36 | { 37 | val = num; 38 | } 39 | 40 | public ShortGuid(byte[] id) 41 | { 42 | val = BitConverter.ToUInt32(id, 0); 43 | } 44 | 45 | public ShortGuid(string id) 46 | { 47 | System.String[] arr = id.Split('-'); 48 | if (arr.Length != 4) throw new Exception("Tried to initialise ShortGuid without 4-byte ID string."); 49 | byte[] array = new byte[arr.Length]; 50 | for (int i = 0; i < arr.Length; i++) array[i] = Convert.ToByte(arr[i], 16); 51 | val = BitConverter.ToUInt32(array, 0); 52 | } 53 | 54 | public override bool Equals(object obj) 55 | { 56 | if (!(obj is ShortGuid)) return false; 57 | return ((ShortGuid)obj).val == this.val; 58 | } 59 | public static bool operator ==(ShortGuid x, ShortGuid y) 60 | { 61 | if (ReferenceEquals(x, null)) return ReferenceEquals(y, null); 62 | return x.val == y.val; 63 | } 64 | public static bool operator !=(ShortGuid x, ShortGuid y) 65 | { 66 | return !(x.val == y.val); 67 | } 68 | 69 | public static bool operator ==(ShortGuid x, string y) 70 | { 71 | return x.ToByteString() == y; 72 | } 73 | 74 | public static bool operator !=(ShortGuid x, string y) 75 | { 76 | return x.ToByteString() != y; 77 | } 78 | 79 | public static bool operator ==(ShortGuid x, uint y) 80 | { 81 | return x.ToUInt32() == y; 82 | } 83 | public static bool operator !=(ShortGuid x, uint y) 84 | { 85 | return x.ToUInt32() != y; 86 | } 87 | 88 | public override int GetHashCode() 89 | { 90 | return 1835847388 + val.GetHashCode(); 91 | } 92 | 93 | public int CompareTo(ShortGuid x) 94 | { 95 | if (x == null) return 1; 96 | 97 | if (this.val > x.val) 98 | return 1; 99 | else if (this.val < x.val) 100 | return -1; 101 | 102 | return 0; 103 | } 104 | 105 | public override string ToString() 106 | { 107 | return ShortGuidUtils.FindString(this); 108 | } 109 | public uint ToUInt32() 110 | { 111 | return val; 112 | } 113 | 114 | public string ToByteString() 115 | { 116 | return BitConverter.ToString(BitConverter.GetBytes(val)); 117 | } 118 | 119 | public byte[] ToBytes() 120 | { 121 | return BitConverter.GetBytes(val); 122 | } 123 | } 124 | 125 | #if DEBUG 126 | public class ShortGuidConverter : JsonConverter 127 | { 128 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 129 | { 130 | ShortGuid user = (ShortGuid)value; 131 | writer.WriteValue(user.ToString()); 132 | } 133 | 134 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 135 | { 136 | return new ShortGuid((byte[])reader.Value); 137 | } 138 | 139 | public override bool CanConvert(Type objectType) 140 | { 141 | return objectType == typeof(ShortGuid); 142 | } 143 | } 144 | #endif 145 | } 146 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/EnumUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using CATHODE; 6 | using CATHODE.Scripting; 7 | using CathodeLib; 8 | #if UNITY_EDITOR || UNITY_STANDALONE 9 | using UnityEngine; 10 | #endif 11 | 12 | namespace CATHODE.Scripting 13 | { 14 | public static class EnumUtils 15 | { 16 | private static List lookup_enum; 17 | static EnumUtils() 18 | { 19 | #if UNITY_EDITOR || UNITY_STANDALONE 20 | byte[] dbContent = File.ReadAllBytes(Application.streamingAssetsPath + "/NodeDBs/cathode_enum_lut.bin"); 21 | #else 22 | byte[] dbContent = CathodeLib.Properties.Resources.cathode_enum_lut; 23 | if (File.Exists("LocalDB/cathode_enum_lut.bin")) 24 | dbContent = File.ReadAllBytes("LocalDB/cathode_enum_lut.bin"); 25 | #endif 26 | lookup_enum = ReadDB(dbContent).Cast().ToList(); 27 | } 28 | 29 | //Check the formatted enum dump for content 30 | public static EnumDescriptor GetEnum(string name) 31 | { 32 | ShortGuid id = ShortGuidUtils.Generate(name); 33 | return GetEnum(id); 34 | } 35 | public static EnumDescriptor GetEnum(ShortGuid id) 36 | { 37 | return lookup_enum.FirstOrDefault(o => o.ID == id); 38 | } 39 | 40 | //Read a generic entity database file 41 | private static List ReadDB(byte[] db_content) 42 | { 43 | List toReturn = new List(); 44 | BinaryReader reader = new BinaryReader(new MemoryStream(db_content)); 45 | int count = reader.ReadInt32(); 46 | for (int i = 0; i < count; i++) 47 | { 48 | EnumDescriptor thisDesc = new EnumDescriptor(); 49 | thisDesc.ID = new ShortGuid(reader.ReadBytes(4)); 50 | thisDesc.Name = reader.ReadString(); 51 | int entryCount = reader.ReadInt32(); 52 | for (int x = 0; x < entryCount; x++) 53 | thisDesc.Entries.Add(new EnumDescriptor.Entry() { Name = reader.ReadString(), Index = reader.ReadInt32() }); 54 | toReturn.Add(thisDesc); 55 | } 56 | reader.Close(); 57 | return toReturn; 58 | } 59 | 60 | public class EnumDescriptor 61 | { 62 | public string Name; 63 | public List Entries = new List(); 64 | public ShortGuid ID; 65 | 66 | public class Entry 67 | { 68 | public string Name; 69 | public int Index; 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs: -------------------------------------------------------------------------------- 1 | //#define DO_DEBUG_DUMP 2 | 3 | using CATHODE.Scripting.Internal; 4 | using CathodeLib; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Diagnostics; 8 | using System.IO; 9 | using System.Security.Cryptography; 10 | using System.Text; 11 | #if UNITY_EDITOR || UNITY_STANDALONE 12 | using UnityEngine; 13 | #endif 14 | 15 | namespace CATHODE.Scripting 16 | { 17 | public static class ShortGuidUtils 18 | { 19 | private static GuidNameTable _vanilla = null; 20 | private static GuidNameTable _custom = null; 21 | 22 | public static Commands LinkedCommands => _commands; 23 | private static Commands _commands; 24 | 25 | /* Pull in strings we know are cached as ShortGuid in Cathode */ 26 | static ShortGuidUtils() 27 | { 28 | #if UNITY_EDITOR || UNITY_STANDALONE 29 | byte[] dbContent = File.ReadAllBytes(Application.streamingAssetsPath + "/NodeDBs/cathode_shortguid_lut.bin"); 30 | #else 31 | byte[] dbContent = CathodeLib.Properties.Resources.cathode_shortguid_lut; 32 | if (File.Exists("LocalDB/cathode_shortguid_lut.bin")) 33 | dbContent = File.ReadAllBytes("LocalDB/cathode_shortguid_lut.bin"); 34 | #endif 35 | 36 | BinaryReader reader = new BinaryReader(new MemoryStream(dbContent)); 37 | _vanilla = new GuidNameTable(); 38 | _custom = new GuidNameTable(); 39 | while (reader.BaseStream.Position < reader.BaseStream.Length) 40 | Cache(new ShortGuid(reader), reader.ReadString(), true); 41 | reader.Close(); 42 | 43 | #if DO_DEBUG_DUMP 44 | Directory.CreateDirectory("DebugDump"); 45 | List parameters = new List(); 46 | foreach (KeyValuePair value in _vanilla.cache) 47 | { 48 | parameters.Add(value.Key); 49 | } 50 | parameters.Sort(); 51 | File.WriteAllLines("DebugDump/parameters.txt", parameters); 52 | #endif 53 | } 54 | 55 | /* Optionally, link a Commands file which can be used to save custom ShortGuids to */ 56 | public static void LinkCommands(Commands commands) 57 | { 58 | if (_commands != null) 59 | _commands.OnSaveSuccess -= SaveCustomNames; 60 | 61 | _commands = commands; 62 | if (_commands == null) return; 63 | 64 | _commands.OnSaveSuccess += SaveCustomNames; 65 | 66 | LoadCustomNames(commands.Filepath); 67 | } 68 | 69 | /* Generate a ShortGuid to interface with the Cathode scripting system */ 70 | public static ShortGuid Generate(string value, bool cache = true) 71 | { 72 | if (_custom.cache.TryGetValue(value, out ShortGuid customVal)) 73 | return customVal; 74 | if (_vanilla.cache.TryGetValue(value, out ShortGuid vanillaVal)) 75 | return vanillaVal; 76 | 77 | SHA1Managed sha1 = new SHA1Managed(); 78 | byte[] hash1 = sha1.ComputeHash(Encoding.UTF8.GetBytes(value)); 79 | //This is referred to as LongGuid - should we make a thing for it? 80 | byte[] arrangedHash = new byte[] { 81 | hash1[3], hash1[2], hash1[1], hash1[0], 82 | hash1[7], hash1[6], hash1[5], hash1[4], 83 | hash1[11], hash1[10], hash1[9], hash1[8], 84 | hash1[15], hash1[14], hash1[13], hash1[12] 85 | }; 86 | byte[] hash2 = sha1.ComputeHash(Encoding.UTF8.GetBytes(BitConverter.ToString(arrangedHash).Replace("-", string.Empty))); 87 | ShortGuid guid = new ShortGuid(new byte[] { hash2[0], hash2[1], hash2[2], hash2[3] }); 88 | if (cache) Cache(guid, value); 89 | return guid; 90 | } 91 | 92 | /* Combines two ShortGuid objects into one */ 93 | public static ShortGuid Combine(this ShortGuid guid1, ShortGuid guid2) 94 | { 95 | if (guid2.ToUInt32() != 0) 96 | { 97 | if (guid1.ToUInt32() != 0) 98 | { 99 | byte[] guid1_b = guid1.ToBytes(); 100 | byte[] guid2_b = guid2.ToBytes(); 101 | 102 | ulong hash = BitConverter.ToUInt64(new byte[8] { guid1_b[0], guid1_b[1], guid1_b[2], guid1_b[3], guid2_b[0], guid2_b[1], guid2_b[2], guid2_b[3] }, 0); 103 | hash = ~hash + hash * 262144; hash = (hash ^ (hash >> 31)) * 21; hash = (hash ^ (hash >> 11)) * 65; 104 | return new ShortGuid(((uint)(hash >> 22) ^ (uint)hash)); 105 | } 106 | return guid2; 107 | } 108 | return guid1; 109 | } 110 | 111 | /* Attempts to look up the string for a given ShortGuid */ 112 | public static string FindString(ShortGuid guid) 113 | { 114 | if (_custom.cacheReversed.TryGetValue(guid, out string customVal)) 115 | return customVal; 116 | if (_vanilla.cacheReversed.TryGetValue(guid, out string vanillaVal)) 117 | return vanillaVal; 118 | 119 | return guid.ToByteString(); 120 | } 121 | 122 | /* Generate a random unique ShortGuid */ 123 | public static ShortGuid GenerateRandom() 124 | { 125 | string str = Guid.NewGuid().ToString(); 126 | ShortGuid guid = Generate(str, false); 127 | int s = 0; 128 | while (_vanilla.cache.ContainsKey(str) || _custom.cache.ContainsKey(str) || _vanilla.cacheReversed.ContainsKey(guid) || _custom.cacheReversed.ContainsKey(guid)) 129 | { 130 | str = $"{str}_{s++}"; 131 | guid = Generate(str, false); 132 | 133 | if (s > 10000) throw new Exception("Failed to generate unique ShortGuid after many attempts."); 134 | } 135 | Cache(guid, str); 136 | return guid; 137 | } 138 | 139 | /* Cache a pre-generated ShortGuid */ 140 | private static void Cache(ShortGuid guid, string value, bool isVanilla = false) 141 | { 142 | if (isVanilla) 143 | { 144 | if (_vanilla.cache.ContainsKey(value)) return; 145 | _vanilla.cache.Add(value, guid); 146 | _vanilla.cacheReversed.Add(guid, value); 147 | } 148 | else 149 | { 150 | //TODO: need to fix this for BSPNOSTROMO_RIPLEY_PATCH (?) 151 | if (_custom.cache.ContainsKey(value)) return; 152 | _custom.cache.Add(value, guid); 153 | try 154 | { 155 | _custom.cacheReversed.Add(guid, value); 156 | } 157 | catch { } 158 | } 159 | } 160 | 161 | /* Pull non-vanilla ShortGuid from the CommandsPAK */ 162 | private static void LoadCustomNames(string filepath) 163 | { 164 | _custom = (GuidNameTable)CustomTable.ReadTable(filepath, CustomEndTables.SHORT_GUIDS); 165 | if (_custom == null) _custom = new GuidNameTable(); 166 | Console.WriteLine("Loaded " + _custom.cache.Count + " custom ShortGuids!"); 167 | } 168 | 169 | /* Write non-vanilla entity names to the CommandsPAK */ 170 | private static void SaveCustomNames(string filepath) 171 | { 172 | CustomTable.WriteTable(filepath, CustomEndTables.SHORT_GUIDS, _custom); 173 | Console.WriteLine("Saved " + _custom.cache.Count + " custom ShortGuids!"); 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/CustomCharacterConstrainedComponents.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using CathodeLib; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Runtime.InteropServices; 8 | using static CATHODE.EXPERIMENTAL.MissionSave; 9 | 10 | namespace CATHODE 11 | { 12 | /* DATA/CHR_INFO/CUSTOMCHARACTERCONSTRAINEDCOMPONENTS.BIN */ 13 | public class CustomCharacterConstrainedComponents : CathodeFile 14 | { 15 | public List Entries = new List(); 16 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 17 | public CustomCharacterConstrainedComponents(string path) : base(path) { } 18 | 19 | #region FILE_IO 20 | override protected bool LoadInternal() 21 | { 22 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 23 | { 24 | reader.BaseStream.Position = 4; 25 | Read(ComponentType.ARMS, reader); 26 | Read(ComponentType.HEADS, reader); 27 | } 28 | return true; 29 | } 30 | 31 | override protected bool SaveInternal() 32 | { 33 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 34 | { 35 | writer.BaseStream.SetLength(0); 36 | writer.Write(20); 37 | for (int i = 0; i < Entries.Count; i++) 38 | { 39 | writer.Write(Entries[i].Components.Count); 40 | for (int x = 0; x < Entries[i].Components.Count; x++) 41 | { 42 | writer.Write(new byte[64]); 43 | writer.BaseStream.Position -= 64; 44 | Utilities.WriteString(Entries[i].Components[x].Name, writer, false); 45 | writer.BaseStream.Position += 64 - Entries[i].Components[x].Name.Length; 46 | 47 | writer.Write(Entries[i].Components[x].unk1); 48 | writer.Write(Entries[i].Components[x].unk2); 49 | writer.Write(Entries[i].Components[x].unk3); 50 | writer.Write(Entries[i].Components[x].unk4); 51 | writer.Write(Entries[i].Components[x].unk5); 52 | writer.Write(Entries[i].Components[x].unk6); 53 | } 54 | } 55 | } 56 | return true; 57 | } 58 | #endregion 59 | 60 | #region HELPERS 61 | private void Read(ComponentType type, BinaryReader reader) 62 | { 63 | int entryCount = reader.ReadInt32(); 64 | Entry arms = new Entry() { Type = ComponentType.ARMS }; 65 | for (int i = 0; i < entryCount; i++) 66 | { 67 | Entry.Component component = new Entry.Component(); 68 | byte[] stringBlock = reader.ReadBytes(64); 69 | component.Name = Utilities.ReadString(stringBlock); 70 | 71 | //TODO: these seem to get concatenated in code 72 | component.unk1 = reader.ReadInt32(); 73 | component.unk2 = reader.ReadInt32(); 74 | component.unk3 = reader.ReadInt32(); 75 | component.unk4 = reader.ReadInt32(); 76 | component.unk5 = reader.ReadInt32(); 77 | component.unk6 = reader.ReadInt32(); 78 | 79 | arms.Components.Add(component); 80 | } 81 | Entries.Add(arms); 82 | } 83 | #endregion 84 | 85 | #region STRUCTURES 86 | public class Entry 87 | { 88 | public ComponentType Type; 89 | public List Components = new List(); 90 | 91 | public class Component 92 | { 93 | public string Name; 94 | 95 | public int unk1; 96 | public int unk2; 97 | public int unk3; 98 | public int unk4; 99 | public int unk5; 100 | public int unk6; 101 | } 102 | }; 103 | 104 | public enum ComponentType 105 | { 106 | ARMS, 107 | HEADS, 108 | } 109 | #endregion 110 | } 111 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/CustomCharacterInfo.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using CathodeLib; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Runtime.InteropServices; 8 | 9 | namespace CATHODE 10 | { 11 | /* DATA/CHR_INFO/CUSTOMCHARACTERINFO.BIN */ 12 | public class CustomCharacterInfo : CathodeFile 13 | { 14 | public List Entries = new List(); 15 | public static new Implementation Implementation = Implementation.NONE; 16 | public CustomCharacterInfo(string path) : base(path) { } 17 | 18 | #region FILE_IO 19 | override protected bool LoadInternal() 20 | { 21 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 22 | { 23 | reader.BaseStream.Position = 4; 24 | int entryCount = 99; 25 | for (int i = 0; i < entryCount; i++) 26 | { 27 | byte[] stringBlock = reader.ReadBytes(64); 28 | Console.WriteLine(Utilities.ReadString(stringBlock)); 29 | } 30 | } 31 | return true; 32 | } 33 | 34 | override protected bool SaveInternal() 35 | { 36 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 37 | { 38 | writer.BaseStream.SetLength(0); 39 | writer.Write(20); 40 | for (int i = 0; i < Entries.Count; i++) 41 | { 42 | 43 | } 44 | } 45 | return true; 46 | } 47 | #endregion 48 | 49 | #region STRUCTURES 50 | public class Entry 51 | { 52 | 53 | }; 54 | #endregion 55 | } 56 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/EnvironmentMaps.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace CATHODE 8 | { 9 | /* DATA/ENV/PRODUCTION/x/WORLD/ENVIRONMENTMAP.BIN */ 10 | public class EnvironmentMaps : CathodeFile 11 | { 12 | public List Entries = new List(); 13 | public static new Implementation Implementation = Implementation.LOAD | Implementation.SAVE | Implementation.CREATE; 14 | public EnvironmentMaps(string path) : base(path) { } 15 | 16 | //This is the number of environment maps in the level. We should never reference an index higher than this. 17 | public int EnvironmentMapCount = 0; 18 | 19 | #region FILE_IO 20 | override protected bool LoadInternal() 21 | { 22 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 23 | { 24 | reader.BaseStream.Position += 8; 25 | int entryCount = reader.ReadInt32(); 26 | for (int i = 0; i < entryCount; i++) 27 | { 28 | Mapping entry = new Mapping(); 29 | entry.MoverIndex = reader.ReadInt32(); 30 | entry.EnvMapIndex = reader.ReadInt32(); 31 | Entries.Add(entry); 32 | } 33 | EnvironmentMapCount = reader.ReadInt32(); 34 | } 35 | return true; 36 | } 37 | 38 | override protected bool SaveInternal() 39 | { 40 | List orderedEntries = Entries.OrderBy(o => o.MoverIndex).ToList(); 41 | 42 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 43 | { 44 | writer.BaseStream.SetLength(0); 45 | Utilities.WriteString("envm", writer); 46 | writer.Write(1); 47 | writer.Write(Entries.Count); 48 | for (int i = 0; i < orderedEntries.Count; i++) 49 | { 50 | writer.Write(orderedEntries[i].MoverIndex); 51 | writer.Write(orderedEntries[i].EnvMapIndex); 52 | } 53 | writer.Write(EnvironmentMapCount); 54 | } 55 | return true; 56 | } 57 | #endregion 58 | 59 | #region STRUCTURES 60 | public class Mapping 61 | { 62 | public int EnvMapIndex; //Sequential index of the env map in texture BIN, when only parsing entries of type CUBEMAP - NOT WRITE INDEX 63 | public int MoverIndex; //Index of the mover in the MODELS.MVR file to apply the env map to 64 | }; 65 | #endregion 66 | } 67 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/Helpers/SoundUtils.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text; 6 | #if UNITY_EDITOR || UNITY_STANDALONE 7 | using UnityEngine; 8 | #endif 9 | 10 | namespace CathodeLib 11 | { 12 | public static class SoundUtils 13 | { 14 | private static Dictionary nameLookup; 15 | 16 | static SoundUtils() 17 | { 18 | #if UNITY_EDITOR || UNITY_STANDALONE 19 | BinaryReader reader = new BinaryReader(File.OpenRead(Application.streamingAssetsPath + "/sound_names.bin")); 20 | #else 21 | BinaryReader reader = new BinaryReader(new MemoryStream(CathodeLib.Properties.Resources.sound_names)); 22 | #endif 23 | int count = reader.ReadInt32(); 24 | nameLookup = new Dictionary(count); 25 | for (int i = 0; i < count; i++) 26 | nameLookup.Add(reader.ReadUInt32(), Utilities.ReadString(reader)); 27 | } 28 | 29 | public static string GetSoundName(uint id) 30 | { 31 | if (nameLookup.TryGetValue(id, out string name)) 32 | return name; 33 | return id.ToString(); 34 | } 35 | 36 | public static uint GetSoundID(string name) 37 | { 38 | foreach (var entry in nameLookup) 39 | if (entry.Value == name) 40 | return entry.Key; 41 | return 0; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/Lights.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace CATHODE.EXPERIMENTAL 8 | { 9 | /* DATA/ENV/PRODUCTION/x/WORLD/LIGHTS.BIN */ 10 | public class Lights : CathodeFile 11 | { 12 | //NOTE: we can read this file in/out, but we don't really know the data yet. 13 | 14 | public List Indexes = new List(); 15 | public List Values = new List(); 16 | 17 | public int UnknownValue0; 18 | public int UnknownValue1; 19 | public int UnknownValue2; 20 | public int UnknownValue3; 21 | public int UnknownValue4; 22 | public int UnknownValue5; 23 | public int UnknownValue6; 24 | public int UnknownValue7; 25 | 26 | public static new Implementation Implementation = Implementation.NONE; 27 | public Lights(string path) : base(path) { } 28 | 29 | #region FILE_IO 30 | override protected bool LoadInternal() 31 | { 32 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 33 | { 34 | reader.BaseStream.Position += 8; 35 | int entryCount = reader.ReadInt32(); 36 | for (int i = 0; i < entryCount; i++) 37 | { 38 | Indexes.Add(reader.ReadInt32()); //I think this is MVR index 39 | } 40 | int nextCount = reader.ReadInt16(); 41 | 42 | //Assertions 43 | if (nextCount != (entryCount * 2) - 1) 44 | { 45 | string gdsfdsf = ""; 46 | } 47 | 48 | for (int i = 0; i < nextCount; i++) 49 | { 50 | short[] array = new short[18]; 51 | for (int x = 0; x < 18; x++) 52 | array[x] = reader.ReadInt16(); 53 | Values.Add(array); 54 | 55 | //Assertions 56 | if (array[17] != 0) 57 | { 58 | string sdsdfd = ""; 59 | } 60 | if (array[16] != 0 && array[16] != 1) 61 | { 62 | string sdsdfd = ""; 63 | } 64 | if (array[15] < 0) 65 | { 66 | string sdsdfd = ""; 67 | } 68 | if (array[14] < 0) 69 | { 70 | //i think this is an index 71 | string sdsdfd = ""; 72 | } 73 | } 74 | 75 | //Additional unknowns 76 | UnknownValue0 = reader.ReadChar(); 77 | UnknownValue1 = reader.ReadInt32(); 78 | UnknownValue2 = reader.ReadInt32(); 79 | UnknownValue3 = reader.ReadInt32(); 80 | UnknownValue4 = reader.ReadInt32(); 81 | UnknownValue5 = reader.ReadInt32(); 82 | UnknownValue6 = reader.ReadInt32(); 83 | UnknownValue7 = reader.ReadInt16(); 84 | 85 | //Assertions 86 | if (UnknownValue0 != 0 || 87 | UnknownValue1 != 0 || 88 | UnknownValue2 != 0 || 89 | UnknownValue3 != 0 || 90 | UnknownValue4 != 0 || 91 | UnknownValue5 != 0 || 92 | UnknownValue6 != 0 || 93 | UnknownValue7 != 0) 94 | { 95 | string dfdf = ""; 96 | } 97 | } 98 | return true; 99 | } 100 | 101 | override protected bool SaveInternal() 102 | { 103 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 104 | { 105 | //TODO: this data is ordered by array entry -4 and then -3 i think 106 | 107 | writer.BaseStream.SetLength(0); 108 | Utilities.WriteString("ligt", writer); 109 | writer.Write(4); 110 | writer.Write(Indexes.Count); 111 | for (int i = 0; i < Indexes.Count; i++) 112 | writer.Write(Indexes[i]); 113 | writer.Write((Int16)Values.Count); 114 | for (int i = 0; i < Values.Count; i++) 115 | { 116 | if (Values[i].Length != 18) 117 | throw new Exception("Entry was of unexpected length."); 118 | 119 | for (int x = 0; x < Values[i].Length; x++) 120 | writer.Write((Int16)Values[i][x]); 121 | } 122 | 123 | writer.Write((char)UnknownValue0); 124 | writer.Write(UnknownValue1); 125 | writer.Write(UnknownValue2); 126 | writer.Write(UnknownValue3); 127 | writer.Write(UnknownValue4); 128 | writer.Write(UnknownValue5); 129 | writer.Write(UnknownValue6); 130 | writer.Write((Int16)UnknownValue7); 131 | 132 | } 133 | return true; 134 | } 135 | #endregion 136 | 137 | #region STRUCTURES 138 | 139 | #endregion 140 | } 141 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/MaterialMappings.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace CATHODE 7 | { 8 | /* DATA/ENV/PRODUCTION/x/WORLD/MATERIAL_MAPPINGS.PAK */ 9 | public class MaterialMappings : CathodeFile 10 | { 11 | public List Entries = new List(); 12 | public static new Implementation Implementation = Implementation.LOAD | Implementation.SAVE; 13 | public MaterialMappings(string path) : base(path) { } 14 | 15 | private byte[] _headerJunk = new byte[8]; 16 | 17 | #region FILE_IO 18 | override protected bool LoadInternal() 19 | { 20 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 21 | { 22 | //Parse header 23 | _headerJunk = reader.ReadBytes(8); //TODO: Work out what this contains 24 | int entryCount = reader.ReadInt32(); 25 | 26 | //Parse entries (XML is broken in the build files - doesn't get shipped) 27 | for (int x = 0; x < entryCount; x++) 28 | { 29 | //This entry 30 | Mapping entry = new Mapping(); 31 | entry.MapHeader = reader.ReadBytes(4); //TODO: Work out the significance of this value, to be able to construct new PAKs from scratch. 32 | entry.MapEntryCoupleCount = reader.ReadInt32(); 33 | entry.MapJunk = reader.ReadBytes(4); //TODO: Work out if this is always null. 34 | for (int p = 0; p < (entry.MapEntryCoupleCount * 2) + 1; p++) 35 | { 36 | //String 37 | int length = reader.ReadInt32(); 38 | string materialString = ""; 39 | for (int i = 0; i < length; i++) 40 | { 41 | materialString += reader.ReadChar(); 42 | } 43 | 44 | //First string is filename, others are materials 45 | if (p == 0) 46 | { 47 | entry.MapFilename = materialString; 48 | } 49 | else 50 | { 51 | entry.MapMatEntries.Add(materialString); 52 | } 53 | } 54 | Entries.Add(entry); 55 | } 56 | } 57 | return true; 58 | } 59 | 60 | override protected bool SaveInternal() 61 | { 62 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 63 | { 64 | writer.BaseStream.SetLength(0); 65 | writer.Write(_headerJunk); 66 | writer.Write(Entries.Count); 67 | foreach (Mapping entry in Entries) 68 | { 69 | writer.Write(entry.MapHeader); 70 | writer.Write(entry.MapEntryCoupleCount); 71 | writer.Write(entry.MapJunk); 72 | writer.Write(entry.MapFilename.Length); 73 | Utilities.WriteString(entry.MapFilename, writer); 74 | foreach (string name in entry.MapMatEntries) 75 | { 76 | writer.Write(name.Length); 77 | Utilities.WriteString(name, writer); 78 | } 79 | } 80 | } 81 | return true; 82 | } 83 | #endregion 84 | 85 | #region STRUCTURES 86 | public class Mapping 87 | { 88 | public byte[] MapHeader = new byte[4]; 89 | public byte[] MapJunk = new byte[4]; //I think this is always null 90 | public string MapFilename = ""; 91 | public int MapEntryCoupleCount = 0; //materials will be 2* this number 92 | public List MapMatEntries = new List(); 93 | } 94 | #endregion 95 | } 96 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/Materials.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using CathodeLib; 6 | using static CATHODE.Models; 7 | 8 | namespace CATHODE 9 | { 10 | /* DATA/ENV/PRODUCTION/x/RENDERABLE/LEVEL_MODELS.MTL & LEVEL_MODELS.CST */ 11 | public class Materials : CathodeFile 12 | { 13 | public List Entries = new List(); 14 | public static new Implementation Implementation = Implementation.LOAD | Implementation.SAVE; 15 | public Materials(string path) : base(path) { } 16 | 17 | public List CSTData { get { return _cstData; } } //WIP 18 | private List _cstData = new List(); 19 | 20 | public int[] CSTOffsets { get { return _unknownOffsets; } } //WIP 21 | private int[] _unknownOffsets; 22 | 23 | private List _writeList = new List(); 24 | 25 | private string _filepathCST; 26 | 27 | #region FILE_IO 28 | override protected bool LoadInternal() 29 | { 30 | _filepathCST = _filepath.Substring(0, _filepath.Length - 3) + "CST"; 31 | if (!File.Exists(_filepathCST)) return false; 32 | 33 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 34 | { 35 | reader.BaseStream.Position = 8; 36 | int firstMaterialOffset = reader.ReadInt32(); 37 | 38 | List cstOffsets = new List(); 39 | for (int x = 0; x < 5; x++) cstOffsets.Add(reader.ReadInt32()); 40 | using (BinaryReader readerCST = new BinaryReader(File.OpenRead(_filepathCST))) 41 | { 42 | cstOffsets.Add((int)readerCST.BaseStream.Length/* - 4*/); 43 | //readerCST.BaseStream.Position = 4; 44 | for (int x = 0; x < cstOffsets.Count - 1; x++) 45 | _cstData.Add(readerCST.ReadBytes(cstOffsets[x+1] - cstOffsets[x])); 46 | } 47 | 48 | _unknownOffsets = Utilities.ConsumeArray(reader, 2); 49 | int entryCount = reader.ReadInt16(); 50 | reader.BaseStream.Position += 2; 51 | 52 | List materialNames = new List(entryCount); 53 | for (int i = 0; i < entryCount; ++i) materialNames.Add(Utilities.ReadString(reader)); 54 | 55 | reader.BaseStream.Position = firstMaterialOffset + 4; 56 | for (int i = 0; i < entryCount; i++) 57 | { 58 | Material material = new Material(); 59 | material.Name = materialNames[i]; 60 | for (int x = 0; x < 12; x++) 61 | { 62 | Material.Texture texRef = new Material.Texture(); 63 | texRef.BinIndex = reader.ReadInt16(); 64 | int texTableIndex = reader.ReadInt16(); 65 | if (texTableIndex == -1) continue; 66 | texRef.Source = (Material.Texture.TextureSource)texTableIndex; 67 | material.TextureReferences[x] = texRef; 68 | } 69 | reader.BaseStream.Position += 8; 70 | int[] cstIndexes = Utilities.ConsumeArray(reader, 5); 71 | for (int x = 0; x < 5; x++) 72 | { 73 | int cstCount = reader.ReadByte(); 74 | //TODO: just read the CST data into the material 75 | material.ConstantBuffers[x] = new Material.ConstantBuffer() { Offset = cstIndexes[x], Length = cstCount }; 76 | } 77 | reader.BaseStream.Position += 7; 78 | material.UnknownValue0 = reader.ReadInt32(); 79 | material.ShaderIndex = reader.ReadInt32(); 80 | reader.BaseStream.Position += 128; 81 | material.UnknownValue1 = reader.ReadInt32(); 82 | reader.BaseStream.Position += 48; 83 | material.Unknown4_ = reader.ReadInt32(); 84 | material.Color = reader.ReadInt32(); 85 | material.UnknownValue2 = reader.ReadInt32(); 86 | reader.BaseStream.Position += 8; 87 | Entries.Add(material); 88 | _writeList.Add(material); 89 | } 90 | } 91 | return true; 92 | } 93 | 94 | override protected bool SaveInternal() 95 | { 96 | //TODO: actually compute this 97 | using (BinaryWriter writerCST = new BinaryWriter(File.OpenWrite(_filepathCST))) 98 | { 99 | writerCST.BaseStream.SetLength(0); 100 | //writerCST.Write(new byte[4] { 0x0B, 0xD7, 0x23, 0x3C }); 101 | for (int i = 0; i < _cstData.Count; i++) 102 | writerCST.Write(_cstData[i]); 103 | } 104 | 105 | _writeList.Clear(); 106 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 107 | { 108 | writer.BaseStream.SetLength(0); 109 | 110 | //Write header 111 | writer.Write(0); //placeholder file length (-4) 112 | writer.Write(40); 113 | writer.Write(0); //placeholder material offset 114 | if (_cstData.Count != 5) throw new Exception("CST data is not formatted as expected!"); 115 | int cstOffset = 0; 116 | for (int x = 0; x < 5; x++) 117 | { 118 | writer.Write(cstOffset); 119 | cstOffset += _cstData[x].Length; 120 | } 121 | for (int i = 0; i < 2; i++) writer.Write(_unknownOffsets[i]); 122 | writer.Write((Int16)Entries.Count); 123 | writer.Write((Int16)296); 124 | 125 | //Write material names 126 | for (int i = 0; i < Entries.Count; ++i) Utilities.WriteString(Entries[i].Name, writer, true); 127 | Utilities.Align(writer, 4, 0x20); 128 | 129 | //Write material data 130 | int materialOffset = (int)writer.BaseStream.Position; 131 | for (int i = 0; i < Entries.Count; i++) 132 | { 133 | if (Entries[i].TextureReferences.Length != 12) throw new Exception("Incorrect texture references!"); 134 | for (int x = 0; x < 12; x++) 135 | { 136 | Material.Texture tex = Entries[i].TextureReferences[x]; 137 | if (tex == null) 138 | { 139 | writer.Write((Int16)(-1)); 140 | writer.Write((Int16)(-1)); 141 | } 142 | else 143 | { 144 | writer.Write((Int16)tex.BinIndex); 145 | writer.Write((Int16)tex.Source); 146 | } 147 | } 148 | writer.Write(new byte[4]); 149 | writer.Write((Int32)i); 150 | if (Entries[i].ConstantBuffers.Length != 5) throw new Exception("Incorrect constant buffer definitions!"); 151 | for (int x = 0; x < 5; x++) 152 | { 153 | writer.Write(Entries[i].ConstantBuffers[x].Offset); 154 | } 155 | for (int x = 0; x < 5; x++) 156 | { 157 | writer.Write((byte)Entries[i].ConstantBuffers[x].Length); 158 | } 159 | writer.Write(new byte[7]); 160 | writer.Write(Entries[i].UnknownValue0); 161 | writer.Write(Entries[i].ShaderIndex); 162 | writer.Write(new byte[128]); 163 | writer.Write(Entries[i].UnknownValue1); 164 | writer.Write(new byte[48]); 165 | writer.Write(Entries[i].Unknown4_); 166 | writer.Write(Entries[i].Color); 167 | writer.Write(Entries[i].UnknownValue2); 168 | writer.Write(new byte[8]); 169 | 170 | _writeList.Add(Entries[i]); 171 | } 172 | 173 | //Correct placeholders 174 | writer.BaseStream.Position = 0; 175 | writer.Write((int)writer.BaseStream.Length - 4); 176 | writer.BaseStream.Position = 8; 177 | writer.Write(materialOffset - 4); 178 | } 179 | return true; 180 | } 181 | #endregion 182 | 183 | #region HELPERS 184 | /* Get the current index for a material (useful for cross-ref'ing with compiled binaries) 185 | * Note: if the file hasn't been saved for a while, the write index may differ from the index on-disk */ 186 | public int GetWriteIndex(Material material) 187 | { 188 | if (!_writeList.Contains(material)) return -1; 189 | return _writeList.IndexOf(material); 190 | } 191 | 192 | /* Get a material by its current index (useful for cross-ref'ing with compiled binaries) 193 | * Note: if the file hasn't been saved for a while, the write index may differ from the index on-disk */ 194 | public Material GetAtWriteIndex(int index) 195 | { 196 | if (_writeList.Count <= index) return null; 197 | return _writeList[index]; 198 | } 199 | #endregion 200 | 201 | #region STRUCTURES 202 | public class Material 203 | { 204 | public string Name; 205 | 206 | public Texture[] TextureReferences = new Texture[12]; //Max of 12 207 | public ConstantBuffer[] ConstantBuffers = new ConstantBuffer[5]; //Should always be 5 (1 per CST block) - TODO: maybe just change this to 5 variables? 208 | 209 | public int UnknownValue0; 210 | public int ShaderIndex; 211 | 212 | public int UnknownValue1; 213 | 214 | public int Unknown4_; 215 | public int Color; // TODO: This is not color 216 | public int UnknownValue2; 217 | 218 | public override string ToString() 219 | { 220 | return "[" + Color + "] " + Name; 221 | } 222 | 223 | //Offset and length within the CST file 224 | public class ConstantBuffer 225 | { 226 | public int Offset = 0; 227 | public int Length = 0; 228 | } 229 | 230 | public class Texture 231 | { 232 | public int BinIndex; // Entry index in texture BIN file. 233 | 234 | public TextureSource Source; 235 | 236 | public enum TextureSource 237 | { 238 | GLOBAL = 2, //Texture comes from ENV/GLOBAL 239 | LEVEL = 0, //Texture comes from the level (in ENV/PRODUCTION) 240 | } 241 | }; 242 | } 243 | #endregion 244 | } 245 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/MissionSave.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using CathodeLib; 3 | using System; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace CATHODE.EXPERIMENTAL 8 | { 9 | /* *.AIS */ 10 | public class MissionSave : CathodeFile 11 | { 12 | public static new Implementation Implementation = Implementation.NONE; 13 | public MissionSave(string path) : base(path) { } 14 | 15 | private Header _header; 16 | 17 | // From the iOS decomp: the saves work with a "leaf and node" system, where you have 18 | // "node" names saved with their connected "leafs" which acts like a "system" and 19 | // "parameter" to apply to the system 20 | 21 | // Check CATHODE::SaveState::save_leaf! 22 | 23 | #region FILE_IO 24 | /* Load the file */ 25 | override protected bool LoadInternal() 26 | { 27 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 28 | { 29 | _header = Utilities.Consume
(reader); 30 | switch (_header.VersionNum) 31 | { 32 | case AISType.SAVE: 33 | string levelName = Utilities.ReadString(reader.ReadBytes(128)); 34 | Console.WriteLine("Level Name: " + levelName); 35 | string saveName = Utilities.ReadStringAlternating(reader.ReadBytes(256)); 36 | Console.WriteLine("Save Name: " + saveName); 37 | string levelSaveDescriptor = Utilities.ReadString(reader.ReadBytes(160)); 38 | Console.WriteLine("Localised Save Descriptor: " + levelSaveDescriptor); 39 | reader.BaseStream.Position += 8; 40 | string playlist = Utilities.ReadString(reader.ReadBytes(64)); //unsure on this 41 | Console.WriteLine("Playlist: " + playlist); 42 | 43 | reader.BaseStream.Position = 1208; 44 | while (true) 45 | { 46 | if (!ReadEntry(reader)) break; 47 | } 48 | break; 49 | } 50 | 51 | reader.BaseStream.Position = _header.save_root_offset; 52 | while (true) 53 | { 54 | string id = ReadNode(reader); 55 | if (_header.VersionNum == AISType.SAVE && id == "temp_entities") break; //This seems to be the last resolvable in SAVE? 56 | if (id == null) break; 57 | } 58 | Console.WriteLine("Finished root nodes at " + reader.BaseStream.Position); 59 | } 60 | return true; 61 | } 62 | 63 | /* Save the file */ 64 | override protected bool SaveInternal() 65 | { 66 | using (BinaryWriter stream = new BinaryWriter(File.OpenWrite(_filepath))) 67 | { 68 | stream.BaseStream.SetLength(0); 69 | Utilities.Write
(stream, _header); 70 | } 71 | return true; 72 | } 73 | #endregion 74 | 75 | #region HELPERS 76 | private bool ReadEntry(BinaryReader stream) 77 | { 78 | UInt32 type = stream.ReadUInt32(); 79 | if (type == 0) return false; 80 | switch (type) 81 | { 82 | case 55762421: 83 | stream.BaseStream.Position += 8; 84 | break; 85 | default: 86 | UInt32 id = stream.ReadUInt32(); 87 | int val = stream.ReadInt32(); 88 | Console.WriteLine(type + ": " + id + " -> " + val); 89 | break; 90 | } 91 | return true; 92 | } 93 | 94 | private string ReadNode(BinaryReader stream) 95 | { 96 | //Read leaf name 97 | ShortGuid id = Utilities.Consume(stream); 98 | if (id.ToUInt32() == 0) return null; 99 | 100 | string id_str = id.ToString(); 101 | Console.WriteLine("Reading " + id_str); 102 | 103 | //The root nodes are always 8 in length 104 | if (id_str == "save_root" || id_str == "progression_root") 105 | { 106 | stream.BaseStream.Position += 8; 107 | return id_str; 108 | } 109 | 110 | //Read entry header 111 | byte type = stream.ReadByte(); 112 | 113 | if (type == 0x01) 114 | { 115 | stream.BaseStream.Position += 1; 116 | return id_str; 117 | } 118 | 119 | int offset = stream.ReadInt16(); 120 | byte unk = stream.ReadByte(); 121 | if (unk == 0x01) 122 | throw new Exception("Unhandled"); 123 | 124 | //Read entry contents 125 | int length = 0; 126 | switch (type) 127 | { 128 | case 0x02: 129 | length = 0; 130 | break; 131 | case 0x04: 132 | length = 1; 133 | break; 134 | case 0x40: 135 | case 0x0D: 136 | length = offset; 137 | break; 138 | case 0x4D: 139 | length = offset + 3; 140 | break; 141 | default: 142 | throw new Exception("Unhandled"); 143 | } 144 | byte[] content = stream.ReadBytes(length); 145 | 146 | switch (id_str) 147 | { 148 | case "m_last_saved_level": 149 | string lvl = Utilities.ReadString(content); 150 | Console.WriteLine("\t" + lvl); 151 | break; 152 | } 153 | return id_str; 154 | } 155 | #endregion 156 | 157 | #region STRUCTURES 158 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 159 | public struct Header 160 | { 161 | public fourcc FourCC; 162 | public AISType VersionNum; 163 | 164 | public ShortGuid unk1; 165 | public ShortGuid unk2; 166 | public ShortGuid unk3; 167 | 168 | public int Offset1; 169 | public int save_root_offset; 170 | public int Offset3; 171 | }; 172 | public enum AISType : Int32 173 | { 174 | SAVE = 18, 175 | PROGRESSION = 4 176 | } 177 | #endregion 178 | } 179 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/NavigationMesh.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.InteropServices; 4 | using CathodeLib; 5 | #if UNITY_EDITOR || UNITY_STANDALONE_WIN 6 | using UnityEngine; 7 | #else 8 | using System.Numerics; 9 | #endif 10 | 11 | namespace CATHODE.EXPERIMENTAL 12 | { 13 | /* DATA/ENV/PRODUCTION/x/WORLD/STATE_x/NAV_MESH */ 14 | public class NavigationMesh : CathodeFile 15 | { 16 | dtMeshHeader Header; 17 | 18 | public Vector3[] Vertices; 19 | public dtPoly[] Polygons; 20 | public dtLink[] Links; 21 | public dtPolyDetail[] DetailMeshes; 22 | public Vector3[] DetailVertices; 23 | public byte[] DetailIndices; 24 | public dtBVNode[] BoundingVolumeTree; 25 | public dtOffMeshConnection[] OffMeshConnections; 26 | 27 | public static new Implementation Implementation = Implementation.LOAD; 28 | public NavigationMesh(string path) : base(path) { } 29 | 30 | #region FILE_IO 31 | override protected bool LoadInternal() 32 | { 33 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 34 | { 35 | Header = Utilities.Consume(reader); 36 | Vertices = Utilities.ConsumeArray(reader, Header.vertCount); 37 | Polygons = Utilities.ConsumeArray(reader, Header.polyCount); 38 | Links = Utilities.ConsumeArray(reader, Header.maxLinkCount); 39 | DetailMeshes = Utilities.ConsumeArray(reader, Header.detailMeshCount); 40 | DetailVertices = Utilities.ConsumeArray(reader, Header.vertCount); 41 | DetailIndices = Utilities.ConsumeArray(reader, Header.detailTriCount * 4); 42 | BoundingVolumeTree = Utilities.ConsumeArray(reader, Header.bvNodeCount); 43 | OffMeshConnections = Utilities.ConsumeArray(reader, Header.offMeshConCount); 44 | } 45 | return true; 46 | } 47 | #endregion 48 | 49 | #region STRUCTURES 50 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 51 | public struct dtMeshHeader 52 | { 53 | public int ayz_Version; 54 | public int ayz_FileSize; 55 | 56 | /// Tile magic number. (Used to identify the data format.) 57 | public fourcc FourCC; 58 | /// Tile data format version number. 59 | public int version; 60 | /// The x-position of the tile within the dtNavMesh tile grid. (x, y, layer) 61 | public int x; 62 | /// The y-position of the tile within the dtNavMesh tile grid. (x, y, layer) 63 | public int y; 64 | /// The layer of the tile within the dtNavMesh tile grid. (x, y, layer) 65 | public int layer; 66 | /// The user defined id of the tile. 67 | public int userId; 68 | /// The number of polygons in the tile. 69 | public int polyCount; 70 | /// The number of vertices in the tile. 71 | public int vertCount; 72 | /// The number of allocated links. 73 | public int maxLinkCount; 74 | /// The number of sub-meshes in the detail mesh. 75 | public int detailMeshCount; 76 | /// The number of unique vertices in the detail mesh. (In addition to the polygon vertices.) 77 | public int detailVertCount; 78 | /// The number of triangles in the detail mesh. 79 | public int detailTriCount; 80 | /// The number of bounding volume nodes. (Zero if bounding volumes are disabled.) 81 | public int bvNodeCount; 82 | /// The number of off-mesh connections. 83 | public int offMeshConCount; 84 | /// The index of the first polygon which is an off-mesh connection. 85 | public int offMeshBase; 86 | /// The height of the agents using the tile. 87 | public float walkableHeight; 88 | /// The radius of the agents using the tile. 89 | public float walkableRadius; 90 | /// The maximum climb height of the agents using the tile. 91 | public float walkableClimb; 92 | /// The minimum bounds of the tile's AABB. [(x, y, z)] 93 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] 94 | public float[] bMin; 95 | /// The maximum bounds of the tile's AABB. [(x, y, z)] 96 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] 97 | public float[] bMax; 98 | /// The bounding volume quantization factor. 99 | public float bvQuantFactor; 100 | }; 101 | 102 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 103 | public struct dtPoly 104 | { 105 | /// Index to first link in linked list. (Or #DT_NULL_LINK if there is no link.) 106 | public int firstLink; 107 | /// The indices of the polygon's vertices. 108 | /// The actual vertices are located in dtMeshTile::verts. 109 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] 110 | public UInt16[] verts; 111 | /// Packed data representing neighbor polygons references and flags for each edge. 112 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] 113 | public UInt16[] neis; 114 | }; 115 | 116 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 117 | public struct dtLink 118 | { 119 | /// Neighbour reference. (The neighbor that is linked to.) 120 | public int polygonRef; 121 | /// Index of the next link. 122 | public int next; 123 | /// Index of the polygon edge that owns this link. 124 | public char edge; 125 | /// If a boundary link, defines on which side the link is. 126 | public char side; 127 | /// If a boundary link, defines the minimum sub-edge area. 128 | public char bmin; 129 | /// If a boundary link, defines the maximum sub-edge area. 130 | public char bmax; 131 | }; 132 | 133 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 134 | public struct dtPolyDetail 135 | { 136 | /// The offset of the vertices in the dtMeshTile::detailVerts array. 137 | public int vertBase; 138 | /// The offset of the triangles in the dtMeshTile::detailTris array. 139 | public int triBase; 140 | /// The number of vertices in the sub-mesh. 141 | public char vertCount; 142 | /// The number of triangles in the sub-mesh. 143 | public char triCount; 144 | 145 | //Added by CA: this is always zero 146 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] 147 | public byte[] _padding; 148 | }; 149 | 150 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 151 | public struct dtBVNode 152 | { 153 | /// Minimum bounds of the node's AABB. [(x, y, z)] 154 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] 155 | public short[] bmin; 156 | /// Maximum bounds of the node's AABB. [(x, y, z)] 157 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] 158 | public short[] bmax; 159 | /// The node's index. (Negative for escape sequence.) 160 | public int i; 161 | }; 162 | 163 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 164 | public struct dtOffMeshConnection 165 | { 166 | /// The endpoints of the connection. [(ax, ay, az, bx, by, bz)] 167 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] 168 | public float[] pos; 169 | /// The radius of the endpoints. [Limit: >= 0] 170 | public float rad; 171 | /// The polygon reference of the connection within the tile. 172 | public short poly; 173 | /// Link flags. 174 | /// @note These are not the connection's user defined flags. Those are assigned via the 175 | /// connection's dtPoly definition. These are link flags used for internal purposes. 176 | public char flags; 177 | /// End point side. 178 | public char side; 179 | /// The id of the offmesh connection. (User assigned when the navigation mesh is built.) 180 | public int userId; 181 | 182 | 183 | //Below are additions by CA 184 | 185 | public int zero_1; //Always 0 186 | 187 | // entity handle to PathfindingWaitNode 188 | public EntityHandle entity; 189 | 190 | public float unk; 191 | 192 | public int zero_2; //Always 0 193 | public int three; //Always 3 194 | }; 195 | #endregion 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/PAK1.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace CATHODE 7 | { 8 | /* For legacy Spartan: Total Warrior PAK1 files */ 9 | public class PAK1 : CathodeFile 10 | { 11 | public List Entries = new List(); 12 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 13 | public PAK1(string path) : base(path) { } 14 | 15 | ~PAK1() 16 | { 17 | Entries.Clear(); 18 | } 19 | 20 | #region FILE_IO 21 | override protected bool LoadInternal() 22 | { 23 | using (BinaryReader reader = new BinaryReader(System.IO.File.OpenRead(_filepath))) 24 | { 25 | //Read the header info 26 | string MagicValidation = ""; 27 | for (int i = 0; i < 4; i++) { MagicValidation += reader.ReadChar(); } 28 | if (MagicValidation != "PAK1") { reader.Close(); return false; } 29 | int offsetListBegin = (reader.ReadInt32() * 2) + 16; 30 | int entryCount = reader.ReadInt32(); 31 | reader.BaseStream.Position += 4; //Skip "2048" 32 | 33 | //Read all file names and create entries 34 | string name = ""; 35 | while (Entries.Count < entryCount) 36 | { 37 | byte c = reader.ReadByte(); 38 | reader.BaseStream.Position += 1; 39 | if (c == 0x00) 40 | { 41 | File NewPakFile = new File(); 42 | NewPakFile.Filename = name; 43 | Entries.Add(NewPakFile); 44 | name = ""; 45 | } 46 | else 47 | { 48 | name += (char)c; 49 | } 50 | } 51 | 52 | //Read all file offsets 53 | reader.BaseStream.Position = offsetListBegin; 54 | List FileOffsets = new List(); 55 | FileOffsets.Add(offsetListBegin + (entryCount * 4)); 56 | for (int i = 0; i < entryCount; i++) FileOffsets.Add(reader.ReadInt32()); 57 | 58 | //Read in the files to entries 59 | for (int i = 0; i < entryCount; i++) 60 | Entries[i].Content = Utilities.RemoveLeadingNulls(reader.ReadBytes(FileOffsets[i + 1] - FileOffsets[i])); 61 | } 62 | return true; 63 | } 64 | 65 | override protected bool SaveInternal() 66 | { 67 | using (BinaryWriter writer = new BinaryWriter(System.IO.File.OpenWrite(_filepath))) 68 | { 69 | writer.BaseStream.SetLength(0); 70 | Utilities.WriteString("PAK1", writer); 71 | int OffsetListBegin_New = 0; 72 | for (int i = 0; i < Entries.Count; i++) OffsetListBegin_New += Entries[i].Filename.Length + 1; 73 | writer.Write(OffsetListBegin_New); 74 | writer.Write(Entries.Count); 75 | writer.Write(2048); 76 | 77 | //Write filenames 78 | for (int i = 0; i < Entries.Count; i++) 79 | { 80 | for (int x = 0; x < Entries[i].Filename.Length; x++) 81 | { 82 | writer.Write(Entries[i].Filename[x]); 83 | writer.Write(0x00); 84 | } 85 | writer.Write(0x00); 86 | writer.Write(0x00); 87 | } 88 | 89 | //Write placeholder offsets for now, we'll correct them after writing the content 90 | int offsetListBegin = (int)writer.BaseStream.Position; 91 | for (int i = 0; i < Entries.Count; i++) writer.Write(0); 92 | 93 | //Write files 94 | List offsets = new List(); 95 | for (int i = 0; i < Entries.Count; i++) 96 | { 97 | while (writer.BaseStream.Position % 2048 != 0) writer.Write((byte)0x00); 98 | writer.Write(Entries[i].Content); 99 | offsets.Add((int)writer.BaseStream.Position); 100 | } 101 | 102 | //Re-write offsets with correct values 103 | writer.BaseStream.Position = offsetListBegin; 104 | for (int i = 0; i < Entries.Count; i++) writer.Write(offsets[i]); 105 | } 106 | return true; 107 | } 108 | #endregion 109 | 110 | #region STRUCTURES 111 | public class File 112 | { 113 | ~File() 114 | { 115 | Content = null; 116 | } 117 | 118 | public string Filename = ""; 119 | public byte[] Content; 120 | } 121 | #endregion 122 | } 123 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/PAK2.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace CATHODE 7 | { 8 | /* DATA/UI.PAK & DATA/CHR_INFO.PAK & DATA/GLOBAL/ANIMATION.PAK & DATA/GLOBAL/UI.PAK */ 9 | /* Note: Also supports the PAK2 files in Viking: Battle for Asgard */ 10 | public class PAK2 : CathodeFile 11 | { 12 | public List Entries = new List(); 13 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 14 | public PAK2(string path) : base(path) { } 15 | 16 | ~PAK2() 17 | { 18 | Entries.Clear(); 19 | } 20 | 21 | #region FILE_IO 22 | override protected bool LoadInternal() 23 | { 24 | using (BinaryReader reader = new BinaryReader(System.IO.File.OpenRead(_filepath))) 25 | { 26 | //Read the header info 27 | string MagicValidation = ""; 28 | for (int i = 0; i < 4; i++) { MagicValidation += reader.ReadChar(); } 29 | if (MagicValidation != "PAK2") { reader.Close(); return false; } 30 | int offsetListBegin = reader.ReadInt32() + 16; 31 | int entryCount = reader.ReadInt32(); 32 | int alignment = reader.ReadInt32(); 33 | 34 | //Read all file names and create entries 35 | for (int i = 0; i < entryCount; i++) 36 | { 37 | File NewPakFile = new File(); 38 | NewPakFile.Filename = Utilities.ReadString(reader); 39 | Entries.Add(NewPakFile); 40 | } 41 | 42 | //Read all file offsets 43 | reader.BaseStream.Position = offsetListBegin; 44 | List FileOffsets = new List(); 45 | FileOffsets.Add(offsetListBegin + (entryCount * 4)); 46 | for (int i = 0; i < entryCount; i++) FileOffsets.Add(reader.ReadInt32()); 47 | 48 | //Read in the files to entries 49 | for (int i = 0; i < entryCount; i++) 50 | { 51 | Utilities.Align(reader, alignment); 52 | Entries[i].Content = reader.ReadBytes(FileOffsets[i + 1] - (int)reader.BaseStream.Position); 53 | } 54 | } 55 | return true; 56 | } 57 | 58 | override protected bool SaveInternal() 59 | { 60 | using (BinaryWriter writer = new BinaryWriter(System.IO.File.OpenWrite(_filepath))) 61 | { 62 | writer.BaseStream.SetLength(0); 63 | Utilities.WriteString("PAK2", writer); 64 | writer.Write(0); 65 | writer.Write(Entries.Count); 66 | writer.Write(4); 67 | 68 | //Write filenames 69 | for (int i = 0; i < Entries.Count; i++) Utilities.WriteString(Entries[i].Filename, writer, true); 70 | 71 | //Write placeholder offsets for now, we'll correct them after writing the content 72 | int offsetListBegin = (int)writer.BaseStream.Position; 73 | for (int i = 0; i < Entries.Count; i++) writer.Write(0); 74 | 75 | //Write files 76 | List offsets = new List(); 77 | for (int i = 0; i < Entries.Count; i++) 78 | { 79 | Utilities.Align(writer, 4); 80 | writer.Write(Entries[i].Content); 81 | offsets.Add((int)writer.BaseStream.Position); 82 | } 83 | Utilities.Align(writer, 4); 84 | 85 | //Re-write offsets with correct values 86 | writer.BaseStream.Position = 4; 87 | writer.Write(offsetListBegin - 16); 88 | writer.BaseStream.Position = offsetListBegin; 89 | for (int i = 0; i < Entries.Count; i++) writer.Write(offsets[i]); 90 | } 91 | return true; 92 | } 93 | #endregion 94 | 95 | #region STRUCTURES 96 | public class File 97 | { 98 | ~File() 99 | { 100 | Content = null; 101 | } 102 | 103 | public string Filename = ""; 104 | public byte[] Content; 105 | } 106 | #endregion 107 | } 108 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/PathBarrierResources.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text; 6 | 7 | namespace CATHODE 8 | { 9 | /* DATA/ENV/PRODUCTION/x/WORLD/PATH_BARRIER_RESOURCES */ 10 | public class PathBarrierResources : CathodeFile 11 | { 12 | public List Entries = new List(); 13 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 14 | public PathBarrierResources(string path) : base(path) { } 15 | 16 | #region FILE_IO 17 | override protected bool LoadInternal() 18 | { 19 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 20 | { 21 | reader.BaseStream.Position = 4; //59 22 | int entryCount = reader.ReadInt32(); 23 | for (int i = 0; i < entryCount; i++) 24 | { 25 | Entry entry = new Entry(); 26 | entry.resourcesBinIndex = reader.ReadInt32(); 27 | int index = reader.ReadInt16(); 28 | if (index != i+1) throw new Exception(); 29 | entry.unk1 = reader.ReadInt16(); 30 | entry.unk2 = reader.ReadInt16(); 31 | Entries.Add(entry); 32 | } 33 | } 34 | return true; 35 | } 36 | 37 | override protected bool SaveInternal() 38 | { 39 | using (BinaryWriter reader = new BinaryWriter(File.OpenWrite(_filepath))) 40 | { 41 | reader.BaseStream.SetLength(0); 42 | reader.Write((Int32)59); 43 | reader.Write(Entries.Count); 44 | for (int i = 0; i < Entries.Count; i++) 45 | { 46 | reader.Write((Int32)Entries[i].resourcesBinIndex); 47 | reader.Write((Int32)(i + 1)); 48 | reader.Write((Int16)Entries[i].unk1); 49 | reader.Write((Int16)Entries[i].unk2); 50 | } 51 | } 52 | return true; 53 | } 54 | #endregion 55 | 56 | #region STRUCTURES 57 | public class Entry 58 | { 59 | public int resourcesBinIndex; 60 | public int unk1; //todo: perhaps this is a ShortGuid instance thing? 61 | public int unk2; 62 | } 63 | #endregion 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/PhysicsMaps.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using CathodeLib; 3 | using System.Collections.Generic; 4 | using CATHODE.Scripting; 5 | using System; 6 | 7 | #if UNITY_EDITOR || UNITY_STANDALONE_WIN 8 | using UnityEngine; 9 | #else 10 | using System.Numerics; 11 | #endif 12 | 13 | namespace CATHODE 14 | { 15 | //This file defines additional info for entities with DYNAMIC_PHYSICS_SYSTEM resources. 16 | 17 | /* DATA/ENV/PRODUCTION/x/WORLD/PHYSICS.MAP */ 18 | public class PhysicsMaps : CathodeFile 19 | { 20 | public List Entries = new List(); 21 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 22 | public PhysicsMaps(string path) : base(path) { } 23 | 24 | #region FILE_IO 25 | override protected bool LoadInternal() 26 | { 27 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 28 | { 29 | reader.BaseStream.Position = 4; 30 | int entryCount = reader.ReadInt32(); 31 | for (int i = 0; i < entryCount; i++) 32 | { 33 | Entry entry = new Entry(); 34 | entry.physics_system_index = reader.ReadInt32(); 35 | reader.BaseStream.Position += 4; 36 | entry.resource_type = Utilities.Consume(reader); 37 | 38 | if (entry.resource_type != ShortGuidUtils.Generate("DYNAMIC_PHYSICS_SYSTEM")) 39 | throw new Exception("Unexpected resource type! Expected DYNAMIC_PHYSICS_SYSTEM."); 40 | 41 | entry.composite_instance_id = Utilities.Consume(reader); 42 | entry.entity = Utilities.Consume(reader); 43 | 44 | Vector4 Row0 = Utilities.Consume(reader); 45 | Vector4 Row1 = Utilities.Consume(reader); 46 | Vector4 Row2 = Utilities.Consume(reader); 47 | double[,] matrix = new double[,] 48 | { 49 | #if UNITY_EDITOR || UNITY_STANDALONE_WIN 50 | {Row0.x, Row0.y, Row0.z, Row0.w}, 51 | {Row1.x, Row1.y, Row1.z, Row1.w}, 52 | {Row2.x, Row2.y, Row2.z, Row2.w}, 53 | #else 54 | {Row0.X, Row0.Y, Row0.Z, Row0.W}, 55 | {Row1.X, Row1.Y, Row1.Z, Row1.W}, 56 | {Row2.X, Row2.Y, Row2.Z, Row2.W}, 57 | #endif 58 | }; 59 | 60 | entry.Position = new Vector3( 61 | (float)matrix[0, 3], 62 | (float)matrix[1, 3], 63 | (float)matrix[2, 3] 64 | ); 65 | #if UNITY_EDITOR || UNITY_STANDALONE_WIN 66 | Matrix4x4 matrix4x4 = new Matrix4x4( 67 | new Vector4((float)matrix[0, 0], (float)matrix[0, 1], (float)matrix[0, 2], 0), 68 | new Vector4((float)matrix[1, 0], (float)matrix[1, 1], (float)matrix[1, 2], 0), 69 | new Vector4((float)matrix[2, 0], (float)matrix[2, 1], (float)matrix[2, 2], 0), 70 | new Vector4(0, 0, 0, 1) 71 | ); 72 | entry.Rotation = Quaternion.LookRotation(matrix4x4.GetColumn(2), matrix4x4.GetColumn(1)); 73 | #else 74 | entry.Rotation = Quaternion.CreateFromRotationMatrix(new Matrix4x4( 75 | (float)matrix[0, 0], (float)matrix[0, 1], (float)matrix[0, 2], 0, 76 | (float)matrix[1, 0], (float)matrix[1, 1], (float)matrix[1, 2], 0, 77 | (float)matrix[2, 0], (float)matrix[2, 1], (float)matrix[2, 2], 0, 78 | 0, 0, 0, 1 79 | )); 80 | #endif 81 | 82 | reader.BaseStream.Position += 8; 83 | Entries.Add(entry); 84 | } 85 | } 86 | return true; 87 | } 88 | 89 | override protected bool SaveInternal() 90 | { 91 | //Entries = Entries.OrderBy(o => o.physics_system_index).ToList(); 92 | 93 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 94 | { 95 | writer.BaseStream.SetLength(0); 96 | writer.Write(Entries.Count * 80); 97 | writer.Write(Entries.Count); 98 | for (int i = 0; i < Entries.Count; i++) 99 | { 100 | writer.Write(Entries[i].physics_system_index); 101 | writer.Write(new byte[4]); 102 | Utilities.Write(writer, Entries[i].resource_type); 103 | Utilities.Write(writer, Entries[i].composite_instance_id); 104 | Utilities.Write(writer, Entries[i].entity); 105 | 106 | #if UNITY_EDITOR || UNITY_STANDALONE_WIN 107 | Matrix4x4 rotationMatrix4x4 = Matrix4x4.Rotate(Entries[i].Rotation); 108 | Vector4 Row0 = new Vector4(rotationMatrix4x4.m11, rotationMatrix4x4.m12, rotationMatrix4x4.m13, Entries[i].Position.x); 109 | Vector4 Row1 = new Vector4(rotationMatrix4x4.m21, rotationMatrix4x4.m22, rotationMatrix4x4.m23, Entries[i].Position.y); 110 | Vector4 Row2 = new Vector4(rotationMatrix4x4.m31, rotationMatrix4x4.m32, rotationMatrix4x4.m33, Entries[i].Position.z); 111 | #else 112 | Matrix4x4 rotationMatrix4x4 = Matrix4x4.CreateFromQuaternion(Entries[i].Rotation); 113 | Vector4 Row0 = new Vector4(rotationMatrix4x4.M11, rotationMatrix4x4.M12, rotationMatrix4x4.M13, Entries[i].Position.X); 114 | Vector4 Row1 = new Vector4(rotationMatrix4x4.M21, rotationMatrix4x4.M22, rotationMatrix4x4.M23, Entries[i].Position.Y); 115 | Vector4 Row2 = new Vector4(rotationMatrix4x4.M31, rotationMatrix4x4.M32, rotationMatrix4x4.M33, Entries[i].Position.Z); 116 | #endif 117 | 118 | Utilities.Write(writer, Row0); 119 | Utilities.Write(writer, Row1); 120 | Utilities.Write(writer, Row2); 121 | writer.Write(new byte[8]); 122 | } 123 | } 124 | return true; 125 | } 126 | #endregion 127 | 128 | #region STRUCTURES 129 | public class Entry 130 | { 131 | //Should match system_index on the PhysicsSystem entity. 132 | public int physics_system_index; //TODO: is this the havok index? collision.map points to havok indexes, so would make sense 133 | 134 | //DYNAMIC_PHYSICS_SYSTEM 135 | public ShortGuid resource_type; 136 | 137 | //This is the instance ID for the composite containing the PhysicsSystem. 138 | //We do not need to worry about the entity ID for the PhysicsSystem as the resources are written to the composite that contains it. 139 | public ShortGuid composite_instance_id; 140 | 141 | //This is the entity ID and instance ID for the actual instanced composite entity (basically, a step down from the instance above). 142 | public EntityHandle entity; 143 | 144 | //This is the worldspace position of the composite instance 145 | public Vector3 Position; 146 | public Quaternion Rotation; 147 | }; 148 | #endregion 149 | } 150 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/ProgressionSave.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Runtime.InteropServices; 3 | using CathodeLib; 4 | 5 | namespace CATHODE.EXPERIMENTAL 6 | { 7 | /* PROGRESSION.AIS */ 8 | public class ProgressionSave : CathodeFile 9 | { 10 | public Progression Content; 11 | public static new Implementation Implementation = Implementation.LOAD | Implementation.SAVE; 12 | public ProgressionSave(string path) : base(path) { } 13 | 14 | #region FILE_IO 15 | override protected bool LoadInternal() 16 | { 17 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 18 | { 19 | Content = Utilities.Consume(reader); 20 | } 21 | return true; 22 | } 23 | 24 | override protected bool SaveInternal() 25 | { 26 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 27 | { 28 | Utilities.Write(writer, Content); 29 | } 30 | return true; 31 | } 32 | #endregion 33 | 34 | #region STRUCTURES 35 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 36 | public struct Progression 37 | { 38 | public fourcc FourCC; 39 | public int VersionNum; 40 | 41 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 36)] public byte[] unk1; 42 | 43 | public byte gamepad_ControlScheme; //44 44 | 45 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] unk2; 46 | 47 | public float gamepad_ControllerSensitivity; //48 48 | 49 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] unk3; 50 | 51 | public byte InvertX; //56 52 | public byte InvertY; //57 53 | 54 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public byte[] unk4; 55 | 56 | public byte gamepad_Vibration; //59 57 | 58 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte[] unk5; 59 | 60 | public byte aimAssist; 61 | }; 62 | #endregion 63 | } 64 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/RenderableElements.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | 5 | namespace CATHODE 6 | { 7 | /* DATA/ENV/PRODUCTION/x/WORLD/REDS.BIN */ 8 | public class RenderableElements : CathodeFile 9 | { 10 | public List Entries = new List(); 11 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 12 | public RenderableElements(string path) : base(path) { } 13 | 14 | #region FILE_IO 15 | override protected bool LoadInternal() 16 | { 17 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 18 | { 19 | int entryCount = reader.ReadInt32(); 20 | for (int i = 0; i < entryCount; i++) 21 | { 22 | Element element = new Element(); 23 | reader.BaseStream.Position += 4; 24 | element.ModelIndex = reader.ReadInt32(); 25 | reader.BaseStream.Position += 5; 26 | element.MaterialIndex = reader.ReadInt32(); 27 | reader.BaseStream.Position += 1; 28 | element.LODIndex = reader.ReadInt32(); 29 | element.LODCount = reader.ReadByte(); //TODO: convert to int for ease of use? 30 | Entries.Add(element); 31 | } 32 | } 33 | return true; 34 | } 35 | 36 | override protected bool SaveInternal() 37 | { 38 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 39 | { 40 | writer.BaseStream.SetLength(0); 41 | writer.Write(Entries.Count); 42 | for (int i = 0; i < Entries.Count; i++) 43 | { 44 | writer.Write(new byte[] { 0x00, 0x00, 0x00, 0x00 }); 45 | writer.Write(Entries[i].ModelIndex); 46 | writer.Write(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00 }); 47 | writer.Write(Entries[i].MaterialIndex); 48 | writer.Write((byte)0x00); 49 | writer.Write(Entries[i].LODIndex); 50 | writer.Write((byte)Entries[i].LODCount); 51 | } 52 | } 53 | return true; 54 | } 55 | #endregion 56 | 57 | #region STRUCTURES 58 | public class Element 59 | { 60 | public int ModelIndex; 61 | public int MaterialIndex; 62 | 63 | public int LODIndex = -1; //This is the index of the REDS entry that we use for our LOD model/material 64 | public byte LODCount = 0; //This is the number of entries sequentially from the LODIndex to use for the LOD from REDS 65 | } 66 | #endregion 67 | } 68 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/Resources.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Runtime.InteropServices.ComTypes; 7 | using CATHODE.Scripting; 8 | using CathodeLib; 9 | using static CATHODE.Resources; 10 | 11 | namespace CATHODE 12 | { 13 | /* DATA/ENV/PRODUCTION/x/WORLD/RESOURCES.BIN */ 14 | public class Resources : CathodeFile 15 | { 16 | public List Entries = new List(); 17 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 18 | public Resources(string path) : base(path) { } 19 | 20 | #region FILE_IO 21 | override protected bool LoadInternal() 22 | { 23 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 24 | { 25 | reader.BaseStream.Position = 8; 26 | int entryCount = reader.ReadInt32(); 27 | reader.BaseStream.Position += 4; 28 | 29 | Resource[] entries = new Resource[entryCount]; 30 | for (int i = 0; i < entryCount; i++) 31 | { 32 | Resource resource = new Resource(); 33 | resource.composite_instance_id = Utilities.Consume(reader); 34 | resource.resource_id = Utilities.Consume(reader); //this is the id that's used in commands.pak, frequently translates to Door/AnimatedModel/Light/DYNAMIC_PHYSICS_SYSTEM 35 | int index = reader.ReadInt32(); 36 | entries[index] = resource; 37 | } 38 | Entries = entries.ToList(); 39 | } 40 | return true; 41 | } 42 | 43 | override protected bool SaveInternal() 44 | { 45 | List orderedEntries = Entries.OrderBy(o => o.composite_instance_id).ThenBy(o => o.resource_id).ToList(); 46 | 47 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 48 | { 49 | writer.BaseStream.SetLength(0); 50 | writer.Write(new byte[4] { 0xCC, 0xBA, 0xED, 0xFE }); 51 | writer.Write((Int32)1); 52 | writer.Write(orderedEntries.Count); 53 | writer.Write((Int32)0); 54 | 55 | for (int i = 0; i < orderedEntries.Count; i++) 56 | { 57 | Utilities.Write(writer, orderedEntries[i].composite_instance_id); 58 | Utilities.Write(writer, orderedEntries[i].resource_id); 59 | writer.Write(Entries.IndexOf(orderedEntries[i])); 60 | } 61 | } 62 | return true; 63 | } 64 | #endregion 65 | 66 | public void AddUniqueResource(ShortGuid composite_instance_id, ShortGuid resource_id) 67 | { 68 | if (Entries.FirstOrDefault(o => o.composite_instance_id == composite_instance_id && o.resource_id == resource_id) != null) 69 | return; 70 | 71 | Entries.Add(new Resource() 72 | { 73 | composite_instance_id = composite_instance_id, 74 | resource_id = resource_id 75 | }); 76 | } 77 | 78 | #region STRUCTURES 79 | public class Resource 80 | { 81 | public ShortGuid composite_instance_id; 82 | public ShortGuid resource_id; 83 | }; 84 | #endregion 85 | } 86 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/SkeleDB.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Numerics; 6 | using System.Runtime.InteropServices; 7 | using System.Runtime.InteropServices.ComTypes; 8 | using System.Text; 9 | using CATHODE.Scripting; 10 | using CathodeLib; 11 | 12 | namespace CATHODE 13 | { 14 | /* DATA/GLOBAL/ANIMATION.PAK -> ANIM_SYS/SKELE/DB.BIN */ 15 | public class SkeleDB : CathodeFile 16 | { 17 | public Data Entries = new Data(); 18 | public static new Implementation Implementation = Implementation.LOAD | Implementation.CREATE | Implementation.SAVE; 19 | 20 | public SkeleDB(string path, AnimationStrings strings) : base(path) 21 | { 22 | _strings = strings; 23 | 24 | //TEMP 25 | OnLoadBegin?.Invoke(_filepath); 26 | if (LoadInternal()) 27 | { 28 | _loaded = true; 29 | OnLoadSuccess?.Invoke(_filepath); 30 | } 31 | } 32 | 33 | private AnimationStrings _strings; 34 | 35 | #region FILE_IO 36 | override protected bool LoadInternal() 37 | { 38 | if (_strings == null) 39 | return false; 40 | 41 | Entries = new Data(); 42 | 43 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 44 | { 45 | int pairCount = reader.ReadInt32(); 46 | int idCount = reader.ReadInt32(); 47 | 48 | if (pairCount != idCount) 49 | return false; 50 | 51 | Skeletons[] skeletons = new Skeletons[pairCount]; 52 | for (int i = 0; i < pairCount; i++) 53 | { 54 | string name = _strings.Entries[reader.ReadUInt32()]; 55 | skeletons[reader.ReadInt32()] = new Skeletons() { SkeletonName = name }; 56 | } 57 | for (int i = 0; i < idCount; i++) 58 | { 59 | skeletons[i].Filename = _strings.Entries[reader.ReadUInt32()]; 60 | } 61 | 62 | int mappingIDCount = reader.ReadInt32(); 63 | int mappingCount = reader.ReadInt32(); 64 | 65 | if (mappingIDCount != mappingCount) 66 | return false; 67 | 68 | SkeletonMapping[] mappings = new SkeletonMapping[mappingIDCount]; 69 | for (int i = 0; i < mappingCount; i++) 70 | { 71 | string skele1 = _strings.Entries[reader.ReadUInt32()]; 72 | string skele2 = _strings.Entries[reader.ReadUInt32()]; 73 | 74 | mappings[reader.ReadInt32()] = new SkeletonMapping() 75 | { 76 | Skeleton1 = skele1, 77 | Skeleton2 = skele2, 78 | }; 79 | reader.BaseStream.Position += 4; 80 | } 81 | for (int i = 0; i < mappingIDCount; i++) 82 | { 83 | mappings[i].Name = _strings.Entries[reader.ReadUInt32()]; 84 | } 85 | 86 | Entries.Skeletons = skeletons.ToList(); 87 | Entries.Mappings = mappings.ToList(); 88 | } 89 | return true; 90 | } 91 | 92 | override protected bool SaveInternal() 93 | { 94 | //TODO: we should write these anim strings to the db 95 | 96 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 97 | { 98 | writer.BaseStream.SetLength(0); 99 | 100 | writer.Write(Entries.Skeletons.Count); 101 | writer.Write(Entries.Skeletons.Count); 102 | 103 | for (int i = 0; i < Entries.Skeletons.Count; i++) 104 | { 105 | writer.Write(Utilities.AnimationHashedString(Entries.Skeletons[i].SkeletonName)); 106 | writer.Write(i); 107 | } 108 | for (int i = 0; i < Entries.Skeletons.Count; i++) 109 | { 110 | writer.Write(Utilities.AnimationHashedString(Entries.Skeletons[i].Filename)); 111 | } 112 | 113 | writer.Write(Entries.Mappings.Count); 114 | writer.Write(Entries.Mappings.Count); 115 | 116 | for (int i = 0; i < Entries.Mappings.Count; i++) 117 | { 118 | writer.Write(Utilities.AnimationHashedString(Entries.Mappings[i].Skeleton1)); 119 | writer.Write(Utilities.AnimationHashedString(Entries.Mappings[i].Skeleton2)); 120 | writer.Write(i); 121 | writer.Write(0); 122 | } 123 | for (int i = 0; i < Entries.Mappings.Count; i++) 124 | { 125 | writer.Write(Utilities.AnimationHashedString(Entries.Mappings[i].Name)); 126 | } 127 | } 128 | return true; 129 | } 130 | #endregion 131 | 132 | #region STRUCTURES 133 | public class Data 134 | { 135 | public List Skeletons = new List(); 136 | public List Mappings = new List(); 137 | } 138 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 139 | public class Skeletons 140 | { 141 | public string Filename; 142 | public string SkeletonName; 143 | } 144 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 145 | public class SkeletonMapping 146 | { 147 | public string Name; 148 | public string Skeleton1; 149 | public string Skeleton2; 150 | }; 151 | #endregion 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/SoundBankData.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using CathodeLib; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Numerics; 8 | using System.Runtime.InteropServices; 9 | using System.Xml.Linq; 10 | 11 | namespace CATHODE 12 | { 13 | /* DATA/ENV/PRODUCTION/x/WORLD/SOUNDBANKDATA.DAT */ 14 | public class SoundBankData : CathodeFile 15 | { 16 | //NOTE: you can use Utilities.SoundHashedString to hash these strings and get the Wwise ID used in other places like SoundEventData 17 | 18 | public List Entries = new List(); 19 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 20 | public SoundBankData(string path) : base(path) { } 21 | 22 | #region FILE_IO 23 | override protected bool LoadInternal() 24 | { 25 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 26 | { 27 | reader.BaseStream.Position += 4; 28 | int entryCount = reader.ReadInt32(); 29 | for (int i = 0; i < entryCount; i++) 30 | { 31 | int length = reader.ReadInt32(); 32 | string name = ""; 33 | for (int x = 0; x < length; x++) name += reader.ReadChar(); 34 | Entries.Add(name); 35 | reader.BaseStream.Position += 2; 36 | } 37 | } 38 | return true; 39 | } 40 | 41 | override protected bool SaveInternal() 42 | { 43 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 44 | { 45 | writer.BaseStream.SetLength(0); 46 | writer.Write(1); 47 | writer.Write(Entries.Count); 48 | for (int i = 0; i < Entries.Count; i++) 49 | { 50 | writer.Write(Entries[i].Length); 51 | Utilities.WriteString(Entries[i], writer); 52 | writer.Write((Int16)0); 53 | } 54 | } 55 | return true; 56 | } 57 | #endregion 58 | } 59 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/SoundDialogueLookups.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using CathodeLib; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Numerics; 8 | using System.Runtime.InteropServices; 9 | using System.Xml.Linq; 10 | 11 | namespace CATHODE 12 | { 13 | /* DATA/ENV/PRODUCTION/x/WORLD/SOUNDDIALOGUELOOKUPS.DAT */ 14 | public class SoundDialogueLookups : CathodeFile 15 | { 16 | public List Entries = new List(); 17 | public static new Implementation Implementation = Implementation.LOAD; 18 | public SoundDialogueLookups(string path) : base(path) { } 19 | 20 | #region FILE_IO 21 | override protected bool LoadInternal() 22 | { 23 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 24 | { 25 | reader.BaseStream.Position += 16; //All unknowns 26 | int entryCount = ((int)reader.BaseStream.Length / 8) - 2; //We can probably work this out from the previous unknowns 27 | for (int i = 0; i < entryCount; i++) 28 | { 29 | Sound s = new Sound(); 30 | s.id = reader.ReadUInt32(); 31 | s.unk = Utilities.Consume(reader); 32 | Entries.Add(s); 33 | } 34 | 35 | } 36 | return true; 37 | } 38 | 39 | override protected bool SaveInternal() 40 | { 41 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 42 | { 43 | writer.BaseStream.SetLength(0); 44 | writer.Write(new byte[16]); 45 | for (int i = 0; i < Entries.Count; i++) 46 | { 47 | writer.Write(Entries[i].id); 48 | Utilities.Write(writer, Entries[i].unk); 49 | } 50 | } 51 | return true; 52 | } 53 | #endregion 54 | 55 | #region STRUCTURES 56 | public class Sound 57 | { 58 | public uint id; 59 | public ShortGuid unk; 60 | 61 | override public string ToString() 62 | { 63 | return SoundUtils.GetSoundName(id); 64 | } 65 | }; 66 | #endregion 67 | } 68 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/SoundEnvironmentData.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using CathodeLib; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Numerics; 8 | using System.Runtime.InteropServices; 9 | using System.Xml.Linq; 10 | 11 | namespace CATHODE 12 | { 13 | /* DATA/ENV/PRODUCTION/x/WORLD/SOUNDENVIRONMENTDATA.DAT */ 14 | public class SoundEnvironmentData : CathodeFile 15 | { 16 | public List Entries = new List(); 17 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 18 | public SoundEnvironmentData(string path) : base(path) { } 19 | 20 | #region FILE_IO 21 | override protected bool LoadInternal() 22 | { 23 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 24 | { 25 | reader.BaseStream.Position += 4; 26 | int entryCount = reader.ReadInt32(); 27 | for (int i = 0; i < entryCount; i++) 28 | { 29 | byte[] content = reader.ReadBytes(100); 30 | using (BinaryReader contentReader = new BinaryReader(new MemoryStream(content))) 31 | { 32 | Entries.Add(Utilities.ReadString(contentReader)); 33 | } 34 | } 35 | } 36 | return true; 37 | } 38 | 39 | override protected bool SaveInternal() 40 | { 41 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 42 | { 43 | writer.BaseStream.SetLength(0); 44 | writer.Write(2); 45 | writer.Write(Entries.Count); 46 | for (int i = 0; i < Entries.Count; i++) 47 | { 48 | writer.Write(new byte[100]); 49 | long resetPos = writer.BaseStream.Position; 50 | writer.BaseStream.Position -= 100; 51 | Utilities.WriteString(Entries[i], writer); 52 | writer.BaseStream.Position = resetPos; 53 | } 54 | writer.Write(0); 55 | } 56 | return true; 57 | } 58 | #endregion 59 | } 60 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/SoundEventData.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using CathodeLib; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Numerics; 8 | using System.Runtime.InteropServices; 9 | using System.Xml.Linq; 10 | 11 | namespace CATHODE 12 | { 13 | /* DATA/ENV/PRODUCTION/x/WORLD/SOUNDEVENTDATA.DAT */ 14 | public class SoundEventData : CathodeFile 15 | { 16 | public List Entries = new List(); 17 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 18 | public SoundEventData(string path) : base(path) { } 19 | 20 | #region FILE_IO 21 | override protected bool LoadInternal() 22 | { 23 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 24 | { 25 | reader.BaseStream.Position += 4; 26 | int entryCount = reader.ReadInt32(); 27 | for (int i = 0; i < entryCount; i++) 28 | { 29 | Soundbank.Event e = new Soundbank.Event(); 30 | int length = reader.ReadInt32(); 31 | for (int x = 0; x < length; x++) e.name += reader.ReadChar(); 32 | length = reader.ReadInt32(); 33 | for (int x = 0; x < length; x++) e.args += reader.ReadChar(); 34 | reader.BaseStream.Position += 2; 35 | e.unknown = reader.ReadInt16(); 36 | 37 | uint soundbankID = reader.ReadUInt32(); 38 | Soundbank soundbank = Entries.FirstOrDefault(o => o.id == soundbankID); 39 | if (soundbank == null) 40 | { 41 | soundbank = new Soundbank() { id = soundbankID }; 42 | Entries.Add(soundbank); 43 | } 44 | soundbank.events.Add(e); 45 | } 46 | } 47 | return true; 48 | } 49 | 50 | override protected bool SaveInternal() 51 | { 52 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 53 | { 54 | writer.BaseStream.SetLength(0); 55 | writer.Write(0); 56 | writer.Write(Entries.Count); 57 | for (int i = 0; i < Entries.Count; i++) 58 | { 59 | for (int x = 0; x < Entries[i].events.Count; x++) 60 | { 61 | writer.Write(Entries[i].events[x].name.Length); 62 | Utilities.WriteString(Entries[i].events[x].name, writer); 63 | writer.Write(Entries[i].events[x].args.Length); 64 | Utilities.WriteString(Entries[i].events[x].args, writer); 65 | writer.Write((Int16)0); 66 | writer.Write(Entries[i].events[x].unknown); 67 | writer.Write(Entries[i].id); 68 | } 69 | } 70 | } 71 | return true; 72 | } 73 | #endregion 74 | 75 | #region STRUCTURES 76 | public class Soundbank 77 | { 78 | public uint id; //This is the hashed soundbank string name (hashed via Utilities.SoundHashedString) 79 | public List events = new List(); 80 | 81 | public class Event 82 | { 83 | public string name; 84 | public string args; 85 | 86 | public int unknown; 87 | } 88 | }; 89 | #endregion 90 | } 91 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/SoundFlashModels.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | 6 | namespace CATHODE 7 | { 8 | /* DATA/ENV/PRODUCTION/x/WORLD/SOUNDFLASHMODELS.DAT */ 9 | public class SoundFlashModels : CathodeFile 10 | { 11 | public List Entries = new List(); 12 | public static new Implementation Implementation = Implementation.NONE; 13 | public SoundFlashModels(string path) : base(path) { } 14 | 15 | #region FILE_IO 16 | override protected bool LoadInternal() 17 | { 18 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 19 | { 20 | reader.BaseStream.Position += 4; 21 | int entryCount = reader.ReadInt32(); 22 | for (int i = 0; i < entryCount; i++) 23 | { 24 | FlashModel f = new FlashModel(); 25 | f.unk1 = reader.ReadInt16(); 26 | f.unk2 = reader.ReadInt16(); 27 | int count = reader.ReadInt32(); 28 | for (int x = 0; x < count; x++) 29 | f.unk3.Add(reader.ReadInt32()); 30 | Entries.Add(f); 31 | } 32 | } 33 | return true; 34 | } 35 | 36 | override protected bool SaveInternal() 37 | { 38 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 39 | { 40 | writer.BaseStream.SetLength(0); 41 | writer.Write(1); 42 | writer.Write(Entries.Count); 43 | for (int i = 0; i < Entries.Count; i++) 44 | { 45 | writer.Write((Int16)Entries[i].unk1); 46 | writer.Write((Int16)Entries[i].unk2); 47 | for (int x = 0; x < Entries[i].unk3.Count; x++) 48 | writer.Write(Entries[i].unk3[x]); 49 | } 50 | } 51 | return true; 52 | } 53 | #endregion 54 | 55 | #region STRUCTURES 56 | public class FlashModel 57 | { 58 | public int unk1; 59 | public int unk2; 60 | public List unk3 = new List(); 61 | } 62 | #endregion 63 | } 64 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/SoundLoadZones.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using CathodeLib; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Numerics; 8 | using System.Runtime.InteropServices; 9 | using System.Xml.Linq; 10 | 11 | namespace CATHODE 12 | { 13 | /* DATA/ENV/PRODUCTION/x/WORLD/SOUNDLOADZONES.DAT */ 14 | public class SoundLoadZones : CathodeFile 15 | { 16 | public List Entries = new List(); 17 | public static new Implementation Implementation = Implementation.NONE; 18 | public SoundLoadZones(string path) : base(path) { } 19 | 20 | #region FILE_IO 21 | override protected bool LoadInternal() 22 | { 23 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 24 | { 25 | reader.BaseStream.Position += 4; 26 | int entryCount = reader.ReadInt32(); 27 | reader.BaseStream.Position += 8; 28 | for (int i = 0; i < entryCount; i++) 29 | { 30 | byte[] content = reader.ReadBytes(68); 31 | using (BinaryReader contentReader = new BinaryReader(new MemoryStream(content))) 32 | { 33 | Entries.Add(Utilities.ReadString(contentReader)); 34 | } 35 | } 36 | } 37 | return true; 38 | } 39 | 40 | override protected bool SaveInternal() 41 | { 42 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 43 | { 44 | writer.BaseStream.SetLength(0); 45 | writer.Write(0); 46 | writer.Write(Entries.Count); 47 | writer.Write(new byte[8]); 48 | for (int i = 0; i < Entries.Count; i++) 49 | { 50 | writer.Write(new byte[68]); 51 | long resetPos = writer.BaseStream.Position; 52 | writer.BaseStream.Position -= 68; 53 | Utilities.WriteString(Entries[i], writer); 54 | writer.BaseStream.Position = resetPos; 55 | } 56 | } 57 | return true; 58 | } 59 | #endregion 60 | } 61 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/SoundNodeNetwork.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using CathodeLib; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Numerics; 8 | using System.Runtime.InteropServices; 9 | using System.Xml.Linq; 10 | 11 | namespace CATHODE 12 | { 13 | /* DATA/ENV/PRODUCTION/x/WORLD/SNDNODENETWORK.DAT */ 14 | public class SoundNodeNetwork : CathodeFile 15 | { 16 | private List Entries = new List(); 17 | public static new Implementation Implementation = Implementation.NONE; 18 | public SoundNodeNetwork(string path) : base(path) { } 19 | 20 | private int _test = 0; 21 | private int test 22 | { 23 | set 24 | { 25 | _test = value; 26 | Console.WriteLine(_test); 27 | } 28 | get 29 | { 30 | return _test; 31 | } 32 | } 33 | private float _testf = 0; 34 | private float testf 35 | { 36 | set 37 | { 38 | _testf = value; 39 | Console.WriteLine(_testf); 40 | } 41 | get 42 | { 43 | return _testf; 44 | } 45 | } 46 | 47 | //This file is seemingly somewhat ordered by size? Biggest listener networks get their headers written first ish. 48 | 49 | #region FILE_IO 50 | override protected bool LoadInternal() 51 | { 52 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 53 | { 54 | reader.BaseStream.Position += 4; 55 | int count1 = reader.ReadInt16(); 56 | int entryCount = reader.ReadInt16(); 57 | for (int x = 0; x < entryCount; x++) 58 | { 59 | if (Entries.Count != 0 && Entries[Entries.Count - 1] == "Corridor Junction Area") 60 | { 61 | string sddsf = ""; 62 | } 63 | 64 | int strLength = reader.ReadInt16(); 65 | string listenerName = ""; //confirmed via dev screenshot 66 | for (int i = 0; i < strLength; i++) listenerName += reader.ReadChar(); 67 | Entries.Add(listenerName); 68 | 69 | //start header 70 | Console.WriteLine("start header"); 71 | 72 | int typeID = reader.ReadInt16(); 73 | 74 | test = reader.ReadInt16(); 75 | test = reader.ReadInt16(); 76 | 77 | test = reader.ReadInt16(); 78 | test = reader.ReadInt16(); 79 | 80 | testf = reader.ReadSingle(); //always 1? 81 | if (testf != 1) 82 | { 83 | throw new Exception(""); 84 | } 85 | 86 | testf = reader.ReadSingle(); 87 | testf = reader.ReadSingle(); 88 | testf = reader.ReadSingle(); 89 | 90 | testf = reader.ReadSingle(); 91 | testf = reader.ReadSingle(); 92 | testf = reader.ReadSingle(); 93 | 94 | //Somewhere here we should have an Ambience sound event (maybe start/stop?) 95 | 96 | //I'm unsure if these are actually int16 97 | test = reader.ReadInt16(); 98 | test = reader.ReadInt16(); 99 | test = reader.ReadInt16(); 100 | 101 | if (test == 0) 102 | { 103 | string sdfdf = ""; 104 | continue; //44 bytes 105 | } 106 | //^ doing this gets us a bit further on BSP_TORRENS, but we still crash after "Torrens Bridge Corridor" due to something there. 107 | 108 | //I'm unsure if these are actually int16 109 | test = reader.ReadInt16(); 110 | test = reader.ReadInt16(); 111 | 112 | Console.WriteLine("Header Over"); 113 | 114 | //end next bit (48) <- this is all useful above here but just skipping for now, figure out datatypes from ps3 dump 115 | 116 | //TODO: typeID is not the type ID as i expected, since two type 0's load differently on tech_hub 117 | 118 | switch (typeID) 119 | { 120 | //case 0: 121 | // reader.BaseStream.Position = 13044; //temp hack 122 | // break; 123 | default: 124 | //if (typeID == 0) 125 | //{ 126 | // string dafssdf = ""; 127 | //} 128 | 129 | Console.WriteLine("!!!! loading type: " + typeID); 130 | LoadRecursive(reader); 131 | break; 132 | } 133 | } 134 | 135 | 136 | 137 | 138 | //footer? noticing a pattern here 139 | 140 | test = reader.ReadInt32(); 141 | test = reader.ReadInt32(); 142 | test = reader.ReadInt32(); 143 | 144 | test = reader.ReadInt16(); 145 | test = reader.ReadInt16(); 146 | test = reader.ReadByte(); 147 | test = reader.ReadByte(); 148 | 149 | test = reader.ReadInt16(); 150 | test = reader.ReadByte(); 151 | test = reader.ReadByte(); 152 | 153 | test = reader.ReadInt16(); 154 | test = reader.ReadByte(); 155 | test = reader.ReadByte(); 156 | 157 | test = reader.ReadInt16(); 158 | test = reader.ReadByte(); 159 | test = reader.ReadByte(); 160 | 161 | test = reader.ReadInt16(); 162 | test = reader.ReadByte(); 163 | test = reader.ReadByte(); 164 | 165 | test = reader.ReadInt16(); 166 | 167 | // -- 168 | 169 | test = reader.ReadInt32(); 170 | test = reader.ReadInt32(); 171 | test = reader.ReadInt32(); 172 | 173 | test = reader.ReadInt16(); 174 | test = reader.ReadInt16(); 175 | test = reader.ReadByte(); 176 | test = reader.ReadByte(); 177 | 178 | test = reader.ReadInt16(); 179 | test = reader.ReadByte(); 180 | test = reader.ReadByte(); 181 | 182 | test = reader.ReadInt16(); 183 | test = reader.ReadByte(); 184 | test = reader.ReadByte(); 185 | 186 | test = reader.ReadInt16(); 187 | test = reader.ReadByte(); 188 | test = reader.ReadByte(); 189 | 190 | test = reader.ReadInt16(); 191 | 192 | // -- 193 | 194 | test = reader.ReadInt32(); 195 | test = reader.ReadInt32(); 196 | test = reader.ReadInt32(); 197 | 198 | test = reader.ReadInt16(); 199 | test = reader.ReadInt16(); 200 | test = reader.ReadByte(); 201 | test = reader.ReadByte(); 202 | 203 | test = reader.ReadInt16(); 204 | test = reader.ReadByte(); 205 | test = reader.ReadByte(); 206 | 207 | test = reader.ReadInt16(); 208 | test = reader.ReadByte(); 209 | test = reader.ReadByte(); 210 | 211 | test = reader.ReadInt16(); 212 | 213 | // --- 214 | 215 | test = reader.ReadInt32(); 216 | test = reader.ReadInt32(); 217 | test = reader.ReadInt32(); 218 | test = reader.ReadInt16(); 219 | test = reader.ReadInt16(); 220 | 221 | string bruh = ""; 222 | 223 | //38 224 | reader.BaseStream.Position += 38; 225 | 226 | int a = reader.ReadInt16(); 227 | int b = reader.ReadInt16(); 228 | int c = reader.ReadInt16(); 229 | ShortGuid d = Utilities.Consume(reader); 230 | int e = reader.ReadInt32(); 231 | 232 | 233 | for (int i = 0; i < 999; i++) 234 | { 235 | UInt16 x_index = reader.ReadUInt16(); 236 | UInt16 y_index = reader.ReadUInt16(); 237 | UInt16 z_index = reader.ReadUInt16(); 238 | } 239 | } 240 | return true; 241 | } 242 | 243 | override protected bool SaveInternal() 244 | { 245 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 246 | { 247 | writer.BaseStream.SetLength(0); 248 | } 249 | return true; 250 | } 251 | #endregion 252 | 253 | private void LoadRecursive(BinaryReader reader) 254 | { 255 | test = reader.ReadInt16(); //small 256 | test = reader.ReadInt16(); //bigger 257 | 258 | int countOne = reader.ReadInt16(); //count of next block 259 | Console.WriteLine("Count of block 1: " + countOne); 260 | 261 | for (int z = 0; z < countOne; z++) 262 | { 263 | test = reader.ReadInt16(); //something index 264 | int countTwo = reader.ReadInt16(); //count of next ints 265 | Console.WriteLine("Count of block 2: " + countTwo); 266 | 267 | if (countTwo == 0) 268 | { 269 | LoadRecursive(reader); 270 | 271 | break; //?? 272 | } 273 | 274 | for (int i = 0; i < countTwo; i++) 275 | { 276 | test = reader.ReadInt32(); //probs indexes to the float array at the bottom of the file 277 | } 278 | } 279 | } 280 | } 281 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/TextDB.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | using System.Linq; 7 | using System.Text; 8 | #if UNITY_EDITOR || UNITY_STANDALONE_WIN 9 | using UnityEngine; 10 | #else 11 | using System.Numerics; 12 | #endif 13 | 14 | namespace CATHODE 15 | { 16 | /* DATA/TEXT/**//**.TXT */ 17 | public class TextDB : CathodeFile 18 | { 19 | public Dictionary Entries = new Dictionary(); 20 | public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; 21 | public TextDB(string path) : base(path) { } 22 | 23 | #region FILE_IO 24 | override protected bool LoadInternal() 25 | { 26 | CurrentReadState state = CurrentReadState.NONE; 27 | string content = File.ReadAllText(_filepath); 28 | string id = ""; 29 | string value = ""; 30 | bool isInInternalBracket = false; 31 | for (int i = 0; i < content.Length; i++) 32 | { 33 | switch (state) 34 | { 35 | case CurrentReadState.READING_ID: 36 | id += content[i]; 37 | if (content[i] == ']') state = CurrentReadState.NONE; 38 | break; 39 | case CurrentReadState.READING_VALUE: 40 | value += content[i]; 41 | if (content[i] == '{') isInInternalBracket = true; 42 | break; 43 | case CurrentReadState.NONE: 44 | if (content[i] == '[') state = CurrentReadState.READING_ID; 45 | break; 46 | } 47 | 48 | switch (content[i]) 49 | { 50 | case '{': 51 | if (isInInternalBracket) break; 52 | state = CurrentReadState.READING_VALUE; 53 | break; 54 | case '}': 55 | if (isInInternalBracket) 56 | { 57 | isInInternalBracket = false; 58 | break; 59 | } 60 | state = CurrentReadState.NONE; 61 | 62 | id = id.Substring(0, id.Length - 1); 63 | value = value.Substring(0, value.Length - 1); 64 | if (!Entries.ContainsKey(id)) 65 | Entries.Add(id, value); 66 | 67 | id = ""; 68 | value = ""; 69 | isInInternalBracket = false; 70 | break; 71 | } 72 | } 73 | return true; 74 | } 75 | 76 | override protected bool SaveInternal() 77 | { 78 | string content = ""; 79 | foreach (KeyValuePair entry in Entries) 80 | { 81 | content += "[" + entry.Key + "]\n{" + entry.Value + "}\n\n"; 82 | } 83 | File.WriteAllText(_filepath, content, Encoding.Unicode); 84 | return true; 85 | } 86 | #endregion 87 | 88 | public override string ToString() 89 | { 90 | return Path.GetFileNameWithoutExtension(_filepath); 91 | } 92 | 93 | #region STRUCTURES 94 | private enum CurrentReadState 95 | { 96 | NONE, 97 | READING_ID, 98 | READING_VALUE, 99 | } 100 | #endregion 101 | } 102 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/CATHODE/Traversals.cs: -------------------------------------------------------------------------------- 1 | using CATHODE.Scripting; 2 | using CathodeLib; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Runtime.InteropServices; 8 | 9 | #if UNITY_EDITOR || UNITY_STANDALONE_WIN 10 | using UnityEngine; 11 | #else 12 | using System.Numerics; 13 | using System.Runtime.InteropServices; 14 | #endif 15 | 16 | namespace CATHODE.EXPERIMENTAL 17 | { 18 | /* DATA/ENV/PRODUCTION/x/WORLD/COLLISION.BIN */ 19 | public class Traversals : CathodeFile 20 | { 21 | //NOTE: Not bothering finishing reversing this one as it's not actually used. 22 | // The TRAVERSAL file is only populated in the AUTOGENERATION folder which isn't used by the game at runtime. 23 | // Have included write support though to write the empty file. 24 | 25 | /*public*/ private List Entries = new List(); 26 | public static new Implementation Implementation = Implementation.SAVE; 27 | public Traversals(string path) : base(path) { } 28 | 29 | private char[] _magic = new char[4] { 't', 'r', 'a', 'v' }; 30 | private int _version = 2; 31 | 32 | #region FILE_IO 33 | override protected bool LoadInternal() 34 | { 35 | using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) 36 | { 37 | char[] magic = reader.ReadChars(4); 38 | if (!magic.SequenceEqual(_magic)) throw new Exception(); 39 | int version = reader.ReadInt32(); 40 | if (version != _version) throw new Exception(); 41 | 42 | int entryCount = reader.ReadInt16(); 43 | for (int i = 0; i < entryCount; i++) 44 | { 45 | Entries.Add(Utilities.Consume(reader)); 46 | } 47 | 48 | //note: there is more data left behind here. 49 | } 50 | return true; 51 | } 52 | 53 | override protected bool SaveInternal() 54 | { 55 | using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) 56 | { 57 | writer.BaseStream.SetLength(0); 58 | writer.Write(_magic); 59 | writer.Write(_version); 60 | 61 | /* 62 | writer.Write((Int16)Entries.Count); 63 | for (int i = 0; i < Entries.Count; i++) 64 | { 65 | 66 | } 67 | */ 68 | 69 | writer.Write((Int16)0); 70 | writer.Write((Int16)1); 71 | writer.Write((Int16)1); 72 | writer.Write((Int16)0); 73 | writer.Write((Int16)0); 74 | writer.Write((Int16)0); 75 | writer.Write((Int16)0); 76 | writer.Write((Int16)0); 77 | writer.Write(16256); 78 | } 79 | return true; 80 | } 81 | #endregion 82 | 83 | #region STRUCTURES 84 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 85 | public class Entry 86 | { 87 | public short EntryIndex; 88 | public int UnknownID; // NOTE: It is the same value for all entries in 'sci_hub'. Only seen in this file. 89 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] 90 | public byte[] Unknowns_; //5 91 | public ShortGuid NodeID; // NOTE: This is found in 'commands.pak' and it is a "Traversal" node for the Alien indicates animation. 92 | // Seen in 'resources.bin', 'nav_mesh', 'traversal' and 'commands.pak'. 93 | public ShortGuid ResourcesBINID; // NOTE: Seen in 'resources.bin', 'nav_mesh', 'traversal'. MATT: is this instance id? 94 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] 95 | public Vector3[] Ps; //20 96 | }; 97 | #endregion 98 | } 99 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/LEGACY_DAN/CathodePAK.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System; 3 | using System.Buffers.Binary; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Runtime.InteropServices; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace CATHODE.LEGACY 13 | { 14 | public class CathodePAK 15 | { 16 | public GenericPAKHeader header; 17 | public byte[] data; 18 | 19 | public byte[] dataStart; 20 | 21 | public GenericPAKEntry[] entryHeaders; 22 | public List entryContents; 23 | 24 | protected void LoadPAK(string filepath, bool BigEndian) 25 | { 26 | /* 27 | BinaryReader Stream = new BinaryReader(File.OpenRead(filepath)); 28 | 29 | header = Utilities.Consume(Stream); 30 | if (BigEndian) header.EndianSwap(); 31 | 32 | entryHeaders = Utilities.ConsumeArray(Stream, header.entryCount); 33 | entryContents = new List(header.entryCount); 34 | for (int i = 0; i < header.entryCount; ++i) 35 | { 36 | if (BigEndian) entryHeaders[i].EndianSwap(); 37 | byte[] Buffer = (entryHeaders[i].length == -1) ? new byte[]{ } : Stream.ReadBytes(entryHeaders[i].length); 38 | entryContents.Add(Buffer); 39 | } 40 | 41 | Stream.Close(); 42 | */ 43 | 44 | BinaryReader Stream = new BinaryReader(File.OpenRead(filepath)); 45 | 46 | GenericPAKHeader Header = Utilities.Consume(Stream); 47 | if (BigEndian) 48 | { 49 | Header.Version = BinaryPrimitives.ReverseEndianness(Header.Version); 50 | Header.MaxEntryCount = BinaryPrimitives.ReverseEndianness(Header.MaxEntryCount); 51 | Header.EntryCount = BinaryPrimitives.ReverseEndianness(Header.EntryCount); 52 | } 53 | 54 | GenericPAKEntry[] Entries = Utilities.ConsumeArray(Stream, Header.MaxEntryCount); 55 | 56 | //todo-mattf; remove the need for this 57 | long resetpos = Stream.BaseStream.Position; 58 | dataStart = Stream.ReadBytes((int)Stream.BaseStream.Length - (int)resetpos); 59 | Stream.BaseStream.Position = resetpos; 60 | 61 | List EntryDatas = new List(Header.MaxEntryCount); 62 | for (int EntryIndex = 0; EntryIndex < Header.MaxEntryCount; ++EntryIndex) 63 | { 64 | if (BigEndian) 65 | { 66 | GenericPAKEntry Entry = Entries[EntryIndex]; 67 | Entry.Length = BinaryPrimitives.ReverseEndianness(Entries[EntryIndex].Length); 68 | Entry.DataLength = BinaryPrimitives.ReverseEndianness(Entries[EntryIndex].DataLength); 69 | Entry.UnknownIndex = BinaryPrimitives.ReverseEndianness(Entries[EntryIndex].UnknownIndex); 70 | Entry.BINIndex = BinaryPrimitives.ReverseEndianness(Entries[EntryIndex].BINIndex); 71 | Entry.Offset = BinaryPrimitives.ReverseEndianness(Entries[EntryIndex].Offset); 72 | Entries[EntryIndex] = Entry; 73 | } 74 | byte[] Buffer = (Entries[EntryIndex].DataLength == -1) ? new byte[] { } : Stream.ReadBytes(Entries[EntryIndex].DataLength); 75 | EntryDatas.Add(Buffer); 76 | } 77 | 78 | header = Header; 79 | entryHeaders = Entries; 80 | entryContents = EntryDatas; 81 | 82 | Stream.Close(); 83 | } 84 | } 85 | 86 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 87 | public struct GenericPAKHeader 88 | { 89 | public int _Unknown1; 90 | public int _Unknown2; 91 | public int Version; 92 | public int EntryCount; 93 | public int MaxEntryCount; 94 | public int _Unknown3; 95 | public int _Unknown4; 96 | public int _Unknown5; 97 | }; 98 | 99 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 100 | public struct GenericPAKEntry 101 | { 102 | public int _Unknown1; //TODO: Is 'alien_pak_header' 40 bytes long instead? 103 | public int _Unknown2; 104 | public int Length; 105 | public int DataLength; //TODO: Seems to be the aligned version of Length, aligned to 16 bytes. 106 | public int Offset; 107 | public int _Unknown3; 108 | public int _Unknown4; 109 | public int _Unknown5; 110 | public Int16 UnknownIndex; 111 | public Int16 BINIndex; 112 | public int _Unknown6; 113 | public int _Unknown7; 114 | public int _Unknown8; 115 | }; 116 | } -------------------------------------------------------------------------------- /CathodeLib/Scripts/LEGACY_DAN/IDXRemap.cs: -------------------------------------------------------------------------------- 1 | using CathodeLib; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace CATHODE.LEGACY 10 | { 11 | public class IDXRemap : CathodePAK 12 | { 13 | public List Datas; 14 | public IDXRemap(string FullFilePath) 15 | { 16 | LoadPAK(FullFilePath, false); 17 | 18 | Datas = new List(header.EntryCount); 19 | 20 | for (int EntryIndex = 0; EntryIndex < header.EntryCount; ++EntryIndex) 21 | { 22 | Datas.Add(Utilities.Consume(entryContents[EntryIndex])); 23 | } 24 | } 25 | } 26 | 27 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 28 | public struct alien_shader_idx_remap_data 29 | { 30 | public int Index; 31 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] 32 | public int[] Unknown0_; //3 33 | }; 34 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Matt Filer 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # CathodeLib - Alien: Isolation C# Library 4 | 5 | ### CathodeLib is an open source library providing functionality to handle formats from the Cathode game engine, for modding Alien: Isolation. Used to power [OpenCAGE](https://github.com/MattFiler/OpenCAGE)! 6 | 7 | Available as a [NuGet package](https://www.nuget.org/packages/CathodeLib/), or alternatively just include this repo as a submodule in your project! 8 | 9 | --- 10 | 11 | All parsers inherit from a base `CathodeFile` class which provides: 12 | - A static `Implementation` flag, defining if the parser supports `CREATE`, `LOAD`, and/or `SAVE` functionality for the file. Parsers which support all three have the ability to generate files from scratch. 13 | - A `Loaded` bool, which is true if the parser has populated its values from a pre-existing file that it has loaded. If false, the parser is creating a new file on save. 14 | - A `Filepath` string, which is the filepath that the parser is using to either load or save the file. 15 | - A `Save` function, which will save the file out if the parser has the `SAVE` flag. This function can optionally be given a new filepath to save the file to. Returns false if saving fails. 16 | - Events for `OnLoadBegin`, `OnLoadSuccess`, `OnSaveBegin`, `OnSaveSuccess` which fire at load/save start and successful completion respectively, with the appropriate filepath as an arg. 17 | 18 | Most parsers provide access to the file's content via an `Entries` parameter, however this can vary per implementation. 19 | 20 | Note: in debug mode the parsers will all fail hard, however in release mode all load/save calls are wrapped in try/catch statements. 21 | 22 | **Parsers currently available in CathodeLib...** 23 | 24 | ## For scripting: 25 | - `CATHODE.Commands` handles `COMMANDS.PAK` files 26 | - The file consists of `Composite` scripts which hold various `Entity` types for logic 27 | - `FunctionEntity` = functions which execute functionality, with parameters and links to child `Entity` objects 28 | - `VariableEntity` = variables which can be used externally as parameters on an instanced `Composite` via a `FunctionEntity` 29 | - `ProxyEntity` = a proxy of a `FunctionEntity` within another `Composite`, useful for acting on events in another composite 30 | - `OverrideEntity` = an override of a parameter value on an entity within an instanced `Composite` in this `Composite` 31 | 32 | Check out a full overview of the Commands structure [on the Wiki](https://github.com/OpenCAGE/CathodeLib/wiki/Cathode-scripting-overview), and follow [this handy guide](https://github.com/OpenCAGE/CathodeLib/wiki/Creating-your-first-Cathode-script) to create your first script! 33 | 34 | ## For assets: 35 | - `CATHODE.PAK2` handles `UI.PAK` and `ANIMATIONS.PAK` files 36 | - `CATHODE.Models` handles `LEVEL_MODELS.PAK` files, paired with a `MODELS_LEVEL.BIN` 37 | - `CATHODE.Textures` handles `LEVEL_TEXTURES.ALL.PAK` files, paired with a `LEVEL_TEXTURE_HEADERS.ALL.BIN` 38 | - `CATHODE.LEGACY.Assets.Shaders` handles various `SHADERS` `PAK` files (WIP) 39 | 40 | ## For level data and mappings: 41 | - `CATHODE.Movers` handles `MODELS.MVR` files 42 | - `CATHODE.RenderableElements` handles `REDS.BIN` files 43 | - `CATHODE.Resources` handles `RESOURCES.BIN` files 44 | - `CATHODE.Materials` handles `MODELS.MTL` files 45 | - `CATHODE.MaterialMappings` handles `MATERIAL_MAPPINGS.PAK` files 46 | - `CATHODE.EnvironmentMaps` handles `ENVIRONMENTMAP.BIN` files 47 | - `CATHODE.EnvironmentAnimations` handles `ENVIRONMENT_ANIMATION.DAT` files 48 | - `CATHODE.PathBarrierResources` handles `PATH_BARRIER_RESOURCES` files 49 | - `CATHODE.PhysicsMaps` handles `PHYSICS.MAP` files 50 | - `CATHODE.Lights` handles `LIGHTS.BIN` files 51 | - `CATHODE.Collisions` handles `COLLISION.BIN` files 52 | - `CATHODE.CollisionMaps` handles `COLLISION.MAP` files 53 | - `CATHODE.AnimationStrings` handles `ANIM_STRING_DB.BIN` and `ANIM_STRING_DB_DEBUG.BIN` files 54 | - `CATHODE.EXPERIMENTAL.NavigationMesh` handles `NAV_MESH` files (experimental) 55 | - `CATHODE.SoundNodeNetwork` handles `SNDNODENETWORK.DAT` files 56 | - `CATHODE.SoundLoadZones` handles `SOUNDLOADZONES.DAT` files 57 | - `CATHODE.SoundFlashModels` handles `SOUNDFLASHMODELS.DAT` files 58 | - `CATHODE.SoundEventData` handles `SOUNDEVENTDATA.DAT` files 59 | - `CATHODE.SoundEnvironmentData` handles `SOUNDENVIRONMENTDATA.DAT` files 60 | - `CATHODE.SoundDialogueLookups` handles `SOUNDDIALOGUELOOKUPS.DAT` files 61 | - `CATHODE.SoundBankData` handles `SOUNDBANKDATA.DAT` files 62 | - `CATHODE.CharacterAccessorySets` handles `CHARACTERACCESSORYSETS.BIN` files 63 | - `CATHODE.CustomCharacterInfo` handles `CUSTOMCHARACTERINFO.BIN` files 64 | - `CATHODE.CustomCharacterConstrainedComponents` handles `CUSTOMCHARACTERCONSTRAINEDCOMPONENTS.BIN` files 65 | - `CATHODE.Strings` handles `*.TXT` files 66 | 67 | ## For configurations: 68 | - `CATHODE.BML` handles any `.BML` files 69 | - Get/set content as an `XmlDocument` via `BML.Content` 70 | 71 | ## For saves: 72 | - `CATHODE.EXPERIMENTAL.ProgressionSave` handles `PROGRESSION.AIS` files 73 | - `CATHODE.EXPERIMENTAL.MissionSave` handles `*.AIS` files (experimental) 74 | 75 | --- 76 | 77 |

CathodeLib is in no way related to (or endorsed by) Creative Assembly or SEGA.

78 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCAGE/CathodeLib/64aa438afd9bcca5badff4d029a09ffe1fd9976f/icon.png -------------------------------------------------------------------------------- /release.bat: -------------------------------------------------------------------------------- 1 | dotnet nuget push %1 --source "github" --------------------------------------------------------------------------------