fix(security & perf): implement bearer session tokens, salted pbkdf2, object pooling and background caching
This commit is contained in:
1 parent
258b1a9cb1
commit
7cd0792799
15 files changed
+1264
-105
No files matched your search
@@ -153,15 +153,19 @@ window.Plant = class Plant {
|
||||
this.shootTimer = 0;
|
||||
if (this.type === 'peashooter' && this.level === 3) {
|
||||
// Tier 3: Plasma Peashooter
|
||||
gameState.projectiles.push(new window.Projectile(this.x + 24, this.y - 12, this.row, 'plasma', 0, this.damage));
|
||||
if (gameState.spawnProjectile) gameState.spawnProjectile(this.x + 24, this.y - 12, this.row, 'plasma', 0, this.damage);
|
||||
else gameState.projectiles.push(new window.Projectile(this.x + 24, this.y - 12, this.row, 'plasma', 0, this.damage));
|
||||
} else if (this.type === 'snowpea' && this.level === 3) {
|
||||
// Tier 3: Freeze Snowpea
|
||||
const deepFreeze = Math.random() < 0.2;
|
||||
gameState.projectiles.push(new window.Projectile(this.x + 24, this.y - 12, this.row, deepFreeze ? 'freeze_snowpea' : 'snowpea', 0, this.damage));
|
||||
const pType = deepFreeze ? 'freeze_snowpea' : 'snowpea';
|
||||
if (gameState.spawnProjectile) gameState.spawnProjectile(this.x + 24, this.y - 12, this.row, pType, 0, this.damage);
|
||||
else gameState.projectiles.push(new window.Projectile(this.x + 24, this.y - 12, this.row, pType, 0, this.damage));
|
||||
} else {
|
||||
const isCrit = this.critChance && Math.random() < this.critChance;
|
||||
const projType = this.type === 'snowpea' ? 'snowpea' : 'pea';
|
||||
gameState.projectiles.push(new window.Projectile(this.x + 24, this.y - 12, this.row, projType, 0, this.damage, isCrit));
|
||||
if (gameState.spawnProjectile) gameState.spawnProjectile(this.x + 24, this.y - 12, this.row, projType, 0, this.damage, isCrit);
|
||||
else gameState.projectiles.push(new window.Projectile(this.x + 24, this.y - 12, this.row, projType, 0, this.damage, isCrit));
|
||||
}
|
||||
if (window.PvZAudio) window.PvZAudio.playShoot();
|
||||
}
|
||||
@@ -178,7 +182,8 @@ window.Plant = class Plant {
|
||||
this.shootTimer = 0;
|
||||
const targetX = targetZombie ? targetZombie.x : (hasBoss ? gameState.boss.x : 750);
|
||||
const projType = this.type === 'melonpult' ? 'melon' : 'cabbage';
|
||||
gameState.projectiles.push(new window.Projectile(this.x + 15, this.y - 10, this.row, projType, 0, this.damage, false, targetX));
|
||||
if (gameState.spawnProjectile) gameState.spawnProjectile(this.x + 15, this.y - 10, this.row, projType, 0, this.damage, false, targetX);
|
||||
else gameState.projectiles.push(new window.Projectile(this.x + 15, this.y - 10, this.row, projType, 0, this.damage, false, targetX));
|
||||
if (window.PvZAudio) window.PvZAudio.playShoot();
|
||||
}
|
||||
}
|
||||
@@ -191,14 +196,16 @@ window.Plant = class Plant {
|
||||
this.repeaterThirdPea -= dt;
|
||||
if (this.repeaterThirdPea <= 0) {
|
||||
const pType = this.level === 3 ? 'firepea' : 'pea';
|
||||
gameState.projectiles.push(new window.Projectile(this.x + 24, this.y - 12, this.row, pType, 0, 22));
|
||||
if (gameState.spawnProjectile) gameState.spawnProjectile(this.x + 24, this.y - 12, this.row, pType, 0, 22);
|
||||
else gameState.projectiles.push(new window.Projectile(this.x + 24, this.y - 12, this.row, pType, 0, 22));
|
||||
if (window.PvZAudio) window.PvZAudio.playShoot();
|
||||
}
|
||||
} else if (this.repeaterSecondPea > 0) {
|
||||
this.repeaterSecondPea -= dt;
|
||||
if (this.repeaterSecondPea <= 0) {
|
||||
const pType = this.level === 3 ? 'firepea' : 'pea';
|
||||
gameState.projectiles.push(new window.Projectile(this.x + 24, this.y - 12, this.row, pType, 0, 22));
|
||||
if (gameState.spawnProjectile) gameState.spawnProjectile(this.x + 24, this.y - 12, this.row, pType, 0, 22);
|
||||
else gameState.projectiles.push(new window.Projectile(this.x + 24, this.y - 12, this.row, pType, 0, 22));
|
||||
if (window.PvZAudio) window.PvZAudio.playShoot();
|
||||
}
|
||||
} else if (this.shootTimer >= this.shootInterval) {
|
||||
@@ -206,7 +213,8 @@ window.Plant = class Plant {
|
||||
if (hasZombie) {
|
||||
this.shootTimer = 0;
|
||||
const pType = this.level === 3 ? 'firepea' : 'pea';
|
||||
gameState.projectiles.push(new window.Projectile(this.x + 24, this.y - 12, this.row, pType, 0, 22));
|
||||
if (gameState.spawnProjectile) gameState.spawnProjectile(this.x + 24, this.y - 12, this.row, pType, 0, 22);
|
||||
else gameState.projectiles.push(new window.Projectile(this.x + 24, this.y - 12, this.row, pType, 0, 22));
|
||||
this.repeaterSecondPea = 0.16;
|
||||
if (this.level >= 2 && Math.random() < 0.25) {
|
||||
this.repeaterThirdPea = 0.32; // Tier 2+ bonus 3rd pea!
|
||||
@@ -223,7 +231,8 @@ window.Plant = class Plant {
|
||||
const hasZombie = gameState.zombies.some(z => z.row === this.row && z.x > this.x && (z.x - this.x) < 330 && z.health > 0 && !z.toRemove);
|
||||
if (hasZombie) {
|
||||
this.shootTimer = 0;
|
||||
gameState.projectiles.push(new window.Projectile(this.x + 20, this.y - 8, this.row, 'fume'));
|
||||
if (gameState.spawnProjectile) gameState.spawnProjectile(this.x + 20, this.y - 8, this.row, 'fume');
|
||||
else gameState.projectiles.push(new window.Projectile(this.x + 20, this.y - 8, this.row, 'fume'));
|
||||
if (window.PvZAudio) window.PvZAudio.playShoot();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
window.Projectile = class Projectile {
|
||||
constructor(x, y, row, type = 'pea', vy = 0, damage = 20, isCrit = false, targetX = 750) {
|
||||
this.pierceHits = new Set();
|
||||
this.init(x, y, row, type, vy, damage, isCrit, targetX);
|
||||
}
|
||||
|
||||
init(x, y, row, type = 'pea', vy = 0, damage = 20, isCrit = false, targetX = 750) {
|
||||
if (typeof isCrit === 'number' && isCrit > 1 && typeof damage === 'number' && damage >= 100) {
|
||||
targetX = damage;
|
||||
damage = (typeof vy === 'number') ? vy : 80;
|
||||
vy = 0;
|
||||
isCrit = false;
|
||||
} else if (typeof isCrit === 'number' && typeof damage === 'number' && isCrit >= 100) {
|
||||
targetX = isCrit;
|
||||
isCrit = false;
|
||||
}
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.startX = x;
|
||||
@@ -37,10 +52,15 @@ window.Projectile = class Projectile {
|
||||
this.freezes = type === 'freeze_snowpea';
|
||||
this.pierces = type === 'fume' || type === 'plasma';
|
||||
this.maxPierces = type === 'plasma' ? 2 : 999;
|
||||
this.pierceHits = new Set();
|
||||
if (this.pierceHits) {
|
||||
this.pierceHits.clear();
|
||||
} else {
|
||||
this.pierceHits = new Set();
|
||||
}
|
||||
this.lobProgress = 0;
|
||||
this.toRemove = false;
|
||||
this.animTime = 0;
|
||||
this.hitCount = 0;
|
||||
}
|
||||
|
||||
update(dt) {
|
||||
@@ -212,3 +232,38 @@ window.Projectile = class Projectile {
|
||||
ctx.restore();
|
||||
}
|
||||
};
|
||||
|
||||
// Reusable Object Pool for Projectiles (Eliminates GC churn & frame drops)
|
||||
window.ProjectilePool = class ProjectilePool {
|
||||
constructor(initialCapacity = 60) {
|
||||
this.pool = [];
|
||||
for (let i = 0; i < initialCapacity; i++) {
|
||||
this.pool.push(new window.Projectile(0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
get(x, y, row, type = 'pea', vy = 0, damage = 20, isCrit = false, targetX = 750) {
|
||||
const proj = this.pool.length > 0 ? this.pool.pop() : new window.Projectile(x, y, row, type, vy, damage, isCrit, targetX);
|
||||
proj.init(x, y, row, type, vy, damage, isCrit, targetX);
|
||||
return proj;
|
||||
}
|
||||
|
||||
release(proj) {
|
||||
if (!proj) return;
|
||||
proj.toRemove = false;
|
||||
if (proj.pierceHits) proj.pierceHits.clear();
|
||||
this.pool.push(proj);
|
||||
}
|
||||
|
||||
releaseAll(projectiles) {
|
||||
if (!Array.isArray(projectiles)) return;
|
||||
for (const p of projectiles) {
|
||||
this.release(p);
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.pool = [];
|
||||
}
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user