Compare commits

...

99 commits

Author SHA1 Message Date
Sollace
57754d8dec
Change christmas check to include the 24th - 26th Closes #299 2025-01-05 12:28:59 +01:00
Sollace
ec8f92e151
Update hdskins
# Conflicts:
#	gradle.properties
2024-12-17 17:59:46 +01:00
Sollace
e21ce62631
Merge branch '1.20.1' into 1.20.2 2024-07-31 15:13:32 +02:00
Sollace
c78cf32bd4
Fix build 2024-07-31 15:13:14 +02:00
Sollace
4ef2d4ab54
Merge branch '1.20.1' into 1.20.2
# Conflicts:
#	src/main/java/com/minelittlepony/client/model/part/PonyEars.java
2024-04-26 21:02:12 +01:00
Sollace
82a89eb1ba
Apply changeling pony ears fix from 1.20.2+ 2024-04-26 21:01:08 +01:00
Sollace
8bf3bc38a4
Remove patch that only applies to 1.20.1 2024-04-26 20:59:39 +01:00
Sollace
e01580f804
Merge branch '1.20.1' into 1.20.2 2024-04-26 20:55:50 +01:00
­Sollace
040105c792
New Crowdin updates (#275)
* New translations en_us.json (English (upside down))
* New translations en_us.json (Pirate English)
* New translations en_us.json (English, United Kingdom)
* New translations en_us.json (LOLCAT)
* New translations en_us.json (Anglish)
* New translations en_us.json (German)
* New translations en_us.json (Afrikaans)
2024-04-26 20:38:00 +01:00
­Sollace
18591c0720
New Crowdin updates (#274)
* New translations en_us.json (German)

* New translations en_us.json (Russian)
2024-04-09 16:07:34 +01:00
Sollace
31a9a9b0e6
New Crowdin updates (#273)
# Conflicts:
#	src/main/resources/assets/minelittlepony/lang/ru_ru.json
2024-04-09 14:19:51 +01:00
­Sollace
c46cbea872
Update Crowdin configuration file 2024-04-09 14:19:03 +01:00
­Sollace
299a81088c
New Crowdin updates (#273) 2024-04-09 14:17:19 +01:00
­Sollace
bdc807b102 Update Crowdin configuration file 2024-04-09 14:08:12 +01:00
­Sollace
e149e926d2
Update README.md 2024-04-09 13:32:07 +01:00
­Sollace
4d55f546bb
Update Crowdin configuration file 2024-04-09 13:32:01 +01:00
­Sollace
c0e4620355
Update README.md 2024-04-09 13:31:18 +01:00
­Sollace
a3ea4f5982 Update Crowdin configuration file 2024-04-09 13:25:43 +01:00
Sollace
39f4a7d26d
Update dependencies 2024-04-06 15:17:02 +01:00
Sollace
71518d9478
Update dependencies 2024-04-06 15:12:19 +01:00
Sollace
dfa9ce8977
Fix giant scale 2024-03-05 12:25:36 +00:00
Sollace
0d97f6b9d4
Fix giant scale 2024-03-05 12:24:54 +00:00
Sollace
76211930d5
Fixed not all wearables being detected 2024-03-05 12:10:15 +00:00
Sollace
a40b55e142
Fix the leg issue 2024-02-24 16:36:03 +00:00
Sollace
aa08f12320
Add mson to the depends block (almost forgot this) 2024-02-09 19:47:31 +00:00
Sollace
f3cc92dee6
Fix typo 2024-02-09 19:45:42 +00:00
Sollace
9c8d6d0a86
Actually use the dynamic depends blocks 2024-02-09 19:45:34 +00:00
Sollace
8ce2fc4e6d
Update mson 2024-02-09 19:39:12 +00:00
Sollace
7da44b879c
Fix various transformations for when a pony is lying down but not sleeping 2024-02-09 19:34:10 +00:00
Sollace
f5bfa14bb1
Increase time required before a pony will lie down 2024-02-09 19:34:05 +00:00
Sollace
d392b204a3
Update mson 2024-02-09 19:32:22 +00:00
Sollace
21a33ebc76
Temp fix for an hdskins bug 2024-02-09 19:25:44 +00:00
Sollace
0895e94053
Fix various transformations for when a pony is lying down but not sleeping 2024-02-09 19:25:23 +00:00
Sollace
387c9307d0
Increase time required before a pony will lie down 2024-02-09 19:24:49 +00:00
Sollace
475e96726e
Update mson 2024-02-09 17:40:15 +00:00
Sollace
9d65185fcd
Update skins pack 2024-02-09 16:57:40 +00:00
Sollace
c365c141ef
Update mson one last time 2023-12-08 17:23:42 +00:00
Sollace
a94137fda9
1.20.2-rc1 -> 1.20.2 2023-12-08 17:23:34 +00:00
Sollace
34087bd105
Update mson to fix sodium compatibility 2023-12-07 21:49:33 +00:00
Sollace
cb423186e7
Fix reformed changelings' ears 2023-12-07 21:48:10 +00:00
Sollace
af99765bf2
Fix lighting on pony butts 2023-12-07 21:47:59 +00:00
Sollace
1faa192f33
Add nirik skin type 2023-12-07 21:47:49 +00:00
Sollace
b9baba84de
Update skin pack 2023-12-07 21:47:22 +00:00
Sollace
814dac6414
Fix seapony skins. Might have been a simpler issue than I thought 2023-12-06 15:18:39 +00:00
Sollace
667ce0ce4b
Parse pony data on the client thread executor, and don't send unparsed pony data responses to a consenting server. Rather wait for the data to resolve and let the entity send it normally.
# Conflicts:
#	src/main/java/com/minelittlepony/api/events/Channel.java
#	src/main/java/com/minelittlepony/client/util/render/NativeUtil.java
2023-10-29 21:39:25 +00:00
Sollace
8832beac32
Parse pony data on the client thread executor, and don't send unparsed pony data responses to a consenting server. Rather wait for the data to resolve and let the entity send it normally. 2023-10-27 22:09:55 +01:00
Sollace
4de3f3daa2
Fix constant logging when playing on a multiplayer server that doesn't register for receiving pony data packets
# Conflicts:
#	src/main/java/com/minelittlepony/api/events/Channel.java
#	src/main/java/com/minelittlepony/client/render/EquineRenderManager.java
2023-10-24 01:16:53 +01:00
Sollace
9064272771
Fix constant logging when playing on a multiplayer server that doesn't register for receiving pony data packets 2023-10-24 01:12:36 +01:00
Sollace
011ceedafe
Update version range 2023-10-06 19:33:46 +01:00
Sollace
2ed7f91786
Only replace a layer if it has a compatible buffer format. Should fix #254 2023-10-06 18:51:45 +01:00
Sollace
d011c11689
Only replace a layer if it has a compatible buffer format. Should fix #254 2023-10-06 18:51:20 +01:00
Sollace
060c4abfff
Ponies can now lie down by holding crouch and not moving 2023-10-06 00:48:11 +01:00
Sollace
9f77999baf
Fixed tiny silly ponies reverting to normal villagers when they grow up
# Conflicts:
#	src/main/java/com/minelittlepony/client/render/entity/npc/textures/SillyPonyTextureSupplier.java
2023-10-06 00:47:45 +01:00
Sollace
fa0c903c0f
Fixed magic not rendering for items held by other entities 2023-10-06 00:45:48 +01:00
Sollace
a7acd2a1c1
More fixes 2023-10-06 00:45:19 +01:00
Sollace
101b2bd20c
Fixed mobs' arms sticking too far up when sitting in a boat
# Conflicts:
#	src/main/java/com/minelittlepony/client/model/IMobModel.java
2023-10-06 00:40:04 +01:00
Sollace
9334836aa7
Disable shadow position changing
# Conflicts:
#	src/main/java/com/minelittlepony/client/render/entity/PlayerPonyRenderer.java
2023-10-06 00:38:52 +01:00
Sollace
a69140b761
fixes 2023-10-06 00:38:46 +01:00
Sollace
50ce9f92d1
Fixed left ear rotating incorrectly 2023-10-06 00:36:50 +01:00
Sollace
971f3623cf
Fixed pony skin data not being reliably sent to servers
# Conflicts:
#	src/main/java/com/minelittlepony/api/pony/network/fabric/Channel.java
#	src/main/java/com/minelittlepony/client/compat/hdskins/DummyPony.java
#	src/main/java/com/minelittlepony/client/mixin/MixinClientPlayerEntity.java
#	src/main/java/com/minelittlepony/client/render/EquineRenderManager.java
2023-10-06 00:35:33 +01:00
Sollace
24e220bb29
Allow armor to render with translucency 2023-10-06 00:23:08 +01:00
Sollace
f8b21e78ba
Update settings.gradle 2023-10-06 00:20:19 +01:00
Sollace
131bc7cb3f
Fixed armour models loading from the incorrect directory 2023-10-06 00:20:05 +01:00
Sollace
31857e2de0
The direction a pony's head faces when lying in a bed is now determined by which way you're looking when you climb in 2023-10-06 00:19:42 +01:00
Sollace
d3a5c80981
Fixed trident animation. Closes #250 2023-10-06 00:18:09 +01:00
Sollace
be5382ebad
Fixed bat ponies' wings rotating incorrectly and move them up a bit 2023-10-06 00:17:58 +01:00
Sollace
3ae6a48204
Fixed horns not glowing 2023-10-06 00:17:01 +01:00
Sollace
4717c9e458
Ponies can now lie down by holding crouch and not moving 2023-10-05 20:42:31 +01:00
Sollace
e31ee1c53b
Fixed tiny silly ponies reverting to normal villagers when they grow up 2023-10-05 20:28:29 +01:00
Sollace
509f6477f2
Fixed magic not rendering for items held by other entities 2023-10-05 20:22:09 +01:00
Sollace
3322e7eaff
Fixed model visibility not updating for mobs 2023-10-05 20:21:50 +01:00
Sollace
4904c78e01
Fixed mob placement in boats 2023-10-05 20:05:07 +01:00
Sollace
8dad366317
Fixed mobs' arms sticking too far up when sitting in a boat 2023-10-05 20:04:55 +01:00
Sollace
b1869c824e
Disable shadow position changing 2023-10-05 19:53:14 +01:00
Sollace
72ff58015d
Fixed left ear rotating incorrectly 2023-10-05 19:52:03 +01:00
Sollace
76a2e043b7
Clean up the EquineRendermanager (should fix some crashing issues with null seapony models) 2023-10-05 19:46:40 +01:00
横刀天笑(Knife smile)
f54cd5682d
update zh_cn.json (#253) 2023-09-28 14:40:34 +01:00
Sollace
26aa16d684
Fixed pony skin data not being reliably sent to servers 2023-09-28 14:38:39 +01:00
Sollace
9f280f79eb
Move SkinsProxy to the api package and decouple from the implementations a little better 2023-09-28 14:07:36 +01:00
Sollace
b538174933
Clean up the code a little bit 2023-09-28 13:48:52 +01:00
Sollace
f70ec0996c
Fixed buffer overflow 2023-09-28 13:48:14 +01:00
Sollace
c2337058f6
Update russian translation 2023-09-27 17:41:20 +01:00
Sollace
1c4fa62676
Update translations 2023-09-27 17:38:32 +01:00
Sollace
f5603b05b7
Update dependencies 2023-09-27 17:28:30 +01:00
Sollace
ca728ded81
Allow armor to render with translucency 2023-09-27 12:11:20 +01:00
Sollace
24a8afc508
Change mixed humans skins option to a dual skin mode and add a priority trigger pixel to facilitate skin sorting 2023-09-27 02:00:18 +01:00
Sollace
6013fa2ad5
Add experimental option to skip hd skins when showing players as humans 2023-09-27 01:27:20 +01:00
Sollace
2c6c23d05c
Fix typo 2023-09-27 01:18:26 +01:00
Sollace
0f9e865dc4
Update hdskins 2023-09-26 21:13:16 +01:00
Sollace
15274aba2b
Fixed settings screen background not rendering correctly 2023-09-26 20:22:52 +01:00
Sollace
429cdb644e
Update kirin 2023-09-26 20:22:38 +01:00
Sollace
5cf082d28d
Update settings.gradle 2023-09-26 19:56:27 +01:00
Sollace
dcb8631eb9
The direction a pony's head faces when lying in a bed is now determined by which way you're looking when you climb in 2023-09-26 17:57:18 +01:00
Sollace
f99309cd55
Fixed trident animation. Closes #250 2023-09-26 17:14:09 +01:00
Sollace
5b9d85d8ea
Update hdskins 2023-09-26 16:45:35 +01:00
Sollace
cd25b9e269
Fixed bat ponies' wings rotating incorrectly and move them up a bit 2023-09-26 16:45:25 +01:00
Sollace
b37ffa9860
Rewrites round tri 2023-09-26 16:42:55 +01:00
Sollace
0e30b2c8dd
Fix that pesky compiler warning 2023-09-26 01:45:50 +01:00
Sollace
4b842c9e9a
Further refactoring and consolidating 2023-09-26 01:45:28 +01:00
141 changed files with 1592 additions and 1289 deletions

View file

@ -6,6 +6,7 @@
[![Modrinth](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.modrinth.com%2Fv2%2Fproject%2Fmine-little-pony%2Fversion&query=%24%5B0%5D.version_number&label=modrinth)](https://modrinth.com/mod/mine-little-pony) [![Modrinth](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.modrinth.com%2Fv2%2Fproject%2Fmine-little-pony%2Fversion&query=%24%5B0%5D.version_number&label=modrinth)](https://modrinth.com/mod/mine-little-pony)
[![Discord Server](https://img.shields.io/discord/182490536119107584.svg?color=blueviolet)](https://discord.gg/HbJSFyu) [![Discord Server](https://img.shields.io/discord/182490536119107584.svg?color=blueviolet)](https://discord.gg/HbJSFyu)
![License](https://img.shields.io/github/license/MineLittlePony/MineLittlePony) ![License](https://img.shields.io/github/license/MineLittlePony/MineLittlePony)
[![Crowdin](https://badges.crowdin.net/mine-little-pony/localized.svg)](https://crowdin.com/project/mine-little-pony)
![](https://img.shields.io/badge/api-fabric-orange.svg) ![](https://img.shields.io/badge/api-fabric-orange.svg)
Turns players and mobs into ponies. Turns players and mobs into ponies.

View file

@ -1,15 +1,15 @@
buildscript { buildscript {
dependencies { dependencies {
classpath 'com.github.dexman545:Outlet:1.3.10' classpath 'com.github.dexman545:Outlet:1.6.1'
} }
} }
plugins { plugins {
id 'fabric-loom' version '1.3-SNAPSHOT' id 'fabric-loom' version '1.5-SNAPSHOT'
id 'maven-publish' id 'maven-publish'
id 'com.modrinth.minotaur' version '2.+' id 'com.modrinth.minotaur' version '2.+'
id 'org.ajoberstar.reckon' version '0.13.0' id 'org.ajoberstar.reckon' version '0.13.1'
} }
apply plugin: 'dex.plugins.outlet' apply plugin: 'io.github.dexman545.outlet'
java { java {
toolchain { toolchain {
@ -86,7 +86,9 @@ processResources {
expand "version": project.version.toString(), expand "version": project.version.toString(),
"minecraftVersion": project.minecraft_version_range, "minecraftVersion": project.minecraft_version_range,
"loaderVersion": ">=${project.loader_version}", "loaderVersion": ">=${project.loader_version}",
"fabricVersion": ">=${project.fabric_version}" "fabricVersion": ">=${project.fabric_version}",
"kirinVersion": ">=${project.kirin_version}",
"msonVersion": ">=${project.mson_version}"
} }
from 'LICENSE' from 'LICENSE'

3
crowdin.yml Normal file
View file

@ -0,0 +1,3 @@
files:
- source: src/main/resources/assets/minelittlepony/lang/en_us.json
translation: /%original_path%/%locale_with_underscore%.%file_extension%

View file

@ -3,10 +3,10 @@ org.gradle.daemon=false
# Fabric Properties # Fabric Properties
# check these on https://fabricmc.net/develop # check these on https://fabricmc.net/develop
minecraft_version=1.20.2-rc1 minecraft_version=1.20.2
yarn_mappings=1.20.2-rc1+build.2 yarn_mappings=1.20.2+build.4
loader_version=0.14.22 loader_version=0.15.1
fabric_version=0.88.5+1.20.2 fabric_version=0.91.1+1.20.2
# Mod Properties # Mod Properties
group=com.minelittlepony group=com.minelittlepony
@ -20,7 +20,7 @@ org.gradle.daemon=false
modrinth_project_id=JBjInUXM modrinth_project_id=JBjInUXM
# Dependencies # Dependencies
modmenu_version=8.0.0-beta.1 modmenu_version=8.0.0
kirin_version=1.16.0-beta.1+1.20.2 kirin_version=1.16.1+1.20.2
hd_skins_version=6.11.0-beta.2+1.20.2 hd_skins_version=6.12.4+1.20.2
mson_version=1.9.0-beta.1 mson_version=1.9.3+1.20.2

View file

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View file

@ -1,14 +1,8 @@
pluginManagement { pluginManagement {
repositories { repositories {
mavenCentral() mavenCentral()
maven { maven { name 'Fabric'; url 'https://maven.fabricmc.net/' }
name = 'Fabric' maven { name 'Jitpack'; url 'https://jitpack.io' }
url = 'https://maven.fabricmc.net/'
}
maven {
name = 'Jitpack'
url = 'https://jitpack.io'
}
gradlePluginPortal() gradlePluginPortal()
} }
} }

2
skins

@ -1 +1 @@
Subproject commit 8987db558b16657245ab8d0b98be366f46dc157c Subproject commit 45dfe1101b4506077b3d3f2246b08c9b485735eb

View file

@ -3,6 +3,7 @@ package com.minelittlepony.api.config;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.pony.meta.*; import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.common.client.gui.VisibilityMode;
import com.minelittlepony.common.util.GamePaths; import com.minelittlepony.common.util.GamePaths;
import com.minelittlepony.common.util.settings.*; import com.minelittlepony.common.util.settings.*;
@ -53,8 +54,13 @@ public class PonyConfig extends Config {
.addComment("Helps to prevent entities from vanishing when they're in long stacks"); .addComment("Helps to prevent entities from vanishing when they're in long stacks");
public final Setting<Boolean> horsieMode = value("settings", "horsieMode", false) public final Setting<Boolean> horsieMode = value("settings", "horsieMode", false)
.addComment("Enables the alternative horsey models from the April Fools 2023 update"); .addComment("Enables the alternative horsey models from the April Fools 2023 update");
public final Setting<Boolean> mixedHumanSkins = value("settings", "dualSkinMode", false)
.addComment("(Experimental) Use priority to decide between displaying the HDSkins' texture, or vanilla mojang server skin")
.addComment("(Experimental) eg. On pony level = HUMANS")
.addComment("(Experimental) Any time both skins resolve to the same race (eg. on pony-level HUMANS, or if both are ponies)")
.addComment("(Experimental) the skin with the highest priority will be chosen.");;
public final Setting<Sizes> sizeOverride = value("debug", "sizeOverride", Sizes.UNSET) public final Setting<SizePreset> sizeOverride = value("debug", "sizeOverride", SizePreset.UNSET)
.addComment("Overrides pony sizes") .addComment("Overrides pony sizes")
.addComment("Possible values: TALL, BULKY, LANKY, NORMAL, YEARLING, FOAL, UNSET (default)"); .addComment("Possible values: TALL, BULKY, LANKY, NORMAL, YEARLING, FOAL, UNSET (default)");
@ -68,10 +74,17 @@ public class PonyConfig extends Config {
public final Setting<Boolean> flappyElytras = value("customisation", "flappyElytras", false) public final Setting<Boolean> flappyElytras = value("customisation", "flappyElytras", false)
.addComment("Pegasi will use their wings to fly even when they're wearing an elytra"); .addComment("Pegasi will use their wings to fly even when they're wearing an elytra");
public final Setting<Boolean> noFun = value("customisation", "noFun", false) public final Setting<Boolean> noFun = value("customisation", "noFun", false)
.addComment("Disables certain easter eggs and secrets (party pooper)") .addComment("Disables certain easter eggs and secrets (party pooper)")
.addComment("Turning this off may help with compatibility in some cases"); .addComment("Turning this off may help with compatibility in some cases");
public final Setting<VisibilityMode> horseButton = value("horseButton", VisibilityMode.AUTO)
.addComment("Whether to show the mine little pony settings button on the main menu")
.addComment("AUTO (default) - only show when HDSkins is not installed")
.addComment("ON - always show")
.addComment("OFF - never show");
public PonyConfig(Path path) { public PonyConfig(Path path) {
super(HEIRARCHICAL_JSON_ADAPTER, path); super(HEIRARCHICAL_JSON_ADAPTER, path);
instance = this; instance = this;
@ -132,14 +145,14 @@ public class PonyConfig extends Config {
} }
public static Size getEffectiveSize(Size size) { public static Size getEffectiveSize(Size size) {
Sizes sz = instance.sizeOverride.get(); SizePreset sz = instance.sizeOverride.get();
if (sz != Sizes.UNSET) { if (sz != SizePreset.UNSET) {
return sz; return sz;
} }
if (size == Sizes.UNSET || !instance.sizes.get()) { if (size == SizePreset.UNSET || !instance.sizes.get()) {
return Sizes.NORMAL; return SizePreset.NORMAL;
} }
return size; return size;

View file

@ -1,4 +1,4 @@
package com.minelittlepony.api.pony.network.fabric; package com.minelittlepony.api.events;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
@ -8,40 +8,34 @@ import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.api.pony.Pony; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.minelittlepony.api.pony.PonyData; import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.network.MsgPonyData;
import com.minelittlepony.client.MineLittlePony;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public class Channel { public class Channel {
private static final Identifier CLIENT_PONY_DATA = new Identifier("minelittlepony", "pony_data"); private static final Identifier CLIENT_PONY_DATA = new Identifier("minelittlepony", "pony_data");
private static final Identifier REQUEST_PONY_DATA = new Identifier("minelittlepony", "request_pony_data"); private static final Identifier REQUEST_PONY_DATA = new Identifier("minelittlepony", "request_pony_data");
private static final Logger LOGGER = LogManager.getLogger("MineLittlePony:Networking");
private static boolean registered; private static boolean registered;
public static void bootstrap() { public static void bootstrap() {
ClientLoginConnectionEvents.INIT.register((handler, client) -> { ClientLoginConnectionEvents.INIT.register((handler, client) -> {
registered = false; registered = false;
MineLittlePony.logger.info("Resetting registered flag");
}); });
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
MineLittlePony.logger.info("Sending consent packet to " + handler.getPlayer().getName().getString()); LOGGER.info("Sending consent packet to " + handler.getPlayer().getName().getString());
sender.sendPacket(REQUEST_PONY_DATA, PacketByteBufs.empty()); sender.sendPacket(REQUEST_PONY_DATA, PacketByteBufs.empty());
}); });
ClientPlayNetworking.registerGlobalReceiver(REQUEST_PONY_DATA, (client, handler, ignored, sender) -> { ClientPlayNetworking.registerGlobalReceiver(REQUEST_PONY_DATA, (client, handler, ignored, sender) -> {
if (client.player != null) {
Pony pony = Pony.getManager().getPony(client.player);
registered = true; registered = true;
MineLittlePony.logger.info("Server has just consented"); LOGGER.info("Server has just consented");
sender.sendPacket(CLIENT_PONY_DATA, MsgPonyData.write(pony.metadata(), PacketByteBufs.create()));
}
}); });
ServerPlayNetworking.registerGlobalReceiver(CLIENT_PONY_DATA, (server, player, ignore, buffer, ignore2) -> { ServerPlayNetworking.registerGlobalReceiver(CLIENT_PONY_DATA, (server, player, ignore, buffer, ignore2) -> {
PonyData packet = MsgPonyData.read(buffer); PonyData packet = MsgPonyData.read(buffer);
@ -51,20 +45,19 @@ public class Channel {
}); });
} }
public static void broadcastPonyData(PonyData packet) { public static boolean isRegistered() {
return registered;
}
public static boolean broadcastPonyData(PonyData packet) {
if (!isRegistered()) {
return false;
}
if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) { if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) {
throw new RuntimeException("Client packet send called by the server"); throw new RuntimeException("Client packet send called by the server");
} }
if (!registered) {
if (MinecraftClient.getInstance().isInSingleplayer() || MinecraftClient.getInstance().isIntegratedServerRunning()) {
MineLittlePony.logger.info("Sending pony skin data over as we are either in single-player or lan");
} else {
MineLittlePony.logger.info("Skipping network packet as the server has not consented");
return;
}
}
ClientPlayNetworking.send(CLIENT_PONY_DATA, MsgPonyData.write(packet, PacketByteBufs.create())); ClientPlayNetworking.send(CLIENT_PONY_DATA, MsgPonyData.write(packet, PacketByteBufs.create()));
return true;
} }
} }

View file

@ -1,4 +1,4 @@
package com.minelittlepony.api.pony.network; package com.minelittlepony.api.events;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
@ -23,7 +23,8 @@ public class MsgPonyData {
new MsgSize(buffer), new MsgSize(buffer),
buffer.readInt(), buffer.readInt(),
buffer.readBoolean(), buffer.readBoolean(),
Flags.read(Wearable.class, buffer) buffer.readVarInt(),
Flags.read(Wearable.NONE, buffer)
); );
} }
@ -34,13 +35,24 @@ public class MsgPonyData {
buffer.writeEnumConstant(data.tailLength()); buffer.writeEnumConstant(data.tailLength());
buffer.writeEnumConstant(data.tailShape()); buffer.writeEnumConstant(data.tailShape());
buffer.writeEnumConstant(data.gender()); buffer.writeEnumConstant(data.gender());
new MsgSize(data.size()).toBuffer(buffer); write(data.size(), buffer);
buffer.writeInt(data.glowColor()); buffer.writeInt(data.glowColor());
buffer.writeBoolean(data.noSkin()); buffer.writeBoolean(data.noSkin());
buffer.writeVarInt(data.priority());
data.gear().write(buffer); data.gear().write(buffer);
return buffer; return buffer;
} }
private static void write(Size size, PacketByteBuf buffer) {
buffer.writeInt(size.ordinal());
buffer.writeString(size.name());
buffer.writeFloat(size.shadowSize());
buffer.writeFloat(size.scaleFactor());
buffer.writeFloat(size.eyeHeightFactor());
buffer.writeFloat(size.eyeDistanceFactor());
buffer.writeFloat(size.colorCode());
}
private record MsgSize ( private record MsgSize (
int ordinal, int ordinal,
String name, String name,
@ -49,23 +61,8 @@ public class MsgPonyData {
float eyeHeightFactor, float eyeHeightFactor,
float eyeDistanceFactor, float eyeDistanceFactor,
int colorCode) implements Size { int colorCode) implements Size {
MsgSize(Size size) {
this(size.ordinal(), size.name(), size.shadowSize(), size.scaleFactor(), size.eyeHeightFactor(), size.eyeDistanceFactor(), size.colorCode());
}
MsgSize(PacketByteBuf buffer) { MsgSize(PacketByteBuf buffer) {
this(buffer.readInt(), buffer.readString(32767), buffer.readFloat(), buffer.readFloat(), buffer.readFloat(), buffer.readFloat(), buffer.readInt()); this(buffer.readInt(), buffer.readString(), buffer.readFloat(), buffer.readFloat(), buffer.readFloat(), buffer.readFloat(), buffer.readInt());
}
public void toBuffer(PacketByteBuf buffer) {
buffer.writeInt(ordinal);
buffer.writeString(name);
buffer.writeFloat(shadowSize);
buffer.writeFloat(scaleFactor);
buffer.writeFloat(eyeHeightFactor);
buffer.writeFloat(eyeDistanceFactor);
buffer.writeFloat(colorCode);
} }
@Override @Override

View file

@ -1,4 +1,4 @@
package com.minelittlepony.api.pony.network.fabric; package com.minelittlepony.api.events;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.Event;

View file

@ -1,4 +1,4 @@
package com.minelittlepony.api.model.fabric; package com.minelittlepony.api.events;
import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory; import net.fabricmc.fabric.api.event.EventFactory;

View file

@ -1,10 +0,0 @@
package com.minelittlepony.api.model;
import com.minelittlepony.api.pony.PonyData;
public interface IModelWrapper {
/**
* Updates metadata values to this wrapper's contained models.
*/
IModelWrapper applyMetadata(PonyData meta);
}

View file

@ -4,12 +4,8 @@ import net.minecraft.client.model.ModelPart;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.mson.util.PartUtil; import com.minelittlepony.mson.util.PartUtil;
/**
* Common interface for all undead enemies.
*/
public final class MobPosingHelper { public final class MobPosingHelper {
/** /**
* Rotates the provided arm to the correct orientation for holding an item. * Rotates the provided arm to the correct orientation for holding an item.
@ -34,15 +30,21 @@ public final class MobPosingHelper {
arm.roll = cos; arm.roll = cos;
} }
public static void rotateUndeadArms(ClientPonyModel<?> model, float move, float ticks) { public static void rotateUndeadArms(PonyModel<?> model, float move, float ticks) {
ModelPart leftArm = model.getArm(Arm.LEFT); ModelPart leftArm = model.getForeLeg(Arm.LEFT);
ModelPart rightArm = model.getArm(Arm.RIGHT); ModelPart rightArm = model.getForeLeg(Arm.RIGHT);
if (islookAngleRight(move)) { if (islookAngleRight(move)) {
rotateArmHolding(rightArm, 1, model.getSwingAmount(), ticks); rotateArmHolding(rightArm, 1, model.getSwingAmount(), ticks);
if (model.getAttributes().isSitting) {
rightArm.pitch += 0.6F;
}
PartUtil.shift(rightArm, 0.5F, 1.5F, 3); PartUtil.shift(rightArm, 0.5F, 1.5F, 3);
} else { } else {
rotateArmHolding(leftArm, -1, model.getSwingAmount(), ticks); rotateArmHolding(leftArm, -1, model.getSwingAmount(), ticks);
if (model.getAttributes().isSitting) {
leftArm.pitch += 0.6F;
}
PartUtil.shift(leftArm, -0.5F, 1.5F, 3); PartUtil.shift(leftArm, -0.5F, 1.5F, 3);
} }
} }

View file

@ -1,7 +1,7 @@
package com.minelittlepony.api.model; package com.minelittlepony.api.model;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.*; import com.minelittlepony.api.pony.*;
import com.minelittlepony.client.*;
import com.minelittlepony.common.util.animation.Interpolator; import com.minelittlepony.common.util.animation.Interpolator;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
@ -9,6 +9,7 @@ import java.util.*;
import net.minecraft.client.render.entity.model.BipedEntityModel.ArmPose; import net.minecraft.client.render.entity.model.BipedEntityModel.ArmPose;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.*; import net.minecraft.util.*;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
@ -19,6 +20,11 @@ public class ModelAttributes {
* True if the model is sleeping in a bed. * True if the model is sleeping in a bed.
*/ */
public boolean isSleeping; public boolean isSleeping;
/**
* True if the model is lying down comfortably
*/
public boolean isLyingDown;
/** /**
* True if the model is flying like a pegasus. * True if the model is flying like a pegasus.
*/ */
@ -144,9 +150,15 @@ public class ModelAttributes {
public void updateLivingState(LivingEntity entity, Pony pony, Mode mode) { public void updateLivingState(LivingEntity entity, Pony pony, Mode mode) {
visualHeight = entity.getHeight() + 0.125F; visualHeight = entity.getHeight() + 0.125F;
isSitting = PonyPosture.isSitting(entity); isSitting = PonyPosture.isSitting(entity);
isCrouching = !isSitting && mode == Mode.THIRD_PERSON && PonyPosture.isCrouching(pony, entity); isSleeping = entity.isAlive() && entity.isSleeping();;
isSleeping = entity.isAlive() && entity.isSleeping(); isLyingDown = isSleeping;
isFlying = mode == Mode.THIRD_PERSON && PonyPosture.isFlying(entity); if (entity instanceof PlayerEntity) {
boolean moving = entity.getVelocity().multiply(1, 0, 1).length() == 0 && entity.isSneaking();
isLyingDown |= getMainInterpolator().interpolate("lyingDown", moving ? 10 : 0, 200) >= 9;
}
isCrouching = !isLyingDown && !isSitting && mode == Mode.THIRD_PERSON && PonyPosture.isCrouching(pony, entity);
isFlying = !isLyingDown && mode == Mode.THIRD_PERSON && PonyPosture.isFlying(entity);
isGliding = entity.isFallFlying(); isGliding = entity.isFallFlying();
isSwimming = mode == Mode.THIRD_PERSON && PonyPosture.isSwimming(entity); isSwimming = mode == Mode.THIRD_PERSON && PonyPosture.isSwimming(entity);
isSwimmingRotated = isSwimming; isSwimmingRotated = isSwimming;
@ -156,7 +168,7 @@ public class ModelAttributes {
interpolatorId = entity.getUuid(); interpolatorId = entity.getUuid();
} }
isLeftHanded = entity.getMainArm() == Arm.LEFT; isLeftHanded = entity.getMainArm() == Arm.LEFT;
isHorsey = MineLittlePony.getInstance().getConfig().horsieMode.get(); isHorsey = PonyConfig.getInstance().horsieMode.get();
featureSkins = SkinsProxy.instance.getAvailableSkins(entity); featureSkins = SkinsProxy.instance.getAvailableSkins(entity);
mainArm = entity.getMainArm(); mainArm = entity.getMainArm();
activeHand = entity.getActiveHand(); activeHand = entity.getActiveHand();
@ -164,7 +176,7 @@ public class ModelAttributes {
} }
public Interpolator getMainInterpolator() { public Interpolator getMainInterpolator() {
return metadata.getInterpolator(interpolatorId); return Interpolator.linear(interpolatorId);
} }
public boolean shouldLiftArm(ArmPose pose, ArmPose complement, float sigma) { public boolean shouldLiftArm(ArmPose pose, ArmPose complement, float sigma) {

View file

@ -0,0 +1,14 @@
package com.minelittlepony.api.model;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.ModelWithArms;
import net.minecraft.client.render.entity.model.BipedEntityModel.ArmPose;
import net.minecraft.util.Arm;
public interface ModelWithHooves extends ModelWithArms {
ModelPart getForeLeg(Arm side);
ModelPart getHindLeg(Arm side);
ArmPose getArmPoseForSide(Arm side);
}

View file

@ -1,4 +1,4 @@
package com.minelittlepony.client.model; package com.minelittlepony.api.model;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ArmorItem; import net.minecraft.item.ArmorItem;
@ -6,12 +6,11 @@ import net.minecraft.item.ItemStack;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.IModelWrapper;
import com.minelittlepony.api.model.armour.*;
import com.minelittlepony.api.pony.PonyData; import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.client.model.armour.PonyArmourModel; import com.minelittlepony.client.model.PlayerModelKey;
import com.minelittlepony.mson.api.*; import com.minelittlepony.client.model.armour.*;
import com.minelittlepony.mson.api.ModelKey;
import com.minelittlepony.mson.api.MsonModel;
import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -19,14 +18,14 @@ import java.util.function.Consumer;
/** /**
* Container class for the various models and their associated piece of armour. * Container class for the various models and their associated piece of armour.
*/ */
public class ModelWrapper<T extends LivingEntity, M extends PonyModel<?>> implements IModelWrapper { public class Models<T extends LivingEntity, M extends PonyModel<?>> {
@Nullable @Nullable
private final MsonModel.Factory<PonyArmourModel<T>> armorFactory; private final MsonModel.Factory<PonyArmourModel<T>> armorFactory;
private final Map<ModelKey<PonyArmourModel<?>>, PonyArmourModel<T>> armor = new HashMap<>(); private final Map<ModelKey<PonyArmourModel<?>>, PonyArmourModel<T>> armor = new HashMap<>();
private final M body; private final M body;
public ModelWrapper(PlayerModelKey<T, ? super M> playerModelKey, boolean slimArms, @Nullable Consumer<M> initializer) { public Models(PlayerModelKey<T, ? super M> playerModelKey, boolean slimArms, @Nullable Consumer<M> initializer) {
this.armorFactory = playerModelKey.armorFactory(); this.armorFactory = playerModelKey.armorFactory();
this.body = playerModelKey.getKey(slimArms).createModel(); this.body = playerModelKey.getKey(slimArms).createModel();
if (initializer != null) { if (initializer != null) {
@ -34,7 +33,7 @@ public class ModelWrapper<T extends LivingEntity, M extends PonyModel<?>> implem
} }
} }
public ModelWrapper(ModelKey<M> key) { public Models(ModelKey<M> key) {
this.armorFactory = null; this.armorFactory = null;
this.body = key.createModel(); this.body = key.createModel();
} }
@ -50,8 +49,7 @@ public class ModelWrapper<T extends LivingEntity, M extends PonyModel<?>> implem
})); }));
} }
@Override public Models<T, M> applyMetadata(PonyData meta) {
public ModelWrapper<T, M> applyMetadata(PonyData meta) {
body.setMetadata(meta); body.setMetadata(meta);
armor.values().forEach(a -> a.setMetadata(meta)); armor.values().forEach(a -> a.setMetadata(meta));
return this; return this;

View file

@ -12,7 +12,7 @@ import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.*; import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.mson.api.MsonModel; import com.minelittlepony.mson.api.MsonModel;
public interface PonyModel<T extends LivingEntity> extends MsonModel, ModelWithArms, ModelWithHat, ModelWithHead { public interface PonyModel<T extends LivingEntity> extends MsonModel, ModelWithHooves, ModelWithHat, ModelWithHead {
void copyAttributes(BipedEntityModel<T> other); void copyAttributes(BipedEntityModel<T> other);
@ -79,7 +79,7 @@ public interface PonyModel<T extends LivingEntity> extends MsonModel, ModelWithA
* i.e. Used to change wing rendering when using saddlebags. * i.e. Used to change wing rendering when using saddlebags.
*/ */
default boolean isEmbedded(Wearable wearable) { default boolean isEmbedded(Wearable wearable) {
return getAttributes().metadata.isWearing(wearable); return getAttributes().metadata.gear().matches(wearable);
} }
} }

View file

@ -1,21 +1,20 @@
package com.minelittlepony.client.model; package com.minelittlepony.api.model;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.BipedEntityModel; import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.model.ModelWithArms; import net.minecraft.client.render.entity.model.ModelWithArms;
import net.minecraft.client.render.entity.model.BipedEntityModel.ArmPose;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyData; import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.Size; import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
import com.minelittlepony.mson.api.model.BoxBuilder.RenderLayerSetter; import com.minelittlepony.mson.api.model.BoxBuilder.RenderLayerSetter;
public interface IPonyMixinModel<T extends LivingEntity, M extends PonyModel<T>> extends PonyModel<T> { public interface PonyModelMixin<T extends LivingEntity, M extends PonyModel<T>> extends PonyModel<T> {
M mixin(); M mixin();
@Override @Override
@ -71,6 +70,22 @@ public interface IPonyMixinModel<T extends LivingEntity, M extends PonyModel<T>>
return mixin().getRiderYOffset(); return mixin().getRiderYOffset();
} }
@Override
default ModelPart getForeLeg(Arm side) {
return mixin().getForeLeg(side);
}
@Override
default ModelPart getHindLeg(Arm side) {
return mixin().getHindLeg(side);
}
@Override
default ArmPose getArmPoseForSide(Arm side) {
return mixin().getArmPoseForSide(side);
}
@Override @Override
default void setArmAngle(Arm arm, MatrixStack stack) { default void setArmAngle(Arm arm, MatrixStack stack) {
if (mixin() instanceof ModelWithArms) { if (mixin() instanceof ModelWithArms) {
@ -93,7 +108,7 @@ public interface IPonyMixinModel<T extends LivingEntity, M extends PonyModel<T>>
mixin().setHatVisible(hatVisible); mixin().setHatVisible(hatVisible);
} }
interface Caster<T extends LivingEntity, M extends PonyModel<T> & HornedPonyModel<T>, ArmModel> extends IPonyMixinModel<T, M>, HornedPonyModel<T> { interface Caster<T extends LivingEntity, M extends PonyModel<T> & HornedPonyModel<T>, ArmModel> extends PonyModelMixin<T, M>, HornedPonyModel<T> {
@Override @Override
default boolean isCasting() { default boolean isCasting() {
return mixin().isCasting(); return mixin().isCasting();

View file

@ -0,0 +1,7 @@
package com.minelittlepony.api.model;
public interface PreviewModel {
boolean forceSeapony();
boolean forceNirik();
}

View file

@ -3,7 +3,7 @@ package com.minelittlepony.api.model;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
public interface IPart { public interface SubModel {
/** /**
* Sets the model's various rotation angles. * Sets the model's various rotation angles.
*/ */

View file

@ -2,8 +2,8 @@ package com.minelittlepony.api.model;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
public interface WingedPonyModel<T extends LivingEntity> extends PonyModel<T> { public interface WingedPonyModel<T extends LivingEntity> extends PonyModel<T> {
@ -16,7 +16,7 @@ public interface WingedPonyModel<T extends LivingEntity> extends PonyModel<T> {
*/ */
default boolean wingsAreOpen() { default boolean wingsAreOpen() {
return (getAttributes().isSwimming || getAttributes().isFlying || getAttributes().isCrouching) return (getAttributes().isSwimming || getAttributes().isFlying || getAttributes().isCrouching)
&& (MineLittlePony.getInstance().getConfig().flappyElytras.get() || !getAttributes().isGliding); && (PonyConfig.getInstance().flappyElytras.get() || !getAttributes().isGliding);
} }
default boolean isBurdened() { default boolean isBurdened() {
@ -28,7 +28,7 @@ public interface WingedPonyModel<T extends LivingEntity> extends PonyModel<T> {
/** /**
* Gets the wings of this pegasus/flying creature * Gets the wings of this pegasus/flying creature
*/ */
IPart getWings(); SubModel getWings();
/** /**
* Determines angle used to animate wing flaps whilst flying/swimming. * Determines angle used to animate wing flaps whilst flying/swimming.

View file

@ -1,17 +0,0 @@
package com.minelittlepony.api.model.armour;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import com.minelittlepony.api.model.PonyModel;
public interface IArmourModel<T extends LivingEntity> {
/**
* Called to synchronise this armour's angles with that of another.
*
* @param model The other model to mimic
*/
boolean poseModel(T entity, float limbAngle, float limbDistance, float age, float headYaw, float headPitch,
EquipmentSlot slot, ArmourLayer layer,
PonyModel<T> mainModel);
}

View file

@ -1,30 +0,0 @@
package com.minelittlepony.api.model.armour;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.client.model.armour.DefaultArmourTextureResolver;
/**
* A resolver for looking up the texture for a piece of armour.
* <p>
* This is for modders who want to override the default implementation found in {@link DefaultArmourTextureResolver}.
*/
public interface IArmourTextureResolver {
/**
* Gets the armour texture to be used for the given entity, armour piece, slot, and render layer.
*/
Identifier getTexture(LivingEntity entity, ItemStack itemstack, EquipmentSlot slot, ArmourLayer layer, @Nullable String type);
/**
* Gets the armour variant for the identified texture.
* Either normal for pony-style textures, or legacy for other textures.
*/
default ArmourVariant getVariant(ArmourLayer layer, Identifier resolvedTexture) {
return ArmourVariant.NORMAL;
}
}

View file

@ -9,22 +9,23 @@ import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.*; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.render.entity.feature.GearFeature;
import java.util.UUID; import java.util.*;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
* Interface for an accessory on a pony's body. * Interface for an accessory on a pony's body.
*/ */
public interface Gear { public interface Gear {
List<Supplier<Gear>> MOD_GEARS = new ArrayList<>();
/** /**
* Registers a custom gear to be used with the mod. * Registers a custom gear to be used with the mod.
* <p> * <p>
* This would be awesome for creating socks. * This would be awesome for creating socks.
*/ */
static Supplier<Gear> register(Supplier<Gear> gear) { static Supplier<Gear> register(Supplier<Gear> gear) {
GearFeature.addModGear(gear); MOD_GEARS.add(gear);
return gear; return gear;
} }

View file

@ -11,6 +11,9 @@ import java.util.*;
public final class DefaultPonySkinHelper { public final class DefaultPonySkinHelper {
public static final Identifier STEVE = new Identifier("minelittlepony", "textures/entity/player/wide/steve_pony.png"); public static final Identifier STEVE = new Identifier("minelittlepony", "textures/entity/player/wide/steve_pony.png");
public static final Identifier SEAPONY_SKIN_TYPE_ID = new Identifier("minelp", "seapony");
public static final Identifier NIRIK_SKIN_TYPE_ID = new Identifier("minelp", "nirik");
private static final Map<SkinTextures, SkinTextures> SKINS = new HashMap<>(); private static final Map<SkinTextures, SkinTextures> SKINS = new HashMap<>();
public static SkinTextures getTextures(SkinTextures original) { public static SkinTextures getTextures(SkinTextures original) {
@ -27,7 +30,7 @@ public final class DefaultPonySkinHelper {
} }
public static String getModelType(UUID id) { public static String getModelType(UUID id) {
SkinTextures textures = DefaultSkinHelper.getTexture(id); SkinTextures textures = DefaultSkinHelper.getSkinTextures(id);
return getModelType(Pony.getManager().getPony(textures.texture(), id).race(), textures.model()); return getModelType(Pony.getManager().getPony(textures.texture(), id).race(), textures.model());
} }

View file

@ -6,7 +6,6 @@ import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ComparisonChain; import com.google.common.collect.ComparisonChain;
import com.minelittlepony.api.pony.meta.*; import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.common.util.animation.Interpolator;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
@ -50,67 +49,57 @@ public record PonyData (
* rather than a user-uploaded one. * rather than a user-uploaded one.
*/ */
boolean noSkin, boolean noSkin,
/**
* (Experimental) Priority.
* Used to decide which skin to use when dual skin mode is active.
* Provides an optional tie-breaker when the client has to decide between displaying
* either the HDSkins texture or vanilla texture given both are otherwise acceptable.
*
* Any time both skins resolve to the same race (eg. on pony-level HUMANS, or if both are ponies)
* the skin with the highest priority will be chosen.
*
* If both have the same priority, HD Skins' texture will always be used (old default).
*/
int priority,
/** /**
* Gets the trigger pixel values as they appeared in the underlying image. * Gets the trigger pixel values as they appeared in the underlying image.
*/ */
Map<String, TriggerPixelType<?>> attributes Map<String, TValue<?>> attributes
) implements Comparable<PonyData> { ) implements Comparable<PonyData> {
private static final Function<Race, PonyData> OF_RACE = Util.memoize(race -> { public static final int DEFAULT_MAGIC_COLOR = 0x4444aa;
return new PonyData(race, TailLength.FULL, TailShape.STRAIGHT, Gender.MARE, Sizes.NORMAL, 0x4444aa, Wearable.EMPTY_FLAGS, true, Util.make(new TreeMap<>(), attributes -> { private static final Function<Race, PonyData> OF_RACE = Util.memoize(race -> new PonyData(race, TailLength.FULL, TailShape.STRAIGHT, Gender.MARE, SizePreset.NORMAL, DEFAULT_MAGIC_COLOR, true, 0, Wearable.EMPTY_FLAGS));
attributes.put("race", race);
attributes.put("tailLength", TailLength.FULL);
attributes.put("tailShape", TailShape.STRAIGHT);
attributes.put("gender", Gender.MARE);
attributes.put("size", Sizes.NORMAL);
attributes.put("magic", TriggerPixelType.of(0x4444aa));
attributes.put("gear", TriggerPixelType.of(0));
}));
});
public static final PonyData NULL = OF_RACE.apply(Race.HUMAN); public static final PonyData NULL = OF_RACE.apply(Race.HUMAN);
public static PonyData emptyOf(Race race) { public static PonyData emptyOf(Race race) {
return OF_RACE.apply(race); return OF_RACE.apply(race);
} }
public PonyData(TriggerPixel.Mat image, boolean noSkin) {
public PonyData(Race race, TailLength tailLength, TailShape tailShape, Gender gender, Size size, int glowColor, boolean noSkin, Flags<Wearable> wearables) { this(
this(race, tailLength, tailShape, gender, size, glowColor, wearables, noSkin, Util.make(new TreeMap<>(), map -> { TriggerPixel.RACE.read(image),
map.put("race", race); TriggerPixel.TAIL.read(image),
map.put("tailLength", tailLength); TriggerPixel.TAIL_SHAPE.read(image),
map.put("tailShape", tailShape); TriggerPixel.GENDER.read(image),
map.put("gender", gender); TriggerPixel.SIZE.read(image),
map.put("size", size); TriggerPixel.GLOW.read(image),
map.put("magic", TriggerPixelType.of(glowColor)); noSkin,
map.put("gear", TriggerPixelType.of(wearables.colorCode())); TriggerPixel.PRIORITY.read(image),
})); TriggerPixel.WEARABLES.read(image)
}
public PonyData(Race race, TailLength tailLength, TailShape tailShape, Gender gender, Size size, int glowColor, TriggerPixelType.Multiple<Wearable> wearables, boolean noSkin) {
this(race, tailLength, tailShape, gender, size, glowColor,
Flags.of(Wearable.class, wearables.colorCode(), wearables.value()),
noSkin, Util.make(new TreeMap<>(), map -> {
map.put("race", race);
map.put("tailLength", tailLength);
map.put("tailShape", tailShape);
map.put("gender", gender);
map.put("size", size);
map.put("magic", TriggerPixelType.of(glowColor));
map.put("gear", wearables);
})
); );
} }
/** public PonyData(Race race, TailLength tailLength, TailShape tailShape, Gender gender, Size size, int glowColor, boolean noSkin, int priority, Flags<Wearable> wearables) {
* Checks it this pony is wearing the given accessory. this(race, tailLength, tailShape, gender, size, glowColor, wearables, noSkin, priority, Util.make(new TreeMap<>(), map -> {
*/ map.put("race", race);
public boolean isWearing(Wearable wearable) { map.put("tailLength", tailLength);
return gear().includes(wearable); map.put("tailShape", tailShape);
} map.put("gender", gender);
map.put("size", size);
/** map.put("magic", new TValue.Numeric(glowColor));
* Gets an interpolator for interpolating values. map.put("priority", new TValue.Numeric(priority));
*/ map.put("gear", wearables);
public Interpolator getInterpolator(UUID interpolatorId) { })
return Interpolator.linear(interpolatorId); );
} }
@Override @Override

View file

@ -1,6 +1,7 @@
package com.minelittlepony.api.pony; package com.minelittlepony.api.pony;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@ -10,8 +11,7 @@ import java.util.Optional;
import java.util.UUID; import java.util.UUID;
/** /**
* The PonyManager is responsible for reading and recoding all the pony data associated with an entity of skin. * The PonyManager is responsible for reading and recoding all the pony data associated with the skin of an entity.
*
*/ */
public interface PonyManager { public interface PonyManager {
/** /**
@ -19,7 +19,25 @@ public interface PonyManager {
* *
* If the supplied entity is null or can't be determined to be a pony, returns the empty optional. * If the supplied entity is null or can't be determined to be a pony, returns the empty optional.
*/ */
Optional<Pony> getPony(@Nullable Entity entity); default Optional<Pony> getPony(@Nullable Entity entity) {
return entity instanceof LivingEntity living ? getPony(living) : Optional.empty();
}
/**
* Gets a pony representation of the passed in entity.
*
* If the supplied entity is null or can't be determined to be a pony, returns the empty optional.
*/
Optional<Pony> getPony(LivingEntity entity);
/**
* Gets a random background pony determined by the given uuid.
*
* Useful for mods that offer customisation, especially ones that have a whole lot of NPCs.
*
* @param uuid id of a player
*/
Pony getBackgroundPony(UUID uuid);
/** /**
* Gets or creates a pony for the given player. * Gets or creates a pony for the given player.
@ -29,13 +47,6 @@ public interface PonyManager {
*/ */
Pony getPony(PlayerEntity player); Pony getPony(PlayerEntity player);
/**
* Gets or creates a pony for the given skin resource and vanilla model type.
*
* @param resource A texture resource
*/
Pony getPony(Identifier resource);
/** /**
* Gets or creates a pony for the given skin resource and entity id. * Gets or creates a pony for the given skin resource and entity id.
* *
@ -46,23 +57,16 @@ public interface PonyManager {
* @param resource A texture resource * @param resource A texture resource
* @param uuid id of a player * @param uuid id of a player
*/ */
Pony getPony(Identifier resource, UUID uuid); Pony getPony(@Nullable Identifier resource, @Nullable UUID uuid);
/** /**
* Gets a random background pony determined by the given uuid. * Gets or creates a pony for the given skin resource and vanilla model type.
* *
* Useful for mods that offer customisation, especially ones that have a whole lot of NPCs. * @param resource A texture resource
*
* @param uuid A UUID. Either a user or an entity.
*/ */
Pony getBackgroundPony(UUID uuid); default Pony getPony(Identifier resource) {
return getPony(resource, null);
/** }
* De-registers a pony from the cache.
*/
void removePony(Identifier resource);
void clearCache();
interface ForcedPony {} interface ForcedPony {}

View file

@ -1,9 +1,7 @@
package com.minelittlepony.api.pony; package com.minelittlepony.api.pony;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.PreviewModel; import com.minelittlepony.api.model.PreviewModel;
import com.minelittlepony.client.SkinsProxy;
import com.minelittlepony.client.render.entity.AquaticPlayerPonyRenderer;
import java.util.Optional; import java.util.Optional;
@ -101,7 +99,26 @@ public final class PonyPosture {
} }
return Pony.getManager().getPony(entity).filter(pony -> { return Pony.getManager().getPony(entity).filter(pony -> {
return (pony.race() == Race.SEAPONY return (pony.race() == Race.SEAPONY
|| (entity instanceof AbstractClientPlayerEntity player && SkinsProxy.instance.getSkin(AquaticPlayerPonyRenderer.SKIN_TYPE_ID, player).isPresent()) || (entity instanceof AbstractClientPlayerEntity player && SkinsProxy.instance.getSkin(DefaultPonySkinHelper.SEAPONY_SKIN_TYPE_ID, player).isPresent())
);
}).isPresent();
}
public static boolean isNirikModifier(LivingEntity entity) {
if (entity instanceof PreviewModel preview) {
return preview.forceNirik();
}
return false;
}
public static boolean hasNirikForm(LivingEntity entity) {
if (entity instanceof PreviewModel preview) {
return preview.forceNirik();
}
return Pony.getManager().getPony(entity).filter(pony -> {
return (pony.race() == Race.KIRIN
&& (entity instanceof AbstractClientPlayerEntity player && SkinsProxy.instance.getSkin(DefaultPonySkinHelper.NIRIK_SKIN_TYPE_ID, player).isPresent())
); );
}).isPresent(); }).isPresent();
} }

View file

@ -1,40 +1,27 @@
package com.minelittlepony.client; package com.minelittlepony.api.pony;
import com.minelittlepony.common.client.gui.ScrollContainer;
import com.minelittlepony.common.client.gui.Tooltip;
import com.minelittlepony.common.client.gui.element.Button;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.texture.PlayerSkinProvider; import net.minecraft.client.texture.PlayerSkinProvider;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable; /**
* Proxy handler for getting player skin data from HDSkins
*/
public class SkinsProxy { public class SkinsProxy {
public static SkinsProxy instance = new SkinsProxy(); public static SkinsProxy instance = new SkinsProxy();
@Nullable
public Identifier getSkinTexture(GameProfile profile) { public Identifier getSkinTexture(GameProfile profile) {
PlayerSkinProvider skins = MinecraftClient.getInstance().getSkinProvider(); PlayerSkinProvider skins = MinecraftClient.getInstance().getSkinProvider();
return skins.getSkinTextures(profile).texture(); return skins.getSkinTextures(profile).texture();
} }
public void renderOption(Screen screen, @Nullable Screen parent, int row, int RIGHT, ScrollContainer content) {
content.addButton(new Button(RIGHT, row += 20, 150, 20))
.setEnabled(false)
.getStyle()
.setTooltip(Tooltip.of("minelp.options.skins.hdskins.disabled", 200))
.setText("minelp.options.skins.hdskins.open");
}
public Optional<Identifier> getSkin(Identifier skinTypeId, AbstractClientPlayerEntity player) { public Optional<Identifier> getSkin(Identifier skinTypeId, AbstractClientPlayerEntity player) {
return Optional.empty(); return Optional.empty();
} }
@ -43,17 +30,3 @@ public class SkinsProxy {
return Set.of(); return Set.of();
} }
} }

View file

@ -4,50 +4,56 @@ import net.minecraft.network.PacketByteBuf;
import java.util.*; import java.util.*;
public record Flags<T extends Enum<T>> ( public record Flags<T extends Enum<T> & TValue<T>> (
boolean[] flags, T def,
List<T> values, Set<T> values,
int colorCode int colorCode
) implements Comparable<Flags<T>> { ) implements Comparable<Flags<T>>, TValue<T> {
public static <T extends Enum<T>> Flags<T> of(Class<T> type) { public static <T extends Enum<T> & TValue<T>> Flags<T> of(T def) {
return new Flags<>(new boolean[type.getEnumConstants().length], List.<T>of(), 0); return new Flags<>(def, Set.<T>of(), 0);
} }
public static <T extends Enum<T>> Flags<T> of(Class<T> type, int colorCode, boolean...flags) { public static <T extends Enum<T> & TValue<T>> Flags<T> of(T def, int colorCode, Set<T> values) {
return new Flags<>(flags, flags(type.getEnumConstants(), flags), colorCode); return new Flags<>(def, values, colorCode);
} }
public static <T extends Enum<T>> Flags<T> read(Class<T> type, PacketByteBuf buffer) { public static <T extends Enum<T> & TValue<T>> Flags<T> read(T def, PacketByteBuf buffer) {
int length = buffer.readVarInt(); int length = buffer.readVarInt();
List<T> values = new ArrayList<>(); @SuppressWarnings("unchecked")
T[] all = type.getEnumConstants(); Set<T> values = EnumSet.noneOf((Class<T>)def.getClass());
boolean[] flags = new boolean[all.length]; @SuppressWarnings("unchecked")
T[] all = (T[])def.getClass().getEnumConstants();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
values.add(all[buffer.readInt()]); values.add(all[buffer.readInt()]);
flags[i] = true;
} }
return new Flags<>(flags, values, buffer.readInt()); return new Flags<>(def, values, buffer.readInt());
}
public static <T> List<T> flags(T[] values, boolean[] flags) {
List<T> wears = new ArrayList<>();
for (int i = 0; i < values.length; i++) {
if (flags[i]) wears.add(values[i]);
}
return wears;
}
public boolean includes(T t) {
return flags[t.ordinal()];
}
public int compareTo(Flags<T> other) {
return Arrays.compare(flags, other.flags);
} }
public void write(PacketByteBuf buffer) { public void write(PacketByteBuf buffer) {
buffer.writeCollection(values, (buf, value) -> buf.writeInt(value.ordinal())); buffer.writeCollection(values, (buf, value) -> buf.writeInt(value.ordinal()));
buffer.writeInt(colorCode); buffer.writeInt(colorCode);
} }
@Override
public String name() {
return "[Flags " + values + "]";
}
@Override
public List<TValue<T>> getOptions() {
return def.getOptions();
}
@SuppressWarnings("unchecked")
@Override
public boolean matches(TValue<?> o) {
return o.getClass() == def.getClass() && values.contains((T)o);
}
@Override
public int compareTo(Flags<T> other) {
return Integer.compare(colorCode(), other.colorCode());
}
} }

View file

@ -1,6 +1,6 @@
package com.minelittlepony.api.pony.meta; package com.minelittlepony.api.pony.meta;
public enum Gender implements TriggerPixelType<Gender> { public enum Gender implements TValue<Gender> {
MARE(0), MARE(0),
STALLION(0xffffff), STALLION(0xffffff),
ABOMONATION(0x888888); ABOMONATION(0x888888);

View file

@ -1,8 +1,6 @@
package com.minelittlepony.api.pony.meta; package com.minelittlepony.api.pony.meta;
import java.util.*; public enum Race implements TValue<Race> {
public enum Race implements TriggerPixelType<Race> {
HUMAN (0x000000, false, false), HUMAN (0x000000, false, false),
EARTH (0xf9b131, false, false), EARTH (0xf9b131, false, false),
PEGASUS (0x88caf0, true, false), PEGASUS (0x88caf0, true, false),
@ -17,16 +15,13 @@ public enum Race implements TriggerPixelType<Race> {
BATPONY (0xeeeeee, true, false), BATPONY (0xeeeeee, true, false),
SEAPONY (0x3655dd, false, true); SEAPONY (0x3655dd, false, true);
private boolean wings; private final boolean wings;
private boolean horn; private final boolean horn;
private int triggerPixel; private final int colorCode;
public static final List<Race> REGISTRY = Arrays.asList(values());
Race(int triggerPixel, boolean wings, boolean horn) {
this.triggerPixel = triggerPixel;
Race(int colorCode, boolean wings, boolean horn) {
this.colorCode = colorCode;
this.wings = wings; this.wings = wings;
this.horn = horn; this.horn = horn;
} }
@ -68,6 +63,6 @@ public enum Race implements TriggerPixelType<Race> {
@Override @Override
public int colorCode() { public int colorCode() {
return triggerPixel; return colorCode;
} }
} }

View file

@ -3,13 +3,13 @@ package com.minelittlepony.api.pony.meta;
/** /**
* Represents the different model sizes that are possible. * Represents the different model sizes that are possible.
* *
* For a list of possible presets, look at {@link Sizes}. * For a list of possible presets, look at {@link SizePreset}.
* This interface exists for servers so they can work with this information even though they might not have access to the client config. * This interface exists for servers so they can work with this information even though they might not have access to the client config.
* *
*/ */
public interface Size extends TriggerPixelType<Size> { public interface Size extends TValue<Size> {
/** /**
* The Enum index of this size. May be used on the client to convert to an instance of Sizes or use {@link Sizes#of} * The Enum index of this size. May be used on the client to convert to an instance of Sizes or use {@link SizePreset#of}
* *
* Made to be compatible with the enum variant. * Made to be compatible with the enum variant.
*/ */
@ -41,4 +41,9 @@ public interface Size extends TriggerPixelType<Size> {
* A scale factor used to alter the camera's distance. * A scale factor used to alter the camera's distance.
*/ */
float eyeDistanceFactor(); float eyeDistanceFactor();
/**
* The trigger pixel colour corresponding to this size.
*/
int colorCode();
} }

View file

@ -9,7 +9,7 @@ import com.minelittlepony.api.config.PonyConfig;
* *
* For spooky things at a distance, use {@link Size} instead. * For spooky things at a distance, use {@link Size} instead.
*/ */
public enum Sizes implements Size { public enum SizePreset implements Size {
TALL (0x534b76, 0.45f, 1.1F, 1.15F), TALL (0x534b76, 0.45f, 1.1F, 1.15F),
BULKY (0xce3254, 0.5f, 1, 1.05F), BULKY (0xce3254, 0.5f, 1, 1.05F),
LANKY (0x3254ce, 0.45F, 0.85F, 0.9F), LANKY (0x3254ce, 0.45F, 0.85F, 0.9F),
@ -18,21 +18,23 @@ public enum Sizes implements Size {
FOAL (0xffbe53, 0.25f, 0.6F, 0.5F), FOAL (0xffbe53, 0.25f, 0.6F, 0.5F),
UNSET (0x000000, 1, 1, 1); UNSET (0x000000, 1, 1, 1);
public static final Sizes[] REGISTRY = values(); private final int triggerValue;
private final float shadowSize;
private final float scale;
private final float camera;
private int triggerValue; SizePreset(int pixel, float shadowSz, float scaleF, float cameraF) {
private float shadowSize;
private float scale;
private float camera;
Sizes(int pixel, float shadowSz, float scaleF, float cameraF) {
triggerValue = pixel; triggerValue = pixel;
shadowSize = shadowSz; shadowSize = shadowSz;
scale = scaleF; scale = scaleF;
camera = cameraF; camera = cameraF;
} }
@Override
public int colorCode() {
return triggerValue;
}
@Override @Override
public float shadowSize() { public float shadowSize() {
return shadowSize * PonyConfig.getInstance().getGlobalScaleFactor(); return shadowSize * PonyConfig.getInstance().getGlobalScaleFactor();
@ -53,25 +55,6 @@ public enum Sizes implements Size {
@Override @Override
public float eyeDistanceFactor() { public float eyeDistanceFactor() {
if (!PonyConfig.getInstance().fillycam.get()) { return eyeHeightFactor();
return 1;
}
return camera * PonyConfig.getInstance().getGlobalScaleFactor();
}
@Override
public int colorCode() {
return triggerValue;
}
public static Sizes of(Size size) {
if (size instanceof Sizes) {
return (Sizes)size;
}
int i = size.ordinal();
if (i < 0 || i >= REGISTRY.length) {
return UNSET;
}
return REGISTRY[i];
} }
} }

View file

@ -0,0 +1,66 @@
package com.minelittlepony.api.pony.meta;
import java.util.Arrays;
import java.util.List;
/**
* Interface for enums that can be parsed from an image trigger pixel value.
*/
public interface TValue<T> {
/**
* Gets the pixel colour matching this enum value.
*/
int colorCode();
/**
* Gets the pixel colour matching this enum value, adjusted to fill all three channels.
*/
default int getChannelAdjustedColorCode() {
return colorCode();
}
/**
* Gets a string representation of this value.
*/
String name();
default String getHexValue() {
return toHex(colorCode());
}
/**
* Returns a list of possible values this trigger pixel can accept.
*/
@SuppressWarnings("unchecked")
default List<TValue<T>> getOptions() {
if (this instanceof Enum) {
// cast is required because gradle's compiler is more strict
return Arrays.asList(getClass().getEnumConstants());
}
return List.of();
}
default boolean matches(TValue<?> o) {
return o != null && colorCode() == o.colorCode();
}
static String toHex(int color) {
String v = Integer.toHexString(color).toUpperCase();
while (v.length() < 6) {
v = "0" + v;
}
return "#" + v;
}
public record Numeric(int colorCode) implements TValue<Integer> {
@Override
public String name() {
return "[Numeric " + getHexValue() + "]";
}
@Override
public List<TValue<Integer>> getOptions() {
return List.of();
}
}
}

View file

@ -1,6 +1,6 @@
package com.minelittlepony.api.pony.meta; package com.minelittlepony.api.pony.meta;
public enum TailLength implements TriggerPixelType<TailLength> { public enum TailLength implements TValue<TailLength> {
STUB (0x425844), STUB (0x425844),
QUARTER (0xd19fe4), QUARTER (0xd19fe4),
HALF (0x534b76), HALF (0x534b76),

View file

@ -1,6 +1,6 @@
package com.minelittlepony.api.pony.meta; package com.minelittlepony.api.pony.meta;
public enum TailShape implements TriggerPixelType<TailShape> { public enum TailShape implements TValue<TailShape> {
STRAIGHT(0), STRAIGHT(0),
BUMPY (0xfc539f), BUMPY (0xfc539f),
SWIRLY (0x3eff22), SWIRLY (0x3eff22),

View file

@ -1,112 +1,92 @@
package com.minelittlepony.api.pony.meta; package com.minelittlepony.api.pony.meta;
import net.minecraft.client.texture.NativeImage; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.util.math.ColorHelper;
import org.joml.Vector2i;
import com.minelittlepony.common.util.Color; import com.minelittlepony.common.util.Color;
import java.util.Arrays; import java.util.*;
/** /**
* Individual trigger pixels for a pony skin. * Individual trigger pixels for a pony skin.
*
*/ */
@SuppressWarnings("unchecked") public interface TriggerPixel<T> {
public enum TriggerPixel { Vector2i MAX_COORDS = new Vector2i();
RACE(Race.HUMAN, Channel.ALL, 0, 0),
TAIL(TailLength.FULL, Channel.ALL, 1, 0),
GENDER(Gender.MARE, Channel.ALL, 2, 0),
SIZE(Sizes.NORMAL, Channel.ALL, 3, 0),
GLOW(null, Channel.RAW, 0, 1),
WEARABLES(Wearable.NONE, Channel.RAW, 1, 1),
TAIL_SHAPE(TailShape.STRAIGHT, Channel.ALL, 2, 1);
private final int x; TriggerPixel<Race> RACE = ofOptions(0, 0, Race.HUMAN, Race.values());
private final int y; TriggerPixel<TailLength> TAIL = ofOptions(1, 0, TailLength.FULL, TailLength.values());
TriggerPixel<Gender> GENDER = ofOptions(2, 0, Gender.MARE, Gender.values());
TriggerPixel<TailShape> TAIL_SHAPE = ofOptions(2, 1, TailShape.STRAIGHT, TailShape.values());
TriggerPixel<Size> SIZE = ofOptions(3, 0, SizePreset.NORMAL, SizePreset.values());
TriggerPixel<Integer> GLOW = ofColor(0, 1);
TriggerPixel<Flags<Wearable>> WEARABLES = ofFlags(1, 1, Wearable.EMPTY_FLAGS, Wearable.values());
TriggerPixel<Integer> PRIORITY = ofColor(2, 2);
private final Channel channel; static <T extends TValue<T>> TriggerPixel<T> ofOptions(int x, int y, T def, T[] options) {
MAX_COORDS.x = Math.max(MAX_COORDS.x, x);
MAX_COORDS.y = Math.max(MAX_COORDS.y, y);
Int2ObjectOpenHashMap<T> lookup = buildLookup(options);
return image -> {
int color = Color.abgrToArgb(image.getColor(x, y));
private final TriggerPixelType<?> def; if (ColorHelper.Argb.getAlpha(color) < 255) {
private static final TriggerPixel[] VALUES = values();
private static final int MAX_READ_X = Arrays.stream(VALUES).mapToInt(i -> i.x).max().getAsInt();
private static final int MAX_READ_Y = Arrays.stream(VALUES).mapToInt(i -> i.y).max().getAsInt();
TriggerPixel(TriggerPixelType<?> def, Channel channel, int x, int y) {
this.def = def;
this.channel = channel;
this.x = x;
this.y = y;
}
/**
* Reads this trigger pixel's value and returns the raw colour.
*
* @param image Image to read
*/
public int readColor(NativeImage image) {
return channel.readValue(x, y, image);
}
/**
* Reads this trigger pixel's value and parses it to an Enum instance.
*
* @param image Image to read
*/
public <T extends TriggerPixelType<T>> T readValue(NativeImage image) {
int color = readColor(image);
if (Channel.ALPHA.readValue(x, y, image) < 255) {
return (T)def; return (T)def;
} }
return lookup.getOrDefault(color & 0x00FFFFFF, def);
return TriggerPixelType.getByTriggerPixel((T)def, color); };
} }
public <T extends Enum<T> & TriggerPixelType<T>> TriggerPixelType.Multiple<T> readFlags(NativeImage image) { static TriggerPixel<Integer> ofColor(int x, int y) {
boolean[] out = new boolean[def.getClass().getEnumConstants().length]; MAX_COORDS.x = Math.max(MAX_COORDS.x, x);
readFlags(out, image); MAX_COORDS.y = Math.max(MAX_COORDS.y, y);
return new TriggerPixelType.Multiple<>(readColor(image), (T)def, out); return image -> Color.abgrToArgb(image.getColor(x, y));
} }
public <T extends Enum<T> & TriggerPixelType<T>> void readFlags(boolean[] out, NativeImage image) { static <T extends Enum<T> & TValue<T>> TriggerPixel<Flags<T>> ofFlags(int x, int y, Flags<T> def, T[] options) {
readFlag(out, Channel.RED, image); MAX_COORDS.x = Math.max(MAX_COORDS.x, x);
readFlag(out, Channel.GREEN, image); MAX_COORDS.y = Math.max(MAX_COORDS.y, y);
readFlag(out, Channel.BLUE, image); Int2ObjectOpenHashMap<T> lookup = buildLookup(options);
var flagReader = new Object() {
boolean readFlag(int color, Set<T> values) {
T value = lookup.get(color);
return value != null && values.add(value);
}
};
return image -> {
int color = Color.abgrToArgb(image.getColor(x, y));
if (ColorHelper.Argb.getAlpha(color) < 255) {
return def;
}
@SuppressWarnings("unchecked")
Set<T> values = EnumSet.noneOf((Class<T>)def.def().getClass());
if (flagReader.readFlag(ColorHelper.Argb.getRed(color), values)
| flagReader.readFlag(ColorHelper.Argb.getGreen(color), values)
| flagReader.readFlag(ColorHelper.Argb.getBlue(color), values)) {
return new Flags<>(def.def(), values, color & 0x00FFFFFF);
}
return def;
};
} }
private <T extends Enum<T> & TriggerPixelType<T>> void readFlag(boolean[] out, Channel channel, NativeImage image) { static <T extends TValue<T>> Int2ObjectOpenHashMap<T> buildLookup(T[] options) {
Int2ObjectOpenHashMap<T> lookup = new Int2ObjectOpenHashMap<>();
if (Channel.ALPHA.readValue(x, y, image) < 255) { for (int i = 0; i < options.length; i++) {
return; lookup.put(options[i].colorCode(), options[i]);
}
return lookup;
} }
T value = TriggerPixelType.getByTriggerPixel((T)def, channel.readValue(x, y, image));
out[value.ordinal()] |= value != def; T read(Mat image);
static boolean isTriggerPixelCoord(int x, int y) {
return x <= MAX_COORDS.x && y <= MAX_COORDS.y;
} }
public static boolean isTriggerPixelCoord(int x, int y) { interface Mat {
return x <= MAX_READ_X && y <= MAX_READ_Y; int getColor(int x, int y);
} }
enum Channel {
RAW (0xFFFFFFFF, 0),
ALL (0x00FFFFFF, 0),
ALPHA(0x000000FF, 24),
RED (0x000000FF, 0),
GREEN(0x000000FF, 8),
BLUE (0x000000FF, 16);
private int mask;
private int offset;
Channel(int mask, int offset) {
this.mask = mask;
this.offset = offset;
}
public int readValue(int x, int y, NativeImage image) {
return (Color.abgrToArgb(image.getColor(x, y)) >> offset) & mask;
}
}
} }

View file

@ -1,97 +0,0 @@
package com.minelittlepony.api.pony.meta;
import java.util.Arrays;
import java.util.List;
/**
* Interface for enums that can be parsed from an image trigger pixel value.
*/
public interface TriggerPixelType<T> {
/**
* Gets the pixel colour matching this enum value.
*/
int colorCode();
/**
* Gets the pixel colour matching this enum value, adjusted to fill all three channels.
*/
default int getChannelAdjustedColorCode() {
return colorCode();
}
/**
* Gets a string representation of this value.
*/
default String name() {
return "[Numeric " + getHexValue() + "]";
}
default String getHexValue() {
return toHex(colorCode());
}
/**
* Returns a list of possible values this trigger pixel can accept.
*/
@SuppressWarnings("unchecked")
default <Option extends TriggerPixelType<T>> List<Option> getOptions() {
if (this instanceof Enum) {
// cast is required because gradle's compiler is more strict
return (List<Option>)List.of(getClass().getEnumConstants());
}
return List.of();
}
default boolean matches(Object o) {
return equals(o);
}
/**
* Gets the enum value corresponding to the given enum type and pixel value.
* If none are found, the first parameter is returned as the default.
*
* @param type Return type and default value.
* @param pixelValue The pixel colour to search for.
*/
@SuppressWarnings("unchecked")
static <T extends TriggerPixelType<T>> T getByTriggerPixel(T type, int pixelValue) {
return (T)type.getOptions().stream()
.filter(i -> i.colorCode() == pixelValue)
.findFirst()
.orElse(type);
}
static TriggerPixelType<?> of(int color) {
return () -> color;
}
static String toHex(int color) {
String v = Integer.toHexString(color).toUpperCase();
while (v.length() < 6) {
v = "0" + v;
}
return "#" + v;
}
public record Multiple<T extends Enum<T> & TriggerPixelType<T>> (
int colorCode,
T def,
boolean[] value
) implements TriggerPixelType<boolean[]> {
@Override
public String name() {
return "[Flags " + Arrays.toString(value) + "]";
}
@SuppressWarnings("unchecked")
@Override
public List<TriggerPixelType<T>> getOptions() {
return def.getOptions();
}
@Override
public boolean matches(Object o) {
return o.getClass() == def.getClass() && value()[((Enum<?>)o).ordinal()];
}
}
}

View file

@ -1,35 +1,31 @@
package com.minelittlepony.api.pony.meta; package com.minelittlepony.api.pony.meta;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.ColorHelper;
import com.minelittlepony.client.model.gear.SaddleBags;
import com.minelittlepony.common.util.Color;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public enum Wearable implements TriggerPixelType<Wearable> { public enum Wearable implements TValue<Wearable> {
NONE (0x00, null), NONE (0x00, null),
CROWN (0x16, new Identifier("minelittlepony", "textures/models/crown.png")), CROWN (0x16, new Identifier("minelittlepony", "textures/models/crown.png")),
MUFFIN (0x32, new Identifier("minelittlepony", "textures/models/muffin.png")), MUFFIN (0x32, new Identifier("minelittlepony", "textures/models/muffin.png")),
HAT (0x64, new Identifier("textures/entity/witch.png")), HAT (0x64, new Identifier("textures/entity/witch.png")),
ANTLERS (0x96, new Identifier("minelittlepony", "textures/models/antlers.png")), ANTLERS (0x96, new Identifier("minelittlepony", "textures/models/antlers.png")),
SADDLE_BAGS_LEFT (0xC6, SaddleBags.TEXTURE), SADDLE_BAGS_LEFT (0xC6, new Identifier("minelittlepony", "textures/models/saddlebags.png")),
SADDLE_BAGS_RIGHT (0xC7, SaddleBags.TEXTURE), SADDLE_BAGS_RIGHT (0xC7, new Identifier("minelittlepony", "textures/models/saddlebags.png")),
SADDLE_BAGS_BOTH (0xC8, SaddleBags.TEXTURE), SADDLE_BAGS_BOTH (0xC8, new Identifier("minelittlepony", "textures/models/saddlebags.png")),
STETSON (0xFA, new Identifier("minelittlepony", "textures/models/stetson.png")); STETSON (0xFA, new Identifier("minelittlepony", "textures/models/stetson.png"));
private int triggerValue; private int triggerValue;
private final Identifier id; private final Identifier id;
private final Identifier texture; private final Identifier texture;
public static final List<Wearable> VALUES = Arrays.stream(values()).toList(); public static final Map<Identifier, Wearable> REGISTRY = Arrays.stream(values()).collect(Collectors.toMap(Wearable::getId, Function.identity()));
public static final Map<Identifier, Wearable> REGISTRY = VALUES.stream().collect(Collectors.toMap(Wearable::getId, Function.identity()));
public static final Flags<Wearable> EMPTY_FLAGS = Flags.of(Wearable.class); public static final Flags<Wearable> EMPTY_FLAGS = Flags.of(NONE);
Wearable(int pixel, Identifier texture) { Wearable(int pixel, Identifier texture) {
triggerValue = pixel; triggerValue = pixel;
@ -56,6 +52,6 @@ public enum Wearable implements TriggerPixelType<Wearable> {
@Override @Override
public int getChannelAdjustedColorCode() { public int getChannelAdjustedColorCode() {
return triggerValue == 0 ? 0 : Color.argbToHex(255, triggerValue, triggerValue, triggerValue); return triggerValue == 0 ? 0 : ColorHelper.Argb.getArgb(255, triggerValue, triggerValue, triggerValue);
} }
} }

View file

@ -1,39 +0,0 @@
package com.minelittlepony.client;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.client.model.armour.DefaultArmourTextureResolver;
import com.minelittlepony.client.render.MobRenderers;
import com.minelittlepony.common.client.gui.VisibilityMode;
import com.minelittlepony.common.util.settings.Setting;
import java.nio.file.Path;
public class ClientPonyConfig extends PonyConfig {
/**
* Visibility mode for the horse button.
*/
public final Setting<VisibilityMode> horseButton = value("horseButton", VisibilityMode.AUTO)
.addComment("Whether to show the mine little pony settings button on the main menu")
.addComment("AUTO (default) - only show when HDSkins is not installed")
.addComment("ON - always show")
.addComment("OFF - never show");
public ClientPonyConfig(Path path) {
super(path);
MobRenderers.REGISTRY.values().forEach(r -> value("entities", r.name, true));
disablePonifiedArmour.onChanged(t -> DefaultArmourTextureResolver.INSTANCE.invalidate());
}
@Override
public void save() {
super.save();
PlayerEntity player = MinecraftClient.getInstance().player;
if (player != null) {
player.calculateDimensions();
}
}
}

View file

@ -5,6 +5,7 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.hit.HitResult; import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.*; import net.minecraft.util.math.*;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.common.util.settings.Setting; import com.minelittlepony.common.util.settings.Setting;
@ -31,7 +32,7 @@ public class HorseCam {
*/ */
public static float transformCameraAngle(float pitch) { public static float transformCameraAngle(float pitch) {
if (!MineLittlePony.getInstance().getConfig().fillycam.get()) { if (!PonyConfig.getInstance().fillycam.get()) {
return pitch; return pitch;
} }
@ -51,7 +52,7 @@ public class HorseCam {
Pony pony = Pony.getManager().getPony(player); Pony pony = Pony.getManager().getPony(player);
if (!pony.race().isHuman()) { if (!pony.race().isHuman()) {
Setting<Boolean> fillyCam = MineLittlePony.getInstance().getConfig().fillycam; Setting<Boolean> fillyCam = PonyConfig.getInstance().fillycam;
fillyCam.set(false); fillyCam.set(false);
final float vanillaHeight = player.getEyeHeight(player.getPose()); final float vanillaHeight = player.getEyeHeight(player.getPose());

View file

@ -1,9 +1,10 @@
package com.minelittlepony.client; package com.minelittlepony.client;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.PonyManager; import com.minelittlepony.api.events.Channel;
import com.minelittlepony.api.pony.network.fabric.Channel;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.armour.ArmourTextureResolver;
import com.minelittlepony.client.render.MobRenderers;
import com.minelittlepony.client.render.PonyRenderDispatcher; import com.minelittlepony.client.render.PonyRenderDispatcher;
import com.minelittlepony.common.client.gui.VisibilityMode; import com.minelittlepony.common.client.gui.VisibilityMode;
import com.minelittlepony.common.client.gui.element.Button; import com.minelittlepony.common.client.gui.element.Button;
@ -13,6 +14,8 @@ import com.minelittlepony.common.event.ScreenInitCallback;
import com.minelittlepony.common.event.SkinFilterCallback; import com.minelittlepony.common.event.SkinFilterCallback;
import com.minelittlepony.common.util.GamePaths; import com.minelittlepony.common.util.GamePaths;
import java.nio.file.Path;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
@ -23,6 +26,7 @@ import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.TitleScreen; import net.minecraft.client.gui.screen.TitleScreen;
import net.minecraft.client.option.KeyBinding; import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.util.InputUtil; import net.minecraft.client.util.InputUtil;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.resource.ResourceType; import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -38,7 +42,6 @@ public class MineLittlePony implements ClientModInitializer {
public static final Logger logger = LogManager.getLogger("MineLittlePony"); public static final Logger logger = LogManager.getLogger("MineLittlePony");
private ClientPonyConfig config;
private PonyManagerImpl ponyManager; private PonyManagerImpl ponyManager;
private VariatedTextureSupplier variatedTextures; private VariatedTextureSupplier variatedTextures;
@ -65,7 +68,7 @@ public class MineLittlePony implements ClientModInitializer {
hasHdSkins = FabricLoader.getInstance().isModLoaded("hdskins"); hasHdSkins = FabricLoader.getInstance().isModLoaded("hdskins");
hasModMenu = FabricLoader.getInstance().isModLoaded("modmenu"); hasModMenu = FabricLoader.getInstance().isModLoaded("modmenu");
config = new ClientPonyConfig(GamePaths.getConfigDirectory().resolve("minelp.json")); PonyConfig config = new ClientPonyConfig(GamePaths.getConfigDirectory().resolve("minelp.json"));
ponyManager = new PonyManagerImpl(config); ponyManager = new PonyManagerImpl(config);
variatedTextures = new VariatedTextureSupplier(); variatedTextures = new VariatedTextureSupplier();
@ -103,13 +106,13 @@ public class MineLittlePony implements ClientModInitializer {
} }
if ((mainMenu || inGame) && keyBinding.isPressed()) { if ((mainMenu || inGame) && keyBinding.isPressed()) {
client.setScreen(new PonySettingsscreen(client.currentScreen)); client.setScreen(new PonySettingsScreen(client.currentScreen));
} }
} }
private void onScreenInit(Screen screen, ScreenInitCallback.ButtonList buttons) { private void onScreenInit(Screen screen, ScreenInitCallback.ButtonList buttons) {
if (screen instanceof TitleScreen) { if (screen instanceof TitleScreen) {
VisibilityMode mode = config.horseButton.get(); VisibilityMode mode = ClientPonyConfig.getInstance().horseButton.get();
boolean show = mode == VisibilityMode.ON || (mode == VisibilityMode.AUTO boolean show = mode == VisibilityMode.ON || (mode == VisibilityMode.AUTO
&& !(hasHdSkins || hasModMenu && !(hasHdSkins || hasModMenu
)); ));
@ -117,7 +120,7 @@ public class MineLittlePony implements ClientModInitializer {
if (show) { if (show) {
int y = hasHdSkins ? 75 : 50; int y = hasHdSkins ? 75 : 50;
Button button = buttons.addButton(new Button(screen.width - 50, screen.height - y, 20, 20)) Button button = buttons.addButton(new Button(screen.width - 50, screen.height - y, 20, 20))
.onClick(sender -> MinecraftClient.getInstance().setScreen(new PonySettingsscreen(screen))); .onClick(sender -> MinecraftClient.getInstance().setScreen(new PonySettingsScreen(screen)));
button.getStyle() button.getStyle()
.setIcon(new TextureSprite() .setIcon(new TextureSprite()
.setPosition(2, 2) .setPosition(2, 2)
@ -130,14 +133,7 @@ public class MineLittlePony implements ClientModInitializer {
} }
} }
/** public PonyManagerImpl getManager() {
* Gets the global MineLP client configuration.
*/
public PonyConfig getConfig() {
return config;
}
public PonyManager getManager() {
return ponyManager; return ponyManager;
} }
@ -151,5 +147,22 @@ public class MineLittlePony implements ClientModInitializer {
public PonyRenderDispatcher getRenderDispatcher() { public PonyRenderDispatcher getRenderDispatcher() {
return renderDispatcher; return renderDispatcher;
} }
private static final class ClientPonyConfig extends PonyConfig {
public ClientPonyConfig(Path path) {
super(path);
MobRenderers.REGISTRY.values().forEach(r -> value("entities", r.name, true));
disablePonifiedArmour.onChanged(t -> ArmourTextureResolver.INSTANCE.invalidate());
}
@Override
public void save() {
super.save();
PlayerEntity player = MinecraftClient.getInstance().player;
if (player != null) {
player.calculateDimensions();
}
}
}
} }

View file

@ -6,7 +6,6 @@ import net.minecraft.util.Identifier;
import com.google.gson.*; import com.google.gson.*;
import com.minelittlepony.api.pony.PonyData; import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.client.util.render.NativeUtil; import com.minelittlepony.client.util.render.NativeUtil;
import java.io.IOException; import java.io.IOException;
@ -53,16 +52,7 @@ class PonyDataLoader {
}).map(PonyDataLoader::loaded).orElseGet(() -> { }).map(PonyDataLoader::loaded).orElseGet(() -> {
return load(callback -> { return load(callback -> {
NativeUtil.parseImage(identifier, image -> { NativeUtil.parseImage(identifier, image -> {
callback.accept(new PonyData( callback.accept(new PonyData(image, noSkin));
TriggerPixel.RACE.readValue(image),
TriggerPixel.TAIL.readValue(image),
TriggerPixel.TAIL_SHAPE.readValue(image),
TriggerPixel.GENDER.readValue(image),
TriggerPixel.SIZE.readValue(image),
TriggerPixel.GLOW.readColor(image),
TriggerPixel.WEARABLES.readFlags(image),
noSkin
));
}, e -> { }, e -> {
MineLittlePony.logger.fatal("Unable to read {} metadata", identifier, e); MineLittlePony.logger.fatal("Unable to read {} metadata", identifier, e);
callback.accept(PonyData.NULL); callback.accept(PonyData.NULL);

View file

@ -9,10 +9,10 @@ import com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.util.DefaultSkinHelper; import net.minecraft.client.util.DefaultSkinHelper;
import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceManager;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@ -22,25 +22,18 @@ import java.util.UUID;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** public class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceReloadListener {
* The PonyManager is responsible for reading and recoding all the pony data associated with an entity of skin.
*/
class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceReloadListener {
private static final Identifier ID = new Identifier("minelittlepony", "background_ponies"); private static final Identifier ID = new Identifier("minelittlepony", "background_ponies");
private final PonyConfig config; private final PonyConfig config;
private final LoadingCache<Identifier, Pony> defaultedPoniesCache = CacheBuilder.newBuilder() private final LoadingCache<Identifier, Pony> defaultedPoniesCache = CacheBuilder.newBuilder()
.expireAfterAccess(30, TimeUnit.SECONDS) .expireAfterAccess(30, TimeUnit.SECONDS)
.build(CacheLoader.from(resource -> { .build(CacheLoader.from(resource -> new Pony(resource, PonyDataLoader.parse(resource, true))));
return new Pony(resource, PonyDataLoader.parse(resource, true));
}));
private final LoadingCache<Identifier, Pony> poniesCache = CacheBuilder.newBuilder() private final LoadingCache<Identifier, Pony> poniesCache = CacheBuilder.newBuilder()
.expireAfterAccess(30, TimeUnit.SECONDS) .expireAfterAccess(30, TimeUnit.SECONDS)
.build(CacheLoader.from(resource -> { .build(CacheLoader.from(resource -> new Pony(resource, PonyDataLoader.parse(resource, false))));
return new Pony(resource, PonyDataLoader.parse(resource, false));
}));
public PonyManagerImpl(PonyConfig config) { public PonyManagerImpl(PonyConfig config) {
this.config = config; this.config = config;
@ -56,78 +49,61 @@ class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceReloadLis
} }
@Override @Override
public Pony getPony(Identifier resource) { public Pony getPony(PlayerEntity player) {
return loadPony(resource, false); return getPony(getSkin(player), player instanceof ForcedPony ? null : player.getGameProfile() == null ? player.getUuid() : player.getGameProfile().getId());
} }
@Override @Override
public Optional<Pony> getPony(@Nullable Entity entity) { public Optional<Pony> getPony(LivingEntity entity) {
if (entity instanceof PlayerEntity player) { if (entity instanceof PlayerEntity player) {
return Optional.of(getPony(player)); return Optional.of(getPony(player));
} }
Identifier skin = getSkin(entity);
if (entity instanceof LivingEntity living) { return skin == null ? Optional.empty() : Optional.of(getPony(skin, null));
return Optional.ofNullable(MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(living)).map(d -> d.getEntityPony(living));
}
return Optional.empty();
} }
@Override @Override
public Pony getPony(PlayerEntity player) { public Pony getPony(@Nullable Identifier resource, @Nullable UUID uuid) {
Identifier skin = getSkin(player); if (resource == null) {
UUID uuid = player.getGameProfile() == null ? player.getUuid() : player.getGameProfile().getId(); return uuid == null ? loadPony(DefaultSkinHelper.getTexture(), true) : getBackgroundPony(uuid);
if (skin != null) {
if (player instanceof PonyManager.ForcedPony) {
return getPony(skin);
} }
return getPony(skin, uuid); Pony pony = loadPony(resource, false);
}
if (config.ponyLevel.get() == PonyLevel.PONIES) { if (uuid != null && PonyConfig.getInstance().ponyLevel.get() == PonyLevel.PONIES && pony.metadata().race().isHuman()) {
return getBackgroundPony(uuid); return getBackgroundPony(uuid);
} }
return loadPony(DefaultSkinHelper.getTexture(uuid).texture(), true);
}
@Override
public Pony getPony(Identifier resource, UUID uuid) {
Pony pony = getPony(resource);
if (config.ponyLevel.get() == PonyLevel.PONIES && pony.metadata().race().isHuman()) {
return getBackgroundPony(uuid);
}
return pony; return pony;
} }
@Override @Override
public Pony getBackgroundPony(UUID uuid) { public Pony getBackgroundPony(@Nullable UUID uuid) {
return loadPony(MineLittlePony.getInstance().getVariatedTextures().get(VariatedTextureSupplier.BACKGROUND_PONIES_POOL, uuid).orElse(DefaultSkinHelper.getTexture(uuid).texture()), true); if (config.ponyLevel.get() == PonyLevel.PONIES) {
return loadPony(MineLittlePony.getInstance().getVariatedTextures().get(VariatedTextureSupplier.BACKGROUND_PONIES_POOL, uuid).orElse(DefaultSkinHelper.getSkinTextures(uuid).texture()), true);
}
return loadPony(DefaultSkinHelper.getSkinTextures(uuid).texture(), true);
} }
@Nullable @Nullable
private Identifier getSkin(PlayerEntity player) { private Identifier getSkin(LivingEntity entity) {
if (player.getGameProfile() == null) { if (entity instanceof PlayerEntity player) {
return null; if (player.getGameProfile() != null && player instanceof AbstractClientPlayerEntity clientPlayer) {
return clientPlayer.getSkinTextures().texture();
}
} else {
if (MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(entity) != null) {
return MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity).getTexture(entity);
} }
if (player instanceof AbstractClientPlayerEntity) {
return ((AbstractClientPlayerEntity)player).method_52814().texture();
} }
return null; return null;
} }
@Override
public void removePony(Identifier resource) { public void removePony(Identifier resource) {
poniesCache.invalidate(resource); poniesCache.invalidate(resource);
defaultedPoniesCache.invalidate(resource); defaultedPoniesCache.invalidate(resource);
} }
@Override
public void clearCache() { public void clearCache() {
MineLittlePony.logger.info("Flushed {} cached ponies.", poniesCache.size()); MineLittlePony.logger.info("Flushed {} cached ponies.", poniesCache.size());
poniesCache.invalidateAll(); poniesCache.invalidateAll();

View file

@ -5,6 +5,7 @@ import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.*; import net.minecraft.text.*;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.client.render.MobRenderers; import com.minelittlepony.client.render.MobRenderers;
import com.minelittlepony.common.client.gui.GameGui; import com.minelittlepony.common.client.gui.GameGui;
import com.minelittlepony.common.client.gui.ScrollContainer; import com.minelittlepony.common.client.gui.ScrollContainer;
@ -23,7 +24,7 @@ import org.jetbrains.annotations.Nullable;
* In-Game options menu. * In-Game options menu.
* *
*/ */
public class PonySettingsscreen extends GameGui { public class PonySettingsScreen extends GameGui {
private static final String OPTIONS_PREFIX = "minelp.options."; private static final String OPTIONS_PREFIX = "minelp.options.";
private static final String PONY_LEVEL = OPTIONS_PREFIX + "ponylevel"; private static final String PONY_LEVEL = OPTIONS_PREFIX + "ponylevel";
private static final String MOB_PREFIX = "minelp.mobs."; private static final String MOB_PREFIX = "minelp.mobs.";
@ -34,17 +35,22 @@ public class PonySettingsscreen extends GameGui {
public static final Text SCALE_SHOW = Text.translatable("minelp.debug.scale.sa"); public static final Text SCALE_SHOW = Text.translatable("minelp.debug.scale.sa");
public static final Text SCALE_MIN = Text.translatable("minelp.debug.scale.min"); public static final Text SCALE_MIN = Text.translatable("minelp.debug.scale.min");
private ClientPonyConfig config; public static HorseButtonFactory buttonFactory = (screen, parent, row, RIGHT, content) -> {
content.addButton(new Button(RIGHT, row += 20, 150, 20))
.setEnabled(false)
.getStyle()
.setTooltip(Tooltip.of("minelp.options.skins.hdskins.disabled", 200))
.setText("minelp.options.skins.hdskins.open");
};
private final PonyConfig config = PonyConfig.getInstance();
private final ScrollContainer content = new ScrollContainer(); private final ScrollContainer content = new ScrollContainer();
private final boolean hiddenOptions; private final boolean hiddenOptions;
public PonySettingsscreen(@Nullable Screen parent) { public PonySettingsScreen(@Nullable Screen parent) {
super(Text.literal(OPTIONS_PREFIX + "title"), parent); super(Text.literal(OPTIONS_PREFIX + "title"), parent);
config = (ClientPonyConfig)MineLittlePony.getInstance().getConfig();
content.margin.top = 30; content.margin.top = 30;
content.margin.bottom = 30; content.margin.bottom = 30;
content.getContentPadding().top = 10; content.getContentPadding().top = 10;
@ -158,7 +164,7 @@ public class PonySettingsscreen extends GameGui {
row += 15; row += 15;
content.addButton(new Label(RIGHT, row)).getStyle().setText("minelp.options.skins"); content.addButton(new Label(RIGHT, row)).getStyle().setText("minelp.options.skins");
SkinsProxy.instance.renderOption(this, parent, row, RIGHT, content); buttonFactory.renderOption(this, parent, row, RIGHT, content);
} }
public Text describeCurrentScale(AbstractSlider<Float> sender) { public Text describeCurrentScale(AbstractSlider<Float> sender) {
@ -188,7 +194,6 @@ public class PonySettingsscreen extends GameGui {
@Override @Override
public void render(DrawContext context, int mouseX, int mouseY, float tickDelta) { public void render(DrawContext context, int mouseX, int mouseY, float tickDelta) {
renderBackground(context, mouseX, mouseY, tickDelta);
super.render(context, mouseX, mouseY, tickDelta); super.render(context, mouseX, mouseY, tickDelta);
content.render(context, mouseX, mouseY, tickDelta); content.render(context, mouseX, mouseY, tickDelta);
} }
@ -197,4 +202,8 @@ public class PonySettingsscreen extends GameGui {
public void removed() { public void removed() {
config.save(); config.save();
} }
public interface HorseButtonFactory {
void renderOption(Screen screen, @Nullable Screen parent, int row, int RIGHT, ScrollContainer content);
}
} }

View file

@ -1,5 +0,0 @@
package com.minelittlepony.client;
public interface PreviewModel {
boolean forceSeapony();
}

View file

@ -2,9 +2,8 @@ package com.minelittlepony.client.compat.hdskins;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import com.minelittlepony.api.model.PreviewModel;
import com.minelittlepony.api.pony.*; import com.minelittlepony.api.pony.*;
import com.minelittlepony.client.PreviewModel;
import com.minelittlepony.client.render.EquineRenderManager;
import com.minelittlepony.hdskins.client.gui.player.*; import com.minelittlepony.hdskins.client.gui.player.*;
import com.minelittlepony.hdskins.client.gui.player.skins.PlayerSkins; import com.minelittlepony.hdskins.client.gui.player.skins.PlayerSkins;
@ -13,20 +12,20 @@ import java.util.UUID;
/** /**
* Dummy model used for the skin uploading screen. * Dummy model used for the skin uploading screen.
*/ */
class DummyPony extends DummyPlayer implements PreviewModel, PonyManager.ForcedPony, EquineRenderManager.RegistrationHandler { class DummyPony extends DummyPlayer implements PreviewModel, PonyManager.ForcedPony {
public DummyPony(ClientWorld world, PlayerSkins<?> textures) { public DummyPony(ClientWorld world, PlayerSkins<?> textures) {
super(world, textures); super(world, textures);
setUuid(UUID.randomUUID()); // uuid must be random so animations aren't linked between the two previews setUuid(UUID.randomUUID()); // uuid must be random so animations aren't linked between the two previews
} }
@Override
public boolean shouldUpdateRegistration(Pony pony) {
return false;
}
@Override @Override
public boolean forceSeapony() { public boolean forceSeapony() {
return getTextures().getPosture().getActiveSkinType() == MineLPHDSkins.seaponySkinType; return getTextures().getPosture().getActiveSkinType() == MineLPHDSkins.seaponySkinType;
} }
@Override
public boolean forceNirik() {
return getTextures().getPosture().getActiveSkinType() == MineLPHDSkins.nirikSkinType;
}
} }

View file

@ -1,7 +1,6 @@
package com.minelittlepony.client.compat.hdskins; package com.minelittlepony.client.compat.hdskins;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.client.PonySettingsScreen;
import com.minelittlepony.client.PonySettingsscreen;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.common.client.gui.dimension.Bounds; import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.common.client.gui.element.Button; import com.minelittlepony.common.client.gui.element.Button;
@ -29,22 +28,22 @@ class GuiSkinsMineLP extends GuiSkins {
chooser.addSkinChangedEventListener(type -> { chooser.addSkinChangedEventListener(type -> {
MineLittlePony.logger.debug("Invalidating old local skin, checking updated local skin"); MineLittlePony.logger.debug("Invalidating old local skin, checking updated local skin");
if (type == SkinType.SKIN) { if (type == SkinType.SKIN) {
Pony.getManager().removePony(previewer.getLocal().getSkins().get(SkinType.SKIN).getId()); MineLittlePony.getInstance().getManager().removePony(previewer.getLocal().getSkins().get(SkinType.SKIN).getId());
} }
}); });
uploader.addSkinLoadedEventListener((type, location, profileTexture) -> { uploader.addSkinLoadedEventListener((type, location, profileTexture) -> {
MineLittlePony.logger.debug("Invalidating old remote skin, checking updated remote skin"); MineLittlePony.logger.debug("Invalidating old remote skin, checking updated remote skin");
if (type == SkinType.SKIN) { if (type == SkinType.SKIN) {
Pony.getManager().removePony(location); MineLittlePony.getInstance().getManager().removePony(location);
} }
}); });
} }
@Override @Override
protected void initServerPreviewButtons(Bounds area) { protected void initServerPreviewButtons(Bounds area) {
if (!(parent instanceof PonySettingsscreen)) { if (!(parent instanceof PonySettingsScreen)) {
addButton(new Button(area.right() - 20, area.bottom() + 5, 20, 20)) addButton(new Button(area.right() - 20, area.bottom() + 5, 20, 20))
.onClick(sender -> client.setScreen(new PonySettingsscreen(this))) .onClick(sender -> client.setScreen(new PonySettingsScreen(this)))
.getStyle() .getStyle()
.setIcon(new TextureSprite() .setIcon(new TextureSprite()
.setPosition(2, 2) .setPosition(2, 2)

View file

@ -4,7 +4,7 @@ import net.minecraft.client.gui.DrawContext;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import com.minelittlepony.api.pony.*; import com.minelittlepony.api.pony.*;
import com.minelittlepony.api.pony.meta.TriggerPixelType; import com.minelittlepony.api.pony.meta.TValue;
import com.minelittlepony.common.client.gui.ITextContext; import com.minelittlepony.common.client.gui.ITextContext;
import com.minelittlepony.common.client.gui.dimension.Bounds; import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.hdskins.client.gui.Carousel; import com.minelittlepony.hdskins.client.gui.Carousel;
@ -37,7 +37,7 @@ class LegendOverlayWidget implements Carousel.Element, ITextContext {
}); });
} }
private void drawLegendBlock(DrawContext context, int index, int x, int y, int mouseX, int mouseY, String key, TriggerPixelType<?> value) { private void drawLegendBlock(DrawContext context, int index, int x, int y, int mouseX, int mouseY, String key, TValue<?> value) {
context.fill(0, 0, LEGEND_BLOCK_BOUNDS.width, LEGEND_BLOCK_BOUNDS.height, 0xFF003333); context.fill(0, 0, LEGEND_BLOCK_BOUNDS.width, LEGEND_BLOCK_BOUNDS.height, 0xFF003333);
context.fill(1, 1, LEGEND_BLOCK_BOUNDS.width - 1, LEGEND_BLOCK_BOUNDS.height - 1, value.colorCode() | 0xFF000000); context.fill(1, 1, LEGEND_BLOCK_BOUNDS.width - 1, LEGEND_BLOCK_BOUNDS.height - 1, value.colorCode() | 0xFF000000);

View file

@ -1,7 +1,8 @@
package com.minelittlepony.client.compat.hdskins; package com.minelittlepony.client.compat.hdskins;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.PonyData; import com.minelittlepony.api.config.PonyLevel;
import com.minelittlepony.api.pony.*;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.common.client.gui.ScrollContainer; import com.minelittlepony.common.client.gui.ScrollContainer;
import com.minelittlepony.common.client.gui.element.Button; import com.minelittlepony.common.client.gui.element.Button;
@ -10,6 +11,7 @@ import com.minelittlepony.hdskins.client.*;
import com.minelittlepony.hdskins.client.gui.GuiSkins; import com.minelittlepony.hdskins.client.gui.GuiSkins;
import com.minelittlepony.hdskins.client.gui.player.DummyPlayer; import com.minelittlepony.hdskins.client.gui.player.DummyPlayer;
import com.minelittlepony.hdskins.client.gui.player.skins.PlayerSkins.PlayerSkin; import com.minelittlepony.hdskins.client.gui.player.skins.PlayerSkins.PlayerSkin;
import com.minelittlepony.hdskins.client.profile.SkinLoader.ProvidedSkins;
import com.minelittlepony.hdskins.profile.SkinType; import com.minelittlepony.hdskins.profile.SkinType;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
@ -27,7 +29,6 @@ import net.minecraft.item.Items;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.client.*; import com.minelittlepony.client.*;
import com.minelittlepony.client.render.entity.AquaticPlayerPonyRenderer;
/** /**
* All the interactions with HD Skins. * All the interactions with HD Skins.
@ -35,15 +36,18 @@ import com.minelittlepony.client.render.entity.AquaticPlayerPonyRenderer;
public class MineLPHDSkins extends SkinsProxy implements ClientModInitializer { public class MineLPHDSkins extends SkinsProxy implements ClientModInitializer {
static SkinType seaponySkinType; static SkinType seaponySkinType;
static SkinType nirikSkinType;
static final Map<SkinType, Wearable> wearableTypes = new HashMap<>(); static final Map<SkinType, Wearable> wearableTypes = new HashMap<>();
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
SkinsProxy.instance = this; SkinsProxy.instance = this;
PonySettingsScreen.buttonFactory = this::renderOption;
seaponySkinType = SkinType.register(AquaticPlayerPonyRenderer.SKIN_TYPE_ID, Items.COD_BUCKET.getDefaultStack()); seaponySkinType = SkinType.register(DefaultPonySkinHelper.SEAPONY_SKIN_TYPE_ID, Items.COD_BUCKET.getDefaultStack());
Wearable.VALUES.forEach(wearable -> { nirikSkinType = SkinType.register(DefaultPonySkinHelper.NIRIK_SKIN_TYPE_ID, Items.LAVA_BUCKET.getDefaultStack());
Wearable.REGISTRY.values().forEach(wearable -> {
if (wearable != Wearable.NONE) { if (wearable != Wearable.NONE) {
wearableTypes.put(SkinType.register(wearable.getId(), Items.BUNDLE.getDefaultStack()), wearable); wearableTypes.put(SkinType.register(wearable.getId(), Items.BUNDLE.getDefaultStack()), wearable);
} }
@ -56,10 +60,29 @@ public class MineLPHDSkins extends SkinsProxy implements ClientModInitializer {
// Ponify the skins GUI. // Ponify the skins GUI.
GuiSkins.setSkinsGui(GuiSkinsMineLP::new); GuiSkins.setSkinsGui(GuiSkinsMineLP::new);
}); });
HDSkins.getInstance().getSkinPrioritySorter().addSelector((skinType, playerSkins) -> {
if (skinType == SkinType.SKIN && PonyConfig.getInstance().mixedHumanSkins.get()) {
Optional<Pony> hdPony = getPony(playerSkins.hd());
Optional<Pony> vanillaPony = getPony(playerSkins.vanilla());
if (hdPony.isPresent() && vanillaPony.isPresent()
&& vanillaPony.get().metadata().priority() > hdPony.get().metadata().priority()
&& (PonyConfig.getInstance().ponyLevel.get() == PonyLevel.HUMANS || vanillaPony.get().metadata().race().isHuman() == hdPony.get().metadata().race().isHuman())) {
return playerSkins.vanilla();
}
}
return playerSkins.combined();
});
} }
@Override static Optional<Pony> getPony(PlayerSkinLayers.Layer layer) {
public void renderOption(Screen screen, @Nullable Screen parent, int row, int RIGHT, ScrollContainer content) { return layer
.getSkin(SkinType.SKIN)
.map(Pony.getManager()::getPony);
}
private void renderOption(Screen screen, @Nullable Screen parent, int row, int RIGHT, ScrollContainer content) {
content.addButton(new Button(RIGHT, row += 20, 150, 20)) content.addButton(new Button(RIGHT, row += 20, 150, 20))
.onClick(button -> MinecraftClient.getInstance().setScreen( .onClick(button -> MinecraftClient.getInstance().setScreen(
parent instanceof GuiSkins ? parent : GuiSkins.create(screen, HDSkins.getInstance().getSkinServerList()) parent instanceof GuiSkins ? parent : GuiSkins.create(screen, HDSkins.getInstance().getSkinServerList())
@ -80,10 +103,11 @@ public class MineLPHDSkins extends SkinsProxy implements ClientModInitializer {
} }
if (entity instanceof AbstractClientPlayerEntity player) { if (entity instanceof AbstractClientPlayerEntity player) {
PlayerSkins skins = PlayerSkins.of(player); return PlayerSkins.of(player)
if (skins != null) { .map(PlayerSkins::layers)
return skins.getProvidedSkinTypes(); .map(PlayerSkinLayers::combined)
} .map(PlayerSkinLayers.Layer::getProvidedSkinTypes)
.orElseGet(Set::of);
} }
return Set.of(); return Set.of();
@ -100,7 +124,7 @@ public class MineLPHDSkins extends SkinsProxy implements ClientModInitializer {
PlayerSkin main = dummy.getTextures().get(SkinType.SKIN); PlayerSkin main = dummy.getTextures().get(SkinType.SKIN);
Wearable wearable = Wearable.REGISTRY.getOrDefault(type.getId(), Wearable.NONE); Wearable wearable = Wearable.REGISTRY.getOrDefault(type.getId(), Wearable.NONE);
PonyData metadata = Pony.getManager().getPony(main.getId()).metadata(); PonyData metadata = Pony.getManager().getPony(main.getId()).metadata();
if (wearable != Wearable.NONE && metadata.isWearing(wearable)) { if (wearable != Wearable.NONE && metadata.gear().matches(wearable)) {
if (wearable.isSaddlebags() && metadata.race().supportsLegacySaddlebags()) { if (wearable.isSaddlebags() && metadata.race().supportsLegacySaddlebags()) {
return Optional.of(main.getId()); return Optional.of(main.getId());
@ -110,13 +134,16 @@ public class MineLPHDSkins extends SkinsProxy implements ClientModInitializer {
} }
} }
return Optional.of(player).map(PlayerSkins::of).map(skins -> skins.getSkin(type)); return Optional.of(player).flatMap(PlayerSkins::of)
.map(PlayerSkins::layers)
.map(PlayerSkinLayers::combined).flatMap(skins -> skins.getSkin(type));
} }
@Override @Override
public Identifier getSkinTexture(GameProfile profile) { public Identifier getSkinTexture(GameProfile profile) {
return HDSkins.getInstance().getProfileRepository() return HDSkins.getInstance().getProfileRepository()
.getNow(profile) .load(profile)
.getNow(ProvidedSkins.EMPTY)
.getSkin(SkinType.SKIN) .getSkin(SkinType.SKIN)
.orElseGet(() -> super.getSkinTexture(profile)); .orElseGet(() -> super.getSkinTexture(profile));
} }

View file

@ -31,6 +31,9 @@ class PonifiedDualCarouselWidget extends DualCarouselWidget {
if (type == MineLPHDSkins.seaponySkinType) { if (type == MineLPHDSkins.seaponySkinType) {
return NativeImageFilters.GREYSCALE.load(SeaponyRenderer.SEAPONY, SeaponyRenderer.SEAPONY, getExclusion()); return NativeImageFilters.GREYSCALE.load(SeaponyRenderer.SEAPONY, SeaponyRenderer.SEAPONY, getExclusion());
} }
if (type == MineLPHDSkins.nirikSkinType) {
return super.getDefaultSkin(SkinType.SKIN, modelVariant);
}
Wearable wearable = MineLPHDSkins.wearableTypes.getOrDefault(type, Wearable.NONE); Wearable wearable = MineLPHDSkins.wearableTypes.getOrDefault(type, Wearable.NONE);

View file

@ -3,11 +3,11 @@ package com.minelittlepony.client.compat.modmenu;
import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi; import com.terraformersmc.modmenu.api.ModMenuApi;
import com.minelittlepony.client.PonySettingsscreen; import com.minelittlepony.client.PonySettingsScreen;
public class MineLPModMenuFactory implements ModMenuApi { public class MineLPModMenuFactory implements ModMenuApi {
@Override @Override
public ConfigScreenFactory<?> getModConfigScreenFactory() { public ConfigScreenFactory<?> getModConfigScreenFactory() {
return PonySettingsscreen::new; return PonySettingsScreen::new;
} }
} }

View file

@ -9,7 +9,6 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityPose; import net.minecraft.entity.EntityPose;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
@ -20,8 +19,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
abstract class MixinClientPlayerEntity extends AbstractClientPlayerEntity implements EquineRenderManager.RegistrationHandler { abstract class MixinClientPlayerEntity extends AbstractClientPlayerEntity implements EquineRenderManager.RegistrationHandler {
public MixinClientPlayerEntity() { super(null, null); } public MixinClientPlayerEntity() { super(null, null); }
@Nullable private final EquineRenderManager.SyncedPony syncedPony = new EquineRenderManager.SyncedPony();
private Pony pony;
@Inject(method = "startRiding(Lnet/minecraft/entity/Entity;Z)Z", at = @At("RETURN")) @Inject(method = "startRiding(Lnet/minecraft/entity/Entity;Z)Z", at = @At("RETURN"))
private void onStartRiding(Entity entity, boolean bl, CallbackInfoReturnable<Boolean> info) { private void onStartRiding(Entity entity, boolean bl, CallbackInfoReturnable<Boolean> info) {
@ -34,12 +32,8 @@ abstract class MixinClientPlayerEntity extends AbstractClientPlayerEntity implem
} }
@Override @Override
public boolean shouldUpdateRegistration(Pony pony) { public EquineRenderManager.SyncedPony getSyncedPony() {
if (this.pony != pony && (this.pony == null || this.pony.metadata().compareTo(pony.metadata()) != 0)) { return syncedPony;
this.pony = pony.immutableCopy();
return true;
}
return false;
} }
@Override @Override

View file

@ -1,8 +1,8 @@
package com.minelittlepony.client.mixin; package com.minelittlepony.client.mixin;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.config.PonyLevel; import com.minelittlepony.api.config.PonyLevel;
import com.minelittlepony.api.pony.DefaultPonySkinHelper; import com.minelittlepony.api.pony.DefaultPonySkinHelper;
import com.minelittlepony.client.MineLittlePony;
import net.minecraft.client.util.DefaultSkinHelper; import net.minecraft.client.util.DefaultSkinHelper;
import net.minecraft.client.util.SkinTextures; import net.minecraft.client.util.SkinTextures;
@ -21,16 +21,16 @@ abstract class MixinDefaultSkinHelper {
at = @At("RETURN"), at = @At("RETURN"),
cancellable = true) cancellable = true)
private static void onGetTexture(CallbackInfoReturnable<Identifier> cir) { private static void onGetTexture(CallbackInfoReturnable<Identifier> cir) {
if (MineLittlePony.getInstance().getConfig().ponyLevel.get() == PonyLevel.PONIES) { if (PonyConfig.getInstance().ponyLevel.get() == PonyLevel.PONIES) {
cir.setReturnValue(DefaultPonySkinHelper.STEVE); cir.setReturnValue(DefaultPonySkinHelper.STEVE);
} }
} }
@Inject(method = "getTexture(Ljava/util/UUID;)Lnet/minecraft/client/util/SkinTextures;", @Inject(method = "getSkinTextures(Ljava/util/UUID;)Lnet/minecraft/client/util/SkinTextures;",
at = @At("RETURN"), at = @At("RETURN"),
cancellable = true) cancellable = true)
private static void onGetTexture(UUID uuid, CallbackInfoReturnable<SkinTextures> cir) { private static void onGetTexture(UUID uuid, CallbackInfoReturnable<SkinTextures> cir) {
if (MineLittlePony.getInstance().getConfig().ponyLevel.get() == PonyLevel.PONIES) { if (PonyConfig.getInstance().ponyLevel.get() == PonyLevel.PONIES) {
cir.setReturnValue(DefaultPonySkinHelper.getTextures(cir.getReturnValue())); cir.setReturnValue(DefaultPonySkinHelper.getTextures(cir.getReturnValue()));
} }
} }

View file

@ -1,8 +1,8 @@
package com.minelittlepony.client.model; package com.minelittlepony.client.model;
import com.minelittlepony.api.model.*; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.model.fabric.PonyModelPrepareCallback; import com.minelittlepony.api.events.PonyModelPrepareCallback;
import com.minelittlepony.api.pony.meta.Sizes; import com.minelittlepony.api.pony.meta.SizePreset;
import com.minelittlepony.client.transform.PonyTransformation; import com.minelittlepony.client.transform.PonyTransformation;
import com.minelittlepony.client.util.render.RenderList; import com.minelittlepony.client.util.render.RenderList;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
@ -50,7 +50,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
protected final RenderList mainRenderList; protected final RenderList mainRenderList;
private final List<IPart> parts = new ArrayList<>(); private final List<SubModel> parts = new ArrayList<>();
public AbstractPonyModel(ModelPart tree) { public AbstractPonyModel(ModelPart tree) {
super(tree); super(tree);
@ -66,18 +66,18 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
.add(withStage(BodyPart.HEAD, helmetRenderList = RenderList.of(hat))); .add(withStage(BodyPart.HEAD, helmetRenderList = RenderList.of(hat)));
} }
protected <P extends IPart> P addPart(P part) { protected <P extends SubModel> P addPart(P part) {
parts.add(part); parts.add(part);
return part; return part;
} }
protected RenderList forPart(Supplier<IPart> part) { protected RenderList forPart(Supplier<SubModel> part) {
return (stack, vertices, overlayUv, lightUv, red, green, blue, alpha) -> { return (stack, vertices, overlayUv, lightUv, red, green, blue, alpha) -> {
part.get().renderPart(stack, vertices, overlayUv, lightUv, red, green, blue, alpha, attributes); part.get().renderPart(stack, vertices, overlayUv, lightUv, red, green, blue, alpha, attributes);
}; };
} }
protected RenderList forPart(IPart part) { protected RenderList forPart(SubModel part) {
return (stack, vertices, overlayUv, lightUv, red, green, blue, alpha) -> { return (stack, vertices, overlayUv, lightUv, red, green, blue, alpha) -> {
part.renderPart(stack, vertices, overlayUv, lightUv, red, green, blue, alpha, attributes); part.renderPart(stack, vertices, overlayUv, lightUv, red, green, blue, alpha, attributes);
}; };
@ -119,11 +119,10 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
} }
protected void setModelAngles(T entity, float limbAngle, float limbSpeed, float animationProgress, float headYaw, float headPitch) { protected void setModelAngles(T entity, float limbAngle, float limbSpeed, float animationProgress, float headYaw, float headPitch) {
float pitch = attributes.motionPitch * MathHelper.RADIANS_PER_DEGREE;
float pitch = (float)Math.toRadians(attributes.motionPitch);
head.setAngles( head.setAngles(
MathHelper.clamp(attributes.isSleeping ? 0.1f : headPitch / 57.29578F, -1.25f - pitch, 0.5f - pitch), MathHelper.clamp(attributes.isSleeping ? 0.1f : headPitch / 57.29578F, -1.25f - pitch, 0.5f - pitch),
attributes.isSleeping ? (Math.abs(entity.getUuid().getMostSignificantBits()) % 2.8F) - 1.9F : headYaw / 57.29578F, attributes.isSleeping ? (Math.signum(MathHelper.wrapDegrees(headYaw)) * 1.3F) : headYaw * MathHelper.RADIANS_PER_DEGREE,
0 0
); );
@ -149,7 +148,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
} else { } else {
adjustBody(0, ORIGIN); adjustBody(0, ORIGIN);
if (!attributes.isSleeping) { if (!attributes.isLyingDown) {
animateBreathing(animationProgress); animateBreathing(animationProgress);
} }
@ -159,7 +158,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
} }
} }
if (attributes.isSleeping) { if (attributes.isLyingDown) {
ponySleep(); ponySleep();
} }
@ -197,7 +196,6 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
leftLeg.pitch = MathUtil.Angles._90_DEG; leftLeg.pitch = MathUtil.Angles._90_DEG;
HEAD_SLEEPING.set(head); HEAD_SLEEPING.set(head);
head.pivotZ = sneaking ? -1 : 1;
FONT_LEGS_SLEEPING.add(rightArm); FONT_LEGS_SLEEPING.add(rightArm);
FONT_LEGS_SLEEPING.add(leftArm); FONT_LEGS_SLEEPING.add(leftArm);
@ -341,7 +339,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
} }
protected float getLegOutset() { protected float getLegOutset() {
if (attributes.isSleeping) { if (attributes.isLyingDown) {
return 3.6f; return 3.6f;
} }
@ -368,6 +366,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
case NECK: return neck; case NECK: return neck;
case TAIL: case TAIL:
case LEGS: case LEGS:
case BACK:
case BODY: return body; case BODY: return body;
} }
} }
@ -437,7 +436,8 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
break; break;
case THROW_SPEAR: case THROW_SPEAR:
arm.pitch = MathUtil.Angles._90_DEG * 2; arm.pitch = MathUtil.Angles._90_DEG * 2;
arm.roll += 0.3F * -limbSpeed * sigma; arm.roll += (0.3F * -limbSpeed + 0.6F) * sigma;
arm.pivotY ++;
break; break;
case SPYGLASS: case SPYGLASS:
float addedPitch = sneaking ? -0.2617994F : 0; float addedPitch = sneaking ? -0.2617994F : 0;
@ -450,10 +450,10 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
arm.pivotX -= 6 * sigma; arm.pivotX -= 6 * sigma;
arm.pivotZ -= 2; arm.pivotZ -= 2;
} }
if (getSize() == Sizes.TALL) { if (getSize() == SizePreset.TALL) {
arm.pivotY += 1; arm.pivotY += 1;
} }
if (getSize() == Sizes.FOAL) { if (getSize() == SizePreset.FOAL) {
arm.pivotY -= 2; arm.pivotY -= 2;
} }
@ -490,7 +490,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
* @param entity The entity we are being called for. * @param entity The entity we are being called for.
*/ */
protected void swingItem(T entity) { protected void swingItem(T entity) {
if (getSwingAmount() > 0 && !attributes.isSleeping) { if (getSwingAmount() > 0 && !attributes.isLyingDown) {
Arm mainSide = getPreferredArm(entity); Arm mainSide = getPreferredArm(entity);
swingArm(getArm(mainSide)); swingArm(getArm(mainSide));
@ -558,7 +558,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
@Override @Override
public float getRiderYOffset() { public float getRiderYOffset() {
switch ((Sizes)getSize()) { switch ((SizePreset)getSize()) {
case NORMAL: return 0.4F; case NORMAL: return 0.4F;
case FOAL: case FOAL:
case TALL: case TALL:
@ -604,10 +604,10 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
matrices.translate(left / 10, -0.2F, -0.5F); matrices.translate(left / 10, -0.2F, -0.5F);
} }
matrices.translate(left * 0.1F, 0.45F, 0); matrices.translate(-left * 0.1F, 0.45F, 0);
if (getAttributes().heldStack.getUseAction() == UseAction.BLOCK && getAttributes().itemUseTime == 0) { if (getAttributes().heldStack.getUseAction() == UseAction.BLOCK && getAttributes().itemUseTime == 0) {
matrices.translate(left * -0.1F, -0.25F, 0); matrices.translate(left * 0.02F, -0.25F, 0);
} }
} }
@ -623,6 +623,13 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
stack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180)); stack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180));
} }
boolean crouching = attributes.isCrouching;
if (attributes.isLyingDown && !attributes.isSleeping) {
stack.translate(0, 1.35F, 0);
attributes.isCrouching = sneaking;
}
if (attributes.isHorsey) { if (attributes.isHorsey) {
if (part == BodyPart.BODY) { if (part == BodyPart.BODY) {
stack.scale(1.5F, 1, 1.5F); stack.scale(1.5F, 1, 1.5F);
@ -634,5 +641,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
} }
PonyTransformation.forSize(getSize()).transform(this, part, stack); PonyTransformation.forSize(getSize()).transform(this, part, stack);
attributes.isCrouching = crouching;
} }
} }

View file

@ -8,12 +8,12 @@ import net.minecraft.util.Hand;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.events.PonyModelPrepareCallback;
import com.minelittlepony.api.model.*; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.model.fabric.PonyModelPrepareCallback;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyData; import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.Size; import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.api.pony.meta.Sizes; import com.minelittlepony.api.pony.meta.SizePreset;
import com.minelittlepony.mson.api.model.biped.MsonPlayer; import com.minelittlepony.mson.api.model.biped.MsonPlayer;
/** /**
@ -51,7 +51,7 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
child = entity.isBaby(); child = entity.isBaby();
attributes.updateLivingState(entity, pony, mode); attributes.updateLivingState(entity, pony, mode);
PonyModelPrepareCallback.EVENT.invoker().onPonyModelPrepared(entity, this, mode); PonyModelPrepareCallback.EVENT.invoker().onPonyModelPrepared(entity, this, mode);
sneaking = attributes.isCrouching; sneaking = attributes.isCrouching && !attributes.isLyingDown;
riding = attributes.isSitting; riding = attributes.isSitting;
} }
@ -79,7 +79,7 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
@Override @Override
public Size getSize() { public Size getSize() {
return child ? Sizes.FOAL : PonyModel.super.getSize(); return child ? SizePreset.FOAL : PonyModel.super.getSize();
} }
@Override @Override
@ -93,10 +93,16 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
} }
@Override @Override
public ModelPart getArm(Arm side) { public ModelPart getForeLeg(Arm side) {
return super.getArm(side); return getArm(side);
} }
@Override
public ModelPart getHindLeg(Arm side) {
return side == Arm.LEFT ? leftLeg : rightLeg;
}
@Override
public ArmPose getArmPoseForSide(Arm side) { public ArmPose getArmPoseForSide(Arm side) {
return side == Arm.RIGHT ? rightArmPose : leftArmPose; return side == Arm.RIGHT ? rightArmPose : leftArmPose;
} }

View file

@ -6,7 +6,7 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.Util; import net.minecraft.util.Util;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.mson.api.*; import com.minelittlepony.mson.api.*;
import com.minelittlepony.mson.api.MsonModel.Factory; import com.minelittlepony.mson.api.MsonModel.Factory;
import com.minelittlepony.mson.api.model.traversal.PartSkeleton; import com.minelittlepony.mson.api.model.traversal.PartSkeleton;
@ -79,7 +79,7 @@ final class ModelKeyImpl<M extends Model> implements ModelKey<M>, LocalBlock {
} }
private ModelContext getModelContext(FileContent<?> content) { private ModelContext getModelContext(FileContent<?> content) {
if (MineLittlePony.getInstance().getConfig().horsieMode.get()) { if (PonyConfig.getInstance().horsieMode.get()) {
return content.createContext(null, null, content.getLocals().extendWith(getId(), Optional.of(this), Optional.empty()).bake()); return content.createContext(null, null, content.getLocals().extendWith(getId(), Optional.of(this), Optional.empty()).bake());
} }
return content.createContext(null, null, content.getLocals().bake()); return content.createContext(null, null, content.getLocals().bake());

View file

@ -7,6 +7,7 @@ import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.model.Models;
import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.model.armour.PonyArmourModel; import com.minelittlepony.client.model.armour.PonyArmourModel;
import com.minelittlepony.mson.api.*; import com.minelittlepony.mson.api.*;
@ -30,12 +31,12 @@ public record PlayerModelKey<T extends LivingEntity, M extends Model & PonyModel
return slimArms ? alexKey : steveKey; return slimArms ? alexKey : steveKey;
} }
public <E extends T, N extends M> ModelWrapper<E, N> create(boolean slimArms) { public <E extends T, N extends M> Models<E, N> create(boolean slimArms) {
return create(slimArms, null); return create(slimArms, null);
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
public <E extends T, N extends M> ModelWrapper<E, N> create(boolean slimArms, @Nullable Consumer<N> initializer) { public <E extends T, N extends M> Models<E, N> create(boolean slimArms, @Nullable Consumer<N> initializer) {
return new ModelWrapper(this, slimArms, initializer); return new Models(this, slimArms, initializer);
} }
} }

View file

@ -1,10 +1,9 @@
package com.minelittlepony.api.model.armour; package com.minelittlepony.client.model.armour;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.client.model.armour.PonyArmourModel;
import com.minelittlepony.mson.api.ModelKey; import com.minelittlepony.mson.api.ModelKey;
import com.minelittlepony.mson.api.Mson; import com.minelittlepony.mson.api.Mson;
@ -18,7 +17,7 @@ public interface ArmorModelRegistry {
if (id.getNamespace().equals("minecraft")) { if (id.getNamespace().equals("minecraft")) {
return Optional.empty(); return Optional.empty();
} }
return REGISTRY.computeIfAbsent(id.withPath(p -> "models/armor/" + layer.name().toLowerCase(Locale.ROOT) + "_" + p + ".json"), i -> { return REGISTRY.computeIfAbsent(id.withPath(p -> "armor/" + layer.name().toLowerCase(Locale.ROOT) + "_" + p + ".json"), i -> {
return Optional.of(Mson.getInstance().registerModel(i, PonyArmourModel::new)); return Optional.of(Mson.getInstance().registerModel(i, PonyArmourModel::new));
}).filter(key -> key.getModelData().isPresent()); }).filter(key -> key.getModelData().isPresent());
} }

View file

@ -1,4 +1,4 @@
package com.minelittlepony.api.model.armour; package com.minelittlepony.client.model.armour;
/** /**
* The layer used to render a given armour piece. * The layer used to render a given armour piece.

View file

@ -13,9 +13,6 @@ import com.google.common.base.Strings;
import com.google.common.cache.Cache; import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.model.armour.ArmourLayer;
import com.minelittlepony.api.model.armour.ArmourVariant;
import com.minelittlepony.api.model.armour.IArmourTextureResolver;
import com.minelittlepony.util.ResourceUtil; import com.minelittlepony.util.ResourceUtil;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -38,8 +35,8 @@ import java.util.concurrent.TimeUnit;
* - the "minecraft" namespace is always replaced with "minelittlepony" * - the "minecraft" namespace is always replaced with "minelittlepony"
* <p> * <p>
*/ */
public class DefaultArmourTextureResolver implements IArmourTextureResolver { public class ArmourTextureResolver {
public static final DefaultArmourTextureResolver INSTANCE = new DefaultArmourTextureResolver(); public static final ArmourTextureResolver INSTANCE = new ArmourTextureResolver();
private final Cache<String, Identifier> cache = CacheBuilder.newBuilder() private final Cache<String, Identifier> cache = CacheBuilder.newBuilder()
.expireAfterAccess(30, TimeUnit.SECONDS) .expireAfterAccess(30, TimeUnit.SECONDS)
@ -49,7 +46,6 @@ public class DefaultArmourTextureResolver implements IArmourTextureResolver {
cache.invalidateAll(); cache.invalidateAll();
} }
@Override
public Identifier getTexture(LivingEntity entity, ItemStack stack, EquipmentSlot slot, ArmourLayer layer, @Nullable String type) { public Identifier getTexture(LivingEntity entity, ItemStack stack, EquipmentSlot slot, ArmourLayer layer, @Nullable String type) {
Identifier material = stack.getItem() instanceof ArmorItem armor Identifier material = stack.getItem() instanceof ArmorItem armor
? new Identifier(armor.getMaterial().getName()) ? new Identifier(armor.getMaterial().getName())
@ -129,7 +125,6 @@ public class DefaultArmourTextureResolver implements IArmourTextureResolver {
return MinecraftClient.getInstance().getResourceManager().getResource(texture).isPresent(); return MinecraftClient.getInstance().getResourceManager().getResource(texture).isPresent();
} }
@Override
public ArmourVariant getVariant(ArmourLayer layer, Identifier resolvedTexture) { public ArmourVariant getVariant(ArmourLayer layer, Identifier resolvedTexture) {
if (resolvedTexture.getPath().endsWith("_pony.png")) { if (resolvedTexture.getPath().endsWith("_pony.png")) {
return ArmourVariant.NORMAL; return ArmourVariant.NORMAL;

View file

@ -1,7 +1,6 @@
package com.minelittlepony.api.model.armour; package com.minelittlepony.client.model.armour;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.armour.PonyArmourModel;
import com.minelittlepony.mson.api.ModelKey; import com.minelittlepony.mson.api.ModelKey;
import java.util.Optional; import java.util.Optional;

View file

@ -6,16 +6,14 @@ import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.armour.*;
import com.minelittlepony.client.model.AbstractPonyModel; import com.minelittlepony.client.model.AbstractPonyModel;
public class PonyArmourModel<T extends LivingEntity> extends AbstractPonyModel<T> implements IArmourModel<T> { public class PonyArmourModel<T extends LivingEntity> extends AbstractPonyModel<T> {
public PonyArmourModel(ModelPart tree) { public PonyArmourModel(ModelPart tree) {
super(tree); super(tree);
} }
@Override
public boolean poseModel(T entity, float limbAngle, float limbDistance, float age, float headYaw, float headPitch, public boolean poseModel(T entity, float limbAngle, float limbDistance, float age, float headYaw, float headPitch,
EquipmentSlot slot, ArmourLayer layer, EquipmentSlot slot, ArmourLayer layer,
PonyModel<T> mainModel) { PonyModel<T> mainModel) {

View file

@ -6,10 +6,11 @@ import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.model.GuardianEntityModel; import net.minecraft.client.render.entity.model.GuardianEntityModel;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.GuardianEntity; import net.minecraft.entity.mob.GuardianEntity;
import com.minelittlepony.client.model.IPonyMixinModel;
import com.minelittlepony.api.model.PonyModelMixin;
import com.minelittlepony.client.model.entity.race.SeaponyModel; import com.minelittlepony.client.model.entity.race.SeaponyModel;
public class GuardianPonyModel extends GuardianEntityModel implements IPonyMixinModel.Caster<GuardianEntity, SeaponyModel<GuardianEntity>, ModelPart> { public class GuardianPonyModel extends GuardianEntityModel implements PonyModelMixin.Caster<GuardianEntity, SeaponyModel<GuardianEntity>, ModelPart> {
private final SeaponyModel<GuardianEntity> mixin; private final SeaponyModel<GuardianEntity> mixin;
public GuardianPonyModel(ModelPart tree) { public GuardianPonyModel(ModelPart tree) {

View file

@ -78,7 +78,7 @@ public class SkeleponyModel<T extends HostileEntity> extends AlicornModel<T> {
@Override @Override
protected float getLegOutset() { protected float getLegOutset() {
if (attributes.isSleeping) return 2.6f; if (attributes.isLyingDown) return 2.6f;
if (attributes.isCrouching) return 0; if (attributes.isCrouching) return 0;
return 4; return 4;
} }

View file

@ -1,6 +1,6 @@
package com.minelittlepony.client.model.entity.race; package com.minelittlepony.client.model.entity.race;
import com.minelittlepony.api.model.IPart; import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.WingedPonyModel; import com.minelittlepony.api.model.WingedPonyModel;
import com.minelittlepony.client.model.part.PonyWings; import com.minelittlepony.client.model.part.PonyWings;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
@ -24,7 +24,7 @@ public class AlicornModel<T extends LivingEntity> extends UnicornModel<T> implem
} }
@Override @Override
public IPart getWings() { public SubModel getWings() {
return wings; return wings;
} }
} }

View file

@ -1,6 +1,6 @@
package com.minelittlepony.client.model.entity.race; package com.minelittlepony.client.model.entity.race;
import com.minelittlepony.api.model.IPart; import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.client.model.AbstractPonyModel; import com.minelittlepony.client.model.AbstractPonyModel;
import com.minelittlepony.client.model.part.*; import com.minelittlepony.client.model.part.*;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
@ -12,7 +12,7 @@ public class EarthPonyModel<T extends LivingEntity> extends AbstractPonyModel<T>
private final boolean smallArms; private final boolean smallArms;
protected IPart tail; protected SubModel tail;
protected PonySnout snout; protected PonySnout snout;
protected PonyEars ears; protected PonyEars ears;

View file

@ -1,6 +1,6 @@
package com.minelittlepony.client.model.entity.race; package com.minelittlepony.client.model.entity.race;
import com.minelittlepony.api.model.IPart; import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.WingedPonyModel; import com.minelittlepony.api.model.WingedPonyModel;
import com.minelittlepony.client.model.part.PonyWings; import com.minelittlepony.client.model.part.PonyWings;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
@ -24,7 +24,7 @@ public class PegasusModel<T extends LivingEntity> extends EarthPonyModel<T> impl
} }
@Override @Override
public IPart getWings() { public SubModel getWings() {
return wings; return wings;
} }
} }

View file

@ -1,9 +1,9 @@
package com.minelittlepony.client.model.entity.race; package com.minelittlepony.client.model.entity.race;
import com.minelittlepony.client.model.armour.PonyArmourModel;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
import com.minelittlepony.api.model.*; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.model.armour.PonyArmourModel;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
@ -65,7 +65,7 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
float flapMotion = MathHelper.cos(ticks / 10) / 5; float flapMotion = MathHelper.cos(ticks / 10) / 5;
if (attributes.isSleeping) { if (attributes.isLyingDown) {
flapMotion /= 2; flapMotion /= 2;
} }

View file

@ -1,9 +1,9 @@
package com.minelittlepony.client.model.entity.race; package com.minelittlepony.client.model.entity.race;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.model.*; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.meta.Size; import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.api.pony.meta.Sizes; import com.minelittlepony.api.pony.meta.SizePreset;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.part.UnicornHorn; import com.minelittlepony.client.model.part.UnicornHorn;
import com.minelittlepony.client.util.render.RenderList; import com.minelittlepony.client.util.render.RenderList;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
@ -57,7 +57,7 @@ public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> impl
@Override @Override
public boolean isCasting() { public boolean isCasting() {
return MineLittlePony.getInstance().getConfig().tpsmagic.get() return PonyConfig.getInstance().tpsmagic.get()
&& (rightArmPose != ArmPose.EMPTY || leftArmPose != ArmPose.EMPTY); && (rightArmPose != ArmPose.EMPTY || leftArmPose != ArmPose.EMPTY);
} }
@ -70,7 +70,7 @@ public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> impl
@Override @Override
public ModelPart getArm(Arm side) { public ModelPart getArm(Arm side) {
if (hasMagic() && getArmPoseForSide(side) != ArmPose.EMPTY && MineLittlePony.getInstance().getConfig().tpsmagic.get()) { if (hasMagic() && getArmPoseForSide(side) != ArmPose.EMPTY && PonyConfig.getInstance().tpsmagic.get()) {
return side == Arm.LEFT ? unicornArmLeft : unicornArmRight; return side == Arm.LEFT ? unicornArmLeft : unicornArmRight;
} }
return super.getArm(side); return super.getArm(side);
@ -80,7 +80,7 @@ public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> impl
protected void positionheldItem(Arm arm, MatrixStack matrices) { protected void positionheldItem(Arm arm, MatrixStack matrices) {
super.positionheldItem(arm, matrices); super.positionheldItem(arm, matrices);
if (!MineLittlePony.getInstance().getConfig().tpsmagic.get() || !hasMagic()) { if (!PonyConfig.getInstance().tpsmagic.get() || !hasMagic()) {
return; return;
} }
@ -101,9 +101,9 @@ public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> impl
float x = 0.3F; float x = 0.3F;
float z = -0.4F; float z = -0.4F;
if (size == Sizes.TALL || size == Sizes.YEARLING) { if (size == SizePreset.TALL || size == SizePreset.YEARLING) {
z += 0.05F; z += 0.05F;
} else if (size == Sizes.FOAL) { } else if (size == SizePreset.FOAL) {
x -= 0.1F; x -= 0.1F;
z -= 0.1F; z -= 0.1F;
} }

View file

@ -23,10 +23,9 @@ public class DeerAntlers extends WearableGear {
dayChecked = true; dayChecked = true;
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
dayResult = cal.get(Calendar.MONTH) == Calendar.DECEMBER dayResult = cal.get(Calendar.MONTH) == Calendar.DECEMBER
&& cal.get(Calendar.DAY_OF_MONTH) == 25; && Math.abs(cal.get(Calendar.DAY_OF_MONTH) - 25) < 2;
} }
return dayResult; return dayResult;
} }

View file

@ -13,13 +13,9 @@ import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
public class SaddleBags extends WearableGear { public class SaddleBags extends WearableGear {
public static final Identifier TEXTURE = new Identifier("minelittlepony", "textures/models/saddlebags.png");
private final ModelPart leftBag; private final ModelPart leftBag;
private final ModelPart rightBag; private final ModelPart rightBag;
@ -63,7 +59,7 @@ public class SaddleBags extends WearableGear {
strap.visible = wearable == Wearable.SADDLE_BAGS_BOTH; strap.visible = wearable == Wearable.SADDLE_BAGS_BOTH;
dropAmount = hangLow ? 0.15F : 0; dropAmount = hangLow ? 0.15F : 0;
dropAmount = model.getAttributes().metadata.getInterpolator(interpolatorId).interpolate("dropAmount", dropAmount, 3); dropAmount = model.getAttributes().getMainInterpolator().interpolate("dropAmount", dropAmount, 3);
} }
@Override @Override

View file

@ -5,11 +5,11 @@ import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.IPart; import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.common.util.animation.Interpolator; import com.minelittlepony.common.util.animation.Interpolator;
public class LionTail implements IPart { public class LionTail implements SubModel {
private ModelPart tail; private ModelPart tail;

View file

@ -5,12 +5,13 @@ import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.IPart; import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.mson.api.*; import com.minelittlepony.mson.api.*;
import com.minelittlepony.mson.api.model.PartBuilder; import com.minelittlepony.mson.api.model.PartBuilder;
public class PonyEars implements IPart, MsonModel { public class PonyEars implements SubModel, MsonModel {
private final ModelPart right; private final ModelPart right;
private final ModelPart left; private final ModelPart left;
@ -29,6 +30,12 @@ public class PonyEars implements IPart, MsonModel {
@Override @Override
public void setPartAngles(ModelAttributes attributes, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) { public void setPartAngles(ModelAttributes attributes, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) {
right.resetTransform(); right.resetTransform();
left.resetTransform();
if (attributes.metadata.race() == Race.CHANGEDLING
|| attributes.metadata.race() == Race.CHANGELING) {
return;
}
limbSpeed = MathHelper.clamp(limbSpeed, 0, 1); limbSpeed = MathHelper.clamp(limbSpeed, 0, 1);

View file

@ -4,14 +4,14 @@ import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import com.minelittlepony.api.model.IPart; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.pony.meta.Gender; import com.minelittlepony.api.pony.meta.Gender;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.mson.api.*; import com.minelittlepony.mson.api.*;
import com.minelittlepony.mson.api.model.PartBuilder; import com.minelittlepony.mson.api.model.PartBuilder;
public class PonySnout implements IPart, MsonModel { public class PonySnout implements SubModel, MsonModel {
private final ModelPart mare; private final ModelPart mare;
private final ModelPart stallion; private final ModelPart stallion;
@ -41,7 +41,7 @@ public class PonySnout implements IPart, MsonModel {
public void setVisible(boolean visible, ModelAttributes attributes) { public void setVisible(boolean visible, ModelAttributes attributes) {
visible &= !attributes.isHorsey visible &= !attributes.isHorsey
&& !attributes.metadata.race().isHuman() && !attributes.metadata.race().isHuman()
&& MineLittlePony.getInstance().getConfig().snuzzles.get(); && PonyConfig.getInstance().snuzzles.get();
Gender gender = attributes.metadata.gender(); Gender gender = attributes.metadata.gender();
mare.visible = (visible && gender.isMare()); mare.visible = (visible && gender.isMare());

View file

@ -14,7 +14,7 @@ import com.minelittlepony.util.MathUtil;
import java.util.List; import java.util.List;
import java.util.stream.IntStream; import java.util.stream.IntStream;
public class PonyTail implements IPart, MsonModel { public class PonyTail implements SubModel, MsonModel {
private static final float TAIL_Z = 14; private static final float TAIL_Z = 14;
private static final float TAIL_RIDING_Y = 3; private static final float TAIL_RIDING_Y = 3;
private static final float TAIL_RIDING_Z = 13; private static final float TAIL_RIDING_Z = 13;

View file

@ -12,7 +12,7 @@ import com.minelittlepony.mson.api.ModelView;
import com.minelittlepony.mson.api.MsonModel; import com.minelittlepony.mson.api.MsonModel;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
public class PonyWings<T extends Model & WingedPonyModel<?>> implements IPart, MsonModel { public class PonyWings<T extends Model & WingedPonyModel<?>> implements SubModel, MsonModel {
protected T pegasus; protected T pegasus;

View file

@ -1,6 +1,6 @@
package com.minelittlepony.client.model.part; package com.minelittlepony.client.model.part;
import com.minelittlepony.api.model.IPart; import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.mson.api.MsonModel; import com.minelittlepony.mson.api.MsonModel;
@ -9,7 +9,7 @@ import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
public class SeaponyTail implements IPart, MsonModel { public class SeaponyTail implements SubModel, MsonModel {
private final ModelPart tailBase; private final ModelPart tailBase;
private final ModelPart tailTip; private final ModelPart tailTip;
@ -23,7 +23,7 @@ public class SeaponyTail implements IPart, MsonModel {
@Override @Override
public void setPartAngles(ModelAttributes attributes, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) { public void setPartAngles(ModelAttributes attributes, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) {
float rotation = attributes.isSleeping ? 0 : MathHelper.sin(animationProgress * 0.536f) / 4; float rotation = attributes.isLyingDown ? 0 : MathHelper.sin(animationProgress * 0.536f) / 4;
tailBase.pitch = MathHelper.HALF_PI + rotation; tailBase.pitch = MathHelper.HALF_PI + rotation;
tailTip.pitch = rotation; tailTip.pitch = rotation;

View file

@ -7,12 +7,12 @@ import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider.Immediate; import net.minecraft.client.render.VertexConsumerProvider.Immediate;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import com.minelittlepony.api.model.IPart; import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.client.render.MagicGlow; import com.minelittlepony.client.render.MagicGlow;
import com.minelittlepony.common.util.Color; import com.minelittlepony.common.util.Color;
public class UnicornHorn implements IPart { public class UnicornHorn implements SubModel {
private final ModelPart horn; private final ModelPart horn;
private final ModelPart glow; private final ModelPart glow;

View file

@ -0,0 +1,33 @@
package com.minelittlepony.client.render;
import net.minecraft.client.render.*;
import net.minecraft.client.render.RenderLayer.MultiPhaseParameters;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import java.util.function.BiFunction;
public class ArmorRenderLayers extends RenderPhase {
private ArmorRenderLayers() {
super(null, null, null);
}
private static final BiFunction<Identifier, Boolean, RenderLayer> ARMOR_TRANSLUCENT_NO_CULL = Util.memoize((texture, decal) -> {
return RenderLayer.of(decal ? "armor_decal_translucent_no_cull" : "armor_translucent_no_cull",
VertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, VertexFormat.DrawMode.QUADS, 256, true, false, MultiPhaseParameters.builder()
.program(ARMOR_CUTOUT_NO_CULL_PROGRAM)
.texture(new RenderPhase.Texture(texture, false, false))
.transparency(TRANSLUCENT_TRANSPARENCY)
.cull(DISABLE_CULLING)
.lightmap(ENABLE_LIGHTMAP)
.overlay(ENABLE_OVERLAY_COLOR)
.layering(VIEW_OFFSET_Z_LAYERING)
.depthTest(decal ? EQUAL_DEPTH_TEST : LEQUAL_DEPTH_TEST)
.build(true)
);
});
public static RenderLayer getArmorTranslucentNoCull(Identifier texture, boolean decal) {
return ARMOR_TRANSLUCENT_NO_CULL.apply(texture, decal);
}
}

View file

@ -17,7 +17,6 @@ import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.PonyBounds; import com.minelittlepony.client.PonyBounds;
public final class DebugBoundingBoxRenderer { public final class DebugBoundingBoxRenderer {
public static <T extends LivingEntity> void render(Pony pony, EntityRenderer<T> renderer, T entity, MatrixStack stack, VertexConsumerProvider renderContext, float tickDelta) { public static <T extends LivingEntity> void render(Pony pony, EntityRenderer<T> renderer, T entity, MatrixStack stack, VertexConsumerProvider renderContext, float tickDelta) {
if (RenderPass.getCurrent() != RenderPass.WORLD) { if (RenderPass.getCurrent() != RenderPass.WORLD) {

View file

@ -1,17 +1,18 @@
package com.minelittlepony.client.render; package com.minelittlepony.client.render;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.events.Channel;
import com.minelittlepony.api.events.PonyDataCallback;
import com.minelittlepony.api.model.*; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.network.fabric.Channel;
import com.minelittlepony.api.pony.network.fabric.PonyDataCallback;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelWrapper;
import com.minelittlepony.client.transform.PonyPosture; import com.minelittlepony.client.transform.PonyPosture;
import com.minelittlepony.mson.api.ModelKey; import com.minelittlepony.mson.api.ModelKey;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@ -22,42 +23,42 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import org.jetbrains.annotations.Nullable;
public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> { public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> {
private ModelWrapper<T, M> playerModel; private Models<T, M> models;
@Nullable
private Function<T, Models<T, M>> modelsLookup;
private final IPonyRenderContext<T, M> renderer; private final PonyRenderContext<T, M> context;
private final Transformer<T> transformer;
private final FrustrumCheck<T> frustrum = new FrustrumCheck<>(this); private final FrustrumCheck<T> frustrum;
public static void disableModelRenderProfile() { public static void disableModelRenderProfile() {
RenderSystem.disableBlend(); RenderSystem.disableBlend();
} }
public EquineRenderManager(IPonyRenderContext<T, M> renderer) { public EquineRenderManager(PonyRenderContext<T, M> context, Transformer<T> transformer, Models<T, M> models) {
this.renderer = renderer; this.context = context;
} this.transformer = transformer;
this.models = models;
public IPonyRenderContext<T, M> getContext() { frustrum = new FrustrumCheck<>(context);
return renderer; context.setModel(models.body());
}
public ModelWrapper<T, M> getModelWrapper() {
return playerModel;
}
public M getModel() {
return playerModel.body();
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
public ModelWrapper<T, M> setModel(ModelKey<? super M> key) { public EquineRenderManager(PonyRenderContext<T, M> context, Transformer<T> transformer, ModelKey<? super M> key) {
return setModel(new ModelWrapper(key)); this(context, transformer, new Models(key));
} }
public ModelWrapper<T, M> setModel(ModelWrapper<T, M> wrapper) { public void setModelsLookup(@Nullable Function<T, Models<T, M>> modelsLookup) {
playerModel = wrapper; this.modelsLookup = modelsLookup;
return wrapper; }
public Models<T, M> getModels() {
return models;
} }
public Frustum getFrustrum(T entity, Frustum vanilla) { public Frustum getFrustrum(T entity, Frustum vanilla) {
@ -65,13 +66,67 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
return FrustrumCheck.ALWAYS_VISIBLE; return FrustrumCheck.ALWAYS_VISIBLE;
} }
if (entity.isSleeping() || !MineLittlePony.getInstance().getConfig().frustrum.get()) { if (entity.isSleeping() || !PonyConfig.getInstance().frustrum.get()) {
return vanilla; return vanilla;
} }
return frustrum.withCamera(entity, vanilla); return frustrum.withCamera(entity, vanilla);
} }
public float getRenderYaw(T entity, float rotationYaw, float partialTicks) { public void preRender(T entity, ModelAttributes.Mode mode) {
Pony pony = context.getEntityPony(entity);
if (modelsLookup != null) {
models = modelsLookup.apply(entity);
context.setModel(models.body());
}
models.applyMetadata(pony.metadata());
models.body().updateLivingState(entity, pony, mode);
if (entity instanceof PlayerEntity player && entity instanceof RegistrationHandler handler) {
handler.getSyncedPony().synchronize(player, pony);
}
}
public void setupTransforms(T entity, MatrixStack stack, float ageInTicks, float rotationYaw, float tickDelta) {
float s = getScaleFactor();
stack.scale(s, s, s);
if (entity.hasVehicle() && entity.getVehicle() instanceof LivingEntity livingVehicles) {
PonyRenderContext<LivingEntity, ?> renderer = MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(livingVehicles);
if (renderer != null) {
// negate vanilla translations so the rider begins at the ridees feet.
stack.translate(0, -livingVehicles.getHeight(), 0);
Pony pony = context.getEntityPony(entity);
if (!pony.race().isHuman()) {
renderer.getInternalRenderer().translateRider(livingVehicles, renderer.getEntityPony(livingVehicles), entity, pony, stack, tickDelta);
}
}
}
if (entity instanceof PlayerEntity) {
if (getModels().body().getAttributes().isSitting) {
stack.translate(0, 0.125D, 0);
}
}
rotationYaw = getMountedYaw(entity, rotationYaw, tickDelta);
transformer.setupTransforms(entity, stack, ageInTicks, rotationYaw, tickDelta);
PonyPosture.of(getModels().body().getAttributes()).apply(entity, getModels().body(), stack, rotationYaw, tickDelta, 1);
}
private void translateRider(T entity, Pony pony, LivingEntity passenger, Pony passengerPony, MatrixStack stack, float tickDelta) {
if (!passengerPony.race().isHuman()) {
float yaw = MathUtil.interpolateDegress((float)entity.prevY, (float)entity.getY(), tickDelta);
models.applyMetadata(pony.metadata());
models.body().transform(BodyPart.BACK, stack);
PonyPosture.of(models.body().getAttributes()).apply(entity, getModels().body(), stack, yaw, tickDelta, -1);
}
}
private float getMountedYaw(T entity, float rotationYaw, float partialTicks) {
if (entity.hasVehicle()) { if (entity.hasVehicle()) {
Entity mount = entity.getVehicle(); Entity mount = entity.getVehicle();
if (mount instanceof LivingEntity) { if (mount instanceof LivingEntity) {
@ -82,72 +137,20 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
return rotationYaw; return rotationYaw;
} }
public void preRenderCallback(T entity, MatrixStack stack, float ticks) {
updateModel(entity, ModelAttributes.Mode.THIRD_PERSON);
float s = getScaleFactor();
stack.scale(s, s, s);
translateRider(entity, stack, ticks);
}
private void translateRider(T entity, MatrixStack stack, float ticks) {
if (entity.hasVehicle() && entity.getVehicle() instanceof LivingEntity) {
LivingEntity ridingEntity = (LivingEntity) entity.getVehicle();
IPonyRenderContext<LivingEntity, ?> renderer = MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(ridingEntity);
if (renderer != null) {
// negate vanilla translations so the rider begins at the ridees feet.
stack.translate(0, -ridingEntity.getHeight(), 0);
Pony riderPony = renderer.getEntityPony(ridingEntity);
renderer.translateRider(ridingEntity, riderPony, entity, renderer.getEntityPony(entity), stack, ticks);
}
}
}
public void setupTransforms(T entity, MatrixStack stack, float yaw, float tickDelta) {
PonyPosture.of(getModel().getAttributes()).apply(entity, getModel(), stack, yaw, tickDelta, 1);
}
public void applyPostureRiding(T entity, MatrixStack stack, float yaw, float tickDelta) {
PonyPosture.of(getModel().getAttributes()).apply(entity, getModel(), stack, yaw, tickDelta, -1);
}
public Pony updateModel(T entity, ModelAttributes.Mode mode) {
Pony pony = renderer.getEntityPony(entity);
playerModel.applyMetadata(pony.metadata());
if (pony.hasMetadata() && entity instanceof RegistrationHandler && ((RegistrationHandler)entity).shouldUpdateRegistration(pony)) {
entity.calculateDimensions();
PlayerEntity clientPlayer = MinecraftClient.getInstance().player;
if (clientPlayer != null) {
if (Objects.equals(entity, clientPlayer) || Objects.equals(((PlayerEntity)entity).getGameProfile(), clientPlayer.getGameProfile())) {
Channel.broadcastPonyData(pony.metadata());
}
}
PonyDataCallback.EVENT.invoker().onPonyDataAvailable((PlayerEntity)entity, pony.metadata(), EnvType.CLIENT);
}
getModel().updateLivingState(entity, pony, mode);
return pony;
}
public float getScaleFactor() { public float getScaleFactor() {
return getModel().getSize().scaleFactor(); return getModels().body().getSize().scaleFactor();
}
public float getShadowSize() {
return getModels().body().getSize().shadowSize();
} }
public double getNamePlateYOffset(T entity) { public double getNamePlateYOffset(T entity) {
// We start by negating the height calculation done by mahjong. // We start by negating the height calculation done by mahjong.
float y = -(entity.getHeight() + 0.5F); float y = -(entity.getHeight() + 0.5F);
// Then we add our own offsets. // Then we add our own offsets.
y += getModel().getAttributes().visualHeight * getScaleFactor() + 0.25F; y += getModels().body().getAttributes().visualHeight * getScaleFactor() + 0.25F;
if (entity.isSneaking()) { if (entity.isSneaking()) {
y -= 0.25F; y -= 0.25F;
@ -164,7 +167,48 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
return y; return y;
} }
public interface Transformer<T extends LivingEntity> {
void setupTransforms(T entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks);
}
public interface RegistrationHandler { public interface RegistrationHandler {
boolean shouldUpdateRegistration(Pony pony); SyncedPony getSyncedPony();
}
public interface ModelHolder<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> {
void setModel(M model);
}
public static class SyncedPony {
@Nullable
private Pony lastRenderedPony;
@Nullable
private Pony lastTransmittedPony;
public void synchronize(PlayerEntity player, Pony pony) {
boolean changed = pony.compareTo(lastRenderedPony) != 0;
if (changed) {
lastRenderedPony = pony;
player.calculateDimensions();
}
if (!(player instanceof PreviewModel)) {
@Nullable
PlayerEntity clientPlayer = MinecraftClient.getInstance().player;
if (Channel.isRegistered() && pony.compareTo(lastTransmittedPony) != 0) {
if (clientPlayer != null && (Objects.equals(player, clientPlayer) || Objects.equals(player.getGameProfile(), clientPlayer.getGameProfile()))) {
if (Channel.broadcastPonyData(pony.metadata())) {
lastTransmittedPony = pony;
}
}
}
if (changed) {
PonyDataCallback.EVENT.invoker().onPonyDataAvailable(player, pony.metadata(), EnvType.CLIENT);
}
}
}
} }
} }

View file

@ -19,11 +19,11 @@ public class FrustrumCheck<T extends LivingEntity> extends Frustum {
private Frustum vanilla; private Frustum vanilla;
private final EquineRenderManager<T, ?> renderer; private final PonyRenderContext<T, ?> context;
public FrustrumCheck(EquineRenderManager<T, ?> render) { public FrustrumCheck(PonyRenderContext<T, ?> context) {
super(new Matrix4f(), new Matrix4f()); super(new Matrix4f(), new Matrix4f());
renderer = render; this.context = context;
} }
public Frustum withCamera(T entity, Frustum vanillaFrustrum) { public Frustum withCamera(T entity, Frustum vanillaFrustrum) {
@ -34,7 +34,7 @@ public class FrustrumCheck<T extends LivingEntity> extends Frustum {
@Override @Override
public boolean isVisible(Box bounds) { public boolean isVisible(Box bounds) {
return vanilla.isVisible(PonyBounds.getBoundingBox(renderer.getContext().getEntityPony(entity), entity)); return vanilla.isVisible(PonyBounds.getBoundingBox(context.getEntityPony(entity), entity));
} }
@Override @Override

View file

@ -1,34 +0,0 @@
package com.minelittlepony.client.render;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.gear.Gear;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.util.MathUtil;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
public interface IPonyRenderContext<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends Gear.Context<T, M> {
Pony getEntityPony(T entity);
EquineRenderManager<T, M> getInternalRenderer();
/**
* Called by riders to have their transportation adjust their position.
*/
default void translateRider(T entity, Pony entityPony, LivingEntity passenger, Pony passengerPony, MatrixStack stack, float ticks) {
if (!passengerPony.race().isHuman()) {
float yaw = MathUtil.interpolateDegress((float)entity.prevY, (float)entity.getY(), ticks);
getInternalRenderer().getModelWrapper().applyMetadata(entityPony.metadata());
M model = getInternalRenderer().getModelWrapper().body();
model.transform(BodyPart.BACK, stack);
getInternalRenderer().applyPostureRiding(entity, stack, yaw, ticks);
}
}
}

View file

@ -1,7 +1,7 @@
package com.minelittlepony.client.render; package com.minelittlepony.client.render;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.util.render.RenderLayerUtil; import com.minelittlepony.client.util.render.RenderLayerUtil;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -11,11 +11,9 @@ import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.json.ModelTransformationMode; import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.CrossbowItem; import net.minecraft.item.CrossbowItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.screen.PlayerScreenHandler; import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.Identifier;
import net.minecraft.util.UseAction; import net.minecraft.util.UseAction;
import net.minecraft.util.math.RotationAxis; import net.minecraft.util.math.RotationAxis;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -24,11 +22,10 @@ public class LevitatingItemRenderer {
private VertexConsumerProvider getProvider(Pony pony, VertexConsumerProvider renderContext) { private VertexConsumerProvider getProvider(Pony pony, VertexConsumerProvider renderContext) {
final int color = pony.metadata().glowColor(); final int color = pony.metadata().glowColor();
return layer -> { return layer -> {
Identifier texture = RenderLayerUtil.getTexture(layer).orElse(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE); if (layer.getVertexFormat() != VertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL) {
if (texture == ItemRenderer.ENTITY_ENCHANTMENT_GLINT || texture == ItemRenderer.ITEM_ENCHANTMENT_GLINT) {
return renderContext.getBuffer(layer); return renderContext.getBuffer(layer);
} }
return renderContext.getBuffer(MagicGlow.getColoured(texture, color)); return renderContext.getBuffer(MagicGlow.getColoured(RenderLayerUtil.getTexture(layer).orElse(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE), color));
}; };
} }
@ -37,13 +34,14 @@ public class LevitatingItemRenderer {
*/ */
public void renderItem(ItemRenderer itemRenderer, @Nullable LivingEntity entity, ItemStack stack, ModelTransformationMode mode, boolean left, MatrixStack matrix, VertexConsumerProvider renderContext, @Nullable World world, int lightUv, int posLong) { public void renderItem(ItemRenderer itemRenderer, @Nullable LivingEntity entity, ItemStack stack, ModelTransformationMode mode, boolean left, MatrixStack matrix, VertexConsumerProvider renderContext, @Nullable World world, int lightUv, int posLong) {
if (entity instanceof PlayerEntity && (mode.isFirstPerson() || mode == ModelTransformationMode.THIRD_PERSON_LEFT_HAND || mode == ModelTransformationMode.THIRD_PERSON_RIGHT_HAND)) { if (mode.isFirstPerson()
|| mode == ModelTransformationMode.THIRD_PERSON_LEFT_HAND
Pony pony = Pony.getManager().getPony((PlayerEntity)entity); || mode == ModelTransformationMode.THIRD_PERSON_RIGHT_HAND
) {
Pony.getManager().getPony(entity).ifPresentOrElse(pony -> {
matrix.push(); matrix.push();
boolean doMagic = MineLittlePony.getInstance().getConfig().fpsmagic.get() && pony.hasMagic(); boolean doMagic = PonyConfig.getInstance().fpsmagic.get() && pony.hasMagic();
if (doMagic && mode.isFirstPerson()) { if (doMagic && mode.isFirstPerson()) {
setupPerspective(itemRenderer, entity, stack, left, matrix); setupPerspective(itemRenderer, entity, stack, left, matrix);
@ -63,6 +61,9 @@ public class LevitatingItemRenderer {
} }
matrix.pop(); matrix.pop();
}, () -> {
itemRenderer.renderItem(entity, stack, mode, left, matrix, renderContext, world, lightUv, OverlayTexture.DEFAULT_UV, posLong);
});
} else { } else {
itemRenderer.renderItem(entity, stack, mode, left, matrix, renderContext, world, lightUv, OverlayTexture.DEFAULT_UV, posLong); itemRenderer.renderItem(entity, stack, mode, left, matrix, renderContext, world, lightUv, OverlayTexture.DEFAULT_UV, posLong);
} }

View file

@ -16,8 +16,8 @@ import java.util.function.BiFunction;
import java.util.function.Supplier; import java.util.function.Supplier;
public abstract class MagicGlow extends RenderPhase { public abstract class MagicGlow extends RenderPhase {
private MagicGlow(String name, Runnable beginAction, Runnable endAction) { private MagicGlow() {
super(name, beginAction, endAction); super(null, null, null);
} }
private static final Supplier<RenderLayer> MAGIC = Suppliers.memoize(() -> { private static final Supplier<RenderLayer> MAGIC = Suppliers.memoize(() -> {
@ -54,7 +54,6 @@ public abstract class MagicGlow extends RenderPhase {
} }
private static class Colored extends Texture { private static class Colored extends Texture {
private final float red; private final float red;
private final float green; private final float green;
private final float blue; private final float blue;

View file

@ -1,5 +1,6 @@
package com.minelittlepony.client.render; package com.minelittlepony.client.render;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.render.entity.*; import com.minelittlepony.client.render.entity.*;
import com.minelittlepony.client.render.entity.npc.*; import com.minelittlepony.client.render.entity.npc.*;
@ -40,7 +41,7 @@ public final class MobRenderers {
pony.switchRenderer(state, EntityType.PIGLIN, PonyPiglinRenderer::piglin); pony.switchRenderer(state, EntityType.PIGLIN, PonyPiglinRenderer::piglin);
pony.switchRenderer(state, EntityType.PIGLIN_BRUTE, PonyPiglinRenderer::brute); pony.switchRenderer(state, EntityType.PIGLIN_BRUTE, PonyPiglinRenderer::brute);
pony.switchRenderer(state, EntityType.ZOMBIFIED_PIGLIN, PonyPiglinRenderer::zombified); pony.switchRenderer(state, EntityType.ZOMBIFIED_PIGLIN, PonyPiglinRenderer::zombified);
if (!MineLittlePony.getInstance().getConfig().noFun.get()) { if (!PonyConfig.getInstance().noFun.get()) {
pony.switchRenderer(state, EntityType.PIG, PonyPigRenderer::new); pony.switchRenderer(state, EntityType.PIG, PonyPigRenderer::new);
} }
}); });
@ -78,7 +79,7 @@ public final class MobRenderers {
} }
public Setting<Boolean> option() { public Setting<Boolean> option() {
return MineLittlePony.getInstance().getConfig().getCategory("entities").<Boolean>get(name); return PonyConfig.getInstance().getCategory("entities").<Boolean>get(name);
} }
public boolean set(boolean value) { public boolean set(boolean value) {

View file

@ -0,0 +1,17 @@
package com.minelittlepony.client.render;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.gear.Gear;
import com.minelittlepony.api.pony.Pony;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.entity.LivingEntity;
public interface PonyRenderContext<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends Gear.Context<T, M> {
Pony getEntityPony(T entity);
EquineRenderManager<T, M> getInternalRenderer();
void setModel(M model);
}

View file

@ -3,11 +3,9 @@ package com.minelittlepony.client.render;
import java.util.function.Function; import java.util.function.Function;
import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.*;
import com.minelittlepony.api.pony.PonyPosture;
import com.minelittlepony.client.mixin.MixinEntityRenderers; import com.minelittlepony.client.mixin.MixinEntityRenderers;
import com.minelittlepony.client.render.entity.PlayerPonyRenderer; import com.minelittlepony.client.render.entity.*;
import com.minelittlepony.client.render.entity.AquaticPlayerPonyRenderer;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -48,16 +46,25 @@ public class PonyRenderDispatcher {
player -> { player -> {
return !Pony.getManager().getPony(player).race().isHuman() return !Pony.getManager().getPony(player).race().isHuman()
&& PonyPosture.hasSeaponyForm(player) && PonyPosture.hasSeaponyForm(player)
&& player.method_52814().model() == armShape; && player.getSkinTextures().model() == armShape;
}, },
context -> new AquaticPlayerPonyRenderer(context, armShape == SkinTextures.Model.SLIM) context -> new AquaticPlayerPonyRenderer(context, armShape == SkinTextures.Model.SLIM)
); );
Mson.getInstance().getEntityRendererRegistry().registerPlayerRenderer(
new Identifier("minelittlepony", "nirik/" + armShape.getName()),
player -> {
return !Pony.getManager().getPony(player).race().isHuman()
&& PonyPosture.hasNirikForm(player)
&& player.getSkinTextures().model() == armShape;
},
context -> new FormChangingPlayerPonyRenderer(context, armShape == SkinTextures.Model.SLIM, DefaultPonySkinHelper.NIRIK_SKIN_TYPE_ID, PonyPosture::isNirikModifier)
);
Mson.getInstance().getEntityRendererRegistry().registerPlayerRenderer( Mson.getInstance().getEntityRendererRegistry().registerPlayerRenderer(
new Identifier("minelittlepony", "land/" + armShape.getName()), new Identifier("minelittlepony", "land/" + armShape.getName()),
player -> { player -> {
return !Pony.getManager().getPony(player).race().isHuman() return !Pony.getManager().getPony(player).race().isHuman()
&& !PonyPosture.hasSeaponyForm(player) && !PonyPosture.hasSeaponyForm(player) && !PonyPosture.hasNirikForm(player)
&& player.method_52814().model() == armShape; && player.getSkinTextures().model() == armShape;
}, },
context -> new PlayerPonyRenderer(context, armShape == SkinTextures.Model.SLIM) context -> new PlayerPonyRenderer(context, armShape == SkinTextures.Model.SLIM)
); );
@ -83,15 +90,15 @@ public class PonyRenderDispatcher {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Nullable @Nullable
public <T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> IPonyRenderContext<T, M> getPonyRenderer(@Nullable T entity) { public <T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> PonyRenderContext<T, M> getPonyRenderer(@Nullable T entity) {
if (entity == null) { if (entity == null) {
return null; return null;
} }
EntityRenderer<?> renderer = MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity); EntityRenderer<?> renderer = MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity);
if (renderer instanceof IPonyRenderContext) { if (renderer instanceof PonyRenderContext) {
return (IPonyRenderContext<T, M>) renderer; return (PonyRenderContext<T, M>) renderer;
} }
return null; return null;

View file

@ -3,8 +3,8 @@ package com.minelittlepony.client.render.blockentity.skull;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.config.PonyLevel; import com.minelittlepony.api.config.PonyLevel;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.SkinsProxy;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.SkinsProxy;
import com.minelittlepony.client.model.*; import com.minelittlepony.client.model.*;
import com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer.ISkull; import com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer.ISkull;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
@ -45,7 +45,7 @@ public class PlayerPonySkull implements ISkull {
return skin; return skin;
} }
return DefaultSkinHelper.getTexture(profile).texture(); return DefaultSkinHelper.getSkinTextures(profile).texture();
} }
return DefaultSkinHelper.getTexture(); return DefaultSkinHelper.getTexture();

View file

@ -3,7 +3,6 @@ package com.minelittlepony.client.render.blockentity.skull;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.render.MobRenderers; import com.minelittlepony.client.render.MobRenderers;
import com.minelittlepony.client.render.entity.SkeleponyRenderer; import com.minelittlepony.client.render.entity.SkeleponyRenderer;
@ -50,7 +49,7 @@ public class PonySkullRenderer {
ISkull skull = SKULLS.get(skullType); ISkull skull = SKULLS.get(skullType);
if (skull == null || !skull.canRender(MineLittlePony.getInstance().getConfig())) { if (skull == null || !skull.canRender(PonyConfig.getInstance())) {
return null; return null;
} }
@ -64,7 +63,7 @@ public class PonySkullRenderer {
MatrixStack stack, VertexConsumerProvider renderContext, RenderLayer layer, MatrixStack stack, VertexConsumerProvider renderContext, RenderLayer layer,
int lightUv) { int lightUv) {
if (selectedSkull == null || !selectedSkull.canRender(MineLittlePony.getInstance().getConfig())) { if (selectedSkull == null || !selectedSkull.canRender(PonyConfig.getInstance())) {
return false; return false;
} }

View file

@ -1,11 +1,12 @@
package com.minelittlepony.client.render.entity; package com.minelittlepony.client.render.entity;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.model.*; import com.minelittlepony.client.model.*;
import com.minelittlepony.client.render.DebugBoundingBoxRenderer; import com.minelittlepony.client.render.DebugBoundingBoxRenderer;
import com.minelittlepony.client.render.IPonyRenderContext; import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.EquineRenderManager; import com.minelittlepony.client.render.EquineRenderManager;
import com.minelittlepony.client.render.entity.feature.*; import com.minelittlepony.client.render.entity.feature.*;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier; import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
@ -27,9 +28,9 @@ import net.minecraft.entity.mob.MobEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public abstract class AbstractPonyRenderer<T extends MobEntity, M extends EntityModel<T> & PonyModel<T> & ModelWithArms> extends MobEntityRenderer<T, M> implements IPonyRenderContext<T, M> { public abstract class AbstractPonyRenderer<T extends MobEntity, M extends EntityModel<T> & PonyModel<T> & ModelWithArms> extends MobEntityRenderer<T, M> implements PonyRenderContext<T, M> {
protected final EquineRenderManager<T, M> manager = new EquineRenderManager<>(this); protected final EquineRenderManager<T, M> manager;
private final Map<Wearable, Identifier> wearableTextures = new EnumMap<>(Wearable.class); private final Map<Wearable, Identifier> wearableTextures = new EnumMap<>(Wearable.class);
@ -39,7 +40,7 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
public AbstractPonyRenderer(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<T> texture, float scale) { public AbstractPonyRenderer(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<T> texture, float scale) {
super(context, null, 0.5F); super(context, null, 0.5F);
this.model = manager.setModel(key).body(); this.manager = new EquineRenderManager<>(this, super::setupTransforms, key);
this.texture = texture; this.texture = texture;
this.scale = scale; this.scale = scale;
addFeatures(context); addFeatures(context);
@ -64,24 +65,17 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
@Override @Override
public void render(T entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) { public void render(T entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
manager.preRender(entity, ModelAttributes.Mode.THIRD_PERSON);
if (manager.getModels().body() instanceof BipedEntityModel model) {
model.setVisible(true);
}
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv); super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
DebugBoundingBoxRenderer.render(getEntityPony(entity), this, entity, stack, renderContext, tickDelta); DebugBoundingBoxRenderer.render(getEntityPony(entity), this, entity, stack, renderContext, tickDelta);
} }
@Override @Override
protected void setupTransforms(T entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) { protected void setupTransforms(T entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) {
manager.preRenderCallback(entity, stack, partialTicks); manager.setupTransforms(entity, stack, ageInTicks, rotationYaw, partialTicks);
if (getModel() instanceof PlayerEntityModel) {
((PlayerEntityModel<?>)getModel()).setVisible(true);
}
if (getModel().getAttributes().isSitting) {
stack.translate(0, 0.125D, 0);
}
rotationYaw = manager.getRenderYaw(entity, rotationYaw, partialTicks);
super.setupTransforms(entity, stack, ageInTicks, rotationYaw, partialTicks);
manager.setupTransforms(entity, stack, rotationYaw, partialTicks);
} }
@Override @Override
@ -91,7 +85,7 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
@Override @Override
public void scale(T entity, MatrixStack stack, float tickDelta) { public void scale(T entity, MatrixStack stack, float tickDelta) {
shadowRadius = manager.getModel().getSize().shadowSize(); shadowRadius = manager.getShadowSize();
if (entity.isBaby()) { if (entity.isBaby()) {
shadowRadius *= 3; // undo vanilla shadow scaling shadowRadius *= 3; // undo vanilla shadow scaling
@ -100,7 +94,7 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
if (!entity.hasVehicle()) { if (!entity.hasVehicle()) {
stack.translate(0, 0, -entity.getWidth() / 2); // move us to the center of the shadow stack.translate(0, 0, -entity.getWidth() / 2); // move us to the center of the shadow
} else { } else {
stack.translate(0, -entity.getRidingOffset(entity.getVehicle()), 0); stack.translate(0, entity.getRidingOffset(entity.getVehicle()), 0);
} }
stack.scale(scale, scale, scale); stack.scale(scale, scale, scale);
@ -117,8 +111,7 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
@Override @Override
public Identifier getDefaultTexture(T entity, Wearable wearable) { public Identifier getDefaultTexture(T entity, Wearable wearable) {
return wearableTextures.computeIfAbsent(wearable, w -> { return wearableTextures.computeIfAbsent(wearable, w -> {
Identifier texture = getTexture(entity); Identifier texture = getTexture(entity).withPath(path -> path.split("\\.")[0] + "_" + wearable.name().toLowerCase(Locale.ROOT) + ".png");
texture = new Identifier(texture.getNamespace(), texture.getPath().split("\\.")[0] + "_" + wearable.name().toLowerCase(Locale.ROOT) + ".png");
if (MinecraftClient.getInstance().getResourceManager().getResource(texture).isPresent()) { if (MinecraftClient.getInstance().getResourceManager().getResource(texture).isPresent()) {
return texture; return texture;
@ -127,6 +120,11 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
}); });
} }
@Override
public void setModel(M model) {
this.model = model;
}
@Override @Override
public EquineRenderManager<T, M> getInternalRenderer() { public EquineRenderManager<T, M> getInternalRenderer() {
return manager; return manager;

View file

@ -1,10 +1,8 @@
package com.minelittlepony.client.render.entity; package com.minelittlepony.client.render.entity;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.model.PreviewModel;
import com.minelittlepony.api.pony.PonyPosture; import com.minelittlepony.api.pony.*;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.PreviewModel;
import com.minelittlepony.client.SkinsProxy;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
@ -12,69 +10,48 @@ import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRendererFactory; import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.util.Arm;
import net.minecraft.util.Identifier;
public class AquaticPlayerPonyRenderer extends PlayerPonyRenderer { public class AquaticPlayerPonyRenderer extends FormChangingPlayerPonyRenderer {
public static final Identifier SKIN_TYPE_ID = new Identifier("minelp", "seapony");
private boolean wet;
public AquaticPlayerPonyRenderer(EntityRendererFactory.Context context, boolean slim) { public AquaticPlayerPonyRenderer(EntityRendererFactory.Context context, boolean slim) {
super(context, slim); super(context, slim, DefaultPonySkinHelper.SEAPONY_SKIN_TYPE_ID, PonyPosture::isSeaponyModifier);
}
@Override
public Identifier getTexture(AbstractClientPlayerEntity player) {
if (wet) {
return SkinsProxy.instance.getSkin(SKIN_TYPE_ID, player).orElseGet(() -> super.getTexture(player));
}
return super.getTexture(player);
} }
@Override @Override
public void render(AbstractClientPlayerEntity player, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int light) { public void render(AbstractClientPlayerEntity player, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int light) {
updateSeaponyState(player);
super.render(player, entityYaw, tickDelta, stack, renderContext, light); super.render(player, entityYaw, tickDelta, stack, renderContext, light);
if (!(player instanceof PreviewModel) && wet && player.getVelocity().length() > 0.1F) { if (!(player instanceof PreviewModel) && transformed && player.getVelocity().length() > 0.1F) {
double x = player.getEntityWorld().getRandom().nextTriangular(player.getX(), 1); double x = player.getEntityWorld().getRandom().nextTriangular(player.getX(), 1);
double y = player.getEntityWorld().getRandom().nextTriangular(player.getY(), 1); double y = player.getEntityWorld().getRandom().nextTriangular(player.getY(), 1);
double z = player.getEntityWorld().getRandom().nextTriangular(player.getZ(), 1); double z = player.getEntityWorld().getRandom().nextTriangular(player.getZ(), 1);
player.getEntityWorld().addParticle(ParticleTypes.BUBBLE, x, y, z, 0, 0, 0); player.getEntityWorld().addParticle(ParticleTypes.BUBBLE, x, y, z, 0, 0, 0);
} }
} }
@Override
protected Race getPlayerRace(AbstractClientPlayerEntity entity, Pony pony) { protected Race getPlayerRace(AbstractClientPlayerEntity entity, Pony pony) {
Race race = super.getPlayerRace(entity, pony); Race race = super.getPlayerRace(entity, pony);
return wet ? Race.SEAPONY : race == Race.SEAPONY ? Race.UNICORN : race; return PonyPosture.isSeaponyModifier(entity) ? Race.SEAPONY : race == Race.SEAPONY ? Race.UNICORN : race;
} }
@Override @Override
protected void setupTransforms(AbstractClientPlayerEntity entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) { protected void setupTransforms(AbstractClientPlayerEntity player, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) {
if (wet) { if (PonyPosture.isSeaponyModifier(player)) {
stack.translate(0, 0.6, 0); stack.translate(0, 0.6, 0);
if (entity.isInSneakingPose()) { if (player.isInSneakingPose()) {
stack.translate(0, 0.125, 0); stack.translate(0, 0.125, 0);
} }
} }
super.setupTransforms(entity, stack, ageInTicks, rotationYaw, partialTicks); super.setupTransforms(player, stack, ageInTicks, rotationYaw, partialTicks);
} }
@Override @Override
protected void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player, Arm side) { protected void updateForm(AbstractClientPlayerEntity player) {
updateSeaponyState(player); super.updateForm(player);
super.renderArm(stack, renderContext, lightUv, player, side);
}
private void updateSeaponyState(AbstractClientPlayerEntity player) {
Pony pony = getEntityPony(player);
wet = PonyPosture.isSeaponyModifier(player);
if (!(player instanceof PreviewModel)) { if (!(player instanceof PreviewModel)) {
float state = wet ? 100 : 0; float state = transformed ? 100 : 0;
float interpolated = pony.metadata().getInterpolator(player.getUuid()).interpolate("seapony_state", state, 5); float interpolated = getInternalRenderer().getModels().body().getAttributes().getMainInterpolator().interpolate("seapony_state", state, 5);
if (!MathUtil.compareFloats(interpolated, state)) { if (!MathUtil.compareFloats(interpolated, state)) {
double x = player.getEntityWorld().getRandom().nextTriangular(player.getX(), 1); double x = player.getEntityWorld().getRandom().nextTriangular(player.getX(), 1);

View file

@ -0,0 +1,50 @@
package com.minelittlepony.client.render.entity;
import com.minelittlepony.api.pony.*;
import java.util.function.Predicate;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Arm;
import net.minecraft.util.Identifier;
public class FormChangingPlayerPonyRenderer extends PlayerPonyRenderer {
protected boolean transformed;
private final Identifier alternateFormSkinId;
private final Predicate<AbstractClientPlayerEntity> formModifierPredicate;
public FormChangingPlayerPonyRenderer(EntityRendererFactory.Context context,
boolean slim, Identifier alternateFormSkinId, Predicate<AbstractClientPlayerEntity> formModifierPredicate) {
super(context, slim);
this.alternateFormSkinId = alternateFormSkinId;
this.formModifierPredicate = formModifierPredicate;
}
@Override
public Identifier getTexture(AbstractClientPlayerEntity player) {
if (transformed) {
return SkinsProxy.instance.getSkin(alternateFormSkinId, player).orElseGet(() -> super.getTexture(player));
}
return super.getTexture(player);
}
@Override
public void render(AbstractClientPlayerEntity player, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int light) {
super.render(player, entityYaw, tickDelta, stack, renderContext, light);
updateForm(player);
}
@Override
protected void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player, Arm side) {
super.renderArm(stack, renderContext, lightUv, player, side);
updateForm(player);
}
protected void updateForm(AbstractClientPlayerEntity player) {
transformed = formModifierPredicate.test(player);
}
}

View file

@ -1,13 +1,14 @@
package com.minelittlepony.client.render.entity; package com.minelittlepony.client.render.entity;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.Models;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.SkinsProxy;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.SkinsProxy;
import com.minelittlepony.client.model.*; import com.minelittlepony.client.model.*;
import com.minelittlepony.client.render.DebugBoundingBoxRenderer; import com.minelittlepony.client.render.DebugBoundingBoxRenderer;
import com.minelittlepony.client.render.IPonyRenderContext; import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.feature.*; import com.minelittlepony.client.render.entity.feature.*;
import com.minelittlepony.client.util.render.RenderLayerUtil; import com.minelittlepony.client.util.render.RenderLayerUtil;
@ -26,24 +27,22 @@ import net.minecraft.client.render.entity.feature.*;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.*; import net.minecraft.util.*;
import net.minecraft.util.math.*;
public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRenderContext<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> { public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRenderContext<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> {
private final Function<Race, Models<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>>> modelsCache;
protected final EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> manager = new EquineRenderManager<>(this); protected final EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> manager;
private final Function<Race, ModelWrapper<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>>> modelsCache;
public PlayerPonyRenderer(EntityRendererFactory.Context context, boolean slim) { public PlayerPonyRenderer(EntityRendererFactory.Context context, boolean slim) {
super(context, slim); super(context, slim);
modelsCache = Util.memoize(race -> ModelType.getPlayerModel(race).create(slim)); modelsCache = Util.memoize(race -> ModelType.getPlayerModel(race).create(slim));
manager = new EquineRenderManager<>(this, super::setupTransforms, modelsCache.apply(Race.EARTH));
manager.setModelsLookup(entity -> modelsCache.apply(getPlayerRace(entity, getEntityPony(entity))));
addLayers(context); addLayers(context);
} }
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
protected void addLayers(EntityRendererFactory.Context context) { protected void addLayers(EntityRendererFactory.Context context) {
// remove vanilla features (keep modded ones) // remove vanilla features (keep modded ones)
// TODO: test with https://github.com/Globox1997/BackSlot
features.removeIf(feature -> { features.removeIf(feature -> {
return feature instanceof ArmorFeatureRenderer return feature instanceof ArmorFeatureRenderer
|| feature instanceof PlayerHeldItemFeatureRenderer || feature instanceof PlayerHeldItemFeatureRenderer
@ -70,30 +69,32 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
@Override @Override
protected void scale(AbstractClientPlayerEntity entity, MatrixStack stack, float tickDelta) { protected void scale(AbstractClientPlayerEntity entity, MatrixStack stack, float tickDelta) {
if (manager.getModel().getAttributes().isSitting && entity.hasVehicle()) { if (manager.getModels().body().getAttributes().isSitting && entity.hasVehicle()) {
stack.translate(0, entity.getRidingOffset(entity.getVehicle()), 0); stack.translate(0, entity.getRidingOffset(entity.getVehicle()), 0);
} }
} }
@Override @Override
public void render(AbstractClientPlayerEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) { public void render(AbstractClientPlayerEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
Pony pony = getEntityPony(entity);
model = manager.setModel(modelsCache.apply(getPlayerRace(entity, pony))).body();
// EntityModelFeatures: We have to force it to use our models otherwise EMF overrides it and breaks pony rendering // EntityModelFeatures: We have to force it to use our models otherwise EMF overrides it and breaks pony rendering
shadowRadius = manager.getModel().getSize().shadowSize(); manager.preRender(entity, ModelAttributes.Mode.THIRD_PERSON);
shadowRadius = manager.getShadowSize();
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv); super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
DebugBoundingBoxRenderer.render(pony, this, entity, stack, renderContext, tickDelta); DebugBoundingBoxRenderer.render(getEntityPony(entity), this, entity, stack, renderContext, tickDelta);
// Translate the shadow position after everything is done // Translate the shadow position after everything is done
// (shadows are drawn after us) // (shadows are drawn after us)
/*
if (!entity.hasVehicle() && !entity.isSleeping()) { if (!entity.hasVehicle() && !entity.isSleeping()) {
float yaw = MathHelper.lerpAngleDegrees(tickDelta, entity.prevBodyYaw, entity.bodyYaw); float yaw = MathHelper.lerpAngleDegrees(tickDelta, entity.prevBodyYaw, entity.bodyYaw);
float l = entity.getWidth() / 2 * pony.size().scaleFactor(); float l = entity.getWidth() / 2 * manager.getScaleFactor();
stack.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(yaw)); stack.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(yaw));
stack.translate(0, 0, -l); stack.translate(0, 0, -l);
stack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw)); stack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw));
} }
*/
} }
protected Race getPlayerRace(AbstractClientPlayerEntity entity, Pony pony) { protected Race getPlayerRace(AbstractClientPlayerEntity entity, Pony pony) {
@ -102,10 +103,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
@Override @Override
protected void setupTransforms(AbstractClientPlayerEntity entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) { protected void setupTransforms(AbstractClientPlayerEntity entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) {
manager.preRenderCallback(entity, stack, partialTicks); manager.setupTransforms(entity, stack, ageInTicks, rotationYaw, partialTicks);
rotationYaw = manager.getRenderYaw(entity, rotationYaw, partialTicks);
super.setupTransforms(entity, stack, ageInTicks, rotationYaw, partialTicks);
manager.setupTransforms(entity, stack, rotationYaw, partialTicks);
} }
@Override @Override
@ -144,9 +142,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
} }
protected void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player, Arm side) { protected void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player, Arm side) {
Pony pony = getEntityPony(player); manager.preRender(player, ModelAttributes.Mode.FIRST_PERSON);
model = manager.setModel(modelsCache.apply(getPlayerRace(player, pony))).body();
manager.updateModel(player, ModelAttributes.Mode.FIRST_PERSON);
stack.push(); stack.push();
float reflect = side == Arm.LEFT ? 1 : -1; float reflect = side == Arm.LEFT ? 1 : -1;
@ -154,7 +150,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
stack.translate(reflect * 0.1F, -0.54F, 0); stack.translate(reflect * 0.1F, -0.54F, 0);
Identifier texture = getTexture(player); Identifier texture = getTexture(player);
Identifier playerSkin = player.method_52814().texture(); Identifier playerSkin = player.getSkinTextures().texture();
VertexConsumerProvider interceptedContext = layer -> { VertexConsumerProvider interceptedContext = layer -> {
return renderContext.getBuffer(RenderLayerUtil return renderContext.getBuffer(RenderLayerUtil
.getTexture(layer) .getTexture(layer)
@ -178,6 +174,11 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
return getEntityPony(player).texture(); return getEntityPony(player).texture();
} }
@Override
public void setModel(ClientPonyModel<AbstractClientPlayerEntity> model) {
this.model = model;
}
@Override @Override
public EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> getInternalRenderer() { public EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> getInternalRenderer() {
return manager; return manager;
@ -191,7 +192,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
@Override @Override
public Identifier getDefaultTexture(AbstractClientPlayerEntity entity, Wearable wearable) { public Identifier getDefaultTexture(AbstractClientPlayerEntity entity, Wearable wearable) {
return SkinsProxy.instance.getSkin(wearable.getId(), entity).orElseGet(() -> { return SkinsProxy.instance.getSkin(wearable.getId(), entity).orElseGet(() -> {
if (wearable.isSaddlebags() && getInternalRenderer().getModel().getRace().supportsLegacySaddlebags()) { if (wearable.isSaddlebags() && getInternalRenderer().getModels().body().getRace().supportsLegacySaddlebags()) {
return getTexture(entity); return getTexture(entity);
} }

View file

@ -11,11 +11,11 @@ import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.entity.decoration.ArmorStandEntity;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import com.minelittlepony.api.model.armour.ArmourLayer; import com.minelittlepony.api.model.Models;
import com.minelittlepony.api.pony.PonyData; import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.ModelWrapper; import com.minelittlepony.client.model.armour.ArmourLayer;
import com.minelittlepony.client.model.entity.PonyArmourStandModel; import com.minelittlepony.client.model.entity.PonyArmourStandModel;
import com.minelittlepony.client.model.entity.race.EarthPonyModel; import com.minelittlepony.client.model.entity.race.EarthPonyModel;
import com.minelittlepony.client.render.entity.feature.ArmourFeature; import com.minelittlepony.client.render.entity.feature.ArmourFeature;
@ -60,7 +60,7 @@ public class PonyStandRenderer extends ArmorStandEntityRenderer {
} }
class Armour extends ArmorFeatureRenderer<ArmorStandEntity, ArmorStandArmorEntityModel, ArmorStandArmorEntityModel> { class Armour extends ArmorFeatureRenderer<ArmorStandEntity, ArmorStandArmorEntityModel, ArmorStandArmorEntityModel> {
private final ModelWrapper<ArmorStandEntity, EarthPonyModel<ArmorStandEntity>> pony = ModelType.EARTH_PONY.<ArmorStandEntity, EarthPonyModel<ArmorStandEntity>>create(false); private final Models<ArmorStandEntity, EarthPonyModel<ArmorStandEntity>> pony = ModelType.EARTH_PONY.<ArmorStandEntity, EarthPonyModel<ArmorStandEntity>>create(false);
public Armour(FeatureRendererContext<ArmorStandEntity, ArmorStandArmorEntityModel> renderer, EntityRendererFactory.Context context) { public Armour(FeatureRendererContext<ArmorStandEntity, ArmorStandArmorEntityModel> renderer, EntityRendererFactory.Context context) {
super(renderer, super(renderer,

View file

@ -2,6 +2,7 @@ package com.minelittlepony.client.render.entity;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.client.mixin.IResizeable; import com.minelittlepony.client.mixin.IResizeable;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.GuardianPonyModel; import com.minelittlepony.client.model.entity.GuardianPonyModel;
@ -52,7 +53,7 @@ public class SeaponyRenderer extends GuardianEntityRenderer {
@Override @Override
public void render(GuardianEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) { public void render(GuardianEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
ponyRenderer.manager.preRenderCallback(entity, stack, tickDelta); ponyRenderer.manager.preRender(entity, ModelAttributes.Mode.THIRD_PERSON);
float height = entity.getStandingEyeHeight(); float height = entity.getStandingEyeHeight();
@ -61,4 +62,9 @@ public class SeaponyRenderer extends GuardianEntityRenderer {
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv); super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
((IResizeable)entity).setStandingEyeHeight(height); ((IResizeable)entity).setStandingEyeHeight(height);
} }
@Override
protected void setupTransforms(GuardianEntity entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) {
ponyRenderer.manager.setupTransforms(entity, stack, ageInTicks, rotationYaw, partialTicks);
}
} }

View file

@ -38,6 +38,6 @@ public class ZomponyRenderer<Zombie extends HostileEntity> extends PonyRenderer<
} }
public static ZomponyRenderer<GiantEntity> giant(EntityRendererFactory.Context context) { public static ZomponyRenderer<GiantEntity> giant(EntityRendererFactory.Context context) {
return new ZomponyRenderer<>(context, TextureSupplier.of(ZOMBIE), 3); return new ZomponyRenderer<>(context, TextureSupplier.of(ZOMBIE), 6.8F);
} }
} }

Some files were not shown because too many files have changed in this diff Show more