bsgmake - Assemble several bsg files into one. [stand-alone tool]

It's a Python program and needs a Python interpreter to run. You can get Python 3 from for Windows, Mac, and Linux.

You call it from your system's command line. (See hints below.) The command syntax is simply "bsgmake makefile.txt". The makefile is a text file (plain ASCII or UTF-8 encoding) that contains your instructions.

Here's an album with some basic examples to give an overview.

The syntax of the makefile is as follows: The very first line must be the filename of the bsg file that shall be created as output. Other lines may begin with an "s" as an option, then contain four space-separated entries: three parameters with three comma-separated values each, and the name of a bsg file. " [shift: x,y,z] [rotate: a,b,c] [origin: x,y,z] [source bsg filename]". For example: "1,2,3 -90,0,45 3.5,0,-2 somemachine.bsg"

The shift parameter is a set of x,y,z coordinates at which the machine from the particular source bsg will be positioned in the output. To visualize the coordinate system, look at the orientations of the arrows that show when you use the "translate machine" tool in the game. The red arrow is the x axis, green is y, blue is z. Positive numbers go in the direction where the arrows point, except for the red arrow which points into negative x values.

The rotate parameter consists of three angles in degrees: a,b,c. See the arrows again to visualize the planes of rotation. First, angle "c" rotates the machine around the blue arrow. Positive numbers counterclockwise, looking in the direction of the arrow. Then angle "b" rotates the machine around the red arrow, positive clockwise. Finally, angle "a" rotates around the green arrow, positive counterclockwise. (That is clockwise looking from above, easier to remember.) The actual center of rotation is determined by the origin parameter.

The origin parameter is a set of x,y,z coordinates measured from the center of the starting block of the particular bsg file. It changes the zero reference point, the position of the machine's 'handle' so to speak. Rotation will occur around this origin point. Positioning done by the shift parameter is relative to this point. Use this if the starting block gets in the way.

The optional "s" at the beginning of a line lets you choose to include the starting block from that particular bsg file. It has no effect on the first bsg file whose starting block gets always included and is never shifted or rotated with the rest of the machine.

The world position and world rotation for the output (those settings where you move and rotate the starting block together with the whole machine in the game) are taken from the first bsg file. You can use an empty machine containing just a starting block to import these settings independent from the other machines.

You can use empty lines and whitespaces to format the makefile, but there must be no space around the commas. A line is skipped entirely if it contains "#" anywhere. You can use this to comment out lines that contain parts and values that you might want to keep for later.

On the command line, if the filename for the makefile contains spaces, it must be enclosed between quotes. The filenames within the makefile can also have spaces but must not be quoted. The filenames for the bsg files support paths, so if you no longer need to edit them in the game, they can be put into a subfolder to keep your source part collection organized.

This code is provided as is. If you feed it a malformed makefile, expect to see meaningless error messages. It overwrites the output file without asking. It does not check for overlapping blocks. It does not check the integrity of the bsg files. Garbage in, garbage out. It's just a humble little tool.

Hints and tips:

The most convenient way to use this should be to put it into your SavedMachines folder and use that as the working directory, so you can directly load and save the files from Besiege.

You may have to call bsgmake with "" or "py" or "python3" depending on your installation.

Users of Windows 7 and later can hold "shift" and right-click on a folder, then select "open command window here" from the context menu to open a console with that folder as the working directory.

Mac users go to "System Preferences > Keyboard > Shortcuts > Services" and check "Enable New Terminal at Folder", then they can right-click on a folder and open a terminal from the context menu.

(I guess this is the right place to post. I'm not "modding" anything, but the master list mentions "mods & projects", so here's my project.)

v1.2 2015-12-13
v1.1 2015-11-28
v1.0 2015-11-22

Attached Files
bsgmake album


Staff member
Oh, I think somebody already made something like this once.
I think it only supported offset in one direction though, and only merging two files, so this one is probably a lot better.
Exellent stuff - I've been tearing my hair out (or what's left of it) on occasions, after discovering that I've build something that would work better upside down, or having to duplicate stuff I'd already made. This is clearly going to be a must-have tool.

@ekbruligas: ROFL
I had a slight hitch - it seems to need Python 3, or at least, it didn't seem to work with 2.7. Probably a good idea to update it anyway.

From a quick test, it works - my shrapnel-canon-powered contraption will hopefully not hop around quite so much with downward-facing cannons (weird physics, I know), and it has to be simpler to move the wheels than rebuild the whole thing.

Just a suggestion - a 'mirror' option might be useful too. Negating coordinates, rather than rotating them.

Yeah, Python 2 won't do. While a mirror feature sounds obvious, there are countless positions and rotations that you want to be able to change on the fly, but you'll never have to mirror a machine more than once and then can use that version. So I'll leave this function to the editor mods.
It's the best thing since sliced peasant you say ?!

ekbruligas That's rich coming from you... mr self righteous defender of the downtrodden peasant community!!! hah! So all this time you've been gorging yourself on sliced peasant sandwiches? I knew it XD
May I ask for some help on rotating machines? I cannot really understand how would you change the rotation on Y axis in code :/
When I tried on that, it seems like I also need to turn on X and Z axis
(Sorry I'm late, didn't check the forum over the weekend.) I'm not sure what you mean, can you clarify? Is this about the three x/y/z angles that the tool takes as input in the makefile, or are you asking about how the program's internal math works on the four rotation values that are used in the bsg files?
Ah, the quaternions. They have become a standard in game engines because they are a very powerful and convenient way to work with orientations in space - if you can let the game engine handle the math in the background. I think even most game developers just call them 'those magic four-number thingies that describe a rotation'. Mathematically, they're an extension of complex numbers, with one real and three imaginary parts, but it isn't really necessary to bother with the deeper algebra.

What's important in this context to know is: 1. The four numbers of a unit quaternion can be used to describe a rotation. 2. You can chain the rotations from two quaternions together by multiplying them. They have their own multiplication rules and the order is important. Like when you first turn an object up and then left, you get a different orientation than if you turn it left and then up.

So, what happens in my program? The 'rotation' entries stored in a bsg file are the four raw values from the orientation quaternions that the game uses internally. To rotate them by the desired angles, we just go and apply another rotation quaternion to them!

First you describe the desired rotation as three euler angles (because this kind of input is easy for humans to visualize). It gets converted to a rotation quaternion (qr,qi,qj,qk) by the code under the 'calculate rotation quaternion' comment. Then for each block, the code under 'apply rotation quaternion to bsg rotation data' multiplies our rotation quaternion with the orientation quaternion from the bsg file (q2r,q2i,q2j,q2k).

And since the blocks are not rotated all about themselves, but around a common zero point, the coordinates from their 'position' entries in the bsg file have to be rotated too. The math under 'apply rotation quaternion to bsg position data' is basically our rotation quaternion expanded to a 3x3 rotation matrix and applied to each block's position vector (vx,vy,vz).

There should be modules or libraries for most programming languages to handle quaternions, but I was also interested in a little bit of the math. I've found and quite helpful in this regard.
while the problem is... are you using yzx instead of using xyz? because in unity y axis is up and down...
Btw, python is a little harder for me to read :p I use java and c# more, which cannot declear variables as python