Performance Tuning
Performance Tuning
Section titled “Performance Tuning”This guide helps you optimize Glamour’s particle system for the best balance between visual quality and server performance.
Understanding Performance Impact
Section titled “Understanding Performance Impact”What Affects Performance
Section titled “What Affects Performance”Glamour’s performance impact comes from three main sources:
- Particle Rendering: Sending particle packets to clients
- Condition Checking: Evaluating persistent particle conditions
- State Management: Reading/writing particle state to database
Performance Metrics
Section titled “Performance Metrics”Monitor performance with /persistentparticles stats:
=== Persistent Particle Stats ===Loaded Configs: 12Active Pokemon: 47Renders This Tick: 28Max Renders/Tick: 100Max Renders/Config: 50LOS Tests: 15/50Cache Hits: 142Cache Misses: 23Key Metrics:
- Renders This Tick: Current particle spawns this tick
- Max Renders/Tick: Global limit (100 default)
- LOS Tests: Line-of-sight checks performed
- Cache Hits/Misses: Condition matching cache efficiency
Configuration Optimization
Section titled “Configuration Optimization”Interval Tuning
Section titled “Interval Tuning”intervalTicks has the biggest performance impact.
Performance Cost by Interval:
| intervalTicks | Spawns/Second | Performance Cost |
|---|---|---|
| 10 | 2.0 | Very High ❌ |
| 20 | 1.0 | High ⚠️ |
| 40 | 0.5 | Medium ✅ |
| 60 | 0.33 | Low ✅ |
| 100 | 0.2 | Very Low ✅ |
Recommendations:
// Ambient particles (continuous){ "intervalTicks": 40 // Good balance for ambient}
// Sendout particles (one-time){ "intervalTicks": 100 // Can be higher, plays once}
// Persistent particles (always active){ "intervalTicks": 60 // Conservative for always-on effects}Particle Count Optimization
Section titled “Particle Count Optimization”particleCount multiplies network traffic.
Impact Analysis:
// Low impact (recommended for common particles){ "particleCount": 1, "intervalTicks": 40}// = 1 particle every 2 seconds
// Medium impact (good for rare particles){ "particleCount": 3, "intervalTicks": 40}// = 3 particles every 2 seconds
// High impact (use sparingly){ "particleCount": 5, "intervalTicks": 20}// = 5 particles per secondGuideline: particleCount * (20 / intervalTicks) should be < 2 for most particles.
Distance Culling
Section titled “Distance Culling”maxDistance determines render range.
Distance vs Performance:
| maxDistance | Performance | Use Case |
|---|---|---|
| 16 | Excellent ✅ | Subtle effects |
| 24 | Very Good ✅ | Common particles |
| 32 | Good ✅ | Standard distance |
| 48 | Moderate ⚠️ | Rare particles |
| 64 | Poor ❌ | Epic only |
| 96+ | Very Poor ❌ | Avoid |
Recommendations:
// Common/Uncommon{ "maxDistance": 24}
// Rare/Epic{ "maxDistance": 32}
// Legendary (if must use long range){ "maxDistance": 48, "onlyWhenVisible": true // REQUIRED at this distance}Radius Optimization
Section titled “Radius Optimization”radius affects visual spread but not performance directly. However, larger radius with high particle count = more visual clutter.
Balanced Approach:
// Subtle effect{ "radius": 0.5, "particleCount": 1}
// Standard effect{ "radius": 1.0, "particleCount": 3}
// Large effect (reduce count!){ "radius": 2.0, "particleCount": 2 // Fewer particles for larger area}Visibility Optimization
Section titled “Visibility Optimization”Visibility Check Comparison
Section titled “Visibility Check Comparison”| Check Type | CPU Cost | Accuracy | When to Use |
|---|---|---|---|
| None | Free | N/A | Always-on particles |
onlyWhenVisible | Very Low | ~80% | Most particles |
requiresLOS | High | 100% | Epic+ only |
Using onlyWhenVisible
Section titled “Using onlyWhenVisible”Cheap view-cone check - Use for most particles:
{ "onlyWhenVisible": true, "requiresLOS": false}Benefits:
- Minimal CPU cost
- Culls ~80% of off-screen particles
- No visual impact when looking at Pokemon
Recommendation: Enable for all particles with intervalTicks < 60.
Using requiresLOS
Section titled “Using requiresLOS”Expensive raytrace check - Use sparingly:
{ "onlyWhenVisible": true, "requiresLOS": true}When to Use:
- Legendary/Mythical rarity only
intervalTicks>= 40maxDistance>= 48- Visual effect justifies cost
Global LOS Budget: Default 50 tests/tick. When exceeded, falls back to view-cone check.
Optimization Strategy
Section titled “Optimization Strategy”Tier 1: Common/Uncommon (No visibility check)
{ "intervalTicks": 60, "particleCount": 1, "maxDistance": 24, "onlyWhenVisible": false, "requiresLOS": false}Tier 2: Rare (View-cone check)
{ "intervalTicks": 40, "particleCount": 3, "maxDistance": 32, "onlyWhenVisible": true, "requiresLOS": false}Tier 3: Epic (View-cone check, longer range)
{ "intervalTicks": 40, "particleCount": 4, "maxDistance": 48, "onlyWhenVisible": true, "requiresLOS": false}Tier 4: Legendary/Mythical (Full LOS)
{ "intervalTicks": 50, "particleCount": 5, "maxDistance": 48, "onlyWhenVisible": true, "requiresLOS": true}Persistent Particle Optimization
Section titled “Persistent Particle Optimization”Priority-Based Culling
Section titled “Priority-Based Culling”Higher priority = checked first. Optimize by priority:
High Priority (Checked Often):
{ "priority": 200, "conditions": { "species": ["mewtwo"], // Very specific "isShiny": true }}Only checks Mewtwo, skips others quickly.
Low Priority (Checked Less):
{ "priority": 50, "conditions": { "isShiny": true // Checks all Pokemon }}Checked last, so other configs short-circuit first.
Condition Complexity
Section titled “Condition Complexity”Fast Conditions:
isShiny(single boolean check)species(simple string match)level.exact(single int comparison)
Medium Conditions:
types(array contains)forms(array contains)healthPercent(calculation required)
Slow Conditions:
biomes(world query)weather(world query)timeOfDay(world query)
Optimization: Combine fast conditions first:
// Good: Fast condition first{ "conditions": { "species": ["charizard"], // Fast, eliminates most "biomes": ["nether"] // Slow, checked only for Charizard }}
// Poor: Slow condition affects all{ "conditions": { "biomes": ["nether"], // Checked for every Pokemon! "species": ["charizard"] }}Cache Optimization
Section titled “Cache Optimization”Glamour caches condition matches. View cache performance:
Cache Hits: 142Cache Misses: 23Hit Rate: 142/(142+23) = 86% (good!)
Target: >80% cache hit rate
If Low:
- Pokemon are changing conditions frequently
- Consider less dynamic conditions (avoid weather/time if possible)
- Increase cache TTL (requires code change)
Server-Wide Settings
Section titled “Server-Wide Settings”Global Render Limits
Section titled “Global Render Limits”Edit Glamour’s main config to set global limits:
{ "particleSystem": { "maxRendersPerTick": 100, "maxRendersPerConfig": 50, "maxLOSTestsPerTick": 50 }}Conservative Settings (Small server, < 10 players):
{ "maxRendersPerTick": 50, "maxRendersPerConfig": 25, "maxLOSTestsPerTick": 25}Balanced Settings (Medium server, 10-30 players):
{ "maxRendersPerTick": 100, "maxRendersPerConfig": 50, "maxLOSTestsPerTick": 50}High Performance (Large server, 30+ players):
{ "maxRendersPerTick": 200, "maxRendersPerConfig": 100, "maxLOSTestsPerTick": 100}Database Optimization
Section titled “Database Optimization”SQLite (Small Servers)
Section titled “SQLite (Small Servers)”Pros:
- Simple setup
- No external dependencies
- Good for < 20 players
Cons:
- Single-threaded writes
- Can lock under high load
Optimization:
{ "database": { "type": "sqlite", "path": "glamour_data.db", "pragmas": { "journal_mode": "WAL", "synchronous": "NORMAL" } }}MySQL (Medium-Large Servers)
Section titled “MySQL (Medium-Large Servers)”Pros:
- Concurrent writes
- Scales well
- Good for 20+ players
Setup:
{ "database": { "type": "mysql", "host": "localhost", "port": 3306, "database": "glamour", "username": "glamour_user", "password": "secure_password", "poolSize": 10 }}Optimization:
- Use connection pooling (
poolSize: 10) - Place MySQL on same machine as game server
- Use SSD for MySQL data directory
MongoDB (Very Large Servers)
Section titled “MongoDB (Very Large Servers)”Pros:
- Horizontal scaling
- Excellent for 50+ players
- Document-based (natural fit for JSON state)
Setup:
{ "database": { "type": "mongodb", "connectionString": "mongodb://localhost:27017/glamour", "poolSize": 20 }}Client-Side Performance
Section titled “Client-Side Performance”Client Particle Settings
Section titled “Client Particle Settings”Educate players on client performance:
Low-End PCs:
- Video Settings → Particles: Minimal
- Reduce render distance
- Disable smooth lighting
Medium PCs:
- Video Settings → Particles: Decreased
High-End PCs:
- Video Settings → Particles: All
- Full render distance
Visual vs Performance Trade-offs
Section titled “Visual vs Performance Trade-offs”If players report FPS drops:
-
Reduce Global Particle Count:
- Lower
particleCountin all configs by 1 - Example: 3 → 2
- Lower
-
Increase Intervals:
- Increase
intervalTicksby 10-20 - Example: 40 → 50
- Increase
-
Reduce Range:
- Lower
maxDistanceby 8 blocks - Example: 32 → 24
- Lower
-
Disable High-Tier Effects:
- Temporarily disable Legendary/Mythical particles
- Re-enable after optimization
Monitoring and Diagnostics
Section titled “Monitoring and Diagnostics”Performance Monitoring Schedule
Section titled “Performance Monitoring Schedule”Every Hour:
/persistentparticles statsCheck if renders are hitting limits.
Daily: Review server TPS:
/tpsIf TPS < 18, investigate particle impact.
Weekly: Analyze logs for warnings:
grep "Glamour.*performance" logs/latest.logPerformance Warning Signs
Section titled “Performance Warning Signs”Red Flags:
- Renders hitting max limit (100/100)
- LOS tests hitting limit (50/50)
- TPS drops when many Pokemon spawn
- Players reporting FPS issues
Yellow Flags:
- Renders consistently > 80
- LOS tests > 40
- Cache hit rate < 70%
Profiling
Section titled “Profiling”If performance issues persist:
-
Use Spark Profiler:
/spark profiler start# Wait 60 seconds/spark profiler stop -
Check Glamour’s CPU Usage: Look for
aster.amo.glamourin profile -
Identify Hotspots:
- Particle rendering?
- Condition checking?
- Database writes?
Optimization Examples
Section titled “Optimization Examples”Before Optimization
Section titled “Before Optimization”{ "id": "laggy_effect", "priority": 100, "settings": { "intervalTicks": 10, // Too frequent! "particleCount": 8, // Too many! "maxDistance": 96, // Too far! "onlyWhenVisible": false, // No culling! "requiresLOS": false }, "conditions": { "types": ["normal"] // Matches too many Pokemon! }}Performance: 🔴 Very Poor
- Spawns 16 particles/second per Pokemon
- Long render distance
- No visibility optimization
- Matches most Pokemon
After Optimization
Section titled “After Optimization”{ "id": "optimized_effect", "priority": 100, "settings": { "intervalTicks": 50, // ✅ More reasonable "particleCount": 3, // ✅ Reduced "maxDistance": 32, // ✅ Standard distance "onlyWhenVisible": true, // ✅ View-cone culling "requiresLOS": false }, "conditions": { "species": ["snorlax", "blissey"] // ✅ More specific }}Performance: 🟢 Good
- Spawns 1.2 particles/second per Pokemon
- Reasonable range
- Visibility optimization
- Specific targets
Impact Reduction: ~93% fewer particles spawned!
Quick Reference
Section titled “Quick Reference”Performance Checklist
Section titled “Performance Checklist”-
intervalTicks>= 40 for common particles -
intervalTicks>= 60 for persistent particles -
particleCount<= 3 for common particles -
maxDistance<= 32 for most particles -
onlyWhenVisible: truefor particles with interval < 60 -
requiresLOSonly on Epic+ rarity - Specific conditions (avoid broad matches)
- Priority structure prevents unnecessary checks
- Database connection optimized
- Regular monitoring with
/persistentparticles stats
Performance Budget
Section titled “Performance Budget”For a 20-player server:
Conservative Budget:
- 10 persistent particle configs
- 50 total renders/tick
- 25 LOS tests/tick
Balanced Budget:
- 20 persistent particle configs
- 100 total renders/tick
- 50 LOS tests/tick
Aggressive Budget:
- 30+ persistent particle configs
- 200 total renders/tick
- 100 LOS tests/tick
Scale based on server hardware and player count.