Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@ jobs:
matrix:
# Use these Java versions
java: [
21, # Current Java LTS
25, # Current Java LTS
]
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: validate gradle wrapper
uses: gradle/wrapper-validation-action@v2
- name: setup jdk ${{ matrix.java }}
uses: actions/setup-java@v4
with:
Expand All @@ -30,8 +28,8 @@ jobs:
- name: build
run: ./gradlew build
- name: capture build artifacts
if: ${{ matrix.java == '21' }} # Only upload artifacts built from latest java
uses: actions/upload-artifact@v4
if: ${{ matrix.java == '25' }} # Only upload artifacts built from latest java
uses: actions/upload-artifact@v7
with:
name: Artifacts
path: build/libs/
19 changes: 10 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id 'fabric-loom' version "${loom_version}"
id 'net.fabricmc.fabric-loom' version "${loom_version}"
id 'maven-publish'
id "io.github.p03w.machete" version "2.0.1"
}
Expand All @@ -20,17 +20,18 @@ repositories {
dependencies {
// To change the versions see the gradle.properties file
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
implementation "net.fabricmc:fabric-loader:${project.loader_version}"

// Fabric API
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}"
implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}"

// ModMenu
modImplementation "com.terraformersmc:modmenu:${project.modmenu_version}"
implementation("com.terraformersmc:modmenu:${project.modmenu_version}"){
exclude(group: "eu.pb4")
}

// Cloth Config
modImplementation("me.shedaniel.cloth:cloth-config-fabric:${project.cloth_config_version}") {
implementation("me.shedaniel.cloth:cloth-config-fabric:${project.cloth_config_version}") {
exclude(group: "net.fabricmc.fabric-api")
}
}
Expand All @@ -44,14 +45,14 @@ processResources {
}

tasks.withType(JavaCompile).configureEach {
it.options.release = 21
it.options.release = 25
}

java {
withSourcesJar()

sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
sourceCompatibility = JavaVersion.VERSION_25
targetCompatibility = JavaVersion.VERSION_25
}

jar {
Expand Down
15 changes: 7 additions & 8 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@ org.gradle.configuration-cache=false

# Fabric Properties
# check these on https://fabricmc.net/develop
minecraft_version=1.21.11
yarn_mappings=1.21.11+build.3
loader_version=0.18.3
loom_version=1.14-SNAPSHOT
minecraft_version=26.1
loader_version=0.18.5
loom_version=1.15-SNAPSHOT

# Mod Properties
mod_version=3.1.3
target_version=1.21.11
target_version=26.1
maven_group=me.contaria
archives_base_name=fastquit

# Dependencies
fabric_api_version=0.140.0+1.21.11
modmenu_version=17.0.0-alpha.1
cloth_config_version=21.11.151
fabric_api_version=0.144.1+26.1
modmenu_version=18.0.0-alpha.7
cloth_config_version=26.1.154
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package me.contaria.fastquit;

import net.fabricmc.loader.api.ModContainer;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screens.Screen;

/**
* Provides support for configuring options through Catalogue.
Expand Down
60 changes: 30 additions & 30 deletions src/main/java/me/contaria/fastquit/FastQuit.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package me.contaria.fastquit;

import me.contaria.fastquit.mixin.MinecraftClientAccessor;
import me.contaria.fastquit.mixin.MinecraftAccessor;
import me.contaria.fastquit.mixin.MinecraftServerAccessor;
import me.contaria.fastquit.mixin.LevelStorageSessionAccessor;
import com.mojang.logging.LogUtils;
Expand All @@ -9,11 +9,11 @@
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.metadata.ModMetadata;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.text.Text;
import net.minecraft.world.level.storage.LevelStorage;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.server.IntegratedServer;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.storage.LevelStorageSource;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
Expand All @@ -36,9 +36,9 @@ public final class FastQuit implements ClientModInitializer {
public static final Map<IntegratedServer, WorldInfo> savingWorlds = Collections.synchronizedMap(new HashMap<>());

/**
* Stores {@link LevelStorage.Session}'s used by FastQuit as to only close them if no other process is currently using them.
* Stores {@link LevelStorageSource.LevelStorageAccess}'s used by FastQuit as to only close them if no other process is currently using them.
*/
public static final List<LevelStorage.Session> occupiedSessions = Collections.synchronizedList(new ArrayList<>());
public static final List<LevelStorageSource.LevelStorageAccess> occupiedSessions = Collections.synchronizedList(new ArrayList<>());

@Override
public void onInitializeClient() {
Expand Down Expand Up @@ -79,9 +79,9 @@ public static void exit() {
error("Something went horribly wrong when exiting FastQuit!", throwable);
savingWorlds.forEach((server, info) -> {
try {
server.getThread().join();
server.getRunningThread().join();
} catch (Throwable throwable2) {
error("Failed to wait for \"" + server.getSaveProperties().getLevelName() + "\"", throwable2);
error("Failed to wait for \"" + server.getWorldData().getLevelName() + "\"", throwable2);
}
});
}
Expand Down Expand Up @@ -119,43 +119,43 @@ public static void wait(Collection<IntegratedServer> servers, @Nullable Callback
return;
}

MinecraftClient client = MinecraftClient.getInstance();
Minecraft client = Minecraft.getInstance();

if (!client.isOnThread()) {
if (servers.stream().anyMatch(server -> Thread.currentThread() == server.getThread())) {
if (!client.isSameThread()) {
if (servers.stream().anyMatch(server -> Thread.currentThread() == server.getRunningThread())) {
throw new IllegalStateException("Tried to call FastQuit.wait(...) from one of the servers it's supposed to wait for.");
}

client.submit(() -> wait(servers)).join();
return;
}

Screen oldScreen = client.currentScreen;
Screen oldScreen = client.screen;

Text stillSaving = TextHelper.translatable("fastquit.screen.waiting", String.join("\" & \"", servers.stream().map(server -> server.getSaveProperties().getLevelName()).toList()));
Component stillSaving = TextHelper.translatable("fastquit.screen.waiting", String.join("\" & \"", servers.stream().map(server -> server.getWorldData().getLevelName()).toList()));
log(stillSaving.getString());

servers.forEach(server -> server.getThread().setPriority(Thread.NORM_PRIORITY));
servers.forEach(server -> server.getRunningThread().setPriority(Thread.NORM_PRIORITY));

try {
client.setScreen(new WaitingScreen(stillSaving, cancellable));

while (servers.stream().anyMatch(server -> !server.isStopping())) {
while (servers.stream().anyMatch(server -> !server.isShutdown())) {
if (cancellable != null && cancellable.isCancelled()) {
if (CONFIG.backgroundPriority != 0) {
servers.forEach(server -> server.getThread().setPriority(CONFIG.backgroundPriority));
servers.forEach(server -> server.getRunningThread().setPriority(CONFIG.backgroundPriority));
}
log("Cancelled waiting for currently saving worlds.");
break;
}
((MinecraftClientAccessor) client).fastquit$render(false);
((MinecraftAccessor) client).fastquit$runTick(false);
}
} finally {
// compatibility with "WorldGen" mod
if (oldScreen != null && oldScreen.getClass().getName().equals("caeruleusTait.WorldGen.gui.screens.WGConfigScreen")) {
client.currentScreen = oldScreen;
client.screen = oldScreen;
} else {
client.setScreenAndRender(oldScreen);
client.setScreenAndShow(oldScreen);
}
}
}
Expand All @@ -165,25 +165,25 @@ public static void wait(Collection<IntegratedServer> servers, @Nullable Callback
*/
public static Optional<IntegratedServer> getSavingWorld(Path path) {
// noinspection resource
return savingWorlds.keySet().stream().filter(server -> ((LevelStorageSessionAccessor) ((MinecraftServerAccessor) server).fastquit$getSession()).fastquit$getDirectory().path().equals(path)).findFirst();
return savingWorlds.keySet().stream().filter(server -> ((LevelStorageSessionAccessor) ((MinecraftServerAccessor) server).fastquit$getStorageSource()).fastquit$getLevelDirectory().path().equals(path)).findFirst();
}

/**
* @return optionally returns the currently saving {@link IntegratedServer} matching the given {@link LevelStorage.Session}
* @return optionally returns the currently saving {@link IntegratedServer} matching the given {@link LevelStorageSource.LevelStorageAccess}
*/
public static Optional<IntegratedServer> getSavingWorld(LevelStorage.Session session) {
public static Optional<IntegratedServer> getSavingWorld(LevelStorageSource.LevelStorageAccess session) {
// noinspection resource
return savingWorlds.keySet().stream().filter(server -> ((MinecraftServerAccessor) server).fastquit$getSession() == session).findFirst();
return savingWorlds.keySet().stream().filter(server -> ((MinecraftServerAccessor) server).fastquit$getStorageSource() == session).findFirst();
}

/**
* @apiNote Remember to {@link LevelStorage.Session#close() close} the session after using it!
* @return optionally returns the {@link LevelStorage.Session} of the currently saving {@link IntegratedServer} matching the given {@link Path}
* @apiNote Remember to {@link LevelStorageSource.LevelStorageAccess#close() close} the session after using it!
* @return optionally returns the {@link LevelStorageSource.LevelStorageAccess} of the currently saving {@link IntegratedServer} matching the given {@link Path}
*/
public static Optional<LevelStorage.Session> getSession(Path path) {
public static Optional<LevelStorageSource.LevelStorageAccess> getSession(Path path) {
return getSavingWorld(path).flatMap(server -> {
LevelStorage.Session session;
synchronized (session = ((MinecraftServerAccessor) server).fastquit$getSession()) {
LevelStorageSource.LevelStorageAccess session;
synchronized (session = ((MinecraftServerAccessor) server).fastquit$getStorageSource()) {
// noinspection resource
if (((LevelStorageSessionAccessor) session).fastquit$getLock().isValid()) {
occupiedSessions.add(session);
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/me/contaria/fastquit/FastQuitConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.metadata.ModMetadata;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.util.Formatting;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.server.IntegratedServer;
import org.jetbrains.annotations.NotNull;

import java.util.List;
Expand Down Expand Up @@ -160,7 +160,7 @@ public Screen createConfigScreen(Screen parent) {
} else {
modCompatCategory.addEntry(entryBuilder.startEnumSelector(TextHelper.translatable("text.autoconfig.fastquit.option.allowMultipleServers"), ModCompat.class, ModCompat.DISABLED)
.setTooltip(TextHelper.translatable("text.autoconfig.fastquit.option.allowMultipleServers.@Tooltip").append("\n\n").append(TextHelper.translatable("fastquit.config.compat.allowMultipleServers.disabledForCompat", String.join(", ", MODS_THAT_CONFLICT_WITH_MULTIPLE_SERVERS))))
.setEnumNameProvider(disabled -> TextHelper.translatable("manageServer.resourcePack.disabled").styled(style -> style.withColor(Formatting.RED)))
.setEnumNameProvider(disabled -> TextHelper.translatable("manageServer.resourcePack.disabled").withStyle(style -> style.withColor(ChatFormatting.RED)))
.build()
);
}
Expand Down
18 changes: 9 additions & 9 deletions src/main/java/me/contaria/fastquit/TextHelper.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
package me.contaria.fastquit;

import net.minecraft.screen.ScreenTexts;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;

/**
* Utility class for ease of porting to older Minecraft versions.
*/
public final class TextHelper {

public static final Text OFF = ScreenTexts.OFF;
public static final Text BACK = ScreenTexts.BACK;
public static final Component OFF = CommonComponents.OPTION_OFF;
public static final Component BACK = CommonComponents.GUI_BACK;

public static MutableText translatable(String key, Object... args) {
return Text.translatable(key, args);
public static MutableComponent translatable(String key, Object... args) {
return Component.translatable(key, args);
}

public static MutableText literal(String string) {
return Text.literal(string);
public static MutableComponent literal(String string) {
return Component.literal(string);
}
}
16 changes: 8 additions & 8 deletions src/main/java/me/contaria/fastquit/WaitingScreen.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package me.contaria.fastquit;

import net.minecraft.client.gui.screen.MessageScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.text.Text;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.GenericMessageScreen;
import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

public class WaitingScreen extends MessageScreen {
public class WaitingScreen extends GenericMessageScreen {

private final CallbackInfo callbackInfo;

public WaitingScreen(Text text, @Nullable CallbackInfo callbackInfo) {
public WaitingScreen(Component text, @Nullable CallbackInfo callbackInfo) {
super(text);
if (callbackInfo != null && !callbackInfo.isCancellable()) {
FastQuit.warn("Provided CallbackInfo for \"" + callbackInfo.getId() + "\" is not cancellable!");
Expand All @@ -23,7 +23,7 @@ public WaitingScreen(Text text, @Nullable CallbackInfo callbackInfo) {
public void init() {
super.init();
if (this.callbackInfo != null) {
this.addDrawableChild(ButtonWidget.builder(TextHelper.BACK, button -> this.close()).dimensions(this.width - 100 - 5, this.height - 20 - 5, 100, 20).build());
this.addRenderableWidget(Button.builder(TextHelper.BACK, button -> this.onClose()).bounds(this.width - 100 - 5, this.height - 20 - 5, 100, 20).build());
}
}

Expand All @@ -33,8 +33,8 @@ public boolean shouldCloseOnEsc() {
}

@Override
public void close() {
super.close();
public void onClose() {
super.onClose();
if (this.callbackInfo != null) {
this.callbackInfo.cancel();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package me.contaria.fastquit.mixin;

import me.contaria.fastquit.FastQuit;
import net.minecraft.client.gui.screen.world.EditWorldScreen;
import net.minecraft.world.level.storage.LevelStorage;
import net.minecraft.client.gui.screens.worldselection.EditWorldScreen;
import net.minecraft.world.level.storage.LevelStorageSource;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
Expand All @@ -15,21 +15,21 @@ public abstract class EditWorldScreenMixin {

@Shadow
@Final
private LevelStorage.Session storageSession;
private LevelStorageSource.LevelStorageAccess levelAccess;

// method_54595 - Optimize World
// method_54596 - Make Backup
@Inject(
method = {
"method_54595",
"method_54596"
"lambda$new$12",
"lambda$new$7"
},
at = @At("HEAD"),
require = 2,
remap = false,
cancellable = true
)
private void waitForSaveOnBackupOrOptimizeWorld_cancellable(CallbackInfo ci) {
FastQuit.getSavingWorld(this.storageSession).ifPresent(server -> FastQuit.wait(server, ci));
FastQuit.getSavingWorld(this.levelAccess).ifPresent(server -> FastQuit.wait(server, ci));
}
}
Loading
Loading