{"id":16298525,"url":"https://github.com/sheepreaper/onisaveparser","last_synced_at":"2026-01-21T14:10:32.662Z","repository":{"id":38067838,"uuid":"198509902","full_name":"SheepReaper/OniSaveParser","owner":"SheepReaper","description":"WIP WIP WIP (based on RoboPhred's Oni parser)","archived":false,"fork":false,"pushed_at":"2025-09-18T04:59:55.000Z","size":70,"stargazers_count":3,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-18T06:36:17.827Z","etag":null,"topics":["csharp","csharp-library","game-development","netstandard","oni","oxygen-not-included","unity"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SheepReaper.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-23T21:20:55.000Z","updated_at":"2025-09-18T05:00:00.000Z","dependencies_parsed_at":"2023-01-24T14:45:19.596Z","dependency_job_id":"1ed7e276-02e8-4903-9dff-c4c77e64a8b4","html_url":"https://github.com/SheepReaper/OniSaveParser","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SheepReaper/OniSaveParser","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SheepReaper%2FOniSaveParser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SheepReaper%2FOniSaveParser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SheepReaper%2FOniSaveParser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SheepReaper%2FOniSaveParser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SheepReaper","download_url":"https://codeload.github.com/SheepReaper/OniSaveParser/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SheepReaper%2FOniSaveParser/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28634791,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-21T04:47:28.174Z","status":"ssl_error","status_checked_at":"2026-01-21T04:47:22.943Z","response_time":86,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","csharp-library","game-development","netstandard","oni","oxygen-not-included","unity"],"created_at":"2024-10-10T20:44:32.302Z","updated_at":"2026-01-21T14:10:32.646Z","avatar_url":"https://github.com/SheepReaper.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OniSaveParser\nThis library deserializes and (in the future will) serialize save data from Oxygen Not Included. It is a .NET standard library and will work with anything .NET.\n\nThis is a utility library for reading saves. If you are looking for a way to edit your save files, you can do so using Duplicity: https://robophred.github.io/oni-duplicity/#/. I do not know of any projects implementing this library yet\n\n## Game Compatibility\nThis library currently supports save version 7.11.\n\nThis library intends to parse the most recent version of the save file (even test build)\n\n## API\nSheepReaper.GameSaves.Klei.Deserializer is the only class you need at the moment.\nIt has 4 constructors:\n- Deserializer(): This default contructor allows you to allocate the object without triggering the deserialization automatically. You must call .Parse() explicitely if you use this constructor.\n- Deserializer(string): Accepts a path to an ONI save file and will automatically deserialize.\n- Deserializer(Stream): Accepts a Stream and will automatically deserialize. (Usually a FileStream or a MemoryStream)\n- Deserializer(Memory\u003cbyte\u003e): Accepts a Memory\u003cbyte\u003e (or byte[]) and will automatically deserialize.\nIn all 4 cases, the deserialized object is accessible through the .GameSave Property. (and the Parse() method returns it as well, if you went that way.)\n\n## Design Philosophy\nThe original project that this work is based on used the \"Idempotent load-save cycle\" (ie a re-serialization without any edits should produce identical byte-code). However, for this version of the library, I intend to write lots of unit tests and plug in some CI/CD. I do not yet know how important the actual element ordering affects the compatibility of the save file. I looked to use as much native .NET serialization support as was available thinking that ONI on Unity makes use of .NET and that Klei would not be insane when building serialization/deserialization. If anyone knows how they actually serialize the thing, I'd appreciate it.\n\n## Example usage (There is also a complete console app that demoes this)\n```csharp\n    internal class Program\n    {\n        private static void Main(string[] args)\n        {\n            const string saveFileLocation = \"F:\\\\Documents\\\\Klei\\\\OxygenNotIncluded\\\\save_files\\\\plucky.sav\";\n            const string jsonOutputLocation = \"C:\\\\temp\\\\output.json\";\n\n            GameSave gameSave;\n\n            using (var deserializer = new Deserializer(saveFileLocation))\n            {\n                gameSave = deserializer.GameSave;\n            }\n\n            // have fun with gameSave\n\n            // write to json\n            using (var writer = new FileStream(jsonOutputLocation, FileMode.OpenOrCreate))\n            {\n                var serialized = JsonConvert.SerializeObject(gameSave, Formatting.Indented);\n                var buffer = new Span\u003cbyte\u003e(new byte[serialized.Length]);\n                Encoding.UTF8.GetBytes(serialized.AsSpan(), buffer);\n\n                writer.Write(buffer);\n            }\n\n            // write to console\n            Console.WriteLine(JsonConvert.SerializeObject(gameSave));\n\n            Console.WriteLine(\"\\nDemo Finished, press ANY key to exit...\");\n            Console.ReadKey();\n        }\n    }\n```\n\n## Still to do\nThe Serializer (Duh) Can only Deserialize at the moment.\nHandle the special-case manual-parse data used by a few of the game object types.\n\n## Special Thanks\nTo RoboPhred - without whose work I would never have gotten this far. This started as a \"How come no one has done this before\" to \"How come there isn't a .NET version of this?\" to me learning a bunch of new stuff about Serialization/Deserialization and byte by byte analysis and lots and lots of gray hairs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsheepreaper%2Fonisaveparser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsheepreaper%2Fonisaveparser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsheepreaper%2Fonisaveparser/lists"}