Skip to content

Commit 28e7cf2

Browse files
Slightly improved explosion performance by spreading spawning across ticks
- new config option `minBlocksToSpawnPerTick`
1 parent 8ec1216 commit 28e7cf2

File tree

8 files changed

+206
-144
lines changed

8 files changed

+206
-144
lines changed

config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
"moduleUUID": "b8622f43-a353-4f04-ba84-d9f4f226af90",
5555
"modules": [
5656
"mojang-minecraft",
57-
"mojang-minecraft-ui"
57+
"mojang-minecraft-ui",
58+
"mojang-gametest"
5859
],
5960
"outfile": "BP/scripts/index.js"
6061
}

packs/BP/scripts/explosion-config.js

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,31 @@ export const explosionConfig = {
4747
/**
4848
* Determines what blocks to ignore, this is helpful for ignoring any blocks that may have issues when being placed down.
4949
*/
50-
ignoreBlocks: ["tnt", "*_door", "bed", "frame", "glowing_frame", "*_double_slab", "*_double_cut_copper_slab", "stonecutter"],
50+
ignoreBlocks: [
51+
"tnt",
52+
"*_door",
53+
"bed",
54+
"frame",
55+
"glowing_frame",
56+
"*_double_slab",
57+
"*_double_cut_copper_slab",
58+
"stonecutter",
59+
"tallgras",
60+
"red_flower",
61+
"yellow_flower",
62+
"brown_mushroom",
63+
"red_mushroom",
64+
"reeds",
65+
"carrots",
66+
"wheat",
67+
"potatoes",
68+
"beetroot",
69+
"pumpkin_stem",
70+
"melon_stem",
71+
"nether_wart",
72+
"*_button",
73+
"*_pressure_plate",
74+
],
5175

5276
/**
5377
* Determines what blocks to allow blocks to replace when being placed.
@@ -67,5 +91,10 @@ export const explosionConfig = {
6791
/**
6892
* Modifies the horizontal launch velocity of blocks. (the horizontal velocity is multiplied by this value)
6993
*/
70-
horizontalVelocityModifier: 0.6,
94+
horizontalVelocityModifier: 1.6,
95+
96+
/**
97+
* Determines the minimum amount of entity blocks to spawn per explosion during a tick before continuing on the next tick.
98+
*/
99+
minBlocksToSpawnPerTick: 15,
71100
};

packs/RP/entity/entity_block.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525
"v.x_dir = 0; v.z_dir = 0;"
2626
],
2727
"pre_animation": [
28-
"v.y_delta = Math.abs(q.position(1) - v.y_prev_pos)/7.5; v.y_prev_pos = q.position(1);",
28+
"v.y_delta = Math.abs(q.position(1) - v.y_prev_pos); v.y_prev_pos = q.position(1);",
2929
"v.y_lerped = Math.lerp(v.y_speed, 0, v.deceleration_rate/2);",
30-
"v.y_speed = v.y_lerped > v.y_delta ? v.y_lerped : v.y_delta;",
30+
"v.y_speed = v.y_lerped > v.y_delta/7.5 ? v.y_lerped : v.y_delta/7.5;",
3131

3232
"v.z_delta = q.position(2) - v.z_prev_pos; v.z_prev_pos = q.position(2);",
3333
"v.z_dir = Math.abs(v.z_delta) > 0.01 ? v.z_delta : v.z_dir;",
@@ -41,7 +41,8 @@
4141
"v.x_speed = Math.abs(v.x_lerped) > Math.abs(v.x_delta) ? v.x_lerped : v.x_delta; v.x_speed = v.x_speed + v.x_dir * v.y_speed;",
4242
"v.x_rot = v.x_rot + v.x_speed * v.rot_rate;"
4343
],
44-
"animate": ["scale", { "rotate": "q.is_ignited" }]
44+
"animate": ["scale", { "rotate": "q.is_ignited" }],
45+
"should_update_bones_and_effects_offscreen": "1"
4546
},
4647
"enable_attachables": true
4748
}

packs/data/gametests/src/block_launcher.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,4 @@ world.events.itemUse.subscribe((evd) => {
4646
eBlock.triggerEvent("despawn_timer");
4747
if (rotateWithVelocity) eBlock.triggerEvent("rotate");
4848
eBlock.setVelocity(Vector.multiply(plr.viewVector, 2));
49-
});
49+
});

packs/data/gametests/src/explosion-config.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,9 @@ export const explosionConfig: {
6767
* Modifies the horizontal launch velocity of blocks. (the horizontal velocity is multiplied by this value)
6868
*/
6969
horizontalVelocityModifier: number;
70-
};
70+
71+
/**
72+
* Determines the minimum amount of entity blocks to spawn per explosion during a tick before continuing on the next tick.
73+
*/
74+
minBlocksToSpawnPerTick: number;
75+
};
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import {
2+
Block,
3+
BlockLocation,
4+
BlockPermutation,
5+
Entity,
6+
EntityDataDrivenTriggerEventOptions,
7+
Items,
8+
ItemStack,
9+
Location,
10+
MinecraftBlockTypes,
11+
Vector,
12+
world,
13+
} from "mojang-minecraft";
14+
import { createEntityBlock, getGamerules, isInList } from "./utils.js";
15+
16+
import { explosionConfig } from "./explosion-config.js";
17+
let {
18+
additionalVerticalVelocity,
19+
collideWithEntities,
20+
despawnTimer,
21+
dropWhenUnplaceable,
22+
enabled,
23+
horizontalVelocityModifier,
24+
ignoreBlocks,
25+
placeWhenHitGround,
26+
replaceBlocks,
27+
rotateWithVelocity,
28+
simpleMath,
29+
verticalVelocityModifier,
30+
minBlocksToSpawnPerTick,
31+
} = explosionConfig;
32+
ignoreBlocks = ignoreBlocks.map((v) => v.replace("minecraft:", ""));
33+
replaceBlocks = replaceBlocks.map((v) => v.replace("minecraft:", ""));
34+
35+
const blockMap = new Map<Entity, BlockPermutation>();
36+
37+
let tick = 0;
38+
world.events.tick.subscribe(({ currentTick }) => (tick = currentTick));
39+
if (enabled) {
40+
world.events.beforeExplosion.subscribe(async (evd) => {
41+
if (!evd.source) return;
42+
43+
const dim = evd.dimension;
44+
const orgLoc = evd.source.location;
45+
const origin = new Vector(orgLoc.x, orgLoc.y + 0.5, orgLoc.z);
46+
47+
const blocks = evd.impactedBlocks
48+
.map((v) => dim.getBlock(v))
49+
.filter((v) => !isInList(ignoreBlocks, v.id.replace("minecraft:", "")));
50+
51+
const blockDist = new Map<Block, number>();
52+
const blockId = new Map<Block, string>();
53+
for (let block of blocks) {
54+
if (!simpleMath) {
55+
blockDist.set(
56+
block,
57+
Math.hypot(
58+
origin.x - block.x,
59+
origin.y - (block.y - 0.5),
60+
origin.z - block.z
61+
)
62+
);
63+
}
64+
blockId.set(block, block.id);
65+
}
66+
const range = Math.max(...blockDist.values());
67+
68+
let currentTick = tick;
69+
let blocksInTick = 0;
70+
71+
for (let block of blocks) {
72+
const pos = new Vector(block.x + 0.5, block.y - 0.5, block.z + 0.5);
73+
74+
let vel = Vector.subtract(pos, origin);
75+
const dist = Math.hypot(vel.x, vel.y, vel.z);
76+
vel = Vector.divide(vel, dist);
77+
78+
if (!simpleMath) {
79+
const distMod =
80+
(range - Math.pow(dist, 1.5) + Math.pow(dist, 1.1)) / range;
81+
vel = Vector.multiply(vel, distMod * 2);
82+
}
83+
84+
vel.y += additionalVerticalVelocity;
85+
vel = Vector.multiply(
86+
vel,
87+
new Vector(
88+
horizontalVelocityModifier,
89+
verticalVelocityModifier,
90+
horizontalVelocityModifier
91+
)
92+
);
93+
94+
const id = blockId.get(block) ?? "minecraft:air";
95+
const eBlock = createEntityBlock(
96+
id,
97+
block.dimension,
98+
new Location(block.x + 0.5, block.y + 0.5, block.z + 0.5)
99+
);
100+
101+
eBlock.addTag("$entityBlockFromTNT");
102+
if (collideWithEntities) eBlock.triggerEvent("collision");
103+
if (despawnTimer) eBlock.triggerEvent("despawn_timer");
104+
if (placeWhenHitGround) blockMap.set(eBlock, block.permutation);
105+
if (rotateWithVelocity) eBlock.triggerEvent("rotate");
106+
eBlock.setVelocity(vel);
107+
block.setType(MinecraftBlockTypes.air);
108+
if (currentTick != tick) {
109+
currentTick = tick;
110+
blocksInTick = 0;
111+
}
112+
blocksInTick++;
113+
if (blocksInTick > minBlocksToSpawnPerTick) await null;
114+
}
115+
});
116+
117+
if (placeWhenHitGround) {
118+
const options = new EntityDataDrivenTriggerEventOptions();
119+
options.eventTypes = ["hit_ground"];
120+
world.events.beforeDataDrivenEntityTriggerEvent.subscribe((evd) => {
121+
const entity = evd.entity;
122+
if (!entity.hasTag("$entityBlockFromTNT")) return;
123+
124+
const perm = blockMap.get(entity);
125+
blockMap.delete(entity);
126+
if (!perm) return;
127+
128+
const loc = entity.location;
129+
const block = entity.dimension.getBlock(
130+
new BlockLocation(
131+
Math.floor(loc.x),
132+
Math.floor(loc.y + 0.25),
133+
Math.floor(loc.z)
134+
)
135+
);
136+
if (isInList(replaceBlocks, block.id.replace("minecraft:", ""))) {
137+
block.setPermutation(perm);
138+
} else if (dropWhenUnplaceable) {
139+
if (getGamerules().dotiledrops) {
140+
const item = new ItemStack(Items.get(perm.type.id), 1);
141+
entity.dimension.spawnItem(item, loc);
142+
}
143+
}
144+
entity.triggerEvent("despawn");
145+
}, options);
146+
}
147+
}

packs/data/gametests/src/index.ts

Lines changed: 2 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,135 +1,3 @@
1-
import {
2-
Block,
3-
BlockLocation,
4-
BlockPermutation,
5-
Entity,
6-
EntityDataDrivenTriggerEventOptions,
7-
Items,
8-
ItemStack,
9-
Location,
10-
MinecraftBlockTypes,
11-
Vector,
12-
world,
13-
} from "mojang-minecraft";
14-
import { createEntityBlock, getGamerules, isInList, setTimeout } from "./utils.js";
15-
16-
import { explosionConfig } from "./explosion-config.js";
17-
let {
18-
additionalVerticalVelocity,
19-
collideWithEntities,
20-
despawnTimer,
21-
dropWhenUnplaceable,
22-
enabled,
23-
horizontalVelocityModifier,
24-
ignoreBlocks,
25-
placeWhenHitGround,
26-
replaceBlocks,
27-
rotateWithVelocity,
28-
simpleMath,
29-
verticalVelocityModifier,
30-
} = explosionConfig;
31-
ignoreBlocks = ignoreBlocks.map((v) => v.replace("minecraft:", ""));
32-
replaceBlocks = replaceBlocks.map((v) => v.replace("minecraft:", ""));
33-
34-
const blockMap = new Map<Entity, BlockPermutation>();
35-
36-
if (enabled) {
37-
world.events.beforeExplosion.subscribe((evd) => {
38-
if (!evd.source) return;
39-
40-
const dim = evd.dimension;
41-
const orgLoc = evd.source.location;
42-
const origin = new Vector(orgLoc.x, orgLoc.y + 0.5, orgLoc.z);
43-
44-
const blocks = evd.impactedBlocks
45-
.map((v) => dim.getBlock(v))
46-
.filter((v) => !isInList(ignoreBlocks, v.id.replace("minecraft:", "")));
47-
48-
const blockDist = new Map<Block, number>();
49-
const blockId = new Map<Block, string>();
50-
for (let block of blocks) {
51-
if (!simpleMath) {
52-
blockDist.set(
53-
block,
54-
Math.hypot(
55-
origin.x - block.x,
56-
origin.y - (block.y - 0.5),
57-
origin.z - block.z
58-
)
59-
);
60-
}
61-
blockId.set(block, block.id);
62-
}
63-
const range = Math.max(...blockDist.values());
64-
65-
for (let block of blocks) {
66-
const pos = new Vector(block.x + 0.5, block.y - 0.5, block.z + 0.5);
67-
68-
let vel = Vector.subtract(pos, origin);
69-
const dist = Math.hypot(vel.x, vel.y, vel.z);
70-
vel = Vector.divide(vel, dist);
71-
72-
if (!simpleMath) {
73-
const distMod =
74-
(range - Math.pow(dist, 1.5) + Math.pow(dist, 1.1)) / range;
75-
vel = Vector.multiply(vel, distMod * 2);
76-
}
77-
78-
vel.y += additionalVerticalVelocity;
79-
vel = Vector.multiply(
80-
vel,
81-
new Vector(
82-
horizontalVelocityModifier,
83-
verticalVelocityModifier,
84-
horizontalVelocityModifier
85-
)
86-
);
87-
88-
const eBlock = createEntityBlock(
89-
block.id,
90-
block.dimension,
91-
new Location(block.x + 0.5, block.y + 0.5, block.z + 0.5)
92-
);
93-
94-
eBlock.addTag("$entityBlockFromTNT");
95-
if (collideWithEntities) eBlock.triggerEvent("collision");
96-
if (despawnTimer) eBlock.triggerEvent("despawn_timer");
97-
if (placeWhenHitGround) blockMap.set(eBlock, block.permutation);
98-
if (rotateWithVelocity) eBlock.triggerEvent("rotate");
99-
eBlock.setVelocity(vel);
100-
block.setType(MinecraftBlockTypes.air);
101-
}
102-
});
103-
104-
if (placeWhenHitGround) {
105-
const options = new EntityDataDrivenTriggerEventOptions();
106-
options.eventTypes = ["hit_ground"];
107-
world.events.beforeDataDrivenEntityTriggerEvent.subscribe((evd) => {
108-
const entity = evd.entity;
109-
if (!entity.hasTag("$entityBlockFromTNT")) return;
110-
111-
const perm = blockMap.get(entity);
112-
blockMap.delete(entity);
113-
if (!perm) return;
114-
115-
const loc = entity.location;
116-
const block = entity.dimension.getBlock(
117-
new BlockLocation(
118-
Math.floor(loc.x),
119-
Math.floor(loc.y + 0.25),
120-
Math.floor(loc.z)
121-
)
122-
);
123-
if (isInList(replaceBlocks, block.id.replace("minecraft:", ""))) {
124-
block.setPermutation(perm);
125-
} else if (dropWhenUnplaceable) {
126-
if (getGamerules().dotiledrops) {
127-
const item = new ItemStack(Items.get(perm.type.id), 1);
128-
entity.dimension.spawnItem(item, loc);
129-
}
130-
}
131-
entity.triggerEvent("despawn");
132-
}, options);
133-
}
134-
}
1+
import "./explosions";
1352
import "./block_launcher";
3+
// import "./ragdolls";

0 commit comments

Comments
 (0)