Skip to content

Commit 13efbdb

Browse files
authored
Merge pull request #138 from litetex-oss/dev
Release
2 parents 0d40461 + 70e9bf1 commit 13efbdb

File tree

11 files changed

+342
-82
lines changed

11 files changed

+342
-82
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# 4.0.1
2+
* Made animated GIF decoding more reliable
3+
* This should fix broken textures #135
4+
* The maximum size for image downloads is now 10MB by default
5+
16
# 4.0.0
27
* Implemented Texture Resolvers
38
* Added support for GIFs #131

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,20 @@ This demo showcases how to apply the capes inside [``custom-cape-demo``](https:/
5353

5454
For more details have a look at [CustomProvider](https://github.com/litetex-oss/mcm-cape-provider/tree/dev/src/main/java/net/litetex/capes/provider/CustomProvider.java) and [CustomProviderConfig](https://github.com/litetex-oss/mcm-cape-provider/tree/dev/src/main/java/net/litetex/capes/config/CustomProviderConfig.java)
5555

56+
##### Maximum size
57+
58+
Images/Textures should not exceed 10MB otherwise they might be ignored.
59+
5660
##### Texture resolvers / Animated textures
5761

5862
Texture resolvers can be selected using the `textureResolverId` attribute.
5963
The following resolvers are currently built-in:
6064

61-
| Resolver-ID | Animated | Format | Example |
62-
| --- | --- | --- | --- |
63-
| `default` / null || [PNG](https://de.wikipedia.org/wiki/Portable_Network_Graphics) | [uuid.png](https://raw.githubusercontent.com/litetex-oss/mcm-cape-provider/refs/heads/dev/custom-cape-demo/uuid.png) |
64-
| `sprite` || Stacked [PNG](https://de.wikipedia.org/wiki/Portable_Network_Graphics) | [animated.png](https://raw.githubusercontent.com/litetex-oss/mcm-cape-provider/refs/heads/dev/custom-cape-demo/animated.png) |
65-
| `gif` || [GIF](https://de.wikipedia.org/wiki/Graphics_Interchange_Format) | [animated.gif](https://raw.githubusercontent.com/litetex-oss/mcm-cape-provider/refs/heads/dev/custom-cape-demo/animated.gif) |
65+
| Resolver-ID | Animated | Format | Example | Notes |
66+
| --- | --- | --- | --- | --- |
67+
| `default` / null || [PNG](https://de.wikipedia.org/wiki/Portable_Network_Graphics) | [uuid.png](https://raw.githubusercontent.com/litetex-oss/mcm-cape-provider/refs/heads/dev/custom-cape-demo/uuid.png) | |
68+
| `sprite` || Stacked [PNG](https://de.wikipedia.org/wiki/Portable_Network_Graphics) | [animated.png](https://raw.githubusercontent.com/litetex-oss/mcm-cape-provider/refs/heads/dev/custom-cape-demo/animated.png) | |
69+
| `gif` || [GIF](https://de.wikipedia.org/wiki/Graphics_Interchange_Format) | [animated.gif](https://raw.githubusercontent.com/litetex-oss/mcm-cape-provider/refs/heads/dev/custom-cape-demo/animated.gif) | _Usage not recommended_<br/>GIFs require more resources when compared to more modern formats like PNG. |
6670

6771
Please note that animated textures can be frozen or completely disabled in the settings.
6872

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

gradlew

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gradlew.bat

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package net.litetex.capes.handler;
2+
3+
import net.minecraft.client.texture.NativeImage;
4+
5+
6+
public record AnimatedNativeImageContainer(
7+
NativeImage image,
8+
int delayMs
9+
)
10+
{
11+
public AnimatedNativeImageContainer(final NativeImage image)
12+
{
13+
this(image, 100);
14+
}
15+
}

src/main/java/net/litetex/capes/handler/PlayerCapeHandler.java

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,14 @@
88
import java.net.http.HttpClient;
99
import java.net.http.HttpRequest;
1010
import java.time.Duration;
11-
import java.util.ArrayList;
1211
import java.util.Arrays;
1312
import java.util.Collection;
14-
import java.util.LinkedHashMap;
1513
import java.util.List;
16-
import java.util.Map;
1714
import java.util.Optional;
1815
import java.util.Set;
1916
import java.util.UUID;
2017
import java.util.concurrent.CompletableFuture;
21-
import java.util.stream.Collectors;
18+
import java.util.concurrent.atomic.AtomicInteger;
2219
import java.util.stream.Stream;
2320

2421
import org.slf4j.Logger;
@@ -172,7 +169,7 @@ private boolean isCapeBlocked(final CapeProvider provider, final byte[] imageByt
172169
return blockedCapeHashes.contains(Arrays.hashCode(imageBytes));
173170
}
174171

175-
private Map<Identifier, NativeImage> determineTexturesToRegister(
172+
private List<TextureToRegister> determineTexturesToRegister(
176173
final TextureResolver textureResolver,
177174
final byte[] imageData,
178175
final boolean freezeAnimation,
@@ -186,40 +183,42 @@ private Map<Identifier, NativeImage> determineTexturesToRegister(
186183

187184
if(resolved instanceof final TextureResolver.DefaultResolvedTextureData defaultResolvedTextureData)
188185
{
189-
return Map.of(identifier(this.uuid().toString()), defaultResolvedTextureData.texture());
186+
return List.of(new TextureToRegister(
187+
identifier(this.uuid().toString()),
188+
defaultResolvedTextureData.texture()));
190189
}
191190
else if(resolved instanceof final TextureResolver.AnimatedResolvedTextureData animatedResolvedTextureData)
192191
{
193-
final Map<Integer, NativeImage> textures = animatedResolvedTextureData.textures();
194-
Stream<Map.Entry<Integer, NativeImage>> animatedTextureStream = textures.entrySet().stream();
192+
final List<AnimatedNativeImageContainer> textures = animatedResolvedTextureData.textures();
193+
Stream<AnimatedNativeImageContainer> animatedTextureStream = textures.stream();
195194

196195
if(textures.isEmpty())
197196
{
198197
LOG.warn(
199198
"Received animated texture with no frames[url='{}',profileId='{}']",
200199
url,
201200
this.profile.getId());
202-
return Map.of();
201+
return List.of();
203202
}
204203

205204
if(freezeAnimation)
206205
{
207206
animatedTextureStream = animatedTextureStream.limit(1);
208207
}
209208

209+
final AtomicInteger counter = new AtomicInteger(0);
210210
return animatedTextureStream
211-
.collect(Collectors.toMap(
212-
e -> identifier(
213-
this.uuid() + (!freezeAnimation ? "/" + e.getKey() : "")),
214-
Map.Entry::getValue,
215-
(l, r) -> r,
216-
LinkedHashMap::new));
211+
.map(c -> new TextureToRegister(
212+
identifier(this.uuid() + (!freezeAnimation ? "/" + counter.getAndIncrement() : "")),
213+
c.image(),
214+
c.delayMs()))
215+
.toList();
217216
}
218217
throw new IllegalStateException("Unexpected ResolvedTextureData: " + resolved.getClass().getSimpleName());
219218
}
220219

221220
private Optional<IdentifierProvider> registerTexturesAndGetProvider(
222-
final Map<Identifier, NativeImage> texturesToRegister)
221+
final List<TextureToRegister> texturesToRegister)
223222
{
224223
if(texturesToRegister.isEmpty())
225224
{
@@ -229,19 +228,31 @@ private Optional<IdentifierProvider> registerTexturesAndGetProvider(
229228
final TextureManager textureManager = MinecraftClient.getInstance().getTextureManager();
230229
// Do texturing work NOT on Render thread
231230
CompletableFuture.runAsync(
232-
() -> texturesToRegister.forEach((id, texture) ->
231+
() -> texturesToRegister.forEach(t ->
233232
textureManager.registerTexture(
234-
id,
235-
new NativeImageBackedTexture(id::toString, texture))),
233+
t.identifier(),
234+
new NativeImageBackedTexture(t.identifier()::toString, t.image()))),
236235
MinecraftClient.getInstance())
237236
.exceptionally(ex -> {
238237
LOG.warn("Failed to register textures", ex);
239238
return null;
240239
});
241240

242241
return Optional.of(texturesToRegister.size() == 1
243-
? new DefaultIdentifierProvider(texturesToRegister.keySet().iterator().next())
244-
: new AnimatedIdentifierProvider(texturesToRegister.keySet()));
242+
? new DefaultIdentifierProvider(texturesToRegister.getFirst().identifier())
243+
: new AnimatedIdentifierProvider(texturesToRegister));
244+
}
245+
246+
record TextureToRegister(
247+
Identifier identifier,
248+
NativeImage image,
249+
int delayMs
250+
)
251+
{
252+
public TextureToRegister(final Identifier identifier, final NativeImage image)
253+
{
254+
this(identifier, image, 100);
255+
}
245256
}
246257

247258
private AnimatedCapesHandling animatedCapesHandling()
@@ -281,13 +292,21 @@ public boolean dynamicIdentifier()
281292

282293
static class AnimatedIdentifierProvider implements IdentifierProvider
283294
{
284-
private final List<Identifier> identifiers;
295+
private final List<IdentifierContainer> identifiers;
285296
private int lastFrameIndex;
286297
private long nextFrameTime;
287298

288-
public AnimatedIdentifierProvider(final Collection<Identifier> identifiers)
299+
public AnimatedIdentifierProvider(final Collection<TextureToRegister> identifiers)
289300
{
290-
this.identifiers = new ArrayList<>(identifiers);
301+
this.identifiers = identifiers.stream()
302+
.map(t -> new IdentifierContainer(
303+
t.identifier(),
304+
Math.clamp(
305+
t.delayMs(),
306+
1,
307+
// 1min
308+
60 * 1_000)))
309+
.toList();
291310
}
292311

293312
@Override
@@ -298,17 +317,25 @@ public Identifier identifier()
298317
{
299318
final int thisFrameIndex = (this.lastFrameIndex + 1) % this.identifiers.size();
300319
this.lastFrameIndex = thisFrameIndex;
301-
this.nextFrameTime = time + 100L;
302320

303-
return this.identifiers.get(thisFrameIndex);
321+
final IdentifierContainer ic = this.identifiers.get(thisFrameIndex);
322+
this.nextFrameTime = time + ic.delay();
323+
324+
return ic.identifier();
304325
}
305-
return this.identifiers.get(this.lastFrameIndex);
326+
return this.identifiers.get(this.lastFrameIndex).identifier();
306327
}
307328

308329
@Override
309330
public boolean dynamicIdentifier()
310331
{
311332
return true;
312333
}
334+
335+
record IdentifierContainer(
336+
Identifier identifier,
337+
int delay)
338+
{
339+
}
313340
}
314341
}

0 commit comments

Comments
 (0)