Blueprint format/API?

  • Hello. My question is regarding the blueprint format/API. Is there a reference someone can point me to?


    There was a post last year


    Well, unfortunately you can't edit the file directly by opening it with a texteditor for example. The blueprint files contain compressed bytes, but basically there is no magic in converting it. You just have to decompress the file, and then read the single bytes. If desired, I can give further information about how to convert the bytes into actual construction elements :)


    that seems to be open unless I missed a response somewhere else. I was so glad when I found the post but then I couldn't find the final answer..


    Any help is greatly appreciated. Thank you --

  • I would also be very interested in this....and another question once we decompress and open the .Blueprint file can we change the texture of the individual construction elements by adjusting some of the bytes?

    • Why is someone interested in changing a blueprint format?
    • If someone would change my house into another model by changing a few bytes I would not appreciate that very much.
    • If you would change something like that why with blueprints?

    And why opening a blueprint file to change things and not build a new model?


    Or trying to put parts together into half data size? A program with such a feature would be very much appreciated. ;)

    • Why is someone interested in changing a blueprint format?
    • If someone would change my house into another model by changing a few bytes I would not appreciate that very much.
    • If you would change something like that why with blueprints?

    And why opening a blueprint file to change things and not build a new model?


    Or trying to put parts together into half data size? A program with such a feature would be very much appreciated. ;)

    1) Say I build a house and I want to have multiple copies of the same house but with different floor textures, roof textures etc. so instead of building the same house again I would go in the blueprint and change the things that I want to change. Maybe not for a simple house but for something more complicated that takes a lot of time to rebuild I would prefer to have that option.


    2) I understand and I would be annoyed too, but by uploading a blueprint on the web it technically becomes public property, there is no copyright law that covers items created in games as far as I am aware of in most countries in Europe. I would be annoyed too if someone changed a bit my blueprint and passed it on as their own but they can do that eitherway by downloading it and changing it in game (the byte changing process would make it easier yes I agree with you on that). It all comes down to the other person's character. Further to that when I upload a blueprint here I hope that someone will take it and either use it as it is or make some changes to personalise it and then use it so long as they don't say they made it from scratch.


    3) I don't have a good answer for that I could as easily blueprint the house once then make the changes and blueprint it again so that I have the two versions as two separate blueprints to place.


    Eitherway Red said he was willing to provide us with a way to read the bytes in blueprints so I personally would like to know how to do that.

  • @Minotorious I totally agree with your arguments. There is no copyright, thats true, and it's needless to say not to change other buildings and to present them as their own. But I'm trying to understand why things are wished, if they are really needful, but mostly why people want it. I like to discuss, I admit it. ^^ It's my favorite game and I'm very interested in other people's imagination or thoughts how they see things which I look at in contrast to them.
    I often tried to change buildings, to separate them from others but to keep the same style .
    It doesn't work. Better to build a new one, costs less time, than to change the old one.
    There are some thoughts we could repaint our buildings in the very far future. But nethertheless I'm still interested in to know why to change blueprint's bytes and so on. :D

  • I too am open for discussion in every topic and I will say it as well that RW is one of my favourite games at the moment. I will give an example where I would like to change the texture for a functional reason rather than an aesthetic one.


    I want to build something that I want to be made completely out of black plaster planks/beams, when I try to position one black plaster element on the other elements I cannot really see where I am placing it because they are all fully black (I have tried and even with the debug light on it is really hard to see them). In this case I would like to build my construction out of some other texture that I can clearly see the features of and position things easier and then go to the .blueprint file and change the texture to the black plaster one to obtain the result I wanted. This way I can do it faster than tying to position one black element on the other black elements and spend hours misplacing/removing and repositioning them.


    Back to the aesthetic reasons:


    I don't know if you have seen it but I recently posted a blueprint of a beer glass bar, it is not the most complicated construction I have created but I would like to have a copy of it in green and black plaster textures and rebuilding the whole thing would take me a few hours. On the other hand writing a short python or bash script that would change the texture (once I know how to decode the bytes in the .blueprint file) would take me a few minutes. It is just a matter of my time being spent creating new things rather than recreating old ones that I decided I wanted to change a few textures in.


    At least this is the way I see it, if I have created the thing once why not be able to reproduce similar but not same copies of it. If this can be achieved without Red or any other member of the developing team spending extra time or effort I don't see why not have the feature and whoever wants it they can use it.


    Another thing I just though of is if I download a blueprint from this forum and I don't like one texture the owner has chosen for some part of it and I don't know exactly how he/she placed the specific construction element at that position it is much safer to go find the element in the .blueprint file and change it rather than knock it out and try to replace it by myself.

  • Basically the first step would be to read the bytes of the blueprint file and decompress it (the game uses GZIP for compression). Once you have the decompressed byte buffer/array, you can start reading the single bytes. This is the structure of every blueprint (I hope I didn't miss anything - if you have any questions, don't hesitate to ask):



    BytesInfo
    1blueprint version
    2blueprint size x
    2blueprint size y
    2blueprint size z
    8creation date (timestamp, amount of milliseconds passed since 1st of January 1970)
    4name length (String bytes)
    xxblueprint name (byte length see previous 4 bytes)
    4author name length (String bytes)
    xxauthor name (byte length see previous 4 bytes)
    4world name length (String bytes)
    xxworld name (byte length see previous 4 bytes)
    4terrain data length
    xxterrain data (see below)
    4block data length
    xxblock data (see below)
    4object data length
    xxobject data (see below)
    4construction data length
    xxconstruction data (see below)
    4vegetation data length
    xxvegetation data (N/A)
    4preview image data length
    xxpreview image data



    Compression information


    The blueprint data is compressed using GZIP. Java provides a class "GZIPInputStream" for decompression (and GZIPOutputStream for compression). Java example for decompression:


    Block data information


    Block arrays are short arrays (i.e. every index consists of 2 bytes). Block arrays are 3-dimensional arrays (blueprint size x * size y * size z) which are flattened (i.e. it is 1-dimensional). To access a particular index, you have to calculate it (x + y*sizex + z*sizex*sizez), e.g. instead of blocks[x][y][z] (which would be the regular way of accessing a 3d array) you have to access it like blocks[x + y * sizey + z * sizex * sizez)].
    Java way to read the blocks:


    Terrain data information


    Terrain data is stored as byte array, i.e. a particular byte represents the actual terrain id. Similar to block arrays, the terrain array is flattened, so you have to access it in the same way (see above).



    Object data information


    Objects (furniture, doors etc) are represented by a special object which holds information about the typeid (short), the variation (byte), position x y and z (float) and rotation x y z (short). The first 4 bytes in the encoded blueprint bytes hold information about the actual amount of objects in this blueprint. Java way to read the objects:


    Construction data information


    Construction data is very much like the object data, only the information per construction element is different. Every construction element holds information about the typeid (short), the texture (int), position x y z (float), rotation x y z (short), size x y z (short), horizontal repetitions (byte), vertical repetitions (byte), gap (byte). Java way to get the construction elements (only rough information, since it's mostly the same as for object elements [see above]):


    Additional information about object elements and construction elements


    To convert the rotation to a world rotation or the size (of construction elements) to the world size, you have to multiply the short values with a conversion factor. For rotations, it is currently 0.025, for the size, it is 0.01. Example:

    Java
    short rotationx = ...;
    short sizex = ...;
    //convert to world rotation (in degree)
    float worldrotation = rotationx * 0.025f;
    //convert to world size (world units)
    float worldsize = sizex * 0.01f;

    Edited 2 times, last by red51: Updated for new blueprint format (including terrain data now) ().

  • ok @red51 thank you very much for all this information. A few questions now again if you don't mind :)


    1) The byte format of the decompressed .blueprint files is hexadecimal correct?


    2) If the answer to the above was yes then I am getting different texture numbers for construction elements (beams, planks, logs) in the files than the numbers in the game. The block texture numbers on the other hand are correct in the decompressed files. I will post an example test blueprint I created to explain and maybe you can help me out if I am calculating something wrong. So this blueprint is of one plank with texture number 21 (i.e. the simple stone texture). Just in case it matters I decompressed the .blueprint file using the Ubuntu 16.04 shell by "gunzip < name.blueprint > out.txt" then I am reading it with the HxD hex editor. I have omitted the preview image bytes

    Code
    03 00 01 00 01 00 01 00 00 01 5B 5E 89 9C 2B 00 00 00 0C 77 6F 6F 64 70 6C 61 6E 6B 20 32 31 00 00 00 0B 4D 69 6E 6F 74 6F 72 69 6F 75 73 00 00 00 0E 41 72 74 69 73 61 6E 73 20 52 65 61 6C 6D FF FF FF FF FF FF FF FF 00 00 00 25 00 00 00 01 00 02 00 00 00 00 3F 00 00 00 3F 00 00 00 3F 00 00 00 00 00 00 00 00 00 00 64 00 64 00 05 00 00 00

    According to the information you gave above I should translate this into:

    and here is the example of a blueprint of 1 block with texture 21.


    3) What is the format of the 8 timestamp bytes? I couldn't find a way to translate them to human date format no matter how I tried to position dd/mm/yyyy or yyyy/mm/dd. ?(

  • I answered my 2nd question by myself by trial and error, so it seems that in the .blueprint files the construction element textures have a 21 number difference to the numbers in the game. i.e. stone 21 is 0, green plaster 200 is 179 and so on. Thanks again @red51 for the information I can now enjoy my yellow beer that turned green with only a few replacements :D


    ------->

  • And what about the other noobs who want to change the colors of their blueprints? I want to change my rocking chair (blueprint in the forum) into a white modern one. If the process is so uncomplicated as it seems, this would be very helpful. I've never imagined that it works so easily as on the yellow to green bar. Is it possible without any further knowledge and not really willing to involve lots of time in it?


    Btw a tutorial or guide would be great.

  • @Deirdre I will start writing a standalone program to edit .blueprint files. I cannot promise it will be coded in java since I have no experience with it (it will either by python or c++, I haven't decided yet) but I will try to make it as simple as possible for everyone.


    For now my only advice would be to look at the file and try to understand it with red's instructions, took me a few hours with simple test case blueprints (like 1 block, or 1 plank, or a series of a few blocks) but after I understood the file structure it took me a couple of minutes to change the textures. When you do it by hand you just need to be careful not to change any of the position or rotation bytes by accident.

  • 3) What is the format of the 8 timestamp bytes? I couldn't find a way to translate them to human date format no matter how I tried to position dd/mm/yyyy or yyyy/mm/dd.

    Sorry, I forgot to mention that this is a special type of timestamp - the amount of milliseconds passed since 1st of January 1970 (so if you divide it by 1000 you can treat it as a regular unix timestamp). The byte order is big endian, as always.


    I answered my 2nd question by myself by trial and error, so it seems that in the .blueprint files the construction element textures have a 21 number difference to the numbers in the game

    That's great! :) And yeah, block- and construction textures start at 21 (to prevent any collisions between block and terrain textures)


    @Deirdre I will start writing a standalone program to edit .blueprint files

    This sounds awesome :thumbup:

  • @red51 construction textures start at 21 same as making texture packs. Is it possible to get a bit more explanation in German too, so that other users could profit from it.


    @Minotorious Maybe it would takes more time to get involved in Java than I would like to spend on it. I learned more about static on roofs and buildings since I'm playing RW and was a bit trying on Lua but I'm not really interested in to learn Java , too. It would be very nice if you could create a standalone program. :D

  • @Deirdre I will start writing a standalone program to edit .blueprint files. I cannot promise it will be coded in java since I have no experience with it (it will either by python or c++, I haven't decided yet) but I will try to make it as simple as possible for everyone.


    For now my only advice would be to look at the file and try to understand it with red's instructions, took me a few hours with simple test case blueprints (like 1 block, or 1 plank, or a series of a few blocks) but after I understood the file structure it took me a couple of minutes to change the textures. When you do it by hand you just need to be careful not to change any of the position or rotation bytes by accident.

    I am also a non-native Java user, so will be using Python. Once I have something to share I will put up link to GitHub page. Thank you very much @red51 this is more than enough to get started :thumbup:

  • Thank you for sharing this! :thumbsup::thumbsup: But this part:


    //easiest way to fill the short array is to use a ByteBuffer
    //it would be faster if you read the single bytes and convert
    //them to shorts (big-endian), but this way is by far more convenient
    ByteBuffer.wrap(blockdata).asShortBuffer().get(blocks);

    What is the alternative faster method?

    "I wish I had a dollar for every time I spent a dollar, because then, I'd have all my money back" :P

  • Thank you for sharing this! :thumbsup::thumbsup: But this part:


    What is the alternative faster method?

    I haven't had a chance to dive in yet, but I'd venture to guess we're talking ms at the most here. For me, and likely anyone else diving in, they will go with the easy route and find that it's more than fast enough to give any sort of optimization a second thought..


    I say this in all seriousness, and would not take the time just to "troll" or to start some argument, just speaking from personal experience (and personal opinion.. so take it for what you will)


    If it turns out I'm completely wrong, then I will promptly update this post, admit I spoke too soon, and jot down a lesson learned ^^


    -- Separate topic for the curious --
    My goal (I don't think I've stated above) is to use image processing/machine learning experience to tackle the task of reversing a "real photo" into RW primatives, which is why I needed to understand the atomic elements of a blueprint (thank you again for the detailed explanation and code, @red51!)


    The idea came when I noticed a lot of friends using internet images as their reference point for RW builds (with a lot of time involved for very detailed buildings) and thought, "wouldn't it be cool if a program could do the same... in seconds or minutes (image processing can be resource intensive both GPU and CPU) not weeks or months". Anyways, thought I'd share my initial project goal while I was posting :saint:

  • just for the record what I did in java was use a 2D byte array with two columns and rows as many as the blocks found in the blueprint. Then I parsed in the first column the position of each block and the second column the texture of each block respectively. This way helped me draw a fast and easy distinction between the position element of the blocks (which I don't care about) and the texture element which is what I want to change in my program.
    And code-wise:

    Code
    byte[][] BPblock = new byte[BPblockl/2][2];
    for (int i=0;i<BPblockl/2;i++){
    BPblock[i][0] = BPbuffer.get();
    BPblock[i][1] = BPbuffer.get();
    }
  • What is the alternative faster method?

    You could read from the byte buffer directly and use bit shifting to convert the bytes to short values. This is the fastest method, however, using a ByteBuffer instead is more convenient ;)

    I haven't had a chance to dive in yet, but I'd venture to guess we're talking ms at the most here.

    That's true. I think we're even talking about ns here (or more precisely, it isn't possible to measure the difference at all). It really doesn't matter, especially if you're not using a performance-critical application (e.g. if you have to execute this code 10000 times per second, it makes sense to use the faster method) ^^

  • You could read from the byte buffer directly and use bit shifting to convert the bytes to short values. This is the fastest method, however, using a ByteBuffer instead is more convenient ;)

    That's true. I think we're even talking about ns here (or more precisely, it isn't possible to measure the difference at all). It really doesn't matter, especially if you're not using a performance-critical application (e.g. if you have to execute this code 10000 times per second, it makes sense to use the faster method) ^^

    If anyone is up for the challenge, I'm sure you could shave off a few n.s. here and there with direct x86 assembly... maybe run on bare metal? :huh:


    You made me think on the kilohertz building output... if the world is infinite you have the room to lay the material but could you? *


    * Side note -- I took the Pepsi challenge from one of your recent change logs on 400?x fly mode, using the native system JDK (Steam java is bogus on Linux, FYI.. I know the Ubuntu 2001 edition er 12.04 runtime and all...) and a few JVM tweaks for GC management to see if I could get screen tear or stutter... Arch Linux 64GB/1TB Nvme on GTX 1070 held up! No bottle necks I could see. RW kept up no problem. :thumbup:


    I take back all the bad things I *may* have said in previous years about Java (friendly Python v. Java, right?! ^^ )

  • wait wouldn't it be wiser to use the inbuilt method buffer.getShort() (i.e. blocks[i] = buffer.getShort() ) instead of reinventing the wheel with bit shifting? ?(


    Also a different question now:
    I created two test cases one with a single ramp texture 21 and one with a single stair1 again texture 21 to test the block data structure.The values I get from the blueprint file are:


    blocktypehexdec
    ramp26C19921
    stair10F513921


    seeing this result I understand that 21 refers to the texture, while the first two numbers refer to the position? If that is the case how does the game know if the block is a square block, a ramp or a stair1, a stair2, or a stair3 etc.?

Participate now!

Don’t have an account yet? Create a new account now and be part of our community!