fix(security & perf): implement bearer session tokens, salted pbkdf2, object pooling and background caching

This commit is contained in:
2026-09-17 13:14:31 +00:00
parent 258b1a9cb1
commit 7cd0792799
15 changed files with 1264 additions and 105 deletions
+86 -29
View File
@@ -1,10 +1,63 @@
// Particle Object Pool to eliminate GC churn during large waves
window.ParticlePool = class ParticlePool {
constructor(initialCapacity = 150) {
this.pool = [];
for (let i = 0; i < initialCapacity; i++) {
this.pool.push({
x: 0,
y: 0,
vx: 0,
vy: 0,
color: '#ffffff',
size: 3,
life: 0,
maxLife: 0
});
}
}
get(x, y, vx, vy, color = '#8bc34a', size = 3, life = 0.35) {
const p = this.pool.length > 0 ? this.pool.pop() : { x: 0, y: 0, vx: 0, vy: 0, color: '#ffffff', size: 3, life: 0, maxLife: 0 };
p.x = x;
p.y = y;
p.vx = vx;
p.vy = vy;
p.color = color;
p.size = size;
p.life = life;
p.maxLife = life;
return p;
}
release(p) {
if (!p) return;
p.life = 0;
this.pool.push(p);
}
releaseAll(particles) {
if (!Array.isArray(particles)) return;
for (let i = 0; i < particles.length; i++) {
this.release(particles[i]);
}
}
clear() {
this.pool = [];
}
};
// Combat & Collision Resolution System (with Bowling Ricochet & Coin Drops)
window.CombatSystem = class CombatSystem {
constructor() {
this.particlePool = new window.ParticlePool(150);
this.particles = [];
}
reset() {
if (this.particlePool) {
this.particlePool.releaseAll(this.particles);
}
this.particles = [];
}
@@ -12,45 +65,50 @@ window.CombatSystem = class CombatSystem {
for (let i = 0; i < count; i++) {
const angle = Math.random() * Math.PI * 2;
const speed = 40 + Math.random() * 80;
this.particles.push({
this.particles.push(this.particlePool.get(
x,
y,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed,
Math.cos(angle) * speed,
Math.sin(angle) * speed,
color,
size: 3 + Math.random() * 3,
life: 0.35,
maxLife: 0.35
});
3 + Math.random() * 3,
0.35
));
}
}
createExplosionParticles(x, y) {
const colors = ['#ff5722', '#ff9800', '#ffeb3b', '#424242'];
for (let i = 0; i < 35; i++) {
const angle = Math.random() * Math.PI * 2;
const speed = 50 + Math.random() * 200;
const colors = ['#ff5722', '#ff9800', '#ffeb3b', '#424242'];
this.particles.push({
this.particles.push(this.particlePool.get(
x,
y,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed,
color: colors[Math.floor(Math.random() * colors.length)],
size: 5 + Math.random() * 8,
life: 0.65,
maxLife: 0.65
});
Math.cos(angle) * speed,
Math.sin(angle) * speed,
colors[Math.floor(Math.random() * colors.length)],
5 + Math.random() * 8,
0.65
));
}
}
update(dt, gameState) {
// 1. Update Particles
for (const p of this.particles) {
// 1. Update Particles in-place (eliminating GC allocations)
let writeIdx = 0;
for (let i = 0; i < this.particles.length; i++) {
const p = this.particles[i];
p.x += p.vx * dt;
p.y += p.vy * dt;
p.life -= dt;
if (p.life > 0) {
this.particles[writeIdx++] = p;
} else {
this.particlePool.release(p);
}
}
this.particles = this.particles.filter(p => p.life > 0);
this.particles.length = writeIdx;
// 2. Projectiles vs Zombies
for (const proj of gameState.projectiles) {
@@ -233,16 +291,15 @@ window.CombatSystem = class CombatSystem {
// Tree of Wisdom Cheat: Daisies
if (gameState.tree && gameState.tree.cheats && gameState.tree.cheats.daisies) {
for (let i = 0; i < 6; i++) {
this.particles.push({
x: zombie.x + (Math.random() - 0.5) * 30,
y: zombie.y + 10 + (Math.random() - 0.5) * 16,
vx: 0,
vy: -8,
color: '#ffffff',
size: 4,
life: 2.5,
maxLife: 2.5
});
this.particles.push(this.particlePool.get(
zombie.x + (Math.random() - 0.5) * 30,
zombie.y + 10 + (Math.random() - 0.5) * 16,
0,
-8,
'#ffffff',
4,
2.5
));
}
}