Skip to content

Commit b747119

Browse files
Merge branch '1.21.8' into 1.21.4
2 parents eefca91 + 767a08a commit b747119

File tree

9 files changed

+130
-98
lines changed

9 files changed

+130
-98
lines changed

.github/workflows/publish.yml

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,26 +82,29 @@ jobs:
8282
GITHUB_TOKEN: ${{ github.token }}
8383
run: ./gradlew closeMilestone --stacktrace --no-configuration-cache
8484

85+
- name: Build website update inputs
86+
id: website_inputs
87+
if: ${{ inputs.update_website }}
88+
run: |
89+
echo "wurst_version=$(grep '^mod_version=' gradle.properties | cut -d'=' -f2 | tr -d ' \r' | sed 's/^v//' | sed 's/-MC.*$//')" >> "$GITHUB_OUTPUT"
90+
echo "mc_version=$(grep '^minecraft_version=' gradle.properties | cut -d'=' -f2 | tr -d ' \r')" >> "$GITHUB_OUTPUT"
91+
echo "fapi_version=$(grep '^fabric_version=' gradle.properties | cut -d'=' -f2 | tr -d ' \r')" >> "$GITHUB_OUTPUT"
92+
8593
- name: Upload backups
8694
if: ${{ inputs.upload_backups }}
87-
env:
88-
WI_BACKUPS_API_KEY: ${{ secrets.WI_BACKUPS_API_KEY }}
89-
run: ./gradlew uploadBackups --stacktrace --no-configuration-cache
95+
uses: Wurst-Imperium/upload-backups@v1
96+
with:
97+
api_key: ${{ secrets.WI_BACKUPS_API_KEY }}
98+
project: Wurst
99+
version: ${{ steps.website_inputs.outputs.wurst_version }}
100+
path: build/libs/*.jar
90101

91102
- name: Publish to GitHub
92103
if: ${{ inputs.publish_github }}
93104
env:
94105
GITHUB_TOKEN: ${{ secrets.OLD_MCX_PUBLISH_TOKEN }}
95106
run: ./gradlew github --stacktrace --no-configuration-cache
96107

97-
- name: Build website update inputs
98-
id: website_inputs
99-
if: ${{ inputs.update_website }}
100-
run: |
101-
echo "wurst_version=$(grep '^mod_version=' gradle.properties | cut -d'=' -f2 | tr -d ' \r' | sed 's/^v//' | sed 's/-MC.*$//')" >> "$GITHUB_OUTPUT"
102-
echo "mc_version=$(grep '^minecraft_version=' gradle.properties | cut -d'=' -f2 | tr -d ' \r')" >> "$GITHUB_OUTPUT"
103-
echo "fapi_version=$(grep '^fabric_version=' gradle.properties | cut -d'=' -f2 | tr -d ' \r')" >> "$GITHUB_OUTPUT"
104-
105108
- name: Trigger website update
106109
if: ${{ inputs.update_website }}
107110
uses: Wurst-Imperium/dispatch-and-wait@v1

build.gradle

Lines changed: 19 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ buildscript {
66

77
plugins {
88
id "fabric-loom" version "${loom_version}"
9-
id "com.diffplug.spotless" version "8.0.0"
9+
id "com.diffplug.spotless" version "8.1.0"
1010
}
1111

1212
def ENV = System.getenv()
@@ -68,6 +68,10 @@ loom {
6868
accessWidenerPath = file("src/main/resources/wurst.accesswidener")
6969

7070
runs {
71+
clientWithMods {
72+
inherit client
73+
}
74+
7175
clientGameTestWithMods {
7276
inherit client
7377
source = sourceSets.gametest
@@ -89,6 +93,20 @@ dependencies {
8993
testMods "maven.modrinth:sodium:${project.sodium_version}"
9094
}
9195

96+
def cleanClientWithMods = tasks.register("cleanClientWithMods", Delete) {
97+
delete "run/mods"
98+
}
99+
100+
def prepareClientWithMods = tasks.register("prepareClientWithMods", Sync) {
101+
from configurations.testMods
102+
into "run/mods"
103+
}
104+
105+
tasks.named("runClientWithMods") {
106+
dependsOn prepareClientWithMods
107+
finalizedBy cleanClientWithMods
108+
}
109+
92110
def cleanClientGameTestWithMods = tasks.register("cleanClientGameTestWithMods", Delete) {
93111
delete layout.buildDirectory.dir("run/clientGameTestWithMods")
94112
}
@@ -247,60 +265,3 @@ task closeMilestone {
247265
}
248266
}
249267
}
250-
251-
task uploadBackups {
252-
dependsOn build
253-
254-
onlyIf {
255-
ENV.WI_BACKUPS_API_KEY
256-
}
257-
258-
doLast {
259-
def shortVersion = getGhVersion().substring(1)
260-
def backupUrl = "https://api.wurstclient.net/artifact-backups/Wurst/${shortVersion}"
261-
262-
def maxRetries = 3
263-
def retryCount = 0
264-
def success = false
265-
266-
while (!success && retryCount < maxRetries) {
267-
try {
268-
def connection = new URL(backupUrl).openConnection() as HttpURLConnection
269-
def boundary = UUID.randomUUID().toString()
270-
connection.setRequestMethod("POST")
271-
connection.setRequestProperty("X-API-Key", ENV.WI_BACKUPS_API_KEY)
272-
connection.setRequestProperty("Accept", "application/json")
273-
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=$boundary")
274-
connection.doOutput = true
275-
276-
def output = connection.outputStream
277-
[remapJar, remapSourcesJar].each { jarTask ->
278-
def file = jarTask.archiveFile.get().asFile
279-
output << "--${boundary}\r\n"
280-
output << "Content-Disposition: form-data; name=\"files\"; filename=\"${file.name}\"\r\n"
281-
output << "Content-Type: application/java-archive\r\n\r\n"
282-
file.withInputStream { input ->
283-
output << input
284-
}
285-
output << "\r\n"
286-
}
287-
output << "--${boundary}--\r\n"
288-
output.flush()
289-
290-
if(connection.responseCode != 200) {
291-
throw new IOException("HTTP ${connection.responseCode}: ${connection.responseMessage}")
292-
}
293-
294-
success = true
295-
296-
} catch (Exception e) {
297-
retryCount++
298-
if (retryCount >= maxRetries) {
299-
throw new GradleException("Failed to upload backups after ${maxRetries} attempts: ${e.message}")
300-
}
301-
println "Upload attempt ${retryCount} failed: ${e.message}. Retrying in 5 seconds..."
302-
Thread.sleep(5000)
303-
}
304-
}
305-
}
306-
}

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ org.gradle.configuration-cache=true
88
# https://modrinth.com/mod/fabric-api/versions
99
minecraft_version=1.21.4
1010
yarn_mappings=1.21.4+build.8
11-
loader_version=0.17.3
11+
loader_version=0.18.1
1212
loom_version=1.13-SNAPSHOT
1313

1414
# Fabric API
1515
fabric_version=0.119.4+1.21.4
1616

1717
# Mod Properties
18-
mod_version=v7.51.1-MC1.21.4
18+
mod_version=v7.51.2-MC1.21.4
1919
maven_group=net.wurstclient
2020
archives_base_name=Wurst-Client
2121
mod_loader=Fabric

src/gametest/java/net/wurstclient/gametest/tests/XRayHackTest.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ public static void testXRayHack(ClientGameTestContext context,
3838
input.pressKey(GLFW.GLFW_KEY_X);
3939
waitForChunkReloading(context, world);
4040
assertScreenshotEquals(context, "xray_default",
41-
WurstTest.IS_MOD_COMPAT_TEST ? "https://i.imgur.com/02KZHLm.png"
42-
: "https://i.imgur.com/Dftamqv.png");
41+
"https://i.imgur.com/Dftamqv.png");
4342

4443
// Exposed only
4544
runWurstCommand(context, "setcheckbox X-Ray only_show_exposed on");
@@ -48,8 +47,7 @@ public static void testXRayHack(ClientGameTestContext context,
4847
input.pressKey(GLFW.GLFW_KEY_X);
4948
waitForChunkReloading(context, world);
5049
assertScreenshotEquals(context, "xray_exposed_only",
51-
WurstTest.IS_MOD_COMPAT_TEST ? "https://i.imgur.com/xplrJwM.png"
52-
: "https://i.imgur.com/QlEpQTu.png");
50+
"https://i.imgur.com/QlEpQTu.png");
5351

5452
// Opacity mode
5553
runWurstCommand(context, "setcheckbox X-Ray only_show_exposed off");
@@ -58,8 +56,7 @@ public static void testXRayHack(ClientGameTestContext context,
5856
input.pressKey(GLFW.GLFW_KEY_X);
5957
waitForChunkReloading(context, world);
6058
assertScreenshotEquals(context, "xray_opacity",
61-
WurstTest.IS_MOD_COMPAT_TEST ? "https://i.imgur.com/MFc821z.png"
62-
: "https://i.imgur.com/0nLulJn.png");
59+
"https://i.imgur.com/0nLulJn.png");
6360

6461
// Exposed only + opacity
6562
runWurstCommand(context, "setcheckbox X-Ray only_show_exposed on");
@@ -68,8 +65,7 @@ public static void testXRayHack(ClientGameTestContext context,
6865
input.pressKey(GLFW.GLFW_KEY_X);
6966
waitForChunkReloading(context, world);
7067
assertScreenshotEquals(context, "xray_exposed_only_opacity",
71-
WurstTest.IS_MOD_COMPAT_TEST ? "https://i.imgur.com/GRHgW6P.png"
72-
: "https://i.imgur.com/noPWDUl.png");
68+
"https://i.imgur.com/noPWDUl.png");
7369

7470
// Clean up
7571
runCommand(server, "fill ~-5 ~-2 ~5 ~5 ~5 ~7 air");

src/main/java/net/wurstclient/WurstClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public enum WurstClient
5050
public static Minecraft MC;
5151
public static IMinecraftClient IMC;
5252

53-
public static final String VERSION = "7.51.1";
53+
public static final String VERSION = "7.51.2";
5454
public static final String MC_VERSION = "1.21.4";
5555

5656
private PlausibleAnalytics plausible;

src/main/java/net/wurstclient/WurstTranslator.java

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,18 @@
1515
import java.util.IllegalFormatException;
1616
import java.util.List;
1717
import java.util.Map;
18+
import java.util.Optional;
1819
import java.util.function.BiConsumer;
1920

2021
import com.google.common.collect.Lists;
22+
import com.google.gson.JsonParseException;
2123

2224
import net.minecraft.client.Minecraft;
2325
import net.minecraft.client.resources.language.ClientLanguage;
2426
import net.minecraft.client.resources.language.I18n;
2527
import net.minecraft.locale.Language;
2628
import net.minecraft.resources.ResourceLocation;
29+
import net.minecraft.server.packs.repository.KnownPack;
2730
import net.minecraft.server.packs.resources.Resource;
2831
import net.minecraft.server.packs.resources.ResourceManager;
2932
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
@@ -187,17 +190,50 @@ private void loadTranslations(ResourceManager manager,
187190
ResourceLocation langId =
188191
ResourceLocation.fromNamespaceAndPath("wurst", langFilePath);
189192

193+
// IMPORTANT: Exceptions thrown by Language.loadFromJson() must
194+
// be caught to prevent mod detection vulnerabilities using
195+
// intentionally corrupted resource packs.
190196
for(Resource resource : manager.getResourceStack(langId))
197+
{
191198
try(InputStream stream = resource.open())
192199
{
193-
Language.loadFromJson(stream, entryConsumer);
200+
if(isBuiltInWurstResourcePack(resource))
201+
Language.loadFromJson(stream, entryConsumer);
202+
203+
}catch(IOException | JsonParseException e)
204+
{
205+
System.out.println(
206+
"Failed to load Wurst translations for " + langCode);
207+
e.printStackTrace();
194208

195-
}catch(IOException e)
209+
}catch(Exception e)
196210
{
197-
System.out.println("Failed to load translations for "
198-
+ langCode + " from pack " + resource.sourcePackId());
211+
System.out.println(
212+
"Unexpected exception while loading Wurst translations for "
213+
+ langCode);
199214
e.printStackTrace();
200215
}
216+
}
201217
}
202218
}
219+
220+
/**
221+
* Ensures that the given resource is from Wurst's built-in resource pack,
222+
* or at least from another client-side mod pretending to be Wurst, as it
223+
* should be impossible for server-provided resource packs to obtain a
224+
* KnownPack of <code>fabric:wurst</code>.
225+
*
226+
* <p>
227+
* ASSUME THEY CAN BYPASS THIS. CATCH EXCEPTIONS ANYWAY.
228+
*/
229+
private boolean isBuiltInWurstResourcePack(Resource resource)
230+
{
231+
KnownPack knownPack = Optional.ofNullable(resource)
232+
.flatMap(Resource::knownPackInfo).orElse(null);
233+
if(knownPack == null)
234+
return false;
235+
236+
return "fabric".equals(knownPack.namespace())
237+
&& "wurst".equals(knownPack.id());
238+
}
203239
}

src/main/java/net/wurstclient/mixin/FluidRendererMixin.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ private boolean modifyShouldSkipRendering(Direction side, float height,
3737
BlockAndTintGetter world, BlockPos pos, VertexConsumer vertexConsumer,
3838
BlockState blockState, FluidState fluidState)
3939
{
40+
// Note: the null BlockPos is here to skip the "exposed only" check
4041
ShouldDrawSideEvent event = new ShouldDrawSideEvent(blockState, null);
4142
EventManager.fire(event);
4243

src/main/java/net/wurstclient/mixin/sodium/DefaultFluidRendererMixin.java

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ private void onIsFluidOccluded(BlockAndTintGetter world, int x, int y,
8787
}
8888

8989
/**
90-
* Hides and shows fluids when using X-Ray with Sodium installed.
90+
* Hides and shows the top side of fluids when using X-Ray with Sodium
91+
* installed.
9192
*
9293
* <p>
9394
* Works with Sodium >=0.6.13. Last updated for Sodium 0.6.13+mc1.21.4.
@@ -101,13 +102,43 @@ private void onIsFullBlockFluidOccluded(BlockAndTintGetter world,
101102
BlockPos pos, Direction dir, BlockState state, FluidState fluid,
102103
CallbackInfoReturnable<Boolean> cir)
103104
{
104-
ShouldDrawSideEvent event = new ShouldDrawSideEvent(state, pos);
105+
// Note: the null BlockPos is here to skip the "exposed only" check
106+
ShouldDrawSideEvent event = new ShouldDrawSideEvent(state, null);
105107
EventManager.fire(event);
106108

107109
if(event.isRendered() != null)
108110
cir.setReturnValue(!event.isRendered());
109111
}
110112

113+
/**
114+
* Hides and shows all other sides of fluids when using X-Ray with Sodium
115+
* installed.
116+
*/
117+
@Inject(at = @At("HEAD"),
118+
method = "isSideExposed(Lnet/minecraft/class_1920;IIILnet/minecraft/class_2350;F)Z",
119+
cancellable = true,
120+
remap = false,
121+
require = 0)
122+
private void onIsSideExposed(BlockAndTintGetter world, int x, int y, int z,
123+
Direction dir, float height, CallbackInfoReturnable<Boolean> cir)
124+
{
125+
BlockPos pos = new BlockPos(x, y, z);
126+
BlockState state = world.getBlockState(pos);
127+
128+
// Note: the null BlockPos is here to skip the "exposed only" check
129+
ShouldDrawSideEvent event = new ShouldDrawSideEvent(state, null);
130+
EventManager.fire(event);
131+
132+
if(event.isRendered() == null)
133+
return;
134+
135+
BlockPos nPos = pos.offset(dir.getUnitVec3i());
136+
BlockState neighborState = world.getBlockState(nPos);
137+
138+
cir.setReturnValue(!neighborState.getFluidState().getType()
139+
.isSame(state.getFluidState().getType()) && event.isRendered());
140+
}
141+
111142
/**
112143
* Modifies opacity of fluids when using X-Ray with Sodium installed.
113144
*
@@ -117,8 +148,8 @@ private void onIsFullBlockFluidOccluded(BlockAndTintGetter world,
117148
@ModifyExpressionValue(at = @At(value = "INVOKE",
118149
target = "Lnet/caffeinemc/mods/sodium/api/util/ColorARGB;toABGR(I)I"),
119150
method = "updateQuad",
120-
require = 0,
121-
remap = false)
151+
remap = false,
152+
require = 0)
122153
private int onUpdateQuad(int original, @Local(argsOnly = true) BlockPos pos,
123154
@Local(argsOnly = true) FluidState state)
124155
{

0 commit comments

Comments
 (0)