nosingleplayer 1.1.3: fix connexion + bouton Quitter SurviePote

- TitleScreenMixin : TransferState null sur startConnecting -> connexion
  normale, corrige "This server does not accept transfers".
- PauseScreenMixin (nouveau) : renomme le bouton de deconnexion du menu
  Echap en "Quitter SurviePote" et redirige vers l'ecran d'accueil
  (TitleScreen) au lieu de la liste des serveurs.
- build.gradle : tache runClient (dev sans loom) reutilisant
  ~/.surviepote/common.
- Jar 1.1.3 copie dans l'atlas + distribution.json regenere.
This commit is contained in:
Anaïs Saraiva
2026-10-19 18:41:56 +02:00
parent 159a594b2c
commit 4a48d2c721
9 changed files with 158 additions and 13 deletions
+4 -4
View File
@@ -407,13 +407,13 @@
} }
}, },
{ {
"id": "fr.surviepote:nosingleplayer:1.1.2@jar", "id": "fr.surviepote:nosingleplayer:1.1.3@jar",
"name": "NoSingleplayer (SurviePote)", "name": "NoSingleplayer (SurviePote)",
"type": "FabricMod", "type": "FabricMod",
"artifact": { "artifact": {
"size": 2292471, "size": 2294172,
"url": "https://git.kisakay.com/k/mc/raw/branch/main/atlas/root/servers/SurviePote-26.3/fabricmods/required/nosingleplayer-1.1.2.jar", "url": "https://git.kisakay.com/k/mc/raw/branch/main/atlas/root/servers/SurviePote-26.3/fabricmods/required/nosingleplayer-1.1.3.jar",
"MD5": "2ba50ec99adb670cdb34fe41b0e3d7dd" "MD5": "577674ec296cbc75ac9da009b8d6532e"
} }
}, },
{ {
+7 -2
View File
@@ -1,6 +1,11 @@
# nosingleplayer (mod maison SurviePote) # nosingleplayer (mod maison SurviePote)
Désactive le bouton **Solo** du menu principal (Mixin sur `TitleScreen.init`). Désactive le bouton **Solo** du menu principal (Mixin sur `TitleScreen.init`) et adapte l'UI
au serveur unique :
- Menu titre : bouton **Rejoindre SurviePote** (connexion directe à `mcpv.ihorizon.org:25565`,
sans transfert) ; Solo, Multi, Realms, réseau social et icônes bas retirés.
- Menu Échap : le bouton de déconnexion devient **Quitter SurviePote** et renvoie à l'écran
d'accueil du jeu (et non la liste des serveurs).
- MC 26.3, Fabric Loader 0.20.0, Java 25, `environment: client`. - MC 26.3, Fabric Loader 0.20.0, Java 25, `environment: client`.
- Particularité 26.x : Mojang ne publie plus de mappings (ni Yarn ni `client_mappings`) et le - Particularité 26.x : Mojang ne publie plus de mappings (ni Yarn ni `client_mappings`) et le
jeu n'est plus obfusqué → **pas de Loom**, compilation directe contre le jar client Mojang jeu n'est plus obfusqué → **pas de Loom**, compilation directe contre le jar client Mojang
@@ -8,4 +13,4 @@ Désactive le bouton **Solo** du menu principal (Mixin sur `TitleScreen.init`).
pas de refmap nécessaire. pas de refmap nécessaire.
Build : `cd mods/nosingleplayer && ./gradlew build` (dans nix-shell racine pour Java 25). Build : `cd mods/nosingleplayer && ./gradlew build` (dans nix-shell racine pour Java 25).
Jar : `build/libs/nosingleplayer-1.0.0.jar` → copié dans `atlas/.../fabricmods/required/`. Jar : `build/libs/nosingleplayer-1.1.3.jar` → copié dans `atlas/.../fabricmods/required/`.
+94
View File
@@ -64,3 +64,97 @@ processResources {
java { java {
withSourcesJar() withSourcesJar()
} }
// ---------------------------------------------------------------------------
// Dev : lance le vrai client MC 26.3 + nosingleplayer (build sans loom).
// Réutilise l'installation commune du launcher SurviePote (~/.surviepote/common :
// versions, libraries, assets — remplie au premier lancement). Le mod est copié
// dans runClient/game/mods/ (Knot le découvre comme un mod Fabric classique).
// Usage : ./gradlew runClient
// ---------------------------------------------------------------------------
def survieCommon = new File(System.getProperty('user.home'), '.surviepote/common')
def mcVersion = project.minecraft_version
def loaderVersion = project.loader_version
tasks.register('extractClientNatives', Copy) {
def versionJson = new groovy.json.JsonSlurper().parse(
new File(survieCommon, "versions/${mcVersion}/${mcVersion}.json"))
from(versionJson.libraries.findAll { lib ->
lib.name.contains(':natives-linux') && (lib.rules == null || lib.rules.any { it.action == 'allow' && (it.os == null || it.os.name == 'linux') })
}.collect { lib ->
zipTree(new File(survieCommon, "libraries/${lib.downloads.artifact.path}"))
})
into(layout.buildDirectory.dir('runClient/natives'))
include('**/*.so')
eachFile { f -> f.path = f.name }
}
tasks.register('runClient', JavaExec) {
dependsOn('extractClientNatives', 'jar')
group = 'fabric'
description = 'Lance le client Minecraft avec le mod (dev visuel, sans loom).'
def versionJson = new groovy.json.JsonSlurper().parse(
new File(survieCommon, "versions/${mcVersion}/${mcVersion}.json"))
def fabricJson = new groovy.json.JsonSlurper().parse(
new File(survieCommon, "versions/${mcVersion}-fabric-${loaderVersion}/${mcVersion}-fabric-${loaderVersion}.json"))
def mavenToPath = { String coord ->
def parts = coord.split(':')
return "${parts[0].replace('.', '/')}/${parts[1]}/${parts[2]}/${parts[1]}-${parts[2]}.jar"
}
doFirst {
def modsDir = layout.buildDirectory.dir('runClient/game/mods').get().asFile
delete(modsDir)
modsDir.mkdirs()
copy {
from(tasks.named('jar'))
into(modsDir)
}
}
// NixOS : dlopen ne voit ni libGL ni libvulkan sans LD_LIBRARY_PATH (cf launcher).
def nixStore = new File('/nix/store')
def glDirs = []
['/run/opengl-driver/lib', '/run/current-system/sw/lib'].each { d ->
if (new File(d).exists()) glDirs << d
}
if (nixStore.exists()) {
nixStore.eachDir { e ->
def n = e.name
if (n.contains('libglvnd') || n.contains('vulkan-loader') || n.contains('alsa-lib')
|| n.contains('pulseaudio') || (n.contains('pipewire') && !n.contains('python'))) {
def lib = new File(e, 'lib')
if (lib.exists()) glDirs << lib.absolutePath
}
}
}
def prevLd = System.getenv('LD_LIBRARY_PATH')
environment('LD_LIBRARY_PATH', (prevLd ? prevLd + ':' : '') + glDirs.join(':'))
if (!System.getenv('SDL_VIDEODRIVER') && (System.getenv('WAYLAND_DISPLAY') || new File('/run/user/1000/wayland-1').exists())) {
environment('SDL_VIDEODRIVER', 'wayland')
}
javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(25) }
classpath = files(
new File(survieCommon, "versions/${mcVersion}/${mcVersion}.jar"),
versionJson.libraries.findAll { lib ->
!(lib.name.contains(':natives-')) && (lib.rules == null || lib.rules.any { it.action == 'allow' && (it.os == null || it.os.name == 'linux') })
}.collect { new File(survieCommon, "libraries/${it.downloads.artifact.path}") },
fabricJson.libraries.collect { new File(survieCommon, "libraries/${mavenToPath(it.name)}") }
)
mainClass = 'net.fabricmc.loader.impl.launch.knot.KnotClient'
args = [
'--gameDir', layout.buildDirectory.dir('runClient/game').get().asFile.absolutePath,
'--assetsDir', new File(survieCommon, 'assets').absolutePath,
'--assetIndex', versionJson.assetIndex.id,
'--version', "${project.archives_base_name}-dev",
'--username', 'Dev', '--uuid', '00000000-0000-0000-0000-000000000000',
'--accessToken', '0', '--versionType', 'release'
]
jvmArgs = [
"-Djava.library.path=${layout.buildDirectory.dir('runClient/natives').get().asFile.absolutePath}",
'-Xmx4G'
]
systemProperties['org.lwjgl.util.Debug'] = 'false'
}
+1 -1
View File
@@ -5,7 +5,7 @@ loader_version=0.20.0
loom_version=1.19.1 loom_version=1.19.1
# Mod Properties # Mod Properties
mod_version=1.1.2 mod_version=1.1.3
maven_group=fr.surviepote maven_group=fr.surviepote
archives_base_name=nosingleplayer archives_base_name=nosingleplayer
@@ -0,0 +1,45 @@
package fr.surviepote.nosingleplayer.mixin;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.PauseScreen;
import net.minecraft.client.gui.screens.TitleScreen;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(PauseScreen.class)
public abstract class PauseScreenMixin {
@Unique
private static final Component SURVIEPOTE_QUIT = Component.literal("Quitter SurviePote");
// Quitte le monde comme le bouton vanilla, mais renvoie vers l'écran d'accueil
// (au lieu de la liste des serveurs pour un serveur distant).
@Unique
private static void surviepote$quitToTitle(Button button) {
button.active = false;
Minecraft minecraft = Minecraft.getInstance();
// Conserve la gestion vanilla du brouillon de signalement, puis redirige.
minecraft.getReportingContext().draftReportHandled(minecraft, minecraft.gui.screen(), () -> {
minecraft.disconnectFromWorld(ClientLevel.DEFAULT_QUIT_MESSAGE);
minecraft.setScreenAndShow(new TitleScreen());
}, true);
}
@Redirect(method = "createPauseMenu",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/gui/components/Button;builder(Lnet/minecraft/network/chat/Component;Lnet/minecraft/client/gui/components/Button$OnPress;)Lnet/minecraft/client/gui/components/Button$Builder;"))
private static Button.Builder surviepote$relabelDisconnect(Component message, Button.OnPress onPress) {
// createPauseMenu ne crée que deux boutons via Button.builder : "Retour au jeu"
// et "Déconnexion". On ne remplace que ce dernier.
if (message.getString().equals(CommonComponents.GUI_DISCONNECT.getString())) {
return Button.builder(SURVIEPOTE_QUIT, PauseScreenMixin::surviepote$quitToTitle);
}
return Button.builder(message, onPress);
}
}
@@ -2,7 +2,6 @@ package fr.surviepote.nosingleplayer.mixin;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.Button;
@@ -13,7 +12,6 @@ import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.ConnectScreen; import net.minecraft.client.gui.screens.ConnectScreen;
import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.client.gui.screens.TitleScreen;
import net.minecraft.client.multiplayer.ServerData; import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.client.multiplayer.TransferState;
import net.minecraft.client.multiplayer.resolver.ServerAddress; import net.minecraft.client.multiplayer.resolver.ServerAddress;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import fr.surviepote.nosingleplayer.NoSingleplayer; import fr.surviepote.nosingleplayer.NoSingleplayer;
@@ -86,8 +84,9 @@ public abstract class TitleScreenMixin {
Button join = Button.builder(Component.literal("Rejoindre SurviePote"), pressed -> { Button join = Button.builder(Component.literal("Rejoindre SurviePote"), pressed -> {
ServerData data = new ServerData("SurviePote", SERVER_HOST, ServerData.Type.OTHER); ServerData data = new ServerData("SurviePote", SERVER_HOST, ServerData.Type.OTHER);
ConnectScreen.startConnecting(self, minecraft, ServerAddress.parseString(SERVER_HOST), data, false, // TransferState null = connexion normale. En passer un déclenche une connexion
new TransferState(Map.of(), Map.of(), false)); // de type "transfert", que le serveur refuse ("This server does not accept transfers").
ConnectScreen.startConnecting(self, minecraft, ServerAddress.parseString(SERVER_HOST), data, false, null);
}).bounds(joinX, joinY, 200, 20).build(); }).bounds(joinX, joinY, 200, 20).build();
((ScreenAccessor) self).surviepote$getRenderables().add(join); ((ScreenAccessor) self).surviepote$getRenderables().add(join);
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -7,6 +7,7 @@
"TitleScreenRenderMixin", "TitleScreenRenderMixin",
"TitleScreenTextMixin", "TitleScreenTextMixin",
"RealmsNotificationsMixin", "RealmsNotificationsMixin",
"PauseScreenMixin",
"ScreenAccessor" "ScreenAccessor"
], ],
"injectors": { "injectors": {
+3 -2
View File
@@ -54,10 +54,11 @@ cp -u "$HOME/.local/share/PrismLauncher/instances/26.3/minecraft/resourcepacks/F
cp -u "$HOME/.local/share/PrismLauncher/instances/26.3/minecraft/shaderpacks/Revelation-dev.zip" "atlas/root/servers/SurviePote-26.3/files/shaderpacks/" 2>/dev/null || true cp -u "$HOME/.local/share/PrismLauncher/instances/26.3/minecraft/shaderpacks/Revelation-dev.zip" "atlas/root/servers/SurviePote-26.3/files/shaderpacks/" 2>/dev/null || true
echo "== mod maison nosingleplayer (build si besoin) ==" echo "== mod maison nosingleplayer (build si besoin) =="
if [ ! -f mods/nosingleplayer/build/libs/nosingleplayer-1.1.2.jar ]; then if [ ! -f mods/nosingleplayer/build/libs/nosingleplayer-1.1.3.jar ]; then
(cd mods/nosingleplayer && ./gradlew build 2>&1 | tail -n 2) || echo "BUILD nosingleplayer échoué (réseau/gradle requis)" (cd mods/nosingleplayer && ./gradlew build 2>&1 | tail -n 2) || echo "BUILD nosingleplayer échoué (réseau/gradle requis)"
fi fi
cp -u mods/nosingleplayer/build/libs/nosingleplayer-1.1.2.jar "$ATLAS_MODS/" 2>/dev/null || true cp -u mods/nosingleplayer/build/libs/nosingleplayer-1.1.3.jar "$ATLAS_MODS/" 2>/dev/null || true
rm -f "$ATLAS_MODS"/nosingleplayer-1.1.2.jar "$ATLAS_MODS"/nosingleplayer-1.1.1.jar "$ATLAS_MODS"/nosingleplayer-1.1.0.jar "$ATLAS_MODS"/nosingleplayer-1.0.0.jar
# Note : environment=client (menu titre), inutile côté serveur. # Note : environment=client (menu titre), inutile côté serveur.
echo "== regen distribution.json ==" echo "== regen distribution.json =="