How exactly are custom ships encoded to PRPL data?

Started by kajacx, November 25, 2016, 03:00:02 PM

Previous topic - Next topic

kajacx

I want to create a map where players can create their custom ships by merging their other ships. This is possible thanks to the "AddCustomShipToInventory" PRPL method, that takes a base64-encoded string containing ship info (the very same string generated by pressing the "PRPL data to clipboard" button in ship editor) and adds that ship to your ship pool.

EDIT: I have already solved this problem, look at my replies below for explanation and yes, PRPL code as well.
Why do work yourself, when you can write a program that will do the work for you.

mirror corparation

#1
3F in hexadecimal is 63, 40 in hexadecimal = 64 and 41 in hexadecimal is 65. might help you
EDIT: converted all your numbers
1 - 128 63
2 - 000 64
3 - 064 64
4 - 224 64
5 - 000 65
6 - 001 65

kajacx

#2
EDIT: Now includes the new ship info (author & description) from version 1.1.4.

After 2 days of testing, I have finally figured everything out.

General overview:
Spoiler

By hitting the "PRPL Data to Clipboard" in editor, you get a base-64 encoded string containing all the info on how to construct the ship. This is how the data looks like for the CRUISER built-in ship: (I rebuild the Cruiser ship in editor, so the order of the modules might be different)

New version for 1.1.4
Spoiler


[close]

Old version (if you find the new one too confusing)
Spoiler


[close]

All the grey parts are always the same for each ship.
All the numbers are in Little Endian format (the least significant bytes are on the left, so for example 7 becomes "07 00 00 00" and not "00 00 00 07") (except in the "module data" section, where the triplet (moduleID, xPosition, yPosition) is encoded as float, so it creates a wierd pattern).
For example, width "0B 00 00 00" means the width is 11.
[close]

Module Data:
Spoiler

Each module on the ship (except the command module) gets exactly 12 bytes in the "module data" section, which look like this:
00 00 MM MM 00 00 XX XX 00 00 YY YY
where X any Y are coordinates of the module, and M is the module ID.

Module ID table:

ENGINE          A0 40
LATHE           10 41
LASER           00 40
CANNON          80 3F
MISSLE_LAUNCHER 40 40
PARTICLE_BEAM   80 40
DISCHARGE       90 41
ENERGY_TANK     C0 40
PORT            00 41
GUPPY           E0 41
SHIELD          40 41
REACTOR         60 41
FIGHTER_BASE    20 41
GRABBER         80 41
MK7             88 41


The position of a module is the distance from it's left-bottom corner to the left-bottom corner of your ship.
In other words, consieder your module in the most left-bottom corner of your ship. Now move your module x cells to the right and y cells up. Congratulation, you have a module at position x,y. But don't think it will be that easy, since this position is not stored in the data itself, but rather some bizzare values are. Here is a complete list of such values for each distace/position:


00: 00 00
01: 80 3F
02: 00 40
03: 40 40
04: 80 40
05: A0 40
06: C0 40
07: E0 40
08: 00 41
09: 10 41
10: 20 41
11: 30 41
12: 40 41
13: 50 41
14: 60 41
15: 70 41
16: 80 41
17: 88 41
18: 90 41
19: 98 41
20: A0 41
21: A8 41
22: B0 41
23: B8 41
24: C0 41
25: C8 41
26: D0 41
27: D8 41
28: E0 41
29: E8 41
30: F0 41
31: F8 41
32: 00 42
33: 04 42
34: 08 42


The number on the left is the distance you want, and the 2 numbers on the right are the 2 bytes that you need to write to the "module data" section to have your module at that position. Note: someone correctly pointed out that is a conversion from an integer to the IEEE short floating point standard, great observation, I wouldn't have seen it otherwise.

Example:
Spoiler



Here, the green square is at the position 0,0 - the most left-bottom position of the ship. The engine (the yellow square) is at position 1,3 because it is one cell to the right and three cells to the top from the 0,0 left-bottom corner of your ship.

Summary: you have an Engine, at position 1,3. Now you look up the code for engine ("A0 40"), position 1 ("80 3F") and position 3 ("40 40"), so the final values is:
00 00 A0 40 00 00 80 3F 00 00 40 40

This is exactly the first 12 bytes of the "module data" section in the example above.
[close]

Convert each module to the 12 bytes as shown in the example, and then simply put them all in the "module data" section. The command module is not stored here.
[close]

Hull info:
Spoiler

The hull is described simply by a list of all hull parts. The part list is here:


After the complete size of the hull (even with empty spaces, so width * height, brown color in overview), just put code for each block (even empty ones), starting from left-bottom, and then goining left-to-right, and then bottom-to-top once you reach the end of each row.
[close]

The rest of the stuff:
Spoiler

The rest should be pretty obivous from the overview, I'll just remind you that all numbers are in 4 bytes little endian format (even in "hull info" section), except in "module data" section, where everything is wierd, and in the "ship's name's length" section, that only contains the lower 2 bytes of the ship's name's length.

The postion of the command module is handled similiary to other modules, it's distance from the left-bottom corner is in the "X/Y position of the center", this time it is the acctual distance, and not some random number like in the "module data" section.
[close]

Well, that's all I have for now, I'll be adding some PRPL code that acctually does all this stuff once I get around to write it, expect method signature similar to this
String construct(int width, int height, int[] hull, List<Module> modules, int centerX, int centerY, String name)
Why do work yourself, when you can write a program that will do the work for you.

planetfall

So, when I was a kid, there was this tetris-clone-ish thing on my computer, which was one of those paleolithic Apple affairs of translucent gray and blue plastic. I don't remember much about the game except there were cones in the background for some reason, and eyeball blocks, and occasionally if you managed to do something sufficiently badass you would hear this dude say "IMPRESSIVE" in an incredibly deep, resounding voice that echoed once or twice. That specific sound effect is my response to the above post.
Pretty sure I'm supposed to be banned, someone might want to get on that.

Quote from: GoodMorning on December 01, 2016, 05:58:30 PM"Build a ladder to the moon" is simple as a sentence, but actually doing it is not.

TonnyT

I wish there was a upvote system so I could upvote this.
Instead I shall have to offer my praise and commentary.

Well done, very well done indeed.
Novus Imperium Corporation
CEO: Tony Carlisle

Today our concern must be with the future. For the world is changing. The old era is ending. The old ways will not do.

-President John Fitzgerald Kennedy

kajacx

#5
Update: the PRPL script now includes the ship description info from version 1.1.4. Also I have re-writen the script to PRPL+, my custom extension of PRPL, but don't worry, the compiled PRPL code is in the zip as well.
I will not update the Java file, since I no longer have all the code in one single file. You can however see the ShipConstruct class from my custom ship editor if you are interested in the source code. (End of update)

Thanks for support, I have managed (at least I think) to make it work in PRPL, I'm too tired now to properly document the API, but just look at the "constructLathe" example, it should be pretty clear from there.

I'm adding the Java code that I used as well, if anyone is interested.
Why do work yourself, when you can write a program that will do the work for you.

Nicant

Woah, looking at those scripts i wonder if it is possible to make an adaptive ship that gets smarter each time it gets destroyed!
CW4 hype!!

Sorrontis

This.... is.... amazing!

I wonder if there's a way to modify a ship once it's already built...
"If you want others to be happy, practice compassion. If you want to be happy, practice compassion."

kajacx

Quote from: Sorrontis on November 27, 2016, 11:24:58 AM
I wonder if there's a way to modify a ship once it's already built...

You could probably destroy your ship and replace it with a new one. Next weekend I'll do merging of ships, and also post the code, so changing ships with it shouldn't be that difficult.
Why do work yourself, when you can write a program that will do the work for you.

GoodMorning

Interesting. A little bit of PRPL, and an enemy which gains a module for each ship it destroys on respawn...

Or a one-shot custom ship which you must collect parts of, before building, and cannot be reconstructed.
A narrative is a lightly-marked path to another reality.

GoodMorning

The thought occurs that with this knowledge, you might be able to stack modules by malformed data.

Time to build the most impressive (and expensive) 7x7 ship possible. You never thought that you could stack fifty shield modules, did you?
A narrative is a lightly-marked path to another reality.

kajacx

QuoteTime to build the most impressive (and expensive) 7x7 ship possible. You never thought that you could stack fifty shield modules, did you?



I'm sorry I had to. I just had to.
Why do work yourself, when you can write a program that will do the work for you.

uncopy2002

QuoteModule ID table:
ENGINE          A0 40
LATHE           10 41
LASER           00 40
CANNON          80 3F
MISSLE_LAUNCHER 40 40
PARTICLE_BEAM   80 40
DISCHARGE       90 41
ENERGY_TANK     C0 40
PORT            00 41
GUPPY           E0 41
SHIELD          40 41
REACTOR         60 41
FIGHTER_BASE    20 41
GRABBER         80 41
MK7             88 41


00: 00 00
01: 80 3F
02: 00 40
03: 40 40
04: 80 40
05: A0 40
06: C0 40
07: E0 40
08: 00 41
09: 10 41
10: 20 41
11: 30 41
12: 40 41
13: 50 41
14: 60 41
15: 70 41
16: 80 41
17: 88 41
18: 90 41
19: 98 41
20: A0 41
21: A8 41
22: B0 41
23: B8 41
24: C0 41
25: C8 41
26: D0 41
27: D8 41
28: E0 41
29: E8 41
30: F0 41
31: F8 41
32: 00 42
33: 04 42
34: 08 42

Uhm, my first reaction from seeing a 00 00 08 3F is that they're floating point numbers. For floating points numbers, 00 00 08 3F = 3F80000 = 1.0. So for some reasons module IDs are in float? Though for the coordinates it really makes sense since the game itself uses float for the positions (so everything don't move in steps of 1, always snapping to the grid).

There should be float to integer type conversion tool online, but I prefer using Cheat Engine to do this.

kajacx

Nice observation. I have noticed a pattern in how the numbers are increased, and have extrapolated that pattern to fit the first 128 positions (with success). Only later I have noticed it's acctually being cast to float, and I had the biggest facepalm ever.
Why do work yourself, when you can write a program that will do the work for you.

tornado

Quote from: kajacx on November 27, 2016, 11:47:37 AM
Quote from: Sorrontis on November 27, 2016, 11:24:58 AM
I wonder if there's a way to modify a ship once it's already built...

You could probably destroy your ship and replace it with a new one. Next weekend I'll do merging of ships, and also post the code, so changing ships with it shouldn't be that difficult.

This is something ive wondered about too(ship that consumes smaller enemy ships?).
Now CEO of Particular Endeavors. http://knucklecracker.com/forums/index.php?topic=23752.new#new
We apologize for all inconveniences that we caused.
Quotefirst, you have to imagine a very big box, fitting inside a very samll box.
then, you have to build one