Custom Scalers
You can effortlessly extend the Web Adaptive Performance system by creating custom Scalers. This is advantageous if you wish to dynamically optimize specific mechanics: for example, reducing crowd density, disabling heavy shaders, or simplifying enemy AI when FPS drops.
WebAP Architecture vs Unity AP
In the official package from Unity, creating custom Scalers requires complex configuration: generating a ScriptableObject, linking settings via interfaces, and choosing one of two mutually exclusive workflows.
In WebAP, everything operates on a Plug-and-Play basis.
You simply write a single C# script inheriting from WebScalerBase. The plugin core automatically detects your class and populates it into the global Scaler list in the Project Settings window, where you can enable it and configure its parameters visually.
Learning by Example
The optimal way to understand how to write custom Scalers is to examine the built-in ones. The source code for all base Scalers (Resolution, Shadows, LOD, etc.) resides in your project at:WebAdaptivePerformance/Runtime/Scalers/.
Custom Scaler Template
To create your Scaler, complete 3 simple steps:
- Inherit a class from
WebScalerBase. - Define default parameters in the constructor (
Target,Visual Impact,Max Level). - Override the lifecycle methods:
OnEnabled(),OnDisabled(), andOnLevel().
IL2CPP Stripping (Critical for WebGL)
When building a project for WebGL, the IL2CPP compiler aggressively strips "dead" code. Because the plugin instantiates your custom Scalers dynamically via reflection, the compiler will deem them unused and remove them from the build.
Always append the [UnityEngine.Scripting.Preserve] attribute to your custom classes. This guarantees that the Scaler will function in the release build.
Example: Texture Quality Scaler
Below is a comprehensive example of creating a Scaler that reduces texture resolution (Mipmap Limit).
using System;
using UnityEngine;
using GrindsetStudios.WebAdaptivePerformance.Scalers;
// Attributes are mandatory for UI display (Project Settings) and Code Stripping protection (IL2CPP)
[Serializable]
[UnityEngine.Scripting.Preserve]
public sealed class WebTextureQualityScaler : WebScalerBase
{
// A variable exclusively for storing the user's initial settings
private int _defaultTextureLimit;
public WebTextureQualityScaler()
{
// Designate that this Scaler reduces load on the video card
_target = ScalerTarget.GPU;
// Reducing texture resolution is highly noticeable, hence High
_visualImpact = ScalerVisualImpact.High;
// Establish 3 texture degradation steps: Half (1), Quarter (2), Eighth (3)
_maxLevel = 3;
}
// Invoked upon game startup or plugin activation
protected override void OnEnabled()
{
// Cache the original value to restore it upon Scaler deactivation
_defaultTextureLimit = QualitySettings.globalTextureMipmapLimit;
ApplyScale();
}
// Invoked upon plugin deactivation or manual Scaler removal
protected override void OnDisabled()
{
// Safely revert the game to its initial state
QualitySettings.globalTextureMipmapLimit = _defaultTextureLimit;
}
// Invoked every time the Indexer resolves to alter the quality level
protected override void OnLevel()
{
ApplyScale();
}
private void ApplyScale()
{
// The ScaleChanged() method recalculates the scale and returns true if it shifted
if (ScaleChanged())
{
// We deliberately avoid using the default value for calculations
// to prevent conflicts if the graphics were already at minimum.
//
// The globalTextureMipmapLimit parameter accepts integers:
// 0 (Full), 1 (Half), 2 (Quarter), 3 (Eighth).
// Our CurrentLevel (from 0 to 3) perfectly aligns with this logic.
QualitySettings.globalTextureMipmapLimit = CurrentLevel;
}
}
}Once you save this script, navigate to Edit -> Project Settings -> Adaptive Performance (Web). Expand the Scalers tab, and you will see your Texture Quality in the list of available modules.
Object Search Optimization
The OnLevel() method can be invoked frequently (during Cooldown triggers). Never utilize heavy methods like GameObject.Find() or GetComponent() within it. Always locate and cache the required components in the OnEnabled() method.
