forked from mirrors/principia
Add package-creator tool for making package files from JSON data
Rewritten from the PackageCreator Python script to use Principia's own package writing utilities instead
This commit is contained in:
parent
6ea828e4d3
commit
10e05d687b
7 changed files with 167 additions and 42 deletions
|
|
@ -717,37 +717,41 @@ bool pkginfo::save() {
|
|||
char *storage = (char*)pkgman::get_pkg_path(this->type);
|
||||
snprintf(path, 1023, "%s/%d.ppkg", storage, this->id);
|
||||
|
||||
return save_to_path(path);
|
||||
}
|
||||
|
||||
bool pkginfo::save_to_path(const char *path) {
|
||||
FILE *fp = fopen(path, "wb");
|
||||
|
||||
if (fp) {
|
||||
// always update the version to the latest on save
|
||||
this->version = PKG_VERSION;
|
||||
|
||||
fwrite(&this->version, 1, 1, fp);
|
||||
fwrite(&this->community_id, 1, sizeof(uint32_t), fp);
|
||||
fwrite(this->name, 1, 255, fp);
|
||||
fwrite(&this->unlock_count, 1, sizeof(uint8_t), fp);
|
||||
fwrite(&this->first_is_menu, 1, sizeof(uint8_t), fp);
|
||||
fwrite(&this->return_on_finish, 1, sizeof(uint8_t), fp);
|
||||
fwrite(&this->num_levels, 1, sizeof(uint8_t), fp);
|
||||
|
||||
for (int x=0; x<this->num_levels; x++) {
|
||||
fwrite(&this->levels[x], 1, sizeof(uint32_t), fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
} else {
|
||||
if (!fp) {
|
||||
tms_errorf("could not open: %s", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
// always update the version to the latest on save
|
||||
this->version = PKG_VERSION;
|
||||
|
||||
fwrite(&this->version, 1, 1, fp);
|
||||
fwrite(&this->community_id, 1, sizeof(uint32_t), fp);
|
||||
fwrite(this->name, 1, 255, fp);
|
||||
fwrite(&this->unlock_count, 1, sizeof(uint8_t), fp);
|
||||
fwrite(&this->first_is_menu, 1, sizeof(uint8_t), fp);
|
||||
fwrite(&this->return_on_finish, 1, sizeof(uint8_t), fp);
|
||||
fwrite(&this->num_levels, 1, sizeof(uint8_t), fp);
|
||||
|
||||
for (int x=0; x<this->num_levels; x++) {
|
||||
fwrite(&this->levels[x], 1, sizeof(uint32_t), fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkginfo::open(int type, uint32_t id) {
|
||||
if (type < 0 || type >= 4) {
|
||||
tms_errorf("invalid level type");
|
||||
return "";
|
||||
return false;
|
||||
}
|
||||
|
||||
char path[1024];
|
||||
|
|
@ -767,37 +771,38 @@ bool pkginfo::open(int type, uint32_t id) {
|
|||
|
||||
FILE *fp = _fopen(path, "rb");
|
||||
|
||||
if (fp) {
|
||||
_fread(&this->version, 1, 1, fp);
|
||||
if (this->version >= 2)
|
||||
_fread(&this->community_id, 1, sizeof(uint32_t), fp);
|
||||
else
|
||||
this->community_id = 0;
|
||||
|
||||
_fread(this->name, 1, 255, fp);
|
||||
|
||||
if (this->version >= 3)
|
||||
_fread(&this->unlock_count, 1, sizeof(uint8_t), fp);
|
||||
|
||||
if (this->version >= 1) {
|
||||
_fread(&this->first_is_menu, 1, sizeof(uint8_t), fp);
|
||||
_fread(&this->return_on_finish, 1, sizeof(uint8_t), fp);
|
||||
}
|
||||
|
||||
_fread(&this->num_levels, 1, sizeof(uint8_t), fp);
|
||||
|
||||
if (this->num_levels)
|
||||
this->levels = (uint32_t*)malloc(this->num_levels * sizeof(uint32_t));
|
||||
|
||||
for (int x=0; x<this->num_levels; x++) {
|
||||
_fread(&this->levels[x], 1, sizeof(uint32_t), fp);
|
||||
}
|
||||
|
||||
_fclose(fp);
|
||||
} else {
|
||||
if (!fp) {
|
||||
tms_errorf("could not open: %s", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
_fread(&this->version, 1, 1, fp);
|
||||
if (this->version >= 2)
|
||||
_fread(&this->community_id, 1, sizeof(uint32_t), fp);
|
||||
else
|
||||
this->community_id = 0;
|
||||
|
||||
_fread(this->name, 1, 255, fp);
|
||||
|
||||
if (this->version >= 3)
|
||||
_fread(&this->unlock_count, 1, sizeof(uint8_t), fp);
|
||||
|
||||
if (this->version >= 1) {
|
||||
_fread(&this->first_is_menu, 1, sizeof(uint8_t), fp);
|
||||
_fread(&this->return_on_finish, 1, sizeof(uint8_t), fp);
|
||||
}
|
||||
|
||||
_fread(&this->num_levels, 1, sizeof(uint8_t), fp);
|
||||
|
||||
if (this->num_levels)
|
||||
this->levels = (uint32_t*)malloc(this->num_levels * sizeof(uint32_t));
|
||||
|
||||
for (int x=0; x<this->num_levels; x++) {
|
||||
_fread(&this->levels[x], 1, sizeof(uint32_t), fp);
|
||||
}
|
||||
|
||||
_fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ class pkgman {
|
|||
}
|
||||
};
|
||||
|
||||
/// Class representing a package of levels (stored as .ppkg files)
|
||||
class pkginfo {
|
||||
public:
|
||||
uint8_t version;
|
||||
|
|
@ -292,8 +293,14 @@ class pkginfo {
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Open package by type and ID.
|
||||
bool open(int type, uint32_t id);
|
||||
|
||||
/// Save current package as .ppkg determined by type and ID.
|
||||
bool save();
|
||||
|
||||
/// Save package to a specific path, rather than the default path determined by type and ID.
|
||||
bool save_to_path(const char *path);
|
||||
};
|
||||
|
||||
// level flags
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
SUBDIRS := featured-list-creator lvl-icon-extractor lvlbuf-decompressor lvledit progress-get
|
||||
SUBDIRS := featured-list-creator lvl-icon-extractor lvlbuf-decompressor lvledit package-creator progress-get
|
||||
|
||||
.PHONY: all clean $(SUBDIRS)
|
||||
|
||||
|
|
|
|||
|
|
@ -13,4 +13,5 @@ Most of these programs rely on source files from the main Principia codebase and
|
|||
- `lvl-icon-extractor`: Extract the embedded level icon in a Principia level file
|
||||
- `lvlbuf-decompressor`: Decompress the level buffer of a Principia level file
|
||||
- `lvledit`: Edit metadata of Principia level files
|
||||
- `package-creator`: Create a Principia package file from JSON data
|
||||
- `progress-get`: Get leaderboard score for a given level from a data.bin file
|
||||
|
|
|
|||
28
utils/package-creator/Makefile
Normal file
28
utils/package-creator/Makefile
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
BIN = ../bin
|
||||
PRINCIPIA = ../..
|
||||
PROGRAM = package-creator
|
||||
SRCS := main.cc $(PRINCIPIA)/src/pkgman.cc $(PRINCIPIA)/src/rand.c
|
||||
|
||||
# always static unless you do STATIC=0
|
||||
STATIC ?= 1
|
||||
|
||||
CXX ?= g++
|
||||
CXXFLAGS ?= -D_NO_TMS -O2 -ffunction-sections -fdata-sections
|
||||
INCLUDES ?= -I$(PRINCIPIA)/src -I$(PRINCIPIA)/lib
|
||||
LDFLAGS ?= -lz -Wl,--gc-sections
|
||||
ifeq ($(STATIC),1)
|
||||
LDFLAGS += -l:libjansson.a
|
||||
else
|
||||
LDFLAGS += -ljansson
|
||||
endif
|
||||
|
||||
all: $(BIN)/$(PROGRAM)
|
||||
|
||||
$(BIN)/$(PROGRAM): $(SRCS)
|
||||
@mkdir -p $(BIN)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm $(BIN)/$(PROGRAM)
|
||||
|
||||
.PHONY: all clean
|
||||
27
utils/package-creator/README.md
Normal file
27
utils/package-creator/README.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# `package-creator`
|
||||
Create a Principia package file from JSON data.
|
||||
|
||||
For more information about Principia level packages, see the [wiki](https://principia-web.se/wiki/Packages).
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
package-creator <package-json> <package-file>
|
||||
```
|
||||
|
||||
## Format
|
||||
Anything except for `name` and `levels` is optional, the default values are the ones provided below:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Test Package",
|
||||
"community_id": 0,
|
||||
"levels_unlocked": 2,
|
||||
"first_is_menu": 0,
|
||||
"return_on_finish": 0,
|
||||
"levels": [
|
||||
67,
|
||||
68
|
||||
]
|
||||
}
|
||||
```
|
||||
57
utils/package-creator/main.cc
Normal file
57
utils/package-creator/main.cc
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include "pkgman.hh"
|
||||
#include <jansson.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define GET_JSON_OBJ(obj, key) json_object_get((obj), (key))
|
||||
|
||||
#define GET_JSON_INTEGER(obj, key, def) json_integer_value(GET_JSON_OBJ((obj), (key)) ? GET_JSON_OBJ((obj), (key)) : json_integer((def)))
|
||||
#define GET_JSON_STRING(obj, key) json_string_value(GET_JSON_OBJ((obj), (key)))
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 3) {
|
||||
printf("usage: package-creator [package-json] [package-file]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *input_filename = argv[1];
|
||||
const char *output_filename = argv[2];
|
||||
|
||||
json_t *root; json_error_t error;
|
||||
root = json_load_file(input_filename, 0, &error);
|
||||
if (!root) {
|
||||
printf("Error loading JSON file: %s\n", error.text);
|
||||
return 1;
|
||||
}
|
||||
|
||||
json_t *levels = json_object_get(root, "levels");
|
||||
|
||||
// Create pkginfo object from JSON data
|
||||
pkginfo p;
|
||||
p.version = 3;
|
||||
|
||||
p.community_id = GET_JSON_INTEGER(root, "community_id", 0);
|
||||
p.unlock_count = GET_JSON_INTEGER(root, "unlock_count", 2);
|
||||
p.first_is_menu = GET_JSON_INTEGER(root, "first_is_menu", 0);
|
||||
p.return_on_finish = GET_JSON_INTEGER(root, "return_on_finish", 0);
|
||||
|
||||
strncpy(p.name, GET_JSON_STRING(root, "name"), 255);
|
||||
p.name[255] = '\0';
|
||||
|
||||
int num_levels = json_array_size(levels);
|
||||
if (num_levels > 255) {
|
||||
printf("Too many levels in package (max 255)\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
p.num_levels = num_levels;
|
||||
if (p.num_levels > 0)
|
||||
p.levels = (uint32_t*)malloc(p.num_levels * sizeof(uint32_t));
|
||||
|
||||
for (size_t i = 0; i < p.num_levels; i++)
|
||||
p.levels[i] = (uint32_t)json_integer_value(json_array_get(levels, i));
|
||||
|
||||
// Write the package to a file
|
||||
p.save_to_path(output_filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue