Skip to content

Commit fd46fd4

Browse files
committed
Add support for block direction (facing/axis), not just position
1 parent 6b4378b commit fd46fd4

8 files changed

Lines changed: 198 additions & 39 deletions

File tree

README.md

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,31 @@ Of course, this mod can also be used independently. As long as you can generate
1919
* Import blocks in bulk from JSON files located in the `config/mybuilds/` directory.
2020
* Players can use the `builder:anchor_block` to set the origin and orientation of the relative coordinate system, allowing precise control over the placement and facing of imported blocks.
2121
* Supports undo functionality to prevent mistakes. You can undo up to the last 3 build operations.
22+
* Supports exporting blocks from the current world to JSON files.
2223

2324
## Usage
2425

2526
1. Create a specially formatted JSON file under the `config/mybuilds/` directory, e.g. [`example.json`](./example.json)
26-
27+
* You can use [**Minecraftify2.0**](https://github.com/Ivans-11/Minecraftify2/releases) to generate JSON files from 3D models. See its [repository documentation](https://github.com/Ivans-11/Minecraftify2) for details.
28+
* You can also use the `/builder save` command to export JSON files from the current world. See the following content for specific usage.
2729
```json
2830
{
2931
"minecraft:stone": [[1, 0, 0],[2, 0, 0],[3, 0, 0]],
30-
"minecraft:oak_planks": [[0, 1, 1],[0, 1, 2]]
32+
"minecraft:oak_planks": [[0, 1, 1],[0, 1, 2]],
33+
"minecraft:spruce_stairs":[[2, 0, 1, 3]],
34+
"minecraft:oak_log":[[3, 0, 1, -3],[4, 0, 1, -1]]
3135
}
3236
```
33-
3437
* Keys are block IDs, and values are arrays of relative coordinates.
35-
* You can use [**Minecraftify2.0**](https://github.com/Ivans-11/Minecraftify2/releases) to generate JSON files from 3D models. See its [repository documentation](https://github.com/Ivans-11/Minecraftify2) for details.
36-
* You can also use the `/builder save` command to export JSON files from the current world. See the following content for specific usage.
38+
* Each element in the relative coordinate array represents a block's relative coordinates, in the format `[x, y, z, w]`.
39+
* `x` represents the offset in the x-axis relative to the origin.
40+
* `y` represents the offset in the y-axis relative to the origin.
41+
* `z` represents the offset in the z-axis relative to the origin.
42+
* `w` is an optional parameter, used to specify the direction of blocks with direction attributes.
43+
* When positive, it represents the horizontal direction. The corresponding numeric values correspond to the following image (for example, stairs):
44+
![](image/stairs.png)
45+
* When negative, it represents the axis direction. The corresponding numeric values correspond to the following image (for example, logs):
46+
![](image/log.png)
3747

3848
2. Place a `builder:anchor_block` in the game world to define the reference origin and orientation.
3949

@@ -62,7 +72,9 @@ Of course, this mod can also be used independently. As long as you can generate
6272
/builder save <x> <y> <z> <name>
6373
```
6474
Where `<x> <y> <z>` represents the selected area range.
75+
6576
The mod will use the nearest anchor block to the player as the starting point `(0,0,0)` and export the block data in the range from `(0,0,0)` to `(x,y,z)` to the `config/mybuilds/<name>.json` file.
77+
6678
Note that the x-axis corresponds to the red axis, the y-axis corresponds to the green axis, and the z-axis corresponds to the blue axis. The format of the exported JSON file is the same as that of the imported one.
6779

6880
## Command List
@@ -92,7 +104,7 @@ Of course, this mod can also be used independently. As long as you can generate
92104

93105
* Undo only applies to blocks placed using the `/builder place` command, and does not affect manually placed blocks.
94106

95-
* Since JSON files only record the relative coordinates of blocks, it is not possible to import some special blocks (such as stairs, doors, etc., which contain more information) accurately.
107+
* Since JSON files only record the relative coordinates of blocks, it is not possible to import some special blocks (such as buttons, doors, etc., which contain more information) accurately.
96108

97109
## Acknowledgements
98110

README_zh.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,32 @@
1818
-`config/mybuilds/` 目录下的 JSON 文件中批量导入方块。
1919
- 玩家可以使用 `builder:anchor_block`(锚点方块)设置相对坐标系原点和朝向,从而精确地控制导入方块的位置与朝向。
2020
- 支持撤回功能,避免误操作。最多可以撤回最近 3 次建造操作。
21+
- 支持导出功能,将当前世界的指定区域内的方块数据导出为 JSON 文件。
2122

2223
## 使用方法
2324

2425
1.`config/mybuilds/` 目录下创建特定格式的 JSON 文件,例如 [`example.json`](./example.json)
25-
26+
- 可使用工具 [**Minecraftify2.0**](https://github.com/Ivans-11/Minecraftify2/releases) 从三维模型文件生成,具体使用方法见其[仓库说明](https://github.com/Ivans-11/Minecraftify2)
27+
- 也可利用 `/builder save` 命令从当前世界导出 JSON 文件,具体使用方法见后文。
2628
```json
2729
{
2830
"minecraft:stone": [[1, 0, 0],[2, 0, 0],[3, 0, 0]],
29-
"minecraft:oak_planks": [[0, 1, 1],[0, 1, 2]]
31+
"minecraft:oak_planks": [[0, 1, 1],[0, 1, 2]],
32+
"minecraft:spruce_stairs":[[2, 0, 1, 3]],
33+
"minecraft:oak_log":[[3, 0, 1, -3],[4, 0, 1, -1]]
3034
}
3135
```
3236
- 其中,键为方块 ID,值为相对坐标数组。
33-
- 可使用工具 [**Minecraftify2.0**](https://github.com/Ivans-11/Minecraftify2/releases) 从三维模型文件生成,具体使用方法见其[仓库说明](https://github.com/Ivans-11/Minecraftify2)
34-
- 也可利用 `/builder save` 命令从当前世界导出 JSON 文件,具体使用方法见后文。
37+
- 相对坐标数组中的每个元素表示一个方块的相对坐标,格式为 `[x, y, z, w]`
38+
- `x` 表示相对于原点的 x 轴偏移量。
39+
- `y` 表示相对于原点的 y 轴偏移量。
40+
- `z` 表示相对于原点的 z 轴偏移量。
41+
- `w` 为可选参数,用于指定 带方向属性方块 的朝向。
42+
- 为正数时,代表水平朝向。具体数值对应关系如图(以楼梯为例):
43+
![](image/stairs.png)
44+
- 为负数时,代表轴向。具体数值对应关系如图(以原木为例):
45+
![](image/log.png)
46+
3547
2. 在游戏中放置一个 `builder:anchor_block`(锚点方块) ,用于确定参考坐标系原点和朝向。
3648

3749
![](image/anchor.png)
@@ -84,7 +96,7 @@
8496

8597
![](image/item_zh.png)
8698
- 撤回仅能恢复由 `/builder place` 命令生成的方块,不影响手动放置的方块。
87-
- 由于 JSON 文件只记录了方块的相对坐标,因此对于一些特殊的方块(如楼梯、门等包含更多信息的方块),无法做到精确导入。
99+
- 由于 JSON 文件只记录了方块的相对坐标和朝向,因此对于一些特殊的方块(如按钮、门等包含更多信息的方块),无法做到精确导入。
88100

89101
## 致谢
90102

example.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,12 @@
3030
[-1, 1, 8],
3131
[0, 1, 8],
3232
[1, 1, 8]
33+
],
34+
"minecraft:spruce_stairs": [
35+
[3, 0, 4, 3]
36+
],
37+
"minecraft:oak_log":[
38+
[3, 0, 5, -3],
39+
[4, 0, 5, -1]
3340
]
3441
}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ loader_version=0.16.14
1010
loom_version=1.11-SNAPSHOT
1111

1212
# Mod Properties
13-
mod_version=1.0.1
13+
mod_version=1.0.2
1414
maven_group=com.example
1515
archives_base_name=builder
1616

image/log.png

14 MB
Loading

image/stairs.png

16.4 MB
Loading

src/main/java/com/example/BuildHandler.java

Lines changed: 155 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
import net.minecraft.util.Identifier;
1212
import net.minecraft.util.math.BlockPos;
1313
import net.minecraft.util.math.Direction;
14+
import net.minecraft.util.math.Direction.Axis;
1415
import net.minecraft.registry.Registries;
1516
import net.minecraft.server.world.ServerWorld;
1617
import net.minecraft.state.property.Properties;
18+
import net.minecraft.state.property.Property;
1719
import net.minecraft.text.Text;
1820

1921
import java.io.FileReader;
@@ -117,38 +119,23 @@ public static void loadAndPlace(ServerCommandSource source, String filename) {
117119

118120
// If it is an anchor block, record the position
119121
if (block instanceof AnchorBlock) {
120-
player.sendMessage(Text.literal("Anchor Block Found: " + origin), false);
121-
for (JsonElement coordEl : coords) {
122-
JsonArray arr = coordEl.getAsJsonArray();
123-
int dx = arr.get(0).getAsInt();
124-
int dy = arr.get(1).getAsInt();
125-
int dz = arr.get(2).getAsInt();
126-
127-
BlockPos placePos = transformPos(origin, dx, dy, dz, facing);
128-
129-
BlockState oldState = world.getBlockState(placePos);
130-
snapshots.add(new UndoManager.BlockSnapshot(placePos, oldState));
131-
world.setBlockState(placePos, block.getDefaultState());
132-
player.sendMessage(Text.literal("Anchor Block Placed: " + placePos), false);
133-
cache.add(placePos);
134-
player.sendMessage(Text.literal("Anchor Block Added: " + placePos), false);
135-
}
122+
handleAnchors(world, coords, block, facing, origin, snapshots, cache);
136123
continue;
137124
}
138125

139-
for (JsonElement coordEl : coords) {
140-
JsonArray arr = coordEl.getAsJsonArray();
141-
int dx = arr.get(0).getAsInt();
142-
int dy = arr.get(1).getAsInt();
143-
int dz = arr.get(2).getAsInt();
144-
145-
BlockPos placePos = transformPos(origin, dx, dy, dz, facing);
146-
147-
BlockState oldState = world.getBlockState(placePos);
148-
snapshots.add(new UndoManager.BlockSnapshot(placePos, oldState));
126+
// If it is a block with facing
127+
if (block.getDefaultState().contains(Properties.HORIZONTAL_FACING)) {
128+
handleFacing(world, coords, block, facing, origin, snapshots);
129+
continue;
130+
}
149131

150-
world.setBlockState(placePos, block.getDefaultState());
132+
// If it is a block with axis
133+
if (block.getDefaultState().contains(Properties.AXIS)) {
134+
handleAxis(world, coords, block, facing, origin, snapshots);
135+
continue;
151136
}
137+
138+
handleNormal(world, coords, block, facing, origin, snapshots);
152139
}
153140

154141
UndoManager.record(player, snapshots);// Record snapshots
@@ -198,6 +185,16 @@ public static void saveStructure(ServerCommandSource source, int x, int y, int z
198185
arr.add(dx);
199186
arr.add(dy);
200187
arr.add(dz);
188+
189+
// Record the rotation of the block
190+
if (state.contains(Properties.HORIZONTAL_FACING)) {
191+
Direction blockFacing = state.get(Properties.HORIZONTAL_FACING);
192+
arr.add(relativeDirection(facing, blockFacing));
193+
} else if (state.contains(Properties.AXIS)) {
194+
Axis blockAxis = state.get(Properties.AXIS);
195+
arr.add(relativeAxis(facing, blockAxis));
196+
}
197+
201198
if (obj.has(blockId)) {
202199
obj.get(blockId).getAsJsonArray().add(arr);
203200
} else {
@@ -221,6 +218,77 @@ public static void saveStructure(ServerCommandSource source, int x, int y, int z
221218
}
222219
}
223220

221+
// Place normal blocks
222+
private static void handleNormal(ServerWorld world, JsonArray coords, Block block, Direction facing, BlockPos origin, List<UndoManager.BlockSnapshot> snapshots) {
223+
for (JsonElement coordEl : coords) {
224+
JsonArray arr = coordEl.getAsJsonArray();
225+
int dx = arr.get(0).getAsInt();
226+
int dy = arr.get(1).getAsInt();
227+
int dz = arr.get(2).getAsInt();
228+
229+
BlockPos placePos = transformPos(origin, dx, dy, dz, facing);
230+
231+
BlockState oldState = world.getBlockState(placePos);
232+
snapshots.add(new UndoManager.BlockSnapshot(placePos, oldState));
233+
234+
world.setBlockState(placePos, block.getDefaultState());
235+
}
236+
}
237+
238+
// Place anchor blocks
239+
private static void handleAnchors(ServerWorld world, JsonArray coords, Block block, Direction facing, BlockPos origin, List<UndoManager.BlockSnapshot> snapshots, AnchorState cache) {
240+
for (JsonElement coordEl : coords) {
241+
JsonArray arr = coordEl.getAsJsonArray();
242+
int dx = arr.get(0).getAsInt();
243+
int dy = arr.get(1).getAsInt();
244+
int dz = arr.get(2).getAsInt();
245+
int rotation = arr.size() > 3 ? arr.get(3).getAsInt() : 0;
246+
247+
BlockPos placePos = transformPos(origin, dx, dy, dz, facing);
248+
249+
BlockState oldState = world.getBlockState(placePos);
250+
snapshots.add(new UndoManager.BlockSnapshot(placePos, oldState));
251+
252+
world.setBlockState(placePos, block.getDefaultState().with(Properties.HORIZONTAL_FACING, absoluteDirection(facing, rotation)));
253+
cache.add(placePos);// Add to cache
254+
}
255+
}
256+
257+
// Place blocks with facing
258+
private static void handleFacing(ServerWorld world, JsonArray coords, Block block, Direction facing, BlockPos origin, List<UndoManager.BlockSnapshot> snapshots) {
259+
for (JsonElement coordEl : coords) {
260+
JsonArray arr = coordEl.getAsJsonArray();
261+
int dx = arr.get(0).getAsInt();
262+
int dy = arr.get(1).getAsInt();
263+
int dz = arr.get(2).getAsInt();
264+
int rotation = arr.size() > 3? arr.get(3).getAsInt() : 0;
265+
266+
BlockPos placePos = transformPos(origin, dx, dy, dz, facing);
267+
268+
BlockState oldState = world.getBlockState(placePos);
269+
snapshots.add(new UndoManager.BlockSnapshot(placePos, oldState));
270+
271+
world.setBlockState(placePos, block.getDefaultState().with(Properties.HORIZONTAL_FACING, absoluteDirection(facing, rotation)));
272+
}
273+
}
274+
275+
// Place blocks with axis
276+
private static void handleAxis(ServerWorld world, JsonArray coords, Block block, Direction facing, BlockPos origin, List<UndoManager.BlockSnapshot> snapshots) {
277+
for (JsonElement coordEl : coords) {
278+
JsonArray arr = coordEl.getAsJsonArray();
279+
int dx = arr.get(0).getAsInt();
280+
int dy = arr.get(1).getAsInt();
281+
int dz = arr.get(2).getAsInt();
282+
int axis = arr.size() > 3? arr.get(3).getAsInt() : 0;
283+
284+
BlockPos placePos = transformPos(origin, dx, dy, dz, facing);
285+
286+
BlockState oldState = world.getBlockState(placePos);
287+
snapshots.add(new UndoManager.BlockSnapshot(placePos, oldState));
288+
289+
world.setBlockState(placePos, block.getDefaultState().with(Properties.AXIS, absoluteAxis(facing, axis)));
290+
}
291+
}
224292

225293
// Transform position based on facing
226294
private static BlockPos transformPos(BlockPos origin, int dx, int dy, int dz, Direction facing) {
@@ -252,4 +320,64 @@ private static List<BlockPos> getAnchors(ServerWorld world) {
252320
// Get copy of anchors to avoid ConcurrentModificationException
253321
return new ArrayList<>(cache.getAnchors());
254322
}
323+
324+
// Get the relative direction of the block to the anchor (using positive numbers)
325+
private static int relativeDirection(Direction anchorFacing, Direction blockFacing) {
326+
int offset = intDirection(blockFacing) - intDirection(anchorFacing);
327+
if (offset < 0) offset += 4;
328+
return offset;
329+
}
330+
331+
// Get the relative axis of the block to the anchor (using negative numbers)
332+
private static int relativeAxis(Direction anchorFacing, Axis blockAxis) {
333+
if (blockAxis == Axis.X) {
334+
if (anchorFacing == Direction.NORTH || anchorFacing == Direction.SOUTH) return -1;
335+
if (anchorFacing == Direction.EAST || anchorFacing == Direction.WEST) return -2;
336+
} else if (blockAxis == Axis.Z) {
337+
if (anchorFacing == Direction.NORTH || anchorFacing == Direction.SOUTH) return -2;
338+
if (anchorFacing == Direction.EAST || anchorFacing == Direction.WEST) return -1;
339+
}
340+
return -3;
341+
}
342+
343+
// Get the absolute direction of the block based on the anchor and the relative direction
344+
private static Direction absoluteDirection(Direction anchorFacing, int relativeDirection) {
345+
int absolute = intDirection(anchorFacing) + relativeDirection;
346+
if (absolute >= 4) absolute -= 4;
347+
return getDirection(absolute);
348+
}
349+
350+
// Get the absolute axis of the block based on the anchor and the relative axis
351+
private static Axis absoluteAxis(Direction anchorFacing, int relativeAxis) {
352+
if (anchorFacing == Direction.NORTH || anchorFacing == Direction.SOUTH) {
353+
if (relativeAxis == -1) return Axis.X;
354+
if (relativeAxis == -2) return Axis.Z;
355+
} else if (anchorFacing == Direction.EAST || anchorFacing == Direction.WEST) {
356+
if (relativeAxis == -1) return Axis.Z;
357+
if (relativeAxis == -2) return Axis.X;
358+
}
359+
return Axis.Y;
360+
}
361+
362+
// Convert direction to integer
363+
private static int intDirection(Direction dir) {
364+
switch (dir) {
365+
case NORTH: return 0;
366+
case EAST: return 1;
367+
case SOUTH: return 2;
368+
case WEST: return 3;
369+
default: return 0;
370+
}
371+
}
372+
373+
// Convert integer to direction
374+
private static Direction getDirection(int dir) {
375+
switch (dir) {
376+
case 0: return Direction.NORTH;
377+
case 1: return Direction.EAST;
378+
case 2: return Direction.SOUTH;
379+
case 3: return Direction.WEST;
380+
default: return Direction.NORTH;
381+
}
382+
}
255383
}
-1.94 KB
Loading

0 commit comments

Comments
 (0)