Skip to content

Commit da47fdc

Browse files
committed
Code Overhaul
Removed hardcoded values and added their respective configurable constants Expanded Player polyfill with all dictionaries that were managed outside of the player object Made all sounds play in the world instead of only the player making them hearing them Added dash cooldown
1 parent d8829fd commit da47fdc

File tree

3 files changed

+161
-76
lines changed

3 files changed

+161
-76
lines changed

scripts/addons/lightFruit/lightFruit.ts

Lines changed: 134 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,60 @@
1-
import { AimAssistTargetMode, ButtonState, EffectTypes, EntityDamageCause, EntityHealthComponent, EntityInventoryComponent, EquipmentSlot, InputButton, InputPermissionCategory, ItemLockMode, ItemStack, MolangVariableMap, Player, RGBA, StartupEvent, system, Vector3, world } from "@minecraft/server";
1+
import { ButtonState, EntityDamageCause, EntityHealthComponent, EntityInventoryComponent, EquipmentSlot, InputButton, InputPermissionCategory, ItemLockMode, ItemStack, MolangVariableMap, Player, StartupEvent, system, Vector3, world } from "@minecraft/server";
22
import { MinecraftEffectTypes } from "@minecraft/vanilla-data";
3-
import { directionVector, drawLine, entityCenter, entityGetSlot, entityHasSlotTag, spawnLine } from "../../utility";
3+
import { directionVector, drawLine, EFFECT_INFINITE, entityCenter, entityHasSlotTag, playSoundFrom } from "../../utility";
44
import { V3 } from "../../math/vectorUtils";
55
import { deg2Rad, PI, remap, TAU } from "../../math/general";
6-
import { VECTOR2_ZERO, VECTOR3_BACK, VECTOR3_ZERO } from "@minecraft/math";
6+
import { VECTOR3_ZERO } from "@minecraft/math";
77

8-
let light: ItemStack
9-
const maxAirJumps: number = 10
10-
const lightTrailThickness: number = 0.15
11-
const lightTrailLengthMax: number = 10.0
12-
const lightTrailLengthMin: number = 1.5
13-
const fCooldownTime = 80
14-
const flyTurnThreshold = Math.cos(deg2Rad(60));
158
enum States {
169
NORMAL,
1710
FLYING,
1811
MOON_JUMP,
1912
DASH
2013
}
2114

22-
class LightVisual {
15+
let light: ItemStack
16+
const maxAirJumps: number = 10
17+
const lightTrailThickness: number = 0.15
18+
const lightSpinTrailThickness: number = 0.075
19+
const fCooldownTime = 80
20+
const flyTurnThreshold = Math.cos(deg2Rad(60));
21+
const flyTurnCooldownTime: number = 10
22+
const airborneAirtime = 3
23+
24+
const moonJumpForce = 0.75
25+
const moonJumpSize1 = 0.5
26+
const moonJumpSize2 = 1.3 / 2
27+
const moonJumpSize3 = 1.5 / 2
28+
const moonJumpPos1 = -0.0
29+
const moonJumpPos2 = -0.2
30+
const moonJumpPos3 = -0.4
31+
32+
const dashCooldownTime = 5
33+
const dashForce = 1.0
34+
const dashLift = 0.1
35+
const dashSlowFallTime = 5
36+
37+
const flightSpeedMin = 0.1
38+
const flightSpeedMax = 1.0
39+
const flightStarSize = 2.0
40+
const flightStarFrames = 5
41+
const spinTrailTurnsPerSecond = 1.5
42+
const spinTrailRadius = 0.5
43+
const flySoundDuration = 7 //8.58
44+
45+
class LightFlightVisual {
2346
lastSpin1: Vector3 | undefined
2447
lastSpin2: Vector3 | undefined
2548
lastTrail: Vector3 | undefined
2649
angle: number = 0.0
2750
}
28-
const flyTurnCooldownTime: number = 10
2951
const flyTurnCooldown: Map<string, number> = new Map()
3052
const flySoundCooldown: Map<string, number> = new Map()
3153
const airTime: Map<string, number> = new Map()
3254
const ignoreFall: Map<string, boolean> = new Map()
33-
const airJumps: Map<string, number> = new Map()
55+
const dashCooldown: Map<string, number> = new Map()
3456
const flyingAngles: Map<string, Vector3> = new Map()
35-
const visuals: Map<string, LightVisual> = new Map()
57+
const lightFlightVisuals: Map<string, LightFlightVisual> = new Map()
3658

3759
// Defining setters for ability cooldowns
3860
Object.defineProperties(Player.prototype, {
@@ -60,6 +82,41 @@ Object.defineProperties(Player.prototype, {
6082
get() {return this.getDynamicProperty("whynot:light_state") ?? States.NORMAL},
6183
set(state: number) {this.setDynamicProperty("whynot:light_state", state)},
6284
},
85+
flyTurnCooldown: {
86+
get() {return flyTurnCooldown.get(this.id) ?? 0},
87+
set(v: number) {flyTurnCooldown.set(this.id, v)}
88+
},
89+
center: {
90+
get() {return entityCenter(this) ?? this.location}
91+
},
92+
flySoundCooldown: {
93+
get() {return flySoundCooldown.get(this.id) ?? 0},
94+
set(v: number) {flySoundCooldown.set(this.id, v)}
95+
},
96+
airTime: {
97+
get() {return airTime.get(this.id) ?? 0},
98+
set(v: number) {airTime.set(this.id, v)}
99+
},
100+
ignoreFall: {
101+
get() {return ignoreFall.get(this.id) ?? false},
102+
set(v: boolean) {ignoreFall.set(this.id, v)}
103+
},
104+
airJumps: {
105+
get() {return this.getDynamicProperty("whynot:air_jumps") ?? 10},
106+
set(v: number) {this.setDynamicProperty("whynot:air_jumps", v)},
107+
},
108+
flyingAngles: {
109+
get() {return flyingAngles.get(this.id) ?? VECTOR3_ZERO},
110+
set(v: Vector3) {flyingAngles.set(this.id, v)}
111+
},
112+
lightFlightVisuals: {
113+
get() {return lightFlightVisuals.get(this.id) ?? new LightFlightVisual()},
114+
set(v: LightFlightVisual) {lightFlightVisuals.set(this.id, v)}
115+
},
116+
dashCooldown: {
117+
get() {return dashCooldown.get(this.id) ?? 0},
118+
set(v: number) {dashCooldown.set(this.id, v)}
119+
}
63120
});
64121

65122
// Eat fruit component
@@ -87,43 +144,47 @@ function changeState(player: Player, state: States) {
87144
switch (player.state) {
88145
case States.FLYING:
89146
player.triggerEvent("whynot:add_static_player");
90-
flyingAngles.set(player.id, player.getViewDirection());
91-
player.addEffect(MinecraftEffectTypes.Invisibility, 20000000, {showParticles: false})
92-
93-
player.playSound("light_dash")
94-
player.playSound("light_beam_start")
95-
visuals.set(player.id, new LightVisual())
96-
flySoundCooldown.set(player.id, 0)
97-
flyTurnCooldown.set(player.id, 0)
147+
player.addEffect(MinecraftEffectTypes.Invisibility, EFFECT_INFINITE, {showParticles: false})
148+
149+
playSoundFrom(player, "light_dash")
150+
playSoundFrom(player, "light_beam_start")
151+
player.flyingAngles = player.getViewDirection()
152+
player.lightFlightVisuals = new LightFlightVisual()
153+
player.flySoundCooldown = 0
154+
player.flyTurnCooldown = 0
98155
player.inputPermissions.setPermissionCategory(InputPermissionCategory.Movement, false)
99156
break;
100157

101158
case States.MOON_JUMP:
102-
ignoreFall.set(player.id, true)
103-
player.applyImpulse(V3.make(0, -player.getVelocity().y + 0.75, 0))
104-
let molangSize1 = new MolangVariableMap(); molangSize1.setFloat("size", 1.0 / 2.0)
105-
let molangSize2 = new MolangVariableMap(); molangSize2.setFloat("size", 1.3 / 2.0)
106-
let molangSize3 = new MolangVariableMap(); molangSize3.setFloat("size", 1.5 / 2.0)
107-
player.spawnParticle("whynot:moon_jump", V3.add(player.location, V3.make(0, 0, 0)), molangSize1)
108-
player.spawnParticle("whynot:moon_jump", V3.add(player.location, V3.make(0, -0.2, 0)), molangSize2)
109-
player.spawnParticle("whynot:moon_jump", V3.add(player.location, V3.make(0, -0.4, 0)), molangSize3)
110-
player.playSound("moon_jump")
111-
airJumps.set(player.id, (airJumps.get(player.id) ?? 0) - 1)
159+
player.airJumps--
160+
player.ignoreFall = true
161+
player.applyImpulse(V3.make(0, -player.getVelocity().y + moonJumpForce, 0))
162+
playSoundFrom(player, "moon_jump")
163+
164+
// Particles
165+
let molangSize1 = new MolangVariableMap(); molangSize1.setFloat("size", moonJumpSize1)
166+
let molangSize2 = new MolangVariableMap(); molangSize2.setFloat("size", moonJumpSize2)
167+
let molangSize3 = new MolangVariableMap(); molangSize3.setFloat("size", moonJumpSize3)
168+
const pos = player.location
169+
player.spawnParticle("whynot:moon_jump", V3.make(pos.x, pos.y + moonJumpPos1, pos.z), molangSize1)
170+
player.spawnParticle("whynot:moon_jump", V3.make(pos.x, pos.y + moonJumpPos2, pos.z), molangSize2)
171+
player.spawnParticle("whynot:moon_jump", V3.make(pos.x, pos.y + moonJumpPos3, pos.z), molangSize3)
112172

113173
changeState(player, States.NORMAL)
114174
break;
115175

116176
case States.DASH:
117177
const dir = player.getViewDirection()
118-
let vel = V3.normalize(V3.make(dir.x, 0, dir.z ))
178+
const vel = V3.normalize(V3.make(dir.x, 0, dir.z))
119179
const dirMap = new MolangVariableMap();
120180
dirMap.setVector3("direction", V3.scale(vel, -1))
121-
player.spawnParticle("whynot:dash", entityCenter(player) ?? player.location, dirMap)
122-
player.addEffect(MinecraftEffectTypes.SlowFalling, 5, {showParticles: false})
123-
player.playSound("dash")
181+
player.spawnParticle("whynot:dash", player.center, dirMap)
182+
player.addEffect(MinecraftEffectTypes.SlowFalling, dashSlowFallTime, {showParticles: false})
183+
playSoundFrom(player, "dash")
124184

185+
player.dashCooldown = dashCooldownTime
125186
player.clearVelocity()
126-
player.applyImpulse(V3.add(V3.scale(vel, 1.0), V3.make(0,0.1,0)))
187+
player.applyImpulse(V3.make(vel.x * dashForce, dashLift, vel.z * dashForce))
127188

128189
changeState(player, States.NORMAL)
129190
break;
@@ -148,26 +209,29 @@ export function main() {
148209
world.getAllPlayers().forEach(player => changeState(player, States.NORMAL))
149210
world.beforeEvents.entityHurt.subscribe(ev => {
150211
if (ev.damageSource.cause != EntityDamageCause.fall) return
151-
if (!ev.hurtEntity.isValid || ev.hurtEntity.typeId != "minecraft:player") return
152-
if (!ignoreFall.get(ev.hurtEntity.id)) return
212+
213+
const player = ev.hurtEntity as Player
214+
if (!player.isValid || player.typeId != "minecraft:player") return
215+
if (!player.ignoreFall) return
153216

154217
ev.cancel = true
155218
})
156219
world.afterEvents.playerButtonInput.subscribe(({button, newButtonState, player}) => {
157220
const pressed = newButtonState == ButtonState.Pressed
158221
if (!entityHasSlotTag(player, EquipmentSlot.Mainhand, "whynot:light")) return;
159222

160-
if (button == InputButton.Sneak && newButtonState == ButtonState.Pressed && player.state == States.NORMAL) {
223+
if (button == InputButton.Sneak && newButtonState == ButtonState.Pressed &&
224+
player.state == States.NORMAL && player.dashCooldown <= 0) {
161225
changeState(player, States.DASH)
162226
}
163227
if (button != InputButton.Jump) return
164-
if (((airTime.get(player.id) ?? 0) > 2) && pressed && player.state == States.NORMAL) {
228+
if (player.airTime >= airborneAirtime && pressed && player.state == States.NORMAL) {
165229
// Activate fly
166230
if (player.fCooldown <= 0 && player.isSneaking) {
167231
changeState(player, States.FLYING)
168232
}
169233
// Moon jump
170-
else if ((airJumps.get(player.id) ?? 0) > 0) {
234+
else if (player.airJumps > 0) {
171235
changeState(player, States.MOON_JUMP)
172236
}
173237
}
@@ -189,55 +253,54 @@ function mainTick() {
189253
// Set Airtime
190254
if (player.isOnGround) {
191255
if (player.state != States.FLYING) {
192-
airJumps.set(player.id, maxAirJumps)
193-
ignoreFall.set(player.id, false)
194-
256+
player.airJumps = maxAirJumps
257+
player.ignoreFall = false
195258
}
196-
airTime.set(player.id, 0)
259+
player.airTime = 0
197260
}
198-
else airTime.set(player.id, (airTime.get(player.id) ?? 0) + 1)
261+
else player.airTime++
199262

200263
if (player.state == States.FLYING) {
201-
ignoreFall.set(player.id, true)
264+
player.ignoreFall = true
202265
player.fCooldown = fCooldownTime
203266

204267
// get move dir
205268
const viewDir = player.getViewDirection();
206-
const addVel = V3.normalize(flyingAngles.get(player.id) ?? viewDir);
269+
const addVel = V3.normalize(player.flyingAngles);
207270

208271
// Scale speed from health
209272
const health = player.getComponent(EntityHealthComponent.componentId) as EntityHealthComponent;
210-
const speed = remap(health.currentValue, health.effectiveMin, health.effectiveMax, 0.1, 1.0);
273+
const speed = remap(health.currentValue, health.effectiveMin, health.effectiveMax, flightSpeedMin, flightSpeedMax);
211274
const vel = V3.scale(addVel, speed)
212275
player.clearVelocity();
213276
player.applyImpulse(vel);
214277

215278
// Particles
216279
const starMap = new MolangVariableMap()
217-
const center = entityCenter(player) ?? player.location
218-
starMap.setFloat("size", 2.0)
219-
starMap.setFloat("frame", system.currentTick % 5)
280+
const center = player.center
281+
starMap.setFloat("size", flightStarSize)
282+
starMap.setFloat("frame", system.currentTick % flightStarFrames)
220283
player.spawnParticle(
221284
"whynot:light_star",
222285
center,
223286
starMap
224287
)
225288

226289
// Visuals
227-
const playerVisuals = visuals.get(player.id)
290+
const playerVisuals = player.lightFlightVisuals
228291
if (playerVisuals) {
229292
const matrix = V3.getBasisMatrix(addVel)
230-
playerVisuals.angle += (1 / 20.0) * TAU * 1.5 * speed
293+
playerVisuals.angle += (1 / 20.0) * TAU * spinTrailTurnsPerSecond * speed
231294

232295
let angle = playerVisuals.angle
233-
const spin1 = V3.make(Math.cos(angle) * 0.5, Math.sin(angle) * 0.5, 0)
234-
const spin2 = V3.make(Math.cos(angle + PI) * 0.5, Math.sin(angle + PI) * 0.5, 0)
296+
const spin1 = V3.make(Math.cos(angle) * spinTrailRadius, Math.sin(angle) * spinTrailRadius, 0)
297+
const spin2 = V3.make(Math.cos(angle + PI) * spinTrailRadius, Math.sin(angle + PI) * spinTrailRadius, 0)
235298

236299
const add1 = V3.add(V3.multiplyVectorByMatrix(spin1, matrix), center)
237300
const add2 = V3.add(V3.multiplyVectorByMatrix(spin2, matrix), center)
238301
if (playerVisuals.lastSpin1 && playerVisuals.lastSpin2) {
239-
drawLine("whynot:light_trail", player.dimension, add1, playerVisuals.lastSpin1, 0.075)
240-
drawLine("whynot:light_trail", player.dimension, add2, playerVisuals.lastSpin2, 0.075)
302+
drawLine("whynot:light_trail", player.dimension, add1, playerVisuals.lastSpin1, lightSpinTrailThickness)
303+
drawLine("whynot:light_trail", player.dimension, add2, playerVisuals.lastSpin2, lightSpinTrailThickness)
241304
}
242305
if (playerVisuals.lastTrail)
243306
drawLine("whynot:light_trail", player.dimension, center, playerVisuals.lastTrail, lightTrailThickness)
@@ -247,29 +310,26 @@ function mainTick() {
247310
}
248311

249312
// Get block in path and bounce if needed
250-
const blockHit = player.dimension.getBlockFromRay(entityCenter(player) ?? player.location, vel, {maxDistance: 4, includeLiquidBlocks:false, includePassableBlocks: false})
313+
const blockHit = player.dimension.getBlockFromRay(player.location, addVel, {maxDistance: 4, includeLiquidBlocks:false, includePassableBlocks: false})
251314
if (blockHit && blockHit.block.isSolid) {
252315
const bounced = V3.reflect(vel, directionVector(blockHit.face));
253-
flyingAngles.set(player.id, bounced);
254-
flyTurnCooldown.set(player.id, flyTurnCooldownTime)
255-
player.playSound("light_dash")
316+
player.flyingAngles = bounced
317+
player.flyTurnCooldown = flyTurnCooldownTime
318+
playSoundFrom(player, "light_dash")
256319
}
257320

258321
// If viewing angle change is significant change direction and did not bounce
259-
else if (V3.dot(viewDir, addVel) < flyTurnThreshold && (flyTurnCooldown.get(player.id) ?? 0) <= 0) {
260-
flyingAngles.set(player.id, viewDir);
261-
player.playSound("light_dash")
322+
else if (V3.dot(viewDir, addVel) < flyTurnThreshold && player.flyTurnCooldown <= 0) {
323+
player.flyingAngles = viewDir;
324+
playSoundFrom(player, "light_dash")
262325
}
263326

264327
// Reduce fly turn cooldown
265-
let currFlyTurnCooldown = flyTurnCooldown.get(player.id) ?? 0;
266-
if (currFlyTurnCooldown > 0) flyTurnCooldown.set(player.id, currFlyTurnCooldown - 1);
267-
268-
let currSoundCooldon = flySoundCooldown.get(player.id) ?? 0;
269-
if (currSoundCooldon > 0) flySoundCooldown.set(player.id, currSoundCooldon - 1);
328+
if (player.flyTurnCooldown > 0) player.flyTurnCooldown--;
329+
if (player.flySoundCooldown > 0) player.flySoundCooldown--;
270330
else {
271-
player.playSound("light_beam_loop", {volume: 10})
272-
flySoundCooldown.set(player.id, 7) //8.58
331+
playSoundFrom(player, "light_beam_loop")
332+
flySoundCooldown.set(player.id, flySoundDuration)
273333
}
274334
}
275335

@@ -279,6 +339,7 @@ function mainTick() {
279339
if (player.cCooldown > 0) player.cCooldown--;
280340
if (player.vCooldown > 0) player.vCooldown--;
281341
if (player.fCooldown > 0) player.fCooldown--;
342+
if (player.dashCooldown > 0) player.dashCooldown--;
282343

283344
// If player is holding light display cooldowns
284345
if (!entityHasSlotTag(player, EquipmentSlot.Mainhand, "whynot:light")) {
Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { Player } from "@minecraft/server";
1+
import { Player, Vector3 } from "@minecraft/server";
2+
3+
class LightFlightVisual {
4+
lastSpin1: Vector3 | undefined
5+
lastSpin2: Vector3 | undefined
6+
lastTrail: Vector3 | undefined
7+
angle: number
8+
}
9+
210
declare module "@minecraft/server" {
311
interface Player {
412
zCooldown: number;
@@ -7,5 +15,15 @@ declare module "@minecraft/server" {
715
vCooldown: number;
816
fCooldown: number;
917
state: number;
18+
19+
flyTurnCooldown: number;
20+
center: Vector3;
21+
flySoundCooldown: number;
22+
airTime: number;
23+
ignoreFall: boolean;
24+
airJumps: number;
25+
dashCooldown: number;
26+
flyingAngles: Vector3;
27+
lightFlightVisuals: LightFlightVisual;
1028
}
1129
}

scripts/utility.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ContainerSlot, Dimension, Direction, Entity, EntityEquippableComponent, EquipmentSlot, MolangVariableMap, RGBA, Vector3 } from "@minecraft/server";
1+
import { ContainerSlot, Dimension, Direction, Entity, EntityEquippableComponent, EquipmentSlot, MolangVariableMap, RGBA, Vector3, WorldSoundOptions } from "@minecraft/server";
22
import { V3 } from "./math/vectorUtils";
33
import { VECTOR3_DOWN, VECTOR3_EAST, VECTOR3_NORTH, VECTOR3_SOUTH, VECTOR3_UP, VECTOR3_WEST } from "@minecraft/math";
44

@@ -59,4 +59,10 @@ export function directionVector(face: Direction): Vector3 {
5959
export function entityCenter(entity: Entity): Vector3 | undefined {
6060
if (!entity || !entity.isValid) return
6161
return V3.shrink(V3.add(entity.location, entity.getHeadLocation()), 2)
62-
}
62+
}
63+
64+
export function playSoundFrom(entity: Entity, soundId: string, soundOptions?: WorldSoundOptions) {
65+
entity.dimension.playSound(soundId, entity.location, soundOptions)
66+
}
67+
68+
export const EFFECT_INFINITE = 20000000

0 commit comments

Comments
 (0)