Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix Export offset, Make defining textures easier #342

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

Merith-TK
Copy link

This has a few features,
Namely you can name your group or cube to apply an texture (will edit this message with screenshots)

and of course fix the -8 offset that Blockbench has, previously the plugin incorrectly assumed x0,y0,z0 was the origin (center) of the workspace, while it is actually -8x, 0y, -8z. this adjusts the values when exporting to contain an +8 to properly center it

The reason for the lines being all altered is because my editor uses tab indentations and using "format document" made them all consistent as there was a mix of 4space and tab indents everywhere,

here are the diff files between my patches (after the indentation was changed) For the Texturing

diff --git a/sam3dj.js b/sam3dj.js
index 0e09b71..0092094 100644
--- a/sam3dj.js
+++ b/sam3dj.js
@@ -34,7 +34,6 @@
 
 		for (let dir in cube.faces) { //in ['north', 'east', 'south', 'west', 'up', 'down']
 			let tmp = cube.faces[dir].getTexture();
-
 			if (!tmp) {
 				if (typeof cube.parent === 'object' && cube.parent.name.includes(":block/")) {
 					texture = cube.parent.name;
@@ -50,14 +49,48 @@
 					missing = true;
 				}
 			} else {
-				// Generate actual ID
-				let id = tmp.namespace + ':' + tmp.folder + '/' + (tmp.name.replace(/\.[^/.]+$/, ""))
+				let id = ""
+				// if cube is titled <group>:<path>, use that as texture
+                if (cube.name.includes(":")) {
+                    id = cube.name.replace(/\.[^/.]+$/, "")
+                } else {
+					// if cube is in a group, use root group as namepsace
+					// use the rest of the path as texture name
+                    if (typeof cube.parent === 'object') {
+						// get all parents
+						let parents = []
+						let parent = cube.parent
+						while (typeof parent.parent === 'object') {
+							parents.push(parent.name)
+							parent = parent.parent
+						}
+						parents.push(parent.name)
+						parents.reverse()
+						// use the first parent as group
+						let group = parents[0]
+						parents.shift()
+						// if the group is not a folder, use the cube name as texture name
+						if (!group.includes(":")) {
+							parents.push(cube.name.replace(/\.[^/.]+$/, ""))
+						}
 
-				if (texture !== id)
-					faces++;
-				texture = id;
-			}
-		}
+						// set id to group:path/to/cube
+						id = group + ":" + parents.join("/") //+ "/" + cube.name.replace(/\.[^/.]+$/, "")
+
+
+					} else {
+						// if cube is not in a group, use the cube name as texture name
+                        id = "minecraft:" + tmp.name.replace(/\.[^/.]+$/, "")
+						console.log(id+" has no parent")
+                    }
+                }
+
+                console.log("Exporting " + cube.name + " as " + id)
+                if (texture !== id)
+                    faces++;
+                texture = id;
+            }
+        }
 
 		return {
 			texture: texture,

For the Offset

diff --git a/sam3dj.js b/sam3dj.js
index 0092094..88305d6 100644
--- a/sam3dj.js
+++ b/sam3dj.js
@@ -51,12 +51,12 @@
 			} else {
 				let id = ""
 				// if cube is titled <group>:<path>, use that as texture
-                if (cube.name.includes(":")) {
-                    id = cube.name.replace(/\.[^/.]+$/, "")
-                } else {
+				if (cube.name.includes(":")) {
+					id = cube.name.replace(/\.[^/.]+$/, "")
+				} else {
 					// if cube is in a group, use root group as namepsace
 					// use the rest of the path as texture name
-                    if (typeof cube.parent === 'object') {
+					if (typeof cube.parent === 'object') {
 						// get all parents
 						let parents = []
 						let parent = cube.parent
@@ -80,17 +80,17 @@
 
 					} else {
 						// if cube is not in a group, use the cube name as texture name
-                        id = "minecraft:" + tmp.name.replace(/\.[^/.]+$/, "")
-						console.log(id+" has no parent")
-                    }
-                }
-
-                console.log("Exporting " + cube.name + " as " + id)
-                if (texture !== id)
-                    faces++;
-                texture = id;
-            }
-        }
+						id = "minecraft:" + tmp.name.replace(/\.[^/.]+$/, "")
+						console.log(id + " has no parent")
+					}
+				}
+
+				console.log("Exporting " + cube.name + " as " + id)
+				if (texture !== id)
+					faces++;
+				texture = id;
+			}
+		}
 
 		return {
 			texture: texture,
@@ -108,13 +108,12 @@
 		let result = getSingleTexture(cube);
 		let shape = {
 			bounds: [
-				cube.from[0],
+				cube.from[0] + 8,
 				cube.from[1],
-				cube.from[2],
-
-				cube.to[0],
+				cube.from[2] + 8,
+				cube.to[0] + 8,
 				cube.to[1],
-				cube.to[2],
+				cube.to[2] + 8,
 			],
 			texture: result.texture,
 		};
@@ -301,12 +300,23 @@
 						texture = (getSingleTexture(cube).multipleTexture);
 
 					if (!border) {
-						function checkNum(num) {
+						// NOTE: If you can find a better way to do this, please do so.
+						// These changes had to be done due to Blockbench's 0,0 origin
+						// being in the center of the block and not in the bottom left corner.
+						// causing an malformed export. (off set by 8 in the x and z axis)
+						function checkNum(num, height) {
 							if (!border)
-								border = (num < 0 || num > 16);
+								if (height)
+									border = (num < -16 || num > 16);
+								else
+									border = (num < -8 || num > 8);
 						}
-						cube.from.forEach(checkNum)
-						cube.to.forEach(checkNum)
+						checkNum(cube.from[0]);
+						checkNum(cube.from[1], true);
+						checkNum(cube.from[2]);
+						checkNum(cube.to[0]);
+						checkNum(cube.to[1], true);
+						checkNum(cube.to[2]);
 					}
 
 					// We are done here

This has a few features,
Namely you can name your group or cube to apply an texture (will edit this message with screenshots)

and of course fix the `-8` offset that Blockbench has, previously the plugin *incorrectly* assumed `x0,y0,z0` was the origin (center) of the workspace, while it is actually `-8x, 0y, -8z`. this adjusts the values when exporting to contain an +8 to properly center it

The reason for the lines being all altered is because my editor uses tab indentations and using "format document" made them all consistent as there was a mix of 4space and tab indents everywhere, 

here are the diff files between my patches (after the indentation was changed)
For the Texturing
```diff
diff --git a/sam3dj.js b/sam3dj.js
index 0e09b71..0092094 100644
--- a/sam3dj.js
+++ b/sam3dj.js
@@ -34,7 +34,6 @@
 
 		for (let dir in cube.faces) { //in ['north', 'east', 'south', 'west', 'up', 'down']
 			let tmp = cube.faces[dir].getTexture();
-
 			if (!tmp) {
 				if (typeof cube.parent === 'object' && cube.parent.name.includes(":block/")) {
 					texture = cube.parent.name;
@@ -50,14 +49,48 @@
 					missing = true;
 				}
 			} else {
-				// Generate actual ID
-				let id = tmp.namespace + ':' + tmp.folder + '/' + (tmp.name.replace(/\.[^/.]+$/, ""))
+				let id = ""
+				// if cube is titled <group>:<path>, use that as texture
+                if (cube.name.includes(":")) {
+                    id = cube.name.replace(/\.[^/.]+$/, "")
+                } else {
+					// if cube is in a group, use root group as namepsace
+					// use the rest of the path as texture name
+                    if (typeof cube.parent === 'object') {
+						// get all parents
+						let parents = []
+						let parent = cube.parent
+						while (typeof parent.parent === 'object') {
+							parents.push(parent.name)
+							parent = parent.parent
+						}
+						parents.push(parent.name)
+						parents.reverse()
+						// use the first parent as group
+						let group = parents[0]
+						parents.shift()
+						// if the group is not a folder, use the cube name as texture name
+						if (!group.includes(":")) {
+							parents.push(cube.name.replace(/\.[^/.]+$/, ""))
+						}
 
-				if (texture !== id)
-					faces++;
-				texture = id;
-			}
-		}
+						// set id to group:path/to/cube
+						id = group + ":" + parents.join("/") //+ "/" + cube.name.replace(/\.[^/.]+$/, "")
+
+
+					} else {
+						// if cube is not in a group, use the cube name as texture name
+                        id = "minecraft:" + tmp.name.replace(/\.[^/.]+$/, "")
+						console.log(id+" has no parent")
+                    }
+                }
+
+                console.log("Exporting " + cube.name + " as " + id)
+                if (texture !== id)
+                    faces++;
+                texture = id;
+            }
+        }
 
 		return {
 			texture: texture,
```

For the Offset
```diff
diff --git a/sam3dj.js b/sam3dj.js
index 0092094..88305d6 100644
--- a/sam3dj.js
+++ b/sam3dj.js
@@ -51,12 +51,12 @@
 			} else {
 				let id = ""
 				// if cube is titled <group>:<path>, use that as texture
-                if (cube.name.includes(":")) {
-                    id = cube.name.replace(/\.[^/.]+$/, "")
-                } else {
+				if (cube.name.includes(":")) {
+					id = cube.name.replace(/\.[^/.]+$/, "")
+				} else {
 					// if cube is in a group, use root group as namepsace
 					// use the rest of the path as texture name
-                    if (typeof cube.parent === 'object') {
+					if (typeof cube.parent === 'object') {
 						// get all parents
 						let parents = []
 						let parent = cube.parent
@@ -80,17 +80,17 @@
 
 					} else {
 						// if cube is not in a group, use the cube name as texture name
-                        id = "minecraft:" + tmp.name.replace(/\.[^/.]+$/, "")
-						console.log(id+" has no parent")
-                    }
-                }
-
-                console.log("Exporting " + cube.name + " as " + id)
-                if (texture !== id)
-                    faces++;
-                texture = id;
-            }
-        }
+						id = "minecraft:" + tmp.name.replace(/\.[^/.]+$/, "")
+						console.log(id + " has no parent")
+					}
+				}
+
+				console.log("Exporting " + cube.name + " as " + id)
+				if (texture !== id)
+					faces++;
+				texture = id;
+			}
+		}
 
 		return {
 			texture: texture,
@@ -108,13 +108,12 @@
 		let result = getSingleTexture(cube);
 		let shape = {
 			bounds: [
-				cube.from[0],
+				cube.from[0] + 8,
 				cube.from[1],
-				cube.from[2],
-
-				cube.to[0],
+				cube.from[2] + 8,
+				cube.to[0] + 8,
 				cube.to[1],
-				cube.to[2],
+				cube.to[2] + 8,
 			],
 			texture: result.texture,
 		};
@@ -301,12 +300,23 @@
 						texture = (getSingleTexture(cube).multipleTexture);
 
 					if (!border) {
-						function checkNum(num) {
+						// NOTE: If you can find a better way to do this, please do so.
+						// These changes had to be done due to Blockbench's 0,0 origin
+						// being in the center of the block and not in the bottom left corner.
+						// causing an malformed export. (off set by 8 in the x and z axis)
+						function checkNum(num, height) {
 							if (!border)
-								border = (num < 0 || num > 16);
+								if (height)
+									border = (num < -16 || num > 16);
+								else
+									border = (num < -8 || num > 8);
 						}
-						cube.from.forEach(checkNum)
-						cube.to.forEach(checkNum)
+						checkNum(cube.from[0]);
+						checkNum(cube.from[1], true);
+						checkNum(cube.from[2]);
+						checkNum(cube.to[0]);
+						checkNum(cube.to[1], true);
+						checkNum(cube.to[2]);
 					}
 
 					// We are done here
```
@Merith-TK
Copy link
Author

Merith-TK commented Feb 27, 2023

Before offset Patch
image
After offset patch
image

example of how the texture labeling system works CURRENTLY (untested with on/off states as I am unaware as to how that works)

Three examples of how you can assign a texture (note, putting an : in your cube name overrides parent groups)
image

{
	"label": "placeholder",
	"tooltip": "Made with Blockbench",
	"isButton": false,
	"collideWhenOn": true,
	"collideWhenOff": true,
	"lightLevel": 0,
	"redstoneLevel": 0,
	"shapesOff": [
		{
			"bounds": [0, 0, 0, 16, 16, 16],
			"texture": "modid:block/cube",
			"tint": "FFFFFF"
		},
		{
			"bounds": [0, 0, 0, 16, 16, 16],
			"texture": "modid:static/cube",
			"tint": "FFFFFF"
		},
		{
			"bounds": [0, 0, 0, 16, 16, 16],
			"texture": "modid:bone/cube",
			"tint": "FFFFFF"
		}
	],
	"shapesOn": []
}

If there is no modid:type/ variation as shown before. It will default to minecraft:[cube name] so an cube called "block/sandwould be assignedminecraft:block/sand`

@JannisX11
Copy link
Owner

@1Turtle What do you think?
I have no notes or concerns.
Of course the version number needs to be increased in the plugin file and in plugins.json.

@JannisX11
Copy link
Owner

@1Turtle bump

@SammyForReal
Copy link
Contributor

SammyForReal commented Mar 27, 2023

Hmm, I'm not sure.
It's a great addition that you can change textures this way, but making it work only so doesn't feel right to me. I would make it optional (you can also enable it by default if you want). Additionally, for a feature like this, it's important to mention it in the plugin's description too, otherwise, people will get confused as to why their textures suddenly don't work anymore. And as JannisX11 said, the version number should be changed too.

About the fix: It's good to know that the center isn't at 0,0,0, though it's weird that the documentation doesn't mention that.

@Merith-TK
Copy link
Author

Hmm, I'm not sure. It's a great addition that you can change textures this way...

In its currently released state, defining textures does not work at all, it outputs :/<texturename>,
meaning if i name the texture minecraft:stone, it outputs :/minecraft:stone, which is an invalid texture within the 3DJ format

currently I do have it setup so if an cube is not within the predefined structure, it utilizes minecraft:<texture>,
image
image

{
	"bounds": [0, 0, 0, 16, 16, 16],
	"texture": "minecraft:placeholder",
	"tint": "FFFFFF"
}

you will note I do not automatically prefix textures,
as part of the 3DJ format, it requires an full texture path, so minecraft:stone would not work, it would need minecraft:block/stone

hence why I went more or less with the format I did.

If you have any suggestions or tweaks I am open to hearing them

@SammyForReal
Copy link
Contributor

In its currently released state, defining textures does not work at all, it outputs :/<texturename>

I see. The problem you are encountering is that your texture does not have a namespace (e.g. minecraft in your case).
It's not a user-friendly use case, if this is not obvious, or if it does not fix by itself, or whatever.

This for sure should get fixed. So for now, ignore the part where I said you should make it optional.
I have to encounter this another time.
But please implement the other points in my previous message. (Documenting it, etc.)

You also mentioned that you didn't test this with the on/off states, because you don't know how they work.
Basically: everything in the state_on folder will only be displayed when the model's state is on.
However, I think it currently is not compatible with recursive folders? Not sure though.

Other than that, I have nothing against this getting merged, thank you. ^^

@Merith-TK
Copy link
Author

Merith-TK commented Mar 27, 2023

I see. The problem you are encountering is that your texture does not have a namespace (e.g. minecraft in your case).
It's not a user-friendly use case, if this is not obvious, or if it does not fix by itself, or whatever.

with the official plugin, if texture is minecraft:stone

{
	"bounds": [-8, 0, -8, 8, 16, 8],
	"texture": ":/minecraft:stone",
	"tint": "FFFFFF"
}

I noticed the code does check for :block/ but that feels wrong to me because what if someone wants to use a texture that does not exist inside the block catagory?

EDIT: "texture": ":/minecraft:block/stone", gets outputted with the official plugin if I define an FULL path

I will update my code to fix texture name output however, maybe even write a program to import textures from an "resourcepack" into a workspace

EDIT: Also my modification logs to console what cube is being exported as what texture,

current fixing up the logging as it spams even for cubes that are hidden and never exported

makes texture name take prioritty over cube name/parenting
@Merith-TK
Copy link
Author

Merith-TK commented Mar 27, 2023

https://mega.nz/file/etYzjZhR#lb2LVJNiI4ZsWvXyyg5w1HmWQoiNN_PuM9KGZX8OSig bbmodel for this file, actual texture file not really important, just pick a placeholder texture if you dont want to use what I provide here

placeholder

image
image

defining texture names supports
path/texture and namespace:path/texture

@Merith-TK
Copy link
Author

saw small typo give second (in exporting modid/block/"cube" ('cube' means the actual cube name)

@Merith-TK
Copy link
Author

fixed typo
modid/block/'cube' now exports as
modid:block/'cube' and not modid:'cube'

	"label": "testBlock",
	"tooltip": "Made with Blockbench",
	"isButton": false,
	"collideWhenOn": true,
	"collideWhenOff": true,
	"lightLevel": 0,
	"redstoneLevel": 0,
	"shapesOff": [
		{
			"bounds": [0, 0, 0, 16, 16, 16],
			"texture": "modid:block/cube",
			"tint": "FFFFFF"
		},
		{
			"bounds": [0, 0, 0, 16, 16, 16],
			"texture": "modid:static/cube",
			"tint": "FFFFFF"
		},
		{
			"bounds": [0, 0, 0, 16, 16, 16],
			"texture": "modid:/bone/cube",
			"tint": "FFFFFF"
		},
		{
			"bounds": [0, 0, 0, 16, 16, 16],
			"texture": "minecraft:block/stone",
			"tint": "FFFFFF"
		},
		{
			"bounds": [0, 0, 0, 16, 16, 16],
			"texture": "minecraft:block/texture",
			"tint": "FFFFFF"
		}
	],
	"shapesOn": []
}

@JannisX11
Copy link
Owner

The plugin version number still isn't increased, as mentioned above.
I also noticed that it fails and throws an error when exporting cubes without a texture.
Also 1Turtle mentioned changed to the plugin description that are not implemented yet.

@Merith-TK
Copy link
Author

Merith-TK commented Apr 26, 2023

I can easily fix the version number
It also never did throw the error of missing textures to begin with

And I honestly dont know how to explain how this works in an short and concise way to put in the description, and I personally never got it to export with textures originally anyways

The easiest fix to exporting without a texture is to just default to stone.

@SammyForReal
Copy link
Contributor

Alright I can do the description, it's fine ^^

I was testing things again now, and I really can't reproduce the bug with the textures. Also, it doesn't have an offset? Exporting it to .3dj and then 3d printing it works just fine for me. So taking the changes for the -8 offset is not really an option right now I think.

Maybe some kind help description or even video maybe is something this plugin needs? Or a more intuitive way, that would be even better. This plugin also still needs tint support... >.>

@JTK222
Copy link
Contributor

JTK222 commented Jun 14, 2023

The offset does make sense sometimes.
Blockbench does only apply the offset to entity based model formats.
Java Block & Item format, does not have that offset.
So the plugin should either lock you to a specific format, or account for the formats offset.
Considering the no rotation limit, it might also be worth to consider making a custom format for this within Blockbench.

And regarding the description, Blockbench does have a help menu, it is always a possibility to just add an entry, and display a more complex help page, or link to an external one.

@SammyForReal
Copy link
Contributor

Oh alright, thank you for clarifying! Yeah I guess making a proper format for it would be reasonable. I don't know if I can manage this however, so someone would need to make a PR.

if (result.border)
warning.form.border = {
type: 'info',
text: '... are out of bounce (16x16x16 Grid / 1x1x1 Block)',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo, "bounce"

function genShape(cube, raw = false) {
let result = getSingleTexture(cube);
let shape = {
bounds: [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like I said in my comment, the offset depends on the model format, this should be accounted for, as otherwise users may run into issues.

id = "minecraft:" + tmp.name
}
if (id === "") {
if (cube.name.includes(":")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole section seems questionable to me, if this condition is met, the other renaming logic further down does never run.
I assume file extension removal should always be performed, and be further down, with the other renaming logic.
Though I am not farmiliar with the 3DJ format, therefore please correct me if I am incorrect in my assumptions.

@Merith-TK
Copy link
Author

Merith-TK commented Jun 14, 2023

I was testing things again now, and I really can't reproduce the bug with the textures. Also, it doesn't have an offset? Exporting it to .3dj and then 3d printing it works just fine for me. So taking the changes for the -8 offset is not really an option right now I think.

the Export Offset is because the printer mod (unless this behavior has been fixed in newer updates) uses 0,0 as the origin (corner) point, while in BlockBench 0,0 is used as the center point. the offset fixes that by moving the object off of blockbench's origin and to the 3dj format's origin

This whole section seems questionable to me, if this condition is met, the other renaming logic further down does never run.
I assume file extension removal should always be performed, and be further down, with the other renaming logic.
Though I am not farmiliar with the 3DJ format, therefore please correct me if I am incorrect in my assumptions.

there are a few ways in which you can name the textures, as shown in this screenshot
image

The idea is that the user can define an valid minecraft texture path through naming the cube or by naming the texture they have applied to the cube, (texture name takes priority on an cube-by-cube basis)
and by default, if an texture is unable to be gathered by the program, default to stone so that the model does not have an missing texture in game

in the example shown, the texture block is assigned placeholder.png as its texture, which as you can see, is not an valid texture within minecraft's code, so instead it defaults to the stone texture

in same instance, stone-texture cube is assigned the block/stone texture, which assigns it minecraft:block/stone

@JTK222
Copy link
Contributor

JTK222 commented Jun 14, 2023

I was testing things again now, and I really can't reproduce the bug with the textures. Also, it doesn't have an offset? Exporting it to .3dj and then 3d printing it works just fine for me. So taking the changes for the -8 offset is not really an option right now I think.

I'll gladly say it a 3rd time, whether Blockbench has 0, 0, at the center, or in the corner. depends solely on the model format you're using. When you're modelling in block/item mode, this will create the exact issue you're trying to solve.

And regarding the texture naming:
Following would be valid names that break your logic and will likely create invalid model files:

  • : (no namespace, no model path, nothing, will still be considered valid
  • block.png (there is no : the file extension will never be removed)
    It's your choice how much hand holding you want to do, but especially the the file extensions can be problematic.

@Merith-TK
Copy link
Author

Merith-TK commented Jun 14, 2023

ah, missunderstood what you were saying there. could add in a check for the model type and apply the offset when in broken modes

for texture namings, block.png wouldn't be valid as it contains no formatting, so it will default as minecraft:block/stone for the texture

as for an cube or texture named as :, yeah but thats an edge case that is extremely unlikely to happen as no sane person to my knowledge (even the redstone maniacs) would name something when modeling ":", an check can be coded in for regex matching however if that will ease your concern?

also, texture name will take priority over cube name,

in the attached image,
cube has block.png attached
: has no texture --

aigth in testing I have discovered that having an cube named : with no texture assigned, causes an error
image

I am willing to discuss in further detail about the format over discord, (user: merith), is faster and easier to discuss over for me due to the lay out taking more than 1/3rd my screen for messages

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants