Skip to content

Commit bc2f500

Browse files
authored
Fix riding, spawning and inventory drop (#67)
* Update ridingTransport.ts * Update ridingTransport.ts * fix spawn variant and inventory drop * form now saves options & fix terminator dupe names * sanitize nametags * Update index.ts * Update initialization.ts
1 parent 712fcf0 commit bc2f500

File tree

6 files changed

+128
-71
lines changed

6 files changed

+128
-71
lines changed

src/commands/index.ts

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,38 @@
1-
import { world, system, Player, Vector3 } from "@minecraft/server";
1+
import { system, Player, Vector3 } from "@minecraft/server";
22
import { ModalFormData } from "@minecraft/server-ui";
3-
import { MinecraftDimensionTypes } from "@minecraft/vanilla-data";
43
import {
54
spawnTerminator,
65
TerminatorInputParam,
76
TerminatorSkinModel,
87
} from "./summon.js";
8+
import { debugEnabled } from "../config.js";
99

1010
function generateModalForm(settings: TerminatorInputParam) {
11-
let dimensionIndex = 0;
1211
let skinModelIndex = 0;
13-
switch (settings.dimension.id) {
14-
case MinecraftDimensionTypes.Overworld:
15-
dimensionIndex = 0;
16-
break;
17-
case MinecraftDimensionTypes.Nether:
18-
dimensionIndex = 1;
19-
break;
20-
case MinecraftDimensionTypes.TheEnd:
21-
dimensionIndex = 2;
22-
break;
23-
}
2412
switch (settings.skinmodel) {
2513
case TerminatorSkinModel.Steve:
2614
skinModelIndex = 0;
2715
break;
2816
case TerminatorSkinModel.Alex:
2917
skinModelIndex = 1;
3018
break;
19+
case TerminatorSkinModel.Custom:
20+
skinModelIndex = 2;
21+
break;
22+
case TerminatorSkinModel.CustomSlim:
23+
skinModelIndex = 3;
24+
break;
3125
}
3226

3327
return new ModalFormData()
3428
.title("Spawn Terminator")
35-
.textField("Name Tag", "Terminator", "Terminator")
29+
.textField("Name Tag", settings.nametag, settings.nametag)
3630
.textField("Spawn Coordinates", "x y z", "~ ~ ~")
37-
.dropdown("Dimension", ["Overworld", "Nether", "The End"], dimensionIndex)
38-
.dropdown("Skin Model", ["Steve", "Alex"], skinModelIndex)
31+
.dropdown(
32+
"Skin Model",
33+
["Steve", "Alex", "Custom (Steve Model)", "Custom (Alex Model)"],
34+
skinModelIndex
35+
)
3936
.toggle("Enable Custom Skin", settings.customskin)
4037
.toggle("Enable Bossbar", settings.bossbar)
4138
.toggle("Enable Immunity", settings.invulnerable)
@@ -75,18 +72,17 @@ function parseCoordinates(paramString: string, playerLocation: Vector3) {
7572
}
7673

7774
type TerminatorSpawnFormValues = [
78-
string,
79-
string,
80-
number,
81-
number,
82-
boolean,
83-
boolean,
84-
boolean,
85-
boolean,
86-
boolean,
87-
boolean,
88-
boolean,
89-
boolean
75+
string, // nameTag
76+
string, // locationString
77+
number, // skinModelIndex
78+
boolean, // customSkin
79+
boolean, // bossbar
80+
boolean, // invulnerable
81+
boolean, // deathEvent
82+
boolean, // physics
83+
boolean, // regeneration
84+
boolean, // respawn
85+
boolean // breedable
9086
];
9187

9288
const getDefaultSpawnOptions = (player: Player): TerminatorInputParam => ({
@@ -100,12 +96,24 @@ const getDefaultSpawnOptions = (player: Player): TerminatorInputParam => ({
10096
respawn: true,
10197
breedable: false,
10298
coords: player.location,
103-
dimension: player.dimension,
10499
skinmodel: TerminatorSkinModel.Steve,
105100
});
106101

102+
function getPlayerSpawnOptions(player: Player): TerminatorInputParam {
103+
const playerOptionString = player.getDynamicProperty(
104+
"terminator:spawn_options"
105+
) as string | undefined;
106+
if (!playerOptionString) return getDefaultSpawnOptions(player);
107+
try {
108+
return JSON.parse(playerOptionString);
109+
} catch (error) {
110+
if (debugEnabled) console.error(error);
111+
return getDefaultSpawnOptions(player);
112+
}
113+
}
114+
107115
export function showSpawnTerminatorForm(player: Player) {
108-
const spawnOptions: TerminatorInputParam = getDefaultSpawnOptions(player);
116+
const spawnOptions = getPlayerSpawnOptions(player);
109117
const form = generateModalForm(spawnOptions);
110118
form
111119
.show(player)
@@ -114,7 +122,6 @@ export function showSpawnTerminatorForm(player: Player) {
114122
const [
115123
nameTag,
116124
locationString,
117-
dimensionIndex,
118125
skinModelIndex,
119126
customSkin,
120127
bossbar,
@@ -125,26 +132,20 @@ export function showSpawnTerminatorForm(player: Player) {
125132
respawn,
126133
breedable,
127134
] = result.formValues as TerminatorSpawnFormValues;
128-
let dimension = world.getDimension("overworld");
129135
let skinmodel: TerminatorSkinModel = TerminatorSkinModel.Steve;
130-
switch (dimensionIndex) {
131-
case 0:
132-
dimension = world.getDimension("overworld");
133-
break;
134-
case 1:
135-
dimension = world.getDimension("nether");
136-
break;
137-
case 2:
138-
dimension = world.getDimension("the_end");
139-
break;
140-
}
141136
switch (skinModelIndex) {
142137
case 0:
143138
skinmodel = TerminatorSkinModel.Steve;
144139
break;
145140
case 1:
146141
skinmodel = TerminatorSkinModel.Alex;
147142
break;
143+
case 2:
144+
skinmodel = TerminatorSkinModel.Custom;
145+
break;
146+
case 3:
147+
skinmodel = TerminatorSkinModel.CustomSlim;
148+
break;
148149
}
149150

150151
const jsonInput: TerminatorInputParam = {
@@ -158,10 +159,9 @@ export function showSpawnTerminatorForm(player: Player) {
158159
respawn: respawn,
159160
breedable: breedable,
160161
coords: parseCoordinates(locationString, player.location),
161-
dimension,
162162
skinmodel,
163163
};
164-
spawnTerminator(jsonInput);
164+
spawnTerminator(jsonInput, player);
165165
})
166166
.catch((error) => console.error(error + "\n" + error.stack));
167167
}

src/commands/summon.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import { Dimension, Vector3, system } from "@minecraft/server";
1+
import { Player, Vector3, system } from "@minecraft/server";
2+
import { debugEnabled } from "../config";
23

34
export enum TerminatorSkinModel {
45
Steve = "steve",
56
Alex = "alex",
7+
Custom = "custom",
8+
CustomSlim = "custom_slim",
69
}
710

811
export interface TerminatorInputParam {
@@ -16,13 +19,15 @@ export interface TerminatorInputParam {
1619
respawn: boolean;
1720
breedable: boolean;
1821
coords: Vector3;
19-
dimension: Dimension;
2022
skinmodel: TerminatorSkinModel;
2123
}
2224

23-
export function spawnTerminator(user_input: TerminatorInputParam) {
25+
export function spawnTerminator(
26+
user_input: TerminatorInputParam,
27+
sourcePlayer: Player
28+
) {
2429
// target: string, user_input: object
25-
const entity = user_input.dimension.spawnEntity(
30+
const entity = sourcePlayer.dimension.spawnEntity(
2631
"entity:terminator",
2732
user_input.coords
2833
);
@@ -33,6 +38,7 @@ export function spawnTerminator(user_input: TerminatorInputParam) {
3338
* If the option is undefined in user_input
3439
* Script Engine will replace key values with 'default_nbt' variable
3540
*/
41+
user_input.nametag = user_input.nametag.replace(/[^a-zA-Z0-9_ ]/g, '').substring(0, 15);
3642
entity.nameTag = user_input.nametag;
3743

3844
if (user_input.customskin == true) {
@@ -59,10 +65,19 @@ export function spawnTerminator(user_input: TerminatorInputParam) {
5965
if (user_input.respawn == false) {
6066
entity.triggerEvent("terminator:disable_respawn");
6167
}
62-
if (user_input.skinmodel == "alex") {
68+
if (user_input.skinmodel == TerminatorSkinModel.Alex) {
69+
entity.triggerEvent("terminator:switch_skin_to_alex");
70+
} else if (user_input.skinmodel == TerminatorSkinModel.Custom) {
71+
entity.triggerEvent("terminator:enable_custom_skin");
72+
} else if (user_input.skinmodel == TerminatorSkinModel.CustomSlim) {
6373
entity.triggerEvent("terminator:enable_customSlim_skin");
6474
}
6575

66-
console.log("User input: " + JSON.stringify(user_input));
76+
const userInputString = JSON.stringify(user_input);
77+
if (debugEnabled) console.log("User input: " + userInputString);
78+
sourcePlayer.setDynamicProperty(
79+
"terminator:spawn_options",
80+
userInputString
81+
);
6782
}, 2);
6883
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Entity, EntityInventoryComponent } from "@minecraft/server";
2+
3+
export function dropEntityInventory(entity: Entity): boolean {
4+
const inventory = entity.getComponent(
5+
"inventory"
6+
) as EntityInventoryComponent;
7+
8+
if (!inventory.container) return false;
9+
for (let slot = 0; slot < inventory.inventorySize; slot++) {
10+
const item = inventory.container.getItem(slot);
11+
if (item) {
12+
const itemEntity = entity.dimension.spawnItem(item, entity.location);
13+
itemEntity.applyImpulse({
14+
x: Math.random() - 0.5,
15+
y: 0,
16+
z: Math.random() - 0.5,
17+
});
18+
}
19+
}
20+
inventory.container.clearAll();
21+
return true;
22+
}

src/terminator-death/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
import { terminatorDie } from "../terminator-events/onTerminatorDie";
77
import { sendDeathMessageCallback } from "./deathMessage";
88
import { MinecraftColor } from "../minecraft-color";
9+
import { dropEntityInventory } from "./dropInventory";
910

1011
enum TerminatorVariant {
1112
SteveDefault = 0,
@@ -34,6 +35,8 @@ terminatorDie.subscribe((event) => {
3435
variant.value === TerminatorVariant.Custom ||
3536
variant.value === TerminatorVariant.CustomSlim;
3637

38+
dropEntityInventory(deadEntity);
39+
3740
// First Death
3841
if (allowRespawn && triggerRespawnEvent && cause !== EntityDamageCause.void) {
3942
const dummyEntity = deadEntity.dimension.spawnEntity(

src/terminator/initialization.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,27 @@ import { MinecraftEffectTypes } from "@minecraft/vanilla-data";
1010
import { MinecraftColor } from "../minecraft-color";
1111

1212
// naming tag
13-
terminatorSpawn.subscribe(({ entity }) => {
14-
const terminatorPopulation = world
15-
.getDimension("overworld")
16-
.getEntities({ type: "entity:terminator" }).length;
17-
18-
if (terminatorPopulation > 1)
19-
entity.nameTag = `Terminator (${terminatorPopulation - 1})`;
20-
else entity.nameTag = "Terminator";
21-
});
22-
23-
// broadcast to world
2413
terminatorSpawn.subscribe(({ entity }) => {
2514
system.runTimeout(() => {
15+
const nameTag = entity.nameTag || "Terminator";
16+
entity.nameTag = nameTag;
17+
const terminators = entity.dimension.getEntities({
18+
type: "entity:terminator",
19+
});
20+
// Check if existing terminator has the same nameTag, if there one set the entity nameTag to "[name] (1)"
21+
// If there's more than one with the same name, increment the index
22+
if (terminators.some((entity) => entity.nameTag === nameTag)) {
23+
const nameTagRegex = new RegExp(`^${nameTag} \\(\\d+\\)$`);
24+
const terminatorsWithSameName = terminators.filter(
25+
(terminator) =>
26+
(terminator.nameTag === nameTag && terminator !== entity) ||
27+
nameTagRegex.test(terminator.nameTag)
28+
);
29+
if (terminatorsWithSameName.length > 0)
30+
entity.nameTag = `${nameTag} (${terminatorsWithSameName.length})`;
31+
}
32+
33+
// broadcast to world
2634
const rawtext: RawText = {
2735
rawtext: [
2836
{ text: MinecraftColor.yellow },

src/terminator/ridingTransport.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
import { TicksPerSecond, system, world } from "@minecraft/server";
1+
import { ItemStack, TicksPerSecond, system, world } from "@minecraft/server";
22
import { MinecraftEntityTypes } from "@minecraft/vanilla-data";
33

4+
const overworld = world.getDimension("overworld");
5+
46
// Replacement of controller.animation.terminator.sitting
57
system.runInterval(() => {
6-
const overworld = world.getDimension("overworld");
78
const terminators = overworld.getEntities({ type: "entity:terminator" });
9+
if (terminators.length === 0) return;
10+
811
const boats = overworld.getEntities({ type: MinecraftEntityTypes.Boat });
912
const chestBoats = overworld.getEntities({
1013
type: MinecraftEntityTypes.ChestBoat,
@@ -14,16 +17,18 @@ system.runInterval(() => {
1417
});
1518

1619
for (const terminator of terminators) {
17-
let rideableCooldown: number =
18-
(terminator.getDynamicProperty("rideableCooldown") as
19-
| number
20-
| undefined) || -1;
20+
let rideableCooldown = terminator.getDynamicProperty(
21+
"terminator:rideable_cooldown"
22+
) as number | undefined;
2123
const isSitting = terminator.getProperty(
2224
"terminator:is_sitting"
2325
) as boolean;
2426

27+
if (!isSitting) continue;
28+
if (typeof rideableCooldown === "undefined") rideableCooldown = -1;
29+
2530
// If the rideable cooldown is -1 but terminator is sitting, then ride for 10 - 20 seconds then leave
26-
if (rideableCooldown === -1 && isSitting) {
31+
if (rideableCooldown === -1) {
2732
const rideDuration = Math.floor(Math.random() * 10 + 10) * TicksPerSecond;
2833

2934
rideableCooldown = rideDuration;
@@ -34,7 +39,7 @@ system.runInterval(() => {
3439
}
3540
// If the rideable cooldown is 0 and terminator is sitting, then leave the transport they're riding in
3641
// Note: Rideable component is not released to stable, kill the transport entity
37-
else if (rideableCooldown === 0 && isSitting) {
42+
else if (rideableCooldown === 0) {
3843
const nearbyBoats = boats.filter(
3944
(boat) =>
4045
boat.matches({ maxDistance: 1, location: terminator.location }) &&
@@ -58,6 +63,10 @@ system.runInterval(() => {
5863
...nearbyMinecarts,
5964
];
6065
for (const transport of nearbyTransport) {
66+
transport.dimension.spawnItem(
67+
new ItemStack(transport.typeId, 1),
68+
transport.location
69+
);
6170
transport.kill();
6271
}
6372
}

0 commit comments

Comments
 (0)