-
Notifications
You must be signed in to change notification settings - Fork 0
Mod Developer Guide
Greenlight is for client features that should stay off on multiplayer unless the server explicitly allows them. Your mod owns the feature, config UI, and behavior. Greenlight only answers: did the current server grant this feature, and with what limits?
Use:
me.flashyreese.mods.greenlight.featureIf your code imports Greenlight API classes, one of these must be true:
- You bundle
greenlight-apiwith your mod for optional compatibility. - You require the full Greenlight runtime mod, which already contains the API classes.
Do not use compileOnly("me.flashyreese.mods:greenlight-api:...") by itself for optional support. Users without Greenlight would be missing the API classes at runtime.
Use this when your mod should still launch for players who do not have Greenlight installed.
Compile against greenlight-api and bundle that API jar with your mod. Do not declare the full greenlight loader mod as required.
When the full runtime is missing:
-
Greenlight.isAvailable()returnsfalse. - Feature registration is accepted.
- Custom policy sources are ignored.
- Every query returns denied.
Use this when your mod requires Greenlight to be installed.
Depend on the loader jar for your platform and declare greenlight as required in your mod metadata. Do not bundle greenlight-api separately.
repositories {
maven("https://maven.flashyreese.me/releases")
// Only for snapshot testing.
maven("https://maven.flashyreese.me/snapshots")
}Modrinth Maven can be used as a fallback for released runtime jars:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = uri("https://api.modrinth.com/maven")
}
}
filter {
includeGroup("maven.modrinth")
}
}
}Prefer FlashyReese Maven when possible. It has the split API artifact and normal Maven metadata.
val greenlightVersion = "0.1.0+mc26.2"FlashyReese Maven artifacts:
me.flashyreese.mods:greenlight-api:<version>
me.flashyreese.mods:greenlight-fabric:<version>
me.flashyreese.mods:greenlight-neoforge:<version>
Use greenlight-api for optional API support. Use the loader-specific artifact for hard dependencies.
Modrinth Maven fallback:
dependencies {
modImplementation("maven.modrinth:EE4vxUHj:<modrinth-version-or-version-id>")
}Do not use Modrinth Maven for the optional API path.
Fabric Loom:
dependencies {
compileOnly("me.flashyreese.mods:greenlight-api:$greenlightVersion")
include("me.flashyreese.mods:greenlight-api:$greenlightVersion")
}Fabric metadata:
{
"suggests": {
"greenlight": ">=0.1.0"
}
}NeoForge metadata:
[[dependencies.yourmod]]
modId = "greenlight"
type = "optional"
versionRange = "[0.1.0,)"
ordering = "AFTER"
side = "CLIENT"Do not relocate the me.flashyreese.mods.greenlight package.
Fabric Loom:
dependencies {
modImplementation("me.flashyreese.mods:greenlight-fabric:$greenlightVersion")
}Fabric metadata:
{
"depends": {
"greenlight": ">=0.1.0"
}
}NeoForge metadata:
[[dependencies.yourmod]]
modId = "greenlight"
type = "required"
versionRange = "[0.1.0,)"
ordering = "NONE"
side = "CLIENT"public static final ClientFeature<CaveTintPolicy> CAVE_TINT = Greenlight
.feature(Identifier.fromNamespaceAndPath("examplemod", "cave_tint"))
.decoder(1, CaveTintPolicy::fromJson)
.register();The feature ID maps to this server policy file:
assets/examplemod/client_features/v1/cave_tint.json
Optional<CaveTintPolicy> policy = CAVE_TINT.policy();
if (policy.isEmpty()) {
return; // No trusted server grant.
}
float strength = Math.min(localConfig.caveTintStrength(), policy.get().maxStrength());
applyCaveTint(strength);Do not cache an allowed result across worlds or servers. The handle already caches decoded settings until Greenlight sees a policy change.
Your decoder should be strict:
- Missing policy means denied.
-
enabled: falsemeans denied. - Unknown
settings_versionmeans denied. - A thrown decoder exception means denied.
- A decoder that returns
nullmeans denied.
Treat a grant as permission plus limits, not as a command to force the player's local setting on.
Document this for every Greenlight feature:
- Feature ID.
- Policy file path.
- Supported
settings_version. - Full JSON example.
- Every key inside
settings. - Most restrictive behavior when a key is missing.
Most mods should use the built-in server resource-pack source.
Only register a FeaturePolicySource if you have another trusted server channel:
Greenlight.registerSource(new MyPayloadPolicySource());A custom source must clear or change its fingerprint when the server context ends. Stale grants must not survive disconnects.