Skip to content

Commit

Permalink
Extraction Abstraction!
Browse files Browse the repository at this point in the history
Changes:
- After working with the C++ code yesterday, and working on MCRegionJS some more, I decided this codebase could use some help too. In favor of using loops to iterate over `x` data instead of slicing the data into multiple chunks, I am moving away from the `chunkify()` function! While it did work very well, it wasn't really necessary because it added an extra step in that didn't need to be there. Rather than splitting the data into individual chunks to read separately, you can just iterate over the full data in `x` steps manually, then get the output relative to that location. Very nice! I started adding that over in MCRegionJS first, but got a bit overwhelmed with all of the features over there, so I decided to remove `chunkify()` from this one first, since it isn't as complex, and it depends on MCRegion's source of `chunkify()` itself. So, now I can go fully remove it from over in MCRegionJS too!
- The exported functions are now part of a class, as static methods. I started using this pattern over in MCRegionJS also, and it's also really nice to describe the data with. Woah! Don't look now, but I think that's Object-Oriented programming? :O (PLEASE, SEND HELP! I'M STARTING TO LIKE IT XD)
- I think the main reason this class-based setup works well for this kind of data management is because I want to be able to read/write (eventually) the data as a whole, but also provide an API to allow other people to use the library's logic to work with the data too. So, I don't only want to be able to read the data, but also provide people with a way to read the header for `x` file, or just get the chunks for `x` region, things like that. I can't predict all of the different things you might want to do with the data, so why not just give the tools to you? That sounds really cool to me! And, I think I'll eventually make other things with those tools too, a bit futher down the line. Like, say if you wanted to replace all of the Stone blocks in your world to Diorite (no, don't do that.), you could just open up the save with `x` API, iterate over all of the Regions, iterate over all of their Chunks, then iterate over all of the blocks and just replace `x` value with `y` value. Simple as that! I guess I want the data to just be there, without the need to figure out how to get it. It should just be plain accessible :)
- Incremented the version number up a step, since this is a significant change for sure (yay).
  • Loading branch information
Offroaders123 committed Oct 28, 2022
1 parent 4334858 commit 4dad69d
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 81 deletions.
36 changes: 3 additions & 33 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gamedata-parser",
"version": "0.2.0",
"version": "0.3.0",
"description": "An experimental script to parse Minecraft Legacy Console PS3 saves!",
"type": "module",
"main": "./dist/index.js",
Expand All @@ -25,9 +25,6 @@
"url": "https://github.com/Offroaders123/Gamedata-Parser/issues"
},
"homepage": "https://github.com/Offroaders123/Gamedata-Parser#readme",
"dependencies": {
"mcregionjs": "file:../MCRegionJS"
},
"devDependencies": {
"typescript": "^4.8.4"
}
Expand Down
55 changes: 53 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,53 @@
export * from "./read.js";
export { chunkify } from "mcregionjs";
export interface Definition {
name: string;
offset: number;
length: number;
}

export class Gamedata {
static read(data: Uint8Array){
const definitions = this.readDefinitions(data);

const result: Gamedata[] = [];

for (const { name, offset, length } of definitions){
const content = new Uint8Array(data.slice(offset,offset + length));
const file = new Gamedata(name,content);
result.push(file);
}

return result;
}

static getDefinitions(data: Uint8Array){
const view = new DataView(data.buffer);
const offset = view.getUint32(0);

return new Uint8Array(data.slice(offset));
}

static readDefinitions(data: Uint8Array){
const definitions = this.getDefinitions(data);
const result: Definition[] = [];

for (let i = 0; i < definitions.byteLength; i += 144){
const definition = new Uint8Array(definitions.slice(i,i + 144));
const name = new TextDecoder("utf-16be").decode(definition).split("\0")[0].replace("-1r.","-1/r.");
// Replace call fixes a naming inconsistency for Nether region files.

const header = new Uint8Array(definition.slice(128));
const view = new DataView(header.buffer);

const length = view.getUint32(0);
const offset = view.getUint32(4);

result.push({ name, offset, length });
}

return result;
}

constructor(public name: string, public data: Uint8Array) {}
}

export default Gamedata;
32 changes: 0 additions & 32 deletions src/read.ts

This file was deleted.

21 changes: 11 additions & 10 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
// @ts-check

import * as fs from "node:fs/promises";
import * as path from "node:path";
import * as GD from "../dist/index.js";
import { readFile, writeFile, mkdir } from "node:fs/promises";
import { join, dirname } from "node:path";
import Gamedata from "../dist/index.js";

const data = await fs.readFile(new URL("./world/GAMEDATA",import.meta.url));
const data = await readFile(new URL("./world/GAMEDATA",import.meta.url));

const files = GD.read(data);
const files = Gamedata.read(data);

for (const [name,data] of files){
const pathname = decodeURIComponent(new URL(path.join("./world_data",name),import.meta.url).pathname);
console.log(name);
await fs.mkdir(path.dirname(pathname),{ recursive: true });
await fs.writeFile(pathname,data);
for (const file of files){
console.log(file);
const path = decodeURIComponent(new URL(join("./world_data",file.name),import.meta.url).pathname);

await mkdir(dirname(path),{ recursive: true });
writeFile(path,file.data);
}

0 comments on commit 4dad69d

Please sign in to comment.