Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
e66a935
start on the new input pipeline
isXander Oct 9, 2026
560c6d0
activator system & more
isXander Oct 10, 2026
b143851
flesh out the pipeline and start wiring things up
isXander Oct 11, 2026
006d8e4
forgot to git add
isXander Oct 12, 2026
d1286ce
allow gyro low pass cutoff hz to be configured
isXander Oct 12, 2026
b2df975
start to wire up the drivers to the new event system; start rewriting…
isXander Oct 12, 2026
dbebcc3
rewrite controller manager and start to wire up fixedupdate/update sy…
isXander Oct 14, 2026
a1ed3ce
extract some of Controlify into ControllerCoordinator; start to reimp…
isXander Oct 16, 2026
7683b39
wire up controller mapping to pipeline
isXander Oct 16, 2026
b7813fb
implement data-driven controller mappings; bit of reorganisation
isXander Oct 16, 2026
92928d6
repackage everything into api and impl packages; rewrite rumble api
isXander Oct 19, 2026
3fdbdb0
repackage the fabric and neoforge sourcesets
isXander Oct 19, 2026
ce182b5
it builds! it runs!
isXander Oct 22, 2026
a25c6da
remove deadzone debugging
isXander Oct 22, 2026
6e32a98
fix drivers never updating
isXander Oct 22, 2026
78853df
fix contextual domains loading from bad path; added warning to catch …
isXander Oct 22, 2026
8909d7a
make look input including gyro per-frame
isXander Oct 22, 2026
09a185b
add unit test for deadzone stage
isXander Oct 22, 2026
80dbabc
bump version
isXander Oct 22, 2026
ac82e56
fix game tests
isXander Oct 22, 2026
9a9b24a
spotless
isXander Oct 22, 2026
8650878
screenop 2
isXander Oct 22, 2026
3290899
more screenop 2 stuff
isXander Oct 23, 2026
5ace655
fix sodium screenop and misc screenop stuff
isXander Oct 23, 2026
1075911
fix test
isXander Oct 23, 2026
a6f3c39
fuck you spotless
isXander Oct 23, 2026
0e2174b
address a few small bugs
isXander Oct 23, 2026
03179de
stuff wasnt staged
isXander Oct 23, 2026
34586f7
stuff
isXander Oct 24, 2026
befcef8
make run configs rundir proper
isXander Oct 27, 2026
97a2236
action layer system; reorganise compat into separate package; misc ap…
isXander Oct 27, 2026
bf4f127
make tap and double tap gestures mutually exclusive, expose gesture t…
isXander Oct 27, 2026
89a647b
fix radial menu not invoking actions
isXander Oct 27, 2026
425d9e4
binding/gesture system; actions can be bound more than once!
isXander Oct 27, 2026
a6b8a1d
Merge branch 'main' into feat/input-pipeline-v3
isXander Oct 27, 2026
3c94d90
fix gamecontrollerdb being put in the wrong directory
isXander Oct 27, 2026
6d13b49
fix darkening on BindConsumerScreen missing a few pixels
isXander Oct 27, 2026
7063375
bump version (test 2)
isXander Oct 27, 2026
65521de
fix spotless
isXander Oct 27, 2026
68a048c
update stonecutter comments
isXander Oct 27, 2026
5f3b9d9
fix gametest
isXander Oct 27, 2026
e37899e
bump fabric loom
isXander Oct 28, 2026
aa1d900
fix warning using stale data in ContextualDomainImpl
isXander Oct 28, 2026
0ed1db5
add more docs and move some things around
isXander Oct 28, 2026
574dd2e
change a lot of activators to tap-by-default instead of press; more l…
isXander Oct 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ build
.gradle
!.gitkeep
.kotlin

.DS_Store
36 changes: 27 additions & 9 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ val commonManifest = manifests.manifest {

mixin("controlify.mixins.json")
mixin("controlify-compat.yacl.mixins.json")
ifPresent("deps.iris") { mixin("controlify-compat.iris.mixins.json") }
ifPresent("deps.sodium") { mixin("controlify-compat.sodium.mixins.json") }
ifPresent("deps.reeses-sodium-options") { mixin("controlify-compat.reeses-sodium-options.mixins.json") }
ifPresent("deps.svc") { mixin("controlify-compat.svc.mixins.json") }
ifPresent("dep.iris") { mixin("controlify-compat.iris.mixins.json") }
ifPresent("dep.sodium") { mixin("controlify-compat.sodium.mixins.json") }
ifPresent("dep.rso") { mixin("controlify-compat.reeses-sodium-options.mixins.json") }
ifPresent("dep.svc") { mixin("controlify-compat.simple-voice-chat.mixins.json") }
mixin("controlify-compat.rrls.mixins.json")

dependency("minecraft", REQUIRED, minecraftRange)
Expand All @@ -169,18 +169,24 @@ manifests {
"controlify:default_config",
"controlify:controller_type",
"controlify:default_binds",
"controlify:trigger_effect",
"controlify:contextual/domain/in_game",
"controlify:contextual/domain/container",
"controlify:contextual/ruleset/guide",
"controlify:contextual/ruleset/trigger_effect",
"controlify:activators",
"controlify:controller_mapping",
"controlify:rumble_sources",
"controlify:radial_icons",
)
))

fabricModJson(sourceSets.fabric.get()) {
from(commonManifest)

entrypoint("modmenu", "dev.isxander.controlify.fabric.compatibility.ModMenuIntegration")
entrypoint("main", "dev.isxander.controlify.fabric.ControlifyBootstrap")
entrypoint("client", "dev.isxander.controlify.fabric.ControlifyBootstrap")
entrypoint("server", "dev.isxander.controlify.fabric.ControlifyBootstrap")
entrypoint("modmenu", "dev.isxander.controlify.fabric.compat.ModMenuIntegration")
entrypoint("main", "dev.isxander.controlify.fabric.impl.ControlifyBootstrap")
entrypoint("client", "dev.isxander.controlify.fabric.impl.ControlifyBootstrap")
entrypoint("server", "dev.isxander.controlify.fabric.impl.ControlifyBootstrap")
dependency("fabricloader", REQUIRED, "[0.19,)")

mixin("controlify-platform.fabric.mixins.json")
Expand Down Expand Up @@ -281,6 +287,18 @@ if (includeNatives) {
}
}

// Run configs

// Fabric
loom.runConfigs.configureEach {
runDirectory = layout.projectDirectory.dir("run")
}

// NeoForge
runs.configureEach {
workingDirectory = layout.projectDirectory.dir("run")
}

/// Testing

fabricApi {
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod.version=3.5.3
mod.version=4.0.0-test.2
mod.id=controlify
mod.name=Controlify
mod.description=The most advanced controller mod for Minecraft.
Expand Down
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[versions]
fabric_loader = "0.19.3"
sdl_natives = "release-3.4.12"
sdl_java = "release-3.4.14-7"
sdl_java = "release-3.4.14-8"
steamdeck4j = "1.1.7"
quilt_parsers = "0.3.0"

modstitch_manifests = "0.1.5"
modstitch_multiloader = "0.1.9"
modstitch_modrepos = "0.1.2"
fabric_loom = "1.17.16"
fabric_loom = "1.19.3"
neoforged_gradle = "7.1.39"
spotless = "8.6.0"
undercouch_download = "5.6.0"
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Tue Jul 21 16:53:14 BST 2026
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
7 changes: 5 additions & 2 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ pluginManagement {
}
}
exclusiveContent {
forRepository { maven("https://maven.kikugie.dev/releases") }
forRepositories(
maven("https://maven.kikugie.dev/releases"),
maven("https://maven.kikugie.dev/snapshots")
)
filter { includeGroupAndSubgroups("dev.kikugie") }
}
exclusiveContent {
Expand All @@ -28,7 +31,7 @@ pluginManagement {
}

plugins {
id("dev.kikugie.stonecutter") version "0.9.7"
id("dev.kikugie.stonecutter") version "0.10-beta.1"
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
package dev.isxander.controlify.fabric.compatibility;
package dev.isxander.controlify.fabric.compat;

import dev.isxander.controlify.compatibility.CompatMixinPlatform;
import dev.isxander.controlify.compat.CompatMixinPlatform;
import net.fabricmc.loader.api.FabricLoader;

public final class FabricCompatMixinPlatform implements CompatMixinPlatform {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
package dev.isxander.controlify.fabric.compatibility;
package dev.isxander.controlify.fabric.compat;

//? if mod_menu {

import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import dev.isxander.controlify.gui.screen.ControlifySettingsScreen;
import dev.isxander.controlify.impl.gui.screen.ControlifySettingsScreen;

public class ModMenuIntegration implements ModMenuApi {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
package dev.isxander.controlify.fabric;
package dev.isxander.controlify.fabric.impl;

import dev.isxander.controlify.Controlify;
import dev.isxander.controlify.fabric.platform.client.FabricPlatformClientImpl;
import dev.isxander.controlify.fabric.platform.FabricPlatformMainImpl;
import dev.isxander.controlify.platform.client.PlatformClientUtil;
import dev.isxander.controlify.platform.main.PlatformMainUtil;
import dev.isxander.controlify.server.ControlifyServer;
import dev.isxander.controlify.impl.Controlify;
import dev.isxander.controlify.fabric.impl.platform.client.FabricPlatformClientImpl;
import dev.isxander.controlify.fabric.impl.platform.FabricPlatformMainImpl;
import dev.isxander.controlify.impl.platform.client.PlatformClientUtil;
import dev.isxander.controlify.impl.platform.main.PlatformMainUtil;
import dev.isxander.controlify.impl.server.ControlifyServer;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.DedicatedServerModInitializer;
import net.fabricmc.api.ModInitializer;
Expand All @@ -20,6 +20,8 @@ public class ControlifyBootstrap implements ClientModInitializer, ModInitializer
@Override
public void onInitializeClient() {
PlatformClientUtil.IMPL = new FabricPlatformClientImpl();
dev.isxander.controlify.impl.screenop.BuiltinScreenBehaviours.initialize();
PlatformMainUtil.invokeControlifyEntrypoints();
Controlify.instance().preInitialiseControlify();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
package dev.isxander.controlify.fabric.platform;
package dev.isxander.controlify.fabric.impl.platform;

import dev.isxander.controlify.platform.EventHandler;
import dev.isxander.controlify.impl.platform.EventHandler;
import net.fabricmc.fabric.api.event.EventFactory;

public class FabricBackedEventHandler<T> implements EventHandler<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
package dev.isxander.controlify.fabric.platform;

import dev.isxander.controlify.api.entrypoint.ControlifyEntrypoint;
import dev.isxander.controlify.fabric.platform.network.C2SNetworkApiFabric;
import dev.isxander.controlify.fabric.platform.network.S2CNetworkApiFabric;
import dev.isxander.controlify.platform.Environment;
import dev.isxander.controlify.platform.main.PlatformMainUtilImpl;
import dev.isxander.controlify.platform.main.events.CommandRegistrationCallbackEvent;
import dev.isxander.controlify.platform.main.events.HandshakeCompletionEvent;
import dev.isxander.controlify.platform.main.events.PlayerJoinedEvent;
import dev.isxander.controlify.platform.network.C2SNetworkApi;
import dev.isxander.controlify.platform.network.S2CNetworkApi;
package dev.isxander.controlify.fabric.impl.platform;

import dev.isxander.controlify.api.ControlifyEntrypoint;
import dev.isxander.controlify.impl.utils.CUtil;
import dev.isxander.controlify.fabric.impl.platform.network.C2SNetworkApiFabric;
import dev.isxander.controlify.fabric.impl.platform.network.S2CNetworkApiFabric;
import dev.isxander.controlify.impl.platform.Environment;
import dev.isxander.controlify.impl.platform.main.PlatformMainUtilImpl;
import dev.isxander.controlify.impl.platform.main.events.CommandRegistrationCallbackEvent;
import dev.isxander.controlify.impl.platform.main.events.HandshakeCompletionEvent;
import dev.isxander.controlify.impl.platform.main.events.PlayerJoinedEvent;
import dev.isxander.controlify.impl.platform.network.C2SNetworkApi;
import dev.isxander.controlify.impl.platform.network.S2CNetworkApi;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.networking.v1.FriendlyByteBufs;
import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents;
Expand All @@ -34,6 +35,8 @@
import java.util.Arrays;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;

Expand All @@ -58,9 +61,27 @@ public boolean isModLoaded(String... modIds) {

@Override
public void applyToControlifyEntrypoint(Consumer<ControlifyEntrypoint> entrypointConsumer) {
// Use both Fabric's entrypoint system and ServiceLoader to maximize compatibility
FabricLoader.getInstance().getEntrypoints("controlify", ControlifyEntrypoint.class).forEach(entrypointConsumer);
ServiceLoader.load(ControlifyEntrypoint.class).forEach(entrypointConsumer);
// Use both discovery mechanisms, without constructing duplicate service providers.
Set<Class<?>> loaded = new HashSet<>();
FabricLoader.getInstance().getEntrypointContainers("controlify", ControlifyEntrypoint.class).forEach(container -> {
try {
var entrypoint = container.getEntrypoint();
if (loaded.add(entrypoint.getClass())) {
entrypointConsumer.accept(entrypoint);
}
} catch (Throwable throwable) {
CUtil.LOGGER.error("Failed to load Controlify addon from mod: {}", container.getProvider().getMetadata().getId(), throwable);
}
});
ServiceLoader.load(ControlifyEntrypoint.class).stream().forEach(provider -> {
try {
if (loaded.add(provider.type())) {
entrypointConsumer.accept(provider.get());
}
} catch (Throwable throwable) {
CUtil.LOGGER.error("Failed to load Controlify addon provider: {}", provider.type().getName(), throwable);
}
});
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
package dev.isxander.controlify.fabric.platform.client;
package dev.isxander.controlify.fabric.impl.platform.client;

import dev.isxander.controlify.platform.client.CreativeTabHelper;
import dev.isxander.controlify.impl.platform.client.CreativeTabHelper;
import net.fabricmc.fabric.api.client.creativetab.v1.FabricCreativeModeInventoryScreen;
import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen;
import net.minecraft.world.item.CreativeModeTab;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
package dev.isxander.controlify.fabric.platform.client;

import dev.isxander.controlify.platform.client.CreativeTabHelper;
import dev.isxander.controlify.platform.client.HudRenderLayer;
import dev.isxander.controlify.platform.client.PlatformClientUtilImpl;
import dev.isxander.controlify.platform.client.events.DisconnectedEvent;
import dev.isxander.controlify.platform.client.events.LifecycleEvent;
import dev.isxander.controlify.platform.client.events.ScreenRenderEvent;
import dev.isxander.controlify.platform.client.events.TickEvent;
import dev.isxander.controlify.platform.client.resource.ControlifyReloadListener;
package dev.isxander.controlify.fabric.impl.platform.client;

import dev.isxander.controlify.impl.platform.client.CreativeTabHelper;
import dev.isxander.controlify.impl.platform.client.HudRenderLayer;
import dev.isxander.controlify.impl.platform.client.PlatformClientUtilImpl;
import dev.isxander.controlify.impl.platform.client.events.DisconnectedEvent;
import dev.isxander.controlify.impl.platform.client.events.LifecycleEvent;
import dev.isxander.controlify.impl.platform.client.events.ScreenRenderEvent;
import dev.isxander.controlify.impl.platform.client.events.TickEvent;
import dev.isxander.controlify.impl.platform.client.resource.ControlifyReloadListener;
import dev.isxander.controlify.fabric.mixins.KeyBindingRegistryImplAccessor;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
package dev.isxander.controlify.fabric.platform.network;
package dev.isxander.controlify.fabric.impl.platform.network;

import dev.isxander.controlify.platform.network.C2SNetworkApi;
import dev.isxander.controlify.impl.platform.network.C2SNetworkApi;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
package dev.isxander.controlify.fabric.platform.network;
package dev.isxander.controlify.fabric.impl.platform.network;

import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import net.minecraft.network.FriendlyByteBuf;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
package dev.isxander.controlify.fabric.platform.network;
package dev.isxander.controlify.fabric.impl.platform.network;

import dev.isxander.controlify.platform.network.S2CNetworkApi;
import dev.isxander.controlify.impl.platform.network.S2CNetworkApi;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,9 @@
*/
package dev.isxander.controlify.gametest.framework;

import dev.isxander.controlify.Controlify;
import dev.isxander.controlify.config.settings.GlobalSettings;
import dev.isxander.controlify.config.settings.profile.ProfileSettings;
import dev.isxander.controlify.controller.ControllerEntity;
import dev.isxander.controlify.controller.gyro.GyroState;
import dev.isxander.controlify.controllermanager.ControllerManager;
import dev.isxander.controlify.gametest.mixin.ControlifySettingsAccessor;
import dev.isxander.controlify.gametest.mixin.ToastInstanceAccessor;
import dev.isxander.controlify.gametest.mixin.ToastManagerAccessor;
import dev.isxander.controlify.utils.MinecraftUtil;
import dev.isxander.controlify.impl.utils.MinecraftUtil;
import net.fabricmc.fabric.api.client.gametest.v1.context.ClientGameTestContext;
import net.fabricmc.fabric.api.resource.v1.ResourceLoader;
import net.fabricmc.fabric.api.resource.v1.pack.PackActivationType;
Expand All @@ -36,10 +29,8 @@
import net.minecraft.world.entity.EntityType;
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@SuppressWarnings("UnstableApiUsage")
Expand Down Expand Up @@ -155,17 +146,17 @@ public static void clearToasts(ClientGameTestContext context) {
//? if >=26.2 {
minecraft.gui.toastManager().clear();
//?} else {
/*minecraft.getToastManager().clear();
*///?}
//minecraft.getToastManager().clear();
//?}
});
}

public static boolean isToastPresent(Minecraft minecraft, String translationKey) {
//? if >=26.2 {
var toastManager = minecraft.gui.toastManager();
//?} else {
/*var toastManager = minecraft.getToastManager();
*///?}
//var toastManager = minecraft.getToastManager();
//?}

String text = Component.translatable(translationKey).getString();

Expand Down
Loading
Loading