Compare commits
7 Commits
1.0.1+1.16
...
master
Author | SHA1 | Date | |
---|---|---|---|
fcb7df74ed | |||
b2ec9ea567 | |||
96860fa2c1 | |||
17687a3056 | |||
419b2c1f21 | |||
26492891a6 | |||
248f925b99 |
|
@ -1,5 +1,11 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
**1.0.3**
|
||||||
|
* Remove ``main_arm`` And ``off_arm``
|
||||||
|
|
||||||
|
**1.0.2**
|
||||||
|
* Add Eating Animation
|
||||||
|
|
||||||
**1.0.1**
|
**1.0.1**
|
||||||
* Average Skin Color In Default Leather Armor
|
* Average Skin Color In Default Leather Armor
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
- In ideal conditions emotes run at 20FPS
|
- In ideal conditions emotes run at 20FPS
|
||||||
- All frames are made up of part rotations separated by spaces
|
- All frames are made up of part rotations separated by spaces
|
||||||
- Parts can only be specified once in a frame
|
- Parts can only be specified once in a frame
|
||||||
|
- If a line is ``maintain``, it will copy the previous frame
|
||||||
|
|
||||||
## Part Rotation Format
|
## Part Rotation Format
|
||||||
```
|
```
|
||||||
|
@ -16,7 +17,4 @@
|
||||||
- ``right_leg``
|
- ``right_leg``
|
||||||
- ``left_arm``
|
- ``left_arm``
|
||||||
- ``right_arm``
|
- ``right_arm``
|
||||||
- ``main_arm``
|
- ``body``
|
||||||
- ``off_arm``
|
|
||||||
- ``body``
|
|
||||||
- ``left_arm``/``right_arm`` is not compatible with ``main_arm``/``off_arm``
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
![Poster](images/poster.png)
|
||||||
|
|
||||||
# Gestus
|
# Gestus
|
||||||
A server-side mod that adds data-driven emotes to Minecraft that can be viewed by vanilla clients.
|
A server-side mod that adds data-driven emotes to Minecraft that can be viewed by vanilla clients.
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,11 @@ org.gradle.jvmargs = -Xmx1G
|
||||||
minecraft_version = 1.16.2
|
minecraft_version = 1.16.2
|
||||||
curseforge_id = 401707
|
curseforge_id = 401707
|
||||||
simple_minecraft_version = 1.16.2
|
simple_minecraft_version = 1.16.2
|
||||||
yarn_build = 1
|
yarn_build = 12
|
||||||
fabric_loader_version = 0.9.0+build.204
|
fabric_loader_version = 0.9.0+build.204
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version = 1.0.1
|
mod_version = 1.0.3
|
||||||
maven_group = com.thebrokenrail
|
maven_group = com.thebrokenrail
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
BIN
images/poster.png
Normal file
BIN
images/poster.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 MiB |
|
@ -11,16 +11,6 @@ import java.util.Map;
|
||||||
public class Emote {
|
public class Emote {
|
||||||
public final EmoteFrame[] frames;
|
public final EmoteFrame[] frames;
|
||||||
|
|
||||||
private static int getArmMode(EmotePart part) {
|
|
||||||
if (part == EmotePart.LEFT_ARM || part == EmotePart.RIGHT_ARM) {
|
|
||||||
return 1;
|
|
||||||
} else if (part == EmotePart.MAIN_ARM || part == EmotePart.OFF_ARM) {
|
|
||||||
return 2;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Emote(String[] lines) throws EmoteSyntaxException {
|
public Emote(String[] lines) throws EmoteSyntaxException {
|
||||||
List<EmoteFrame> list = new ArrayList<>();
|
List<EmoteFrame> list = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -29,11 +19,13 @@ public class Emote {
|
||||||
for (int lineNum = 0; lineNum < lines.length; lineNum++) {
|
for (int lineNum = 0; lineNum < lines.length; lineNum++) {
|
||||||
String line = lines[lineNum].trim();
|
String line = lines[lineNum].trim();
|
||||||
|
|
||||||
if (line.equals("maintain") && list.size() > 0) {
|
if (line.equals("maintain")) {
|
||||||
list.add(list.get(list.size() - 1));
|
if (list.size() > 0) {
|
||||||
|
list.add(list.get(list.size() - 1));
|
||||||
|
} else {
|
||||||
|
throw new EmoteSyntaxException(lineNum, "No Previous Frame");
|
||||||
|
}
|
||||||
} else if (!line.startsWith("#")) {
|
} else if (!line.startsWith("#")) {
|
||||||
int armMode = 0;
|
|
||||||
|
|
||||||
Map<EmotePart, EulerAngle> map = new HashMap<>();
|
Map<EmotePart, EulerAngle> map = new HashMap<>();
|
||||||
|
|
||||||
String[] lineParts = line.split(" ");
|
String[] lineParts = line.split(" ");
|
||||||
|
@ -55,13 +47,6 @@ public class Emote {
|
||||||
throw new EmoteSyntaxException(lineNum, "Invalid Emote Part: " + linePart);
|
throw new EmoteSyntaxException(lineNum, "Invalid Emote Part: " + linePart);
|
||||||
} else if (map.containsKey(selectedPart)) {
|
} else if (map.containsKey(selectedPart)) {
|
||||||
throw new EmoteSyntaxException(lineNum, "Duplicate Emote Part: " + linePart);
|
throw new EmoteSyntaxException(lineNum, "Duplicate Emote Part: " + linePart);
|
||||||
} else if (armMode == 0) {
|
|
||||||
armMode = getArmMode(selectedPart);
|
|
||||||
} else if (armMode > 0) {
|
|
||||||
int newMode = getArmMode(selectedPart);
|
|
||||||
if (newMode != 0 && newMode != armMode) {
|
|
||||||
throw new EmoteSyntaxException(lineNum, "Conflicting Arm Modes");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -6,32 +6,19 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class EmoteFrame {
|
public class EmoteFrame {
|
||||||
public final Map<EmotePart, EulerAngle> rightHanded;
|
public final Map<EmotePart, EulerAngle> normal;
|
||||||
public final Map<EmotePart, EulerAngle> leftHanded;
|
public final Map<EmotePart, EulerAngle> mirrored;
|
||||||
|
|
||||||
public EmoteFrame(Map<EmotePart, EulerAngle> data) {
|
public EmoteFrame(Map<EmotePart, EulerAngle> data) {
|
||||||
rightHanded = resolve(data, false);
|
normal = data;
|
||||||
leftHanded = resolve(data, true);
|
mirrored = mirror(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<EmotePart, EulerAngle> resolve(Map<EmotePart, EulerAngle> data, boolean leftHanded) {
|
private static Map<EmotePart, EulerAngle> mirror(Map<EmotePart, EulerAngle> data) {
|
||||||
Map<EmotePart, EulerAngle> result = new HashMap<>();
|
Map<EmotePart, EulerAngle> result = new HashMap<>();
|
||||||
for (Map.Entry<EmotePart, EulerAngle> entry : data.entrySet()) {
|
for (Map.Entry<EmotePart, EulerAngle> entry : data.entrySet()) {
|
||||||
if (entry.getKey() == EmotePart.MAIN_ARM) {
|
EmotePart newPart = entry.getKey().mirror();
|
||||||
if (leftHanded) {
|
result.put(newPart, new EulerAngle(entry.getValue().getPitch(), -entry.getValue().getYaw(), -entry.getValue().getRoll()));
|
||||||
result.put(EmotePart.LEFT_ARM, new EulerAngle(entry.getValue().getPitch(), -entry.getValue().getYaw(), -entry.getValue().getRoll()));
|
|
||||||
} else {
|
|
||||||
result.put(EmotePart.RIGHT_ARM, entry.getValue());
|
|
||||||
}
|
|
||||||
} else if (entry.getKey() == EmotePart.OFF_ARM) {
|
|
||||||
if (leftHanded) {
|
|
||||||
result.put(EmotePart.RIGHT_ARM, new EulerAngle(entry.getValue().getPitch(), -entry.getValue().getYaw(), -entry.getValue().getRoll()));
|
|
||||||
} else {
|
|
||||||
result.put(EmotePart.LEFT_ARM, entry.getValue());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ public class EmoteLayer {
|
||||||
private Identifier current;
|
private Identifier current;
|
||||||
private final boolean loop;
|
private final boolean loop;
|
||||||
|
|
||||||
private boolean leftHanded = false;
|
private boolean mirrored = false;
|
||||||
|
|
||||||
public EmoteLayer(Identifier start, boolean loop) {
|
public EmoteLayer(Identifier start, boolean loop) {
|
||||||
current = start;
|
current = start;
|
||||||
|
@ -23,10 +23,10 @@ public class EmoteLayer {
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void play(Identifier current, boolean leftHanded) {
|
public void play(Identifier current, boolean mirrored) {
|
||||||
if (!Objects.equals(this.current, current) || this.leftHanded != leftHanded) {
|
if (!Objects.equals(this.current, current) || this.mirrored != mirrored) {
|
||||||
this.current = current;
|
this.current = current;
|
||||||
this.leftHanded = leftHanded;
|
this.mirrored = mirrored;
|
||||||
frame = 0;
|
frame = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ public class EmoteLayer {
|
||||||
return current != null;
|
return current != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLeftHanded() {
|
public boolean isMirrored() {
|
||||||
return leftHanded;
|
return mirrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<EmotePart, EulerAngle> next() {
|
public Map<EmotePart, EulerAngle> next() {
|
||||||
|
@ -53,7 +53,7 @@ public class EmoteLayer {
|
||||||
current = null;
|
current = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return leftHanded ? result.leftHanded : result.rightHanded;
|
return mirrored ? result.mirrored : result.normal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frame = 0;
|
frame = 0;
|
||||||
|
|
|
@ -1,13 +1,36 @@
|
||||||
package com.thebrokenrail.gestus.emote;
|
package com.thebrokenrail.gestus.emote;
|
||||||
|
|
||||||
public enum EmotePart {
|
public enum EmotePart {
|
||||||
MAIN_ARM("main_arm"),
|
RIGHT_ARM("right_arm") {
|
||||||
OFF_ARM("off_arm"),
|
@Override
|
||||||
RIGHT_ARM("right_arm"),
|
public EmotePart mirror() {
|
||||||
LEFT_ARM("left_arm"),
|
return LEFT_ARM;
|
||||||
RIGHT_LEG("right_leg"),
|
}
|
||||||
LEFT_LEG("left_leg"),
|
},
|
||||||
BODY("body");
|
LEFT_ARM("left_arm") {
|
||||||
|
@Override
|
||||||
|
public EmotePart mirror() {
|
||||||
|
return RIGHT_ARM;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RIGHT_LEG("right_leg") {
|
||||||
|
@Override
|
||||||
|
public EmotePart mirror() {
|
||||||
|
return LEFT_LEG;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
LEFT_LEG("left_leg") {
|
||||||
|
@Override
|
||||||
|
public EmotePart mirror() {
|
||||||
|
return RIGHT_LEG;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BODY("body") {
|
||||||
|
@Override
|
||||||
|
public EmotePart mirror() {
|
||||||
|
return BODY;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
@ -18,4 +41,6 @@ public enum EmotePart {
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract EmotePart mirror();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import net.minecraft.entity.EquipmentSlot;
|
||||||
import net.minecraft.entity.damage.DamageSource;
|
import net.minecraft.entity.damage.DamageSource;
|
||||||
import net.minecraft.entity.data.TrackedData;
|
import net.minecraft.entity.data.TrackedData;
|
||||||
import net.minecraft.entity.decoration.ArmorStandEntity;
|
import net.minecraft.entity.decoration.ArmorStandEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.CrossbowItem;
|
import net.minecraft.item.CrossbowItem;
|
||||||
import net.minecraft.item.DyeableItem;
|
import net.minecraft.item.DyeableItem;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
|
@ -20,6 +21,7 @@ import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.text.LiteralText;
|
import net.minecraft.text.LiteralText;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.Arm;
|
import net.minecraft.util.Arm;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
@ -47,8 +49,9 @@ public class FakePlayerEntity extends ArmorStandEntity {
|
||||||
private static final Identifier HIT_EMOTE = new Identifier(Gestus.NAMESPACE, "builtin/hit"); // Hit Layer
|
private static final Identifier HIT_EMOTE = new Identifier(Gestus.NAMESPACE, "builtin/hit"); // Hit Layer
|
||||||
|
|
||||||
private static final Identifier AIM_EMOTE = new Identifier(Gestus.NAMESPACE, "builtin/aim"); // Aim Layer
|
private static final Identifier AIM_EMOTE = new Identifier(Gestus.NAMESPACE, "builtin/aim"); // Aim Layer
|
||||||
private static final Identifier TRIDENT_EMOTE = new Identifier(Gestus.NAMESPACE, "builtin/trident"); // Aim Layer
|
|
||||||
private static final Identifier SHIELD_EMOTE = new Identifier(Gestus.NAMESPACE, "builtin/shield"); // Aim Layer
|
private static final Identifier SHIELD_EMOTE = new Identifier(Gestus.NAMESPACE, "builtin/shield"); // Aim Layer
|
||||||
|
private static final Identifier TRIDENT_EMOTE = new Identifier(Gestus.NAMESPACE, "builtin/trident"); // Aim Layer
|
||||||
|
private static final Identifier EAT_EMOTE = new Identifier(Gestus.NAMESPACE, "builtin/eat"); // Aim Layer
|
||||||
|
|
||||||
public final ServerPlayerEntity player;
|
public final ServerPlayerEntity player;
|
||||||
|
|
||||||
|
@ -175,21 +178,26 @@ public class FakePlayerEntity extends ArmorStandEntity {
|
||||||
emote = TRIDENT_EMOTE;
|
emote = TRIDENT_EMOTE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case EAT:
|
||||||
|
case DRINK: {
|
||||||
|
emote = EAT_EMOTE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (emote != null) {
|
if (emote != null) {
|
||||||
layers[AIM_LAYER].play(emote, (hand == Hand.OFF_HAND) != isLeftHanded());
|
layers[AIM_LAYER].play(emote, (hand == Hand.OFF_HAND) != isLeftHanded());
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAim() {
|
private void updateAim() {
|
||||||
Hand hand = player.getActiveHand();
|
Hand hand = player.getActiveHand();
|
||||||
if (!updateAim(hand, true)) {
|
if (updateAim(hand, true) && updateAim(hand == Hand.MAIN_HAND ? Hand.OFF_HAND : Hand.MAIN_HAND, false)) {
|
||||||
updateAim(hand == Hand.MAIN_HAND ? Hand.OFF_HAND : Hand.MAIN_HAND, false);
|
layers[AIM_LAYER].play(null, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +266,7 @@ public class FakePlayerEntity extends ArmorStandEntity {
|
||||||
|
|
||||||
private void updateEquipment() {
|
private void updateEquipment() {
|
||||||
for (EquipmentSlot slot : EquipmentSlot.values()) {
|
for (EquipmentSlot slot : EquipmentSlot.values()) {
|
||||||
ItemStack target = getFallbackItem(slot, player.getEquippedStack(slot).copy(), isInvisible());
|
ItemStack target = getFallbackItem(slot, player.getEquippedStack(slot).copy(), isInvisible()).copy();
|
||||||
if (!getEquippedStack(slot).isItemEqual(target)) {
|
if (!getEquippedStack(slot).isItemEqual(target)) {
|
||||||
equipStack(slot, target);
|
equipStack(slot, target);
|
||||||
}
|
}
|
||||||
|
@ -293,4 +301,14 @@ public class FakePlayerEntity extends ArmorStandEntity {
|
||||||
public boolean damage(DamageSource source, float amount) {
|
public boolean damage(DamageSource source, float amount) {
|
||||||
return player.damage(source, amount);
|
return player.damage(source, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult interactAt(PlayerEntity player, Vec3d hitPos, Hand hand) {
|
||||||
|
return ActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult interact(PlayerEntity player, Hand hand) {
|
||||||
|
return ActionResult.PASS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.thebrokenrail.gestus.mixin;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import net.minecraft.entity.EquipmentSlot;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.network.packet.s2c.play.EntityEquipmentUpdateS2CPacket;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Mutable;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mixin(EntityEquipmentUpdateS2CPacket.class)
|
||||||
|
public interface EntityEquipmentUpdateS2CPacketAccessor {
|
||||||
|
@Accessor
|
||||||
|
int getId();
|
||||||
|
|
||||||
|
@Accessor
|
||||||
|
List<Pair<EquipmentSlot, ItemStack>> getEquipmentList();
|
||||||
|
|
||||||
|
@Mutable
|
||||||
|
@Accessor
|
||||||
|
void setEquipmentList(List<Pair<EquipmentSlot, ItemStack>> equipmentList);
|
||||||
|
}
|
|
@ -1,27 +0,0 @@
|
||||||
package com.thebrokenrail.gestus.mixin;
|
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
|
||||||
import com.thebrokenrail.gestus.util.Util;
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.EquipmentSlot;
|
|
||||||
import net.minecraft.item.ItemStack;
|
|
||||||
import net.minecraft.server.network.EntityTrackerEntry;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Mixin(EntityTrackerEntry.class)
|
|
||||||
public class MixinEntityTrackerEntry {
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private Entity entity;
|
|
||||||
|
|
||||||
@ModifyArg(at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/EntityEquipmentUpdateS2CPacket;<init>(ILjava/util/List;)V"), method = "*", index = 1)
|
|
||||||
public List<Pair<EquipmentSlot, ItemStack>> modifyEquipment(List<Pair<EquipmentSlot, ItemStack>> list) {
|
|
||||||
return Util.modifyEquipment(entity, list);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package com.thebrokenrail.gestus.mixin;
|
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
|
||||||
import com.thebrokenrail.gestus.util.Util;
|
|
||||||
import net.minecraft.entity.EquipmentSlot;
|
|
||||||
import net.minecraft.entity.LivingEntity;
|
|
||||||
import net.minecraft.item.ItemStack;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Mixin(LivingEntity.class)
|
|
||||||
public class MixinLivingEntity {
|
|
||||||
@ModifyArg(at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/EntityEquipmentUpdateS2CPacket;<init>(ILjava/util/List;)V"), method = "*", index = 1)
|
|
||||||
public List<Pair<EquipmentSlot, ItemStack>> modifyEquipment(List<Pair<EquipmentSlot, ItemStack>> list) {
|
|
||||||
return Util.modifyEquipment((LivingEntity) (Object) this, list);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,13 +5,16 @@ import com.thebrokenrail.gestus.util.Util;
|
||||||
import io.netty.util.concurrent.Future;
|
import io.netty.util.concurrent.Future;
|
||||||
import io.netty.util.concurrent.GenericFutureListener;
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.network.Packet;
|
import net.minecraft.network.Packet;
|
||||||
|
import net.minecraft.network.packet.s2c.play.EntityEquipmentUpdateS2CPacket;
|
||||||
import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket;
|
import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket;
|
||||||
import net.minecraft.network.packet.s2c.play.MobSpawnS2CPacket;
|
import net.minecraft.network.packet.s2c.play.MobSpawnS2CPacket;
|
||||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
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;
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||||
|
@ -33,10 +36,17 @@ public class MixinServerPlayNetworkHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private boolean shouldModify(int id) {
|
||||||
|
return player.getEntityWorld().getEntityById(id) instanceof PlayerEntity && id != player.getEntityId();
|
||||||
|
}
|
||||||
|
|
||||||
@ModifyVariable(at = @At("HEAD"), method = "sendPacket(Lnet/minecraft/network/Packet;Lio/netty/util/concurrent/GenericFutureListener;)V", argsOnly = true)
|
@ModifyVariable(at = @At("HEAD"), method = "sendPacket(Lnet/minecraft/network/Packet;Lio/netty/util/concurrent/GenericFutureListener;)V", argsOnly = true)
|
||||||
public Packet<?> modifyPacket(Packet<?> packet) {
|
public Packet<?> modifyPacket(Packet<?> packet) {
|
||||||
if (packet instanceof EntityTrackerUpdateS2CPacket && ((EntityTrackerUpdateS2CPacketAccessor) packet).getId() == player.getEntityId()) {
|
if (packet instanceof EntityTrackerUpdateS2CPacket && shouldModify(((EntityTrackerUpdateS2CPacketAccessor) packet).getId())) {
|
||||||
return Util.modifyTracker(player, (EntityTrackerUpdateS2CPacket) packet);
|
return Util.modifyTracker(player, (EntityTrackerUpdateS2CPacket) packet);
|
||||||
|
} else if (packet instanceof EntityEquipmentUpdateS2CPacket && shouldModify(((EntityEquipmentUpdateS2CPacketAccessor) packet).getId())) {
|
||||||
|
return Util.modifyEquipment((EntityEquipmentUpdateS2CPacket) packet);
|
||||||
} else {
|
} else {
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import com.mojang.authlib.GameProfile;
|
||||||
import com.thebrokenrail.gestus.Gestus;
|
import com.thebrokenrail.gestus.Gestus;
|
||||||
import com.thebrokenrail.gestus.entity.FakePlayerEntity;
|
import com.thebrokenrail.gestus.entity.FakePlayerEntity;
|
||||||
import com.thebrokenrail.gestus.util.ServerPlayerEntityExtension;
|
import com.thebrokenrail.gestus.util.ServerPlayerEntityExtension;
|
||||||
import net.minecraft.entity.effect.StatusEffects;
|
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
|
@ -18,6 +17,8 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Mixin(ServerPlayerEntity.class)
|
@Mixin(ServerPlayerEntity.class)
|
||||||
public abstract class MixinServerPlayerEntity extends PlayerEntity implements ServerPlayerEntityExtension {
|
public abstract class MixinServerPlayerEntity extends PlayerEntity implements ServerPlayerEntityExtension {
|
||||||
@Unique
|
@Unique
|
||||||
|
@ -40,17 +41,23 @@ public abstract class MixinServerPlayerEntity extends PlayerEntity implements Se
|
||||||
spawn = true;
|
spawn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean invisible = hasStatusEffect(StatusEffects.INVISIBILITY);
|
boolean invisible = isInvisible();
|
||||||
boolean glowing = hasStatusEffect(StatusEffects.GLOWING);
|
|
||||||
|
|
||||||
shadow.setInvisible(invisible);
|
shadow.setInvisible(invisible);
|
||||||
shadow.setGlowing(glowing);
|
shadow.setGlowing(isGlowing());
|
||||||
|
|
||||||
shadow.setWorld(getEntityWorld());
|
shadow.setWorld(getEntityWorld());
|
||||||
shadow.refreshPositionAndAngles(getX(), getY(), getZ(), yaw, pitch);
|
shadow.refreshPositionAndAngles(getX(), getY(), getZ(), yaw, pitch);
|
||||||
|
|
||||||
shadow.setHeadRotation(new EulerAngle(pitch, getHeadYaw() - yaw, 0f));
|
shadow.setHeadRotation(new EulerAngle(pitch, getHeadYaw() - yaw, 0f));
|
||||||
shadow.setVelocity(getVelocity());
|
|
||||||
|
Vec3d olVVelocity = shadow.getVelocity();
|
||||||
|
Vec3d velocity = getVelocity();
|
||||||
|
if (!Objects.equals(olVVelocity, velocity)) {
|
||||||
|
shadow.setVelocity(velocity);
|
||||||
|
shadow.velocityDirty = true;
|
||||||
|
shadow.velocityModified = true;
|
||||||
|
}
|
||||||
|
|
||||||
shadow.setCustomNameVisible(!invisible && !isSneaking());
|
shadow.setCustomNameVisible(!invisible && !isSneaking());
|
||||||
|
|
||||||
|
@ -66,8 +73,6 @@ public abstract class MixinServerPlayerEntity extends PlayerEntity implements Se
|
||||||
|
|
||||||
@Inject(at = @At("HEAD"), method = "tick")
|
@Inject(at = @At("HEAD"), method = "tick")
|
||||||
public void tick(CallbackInfo info) {
|
public void tick(CallbackInfo info) {
|
||||||
setInvisible(true);
|
|
||||||
setGlowing(false);
|
|
||||||
updateShadow();
|
updateShadow();
|
||||||
lastPos = getPos();
|
lastPos = getPos();
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ public final class SkinColor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Color averageColor(Color color1, Color color2) {
|
private static Color averageColor(Color color1, Color color2) {
|
||||||
int sumRed = color1.getRed() + color2.getRed();
|
long sumRed = color1.getRed() + color2.getRed();
|
||||||
long sumGreen = color1.getGreen() + color2.getGreen();
|
long sumGreen = color1.getGreen() + color2.getGreen();
|
||||||
long sumBlue = color1.getBlue() + color2.getBlue();
|
long sumBlue = color1.getBlue() + color2.getBlue();
|
||||||
return new Color(sumRed / 2, sumGreen / 2, sumBlue / 2);
|
return new Color(sumRed / 2, sumGreen / 2, sumBlue / 2);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package com.thebrokenrail.gestus.skin;
|
package com.thebrokenrail.gestus.skin;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -47,6 +49,10 @@ final class SkinJSON {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void error(String data) {
|
||||||
|
LogManager.getLogger("Gestus").error(data);
|
||||||
|
}
|
||||||
|
|
||||||
private static final String SKIN_TEXTURE_KEY = "SKIN";
|
private static final String SKIN_TEXTURE_KEY = "SKIN";
|
||||||
|
|
||||||
static String get(UUID uuid) {
|
static String get(UUID uuid) {
|
||||||
|
@ -54,26 +60,40 @@ final class SkinJSON {
|
||||||
String data = urlToString(url);
|
String data = urlToString(url);
|
||||||
|
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
Gson gson = new Gson();
|
try {
|
||||||
Response response = gson.fromJson(data, Response.class);
|
Gson gson = new Gson();
|
||||||
|
Response response = gson.fromJson(data, Response.class);
|
||||||
|
|
||||||
if (response != null && response.properties != null) {
|
if (response != null && response.properties != null) {
|
||||||
for (Property property : response.properties) {
|
for (Property property : response.properties) {
|
||||||
if ("textures".equals(property.name)) {
|
if ("textures".equals(property.name)) {
|
||||||
String texturesJSON = new String(Base64.getDecoder().decode(property.value));
|
try {
|
||||||
Data textures = gson.fromJson(texturesJSON, Data.class);
|
String texturesJSON = new String(Base64.getDecoder().decode(property.value));
|
||||||
|
Data textures = gson.fromJson(texturesJSON, Data.class);
|
||||||
|
|
||||||
if (textures.textures.containsKey(SKIN_TEXTURE_KEY)) {
|
if (textures.textures.containsKey(SKIN_TEXTURE_KEY)) {
|
||||||
Texture skin = textures.textures.get(SKIN_TEXTURE_KEY);
|
Texture skin = textures.textures.get(SKIN_TEXTURE_KEY);
|
||||||
return skin.url;
|
return skin.url;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
error("Unable To Parse Embedded Skin Metadata: " + uuid.toString());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
error("Embedded Skin Metadata Is Invalid: " + uuid.toString());
|
||||||
|
return null;
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
error("Unable To Parse Skin Metadata: " + uuid);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error("Unable To Download Skin Metadata: " + uuid);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,30 +2,26 @@ package com.thebrokenrail.gestus.util;
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.thebrokenrail.gestus.mixin.EntityAccessor;
|
import com.thebrokenrail.gestus.mixin.EntityAccessor;
|
||||||
|
import com.thebrokenrail.gestus.mixin.EntityEquipmentUpdateS2CPacketAccessor;
|
||||||
import com.thebrokenrail.gestus.mixin.EntityTrackerUpdateS2CPacketAccessor;
|
import com.thebrokenrail.gestus.mixin.EntityTrackerUpdateS2CPacketAccessor;
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.EquipmentSlot;
|
import net.minecraft.entity.EquipmentSlot;
|
||||||
import net.minecraft.entity.data.DataTracker;
|
import net.minecraft.entity.data.DataTracker;
|
||||||
import net.minecraft.entity.data.TrackedData;
|
import net.minecraft.entity.data.TrackedData;
|
||||||
import net.minecraft.entity.effect.StatusEffects;
|
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.network.packet.s2c.play.EntityEquipmentUpdateS2CPacket;
|
||||||
import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket;
|
import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Util {
|
public class Util {
|
||||||
public static List<Pair<EquipmentSlot, ItemStack>> modifyEquipment(Entity entity, List<Pair<EquipmentSlot, ItemStack>> list) {
|
public static EntityEquipmentUpdateS2CPacket modifyEquipment(EntityEquipmentUpdateS2CPacket packet) {
|
||||||
if (entity instanceof PlayerEntity) {
|
List<Pair<EquipmentSlot, ItemStack>> newList = new ArrayList<>();
|
||||||
List<Pair<EquipmentSlot, ItemStack>> newList = new ArrayList<>();
|
for (EquipmentSlot slot : EquipmentSlot.values()) {
|
||||||
for (EquipmentSlot slot : EquipmentSlot.values()) {
|
newList.add(Pair.of(slot, ItemStack.EMPTY));
|
||||||
newList.add(Pair.of(slot, ItemStack.EMPTY));
|
|
||||||
}
|
|
||||||
return newList;
|
|
||||||
} else {
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
return new EntityEquipmentUpdateS2CPacket(((EntityEquipmentUpdateS2CPacketAccessor) packet).getId(), newList);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int INVISIBILITY_FLAG = 5;
|
private static final int INVISIBILITY_FLAG = 5;
|
||||||
|
@ -48,8 +44,8 @@ public class Util {
|
||||||
for (DataTracker.Entry<?> entry : entries) {
|
for (DataTracker.Entry<?> entry : entries) {
|
||||||
if (entry.getData() == flags) {
|
if (entry.getData() == flags) {
|
||||||
byte data = (Byte) entry.get();
|
byte data = (Byte) entry.get();
|
||||||
data = setFlag(data, INVISIBILITY_FLAG, entity.hasStatusEffect(StatusEffects.INVISIBILITY));
|
data = setFlag(data, INVISIBILITY_FLAG, true);
|
||||||
data = setFlag(data, GLOWING_FLAG, entity.hasStatusEffect(StatusEffects.GLOWING));
|
data = setFlag(data, GLOWING_FLAG, false);
|
||||||
newEntries.add(new DataTracker.Entry<>(flags, data));
|
newEntries.add(new DataTracker.Entry<>(flags, data));
|
||||||
} else {
|
} else {
|
||||||
newEntries.add(entry);
|
newEntries.add(entry);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
main_arm 0 -90 0 off_arm 40 -90 0
|
right_arm 0 -90 0 left_arm 40 -90 0
|
5
src/main/resources/data/gestus/emotes/builtin/eat.emote
Normal file
5
src/main/resources/data/gestus/emotes/builtin/eat.emote
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
right_arm -51 -76 0
|
||||||
|
right_arm -55 -80 0
|
||||||
|
right_arm -59 -84 0
|
||||||
|
right_arm -55 -80 0
|
||||||
|
right_arm -51 -76 0
|
|
@ -1,9 +1,9 @@
|
||||||
main_arm 0 0 0
|
right_arm 0 0 0
|
||||||
main_arm -8.5 -17 0
|
right_arm -8.5 -17 0
|
||||||
main_arm -17 -34 0
|
right_arm -17 -34 0
|
||||||
main_arm -25.5 -51 0
|
right_arm -25.5 -51 0
|
||||||
main_arm -34 -68 0
|
right_arm -34 -68 0
|
||||||
main_arm -25.5 -51 0
|
right_arm -25.5 -51 0
|
||||||
main_arm -17 -34 0
|
right_arm -17 -34 0
|
||||||
main_arm -8.5 -17 0
|
right_arm -8.5 -17 0
|
||||||
main_arm 0 0 0
|
right_arm 0 0 0
|
|
@ -1 +1 @@
|
||||||
main_arm -42 -90 0
|
right_arm -42 -90 0
|
|
@ -1 +1 @@
|
||||||
main_arm 0 0 0 off_arm 0 0 0 left_leg 0 0 0 right_leg 0 0 0 body 0 0 0
|
right_arm 0 0 0 left_arm 0 0 0 left_leg 0 0 0 right_leg 0 0 0 body 0 0 0
|
|
@ -1 +1 @@
|
||||||
main_arm 0 -180 0
|
right_arm 0 -180 0
|
|
@ -1,40 +1,40 @@
|
||||||
main_arm 0 0 0
|
right_arm 0 0 0
|
||||||
main_arm 0 0 16
|
right_arm 0 0 16
|
||||||
main_arm 0 0 32
|
right_arm 0 0 32
|
||||||
main_arm 0 0 48
|
right_arm 0 0 48
|
||||||
main_arm 0 0 64
|
right_arm 0 0 64
|
||||||
main_arm 0 0 80
|
right_arm 0 0 80
|
||||||
main_arm 0 0 96
|
right_arm 0 0 96
|
||||||
main_arm 0 0 112
|
right_arm 0 0 112
|
||||||
main_arm 0 0 128
|
right_arm 0 0 128
|
||||||
main_arm 0 0 144
|
right_arm 0 0 144
|
||||||
main_arm 0 0 145
|
right_arm 0 0 145
|
||||||
main_arm 0 0 140
|
right_arm 0 0 140
|
||||||
main_arm 0 0 135
|
right_arm 0 0 135
|
||||||
main_arm 0 0 130
|
right_arm 0 0 130
|
||||||
main_arm 0 0 125
|
right_arm 0 0 125
|
||||||
main_arm 0 0 120
|
right_arm 0 0 120
|
||||||
main_arm 0 0 125
|
right_arm 0 0 125
|
||||||
main_arm 0 0 130
|
right_arm 0 0 130
|
||||||
main_arm 0 0 135
|
right_arm 0 0 135
|
||||||
main_arm 0 0 140
|
right_arm 0 0 140
|
||||||
main_arm 0 0 145
|
right_arm 0 0 145
|
||||||
main_arm 0 0 145
|
right_arm 0 0 145
|
||||||
main_arm 0 0 140
|
right_arm 0 0 140
|
||||||
main_arm 0 0 135
|
right_arm 0 0 135
|
||||||
main_arm 0 0 130
|
right_arm 0 0 130
|
||||||
main_arm 0 0 125
|
right_arm 0 0 125
|
||||||
main_arm 0 0 120
|
right_arm 0 0 120
|
||||||
main_arm 0 0 125
|
right_arm 0 0 125
|
||||||
main_arm 0 0 130
|
right_arm 0 0 130
|
||||||
main_arm 0 0 135
|
right_arm 0 0 135
|
||||||
main_arm 0 0 140
|
right_arm 0 0 140
|
||||||
main_arm 0 0 145
|
right_arm 0 0 145
|
||||||
main_arm 0 0 112
|
right_arm 0 0 112
|
||||||
main_arm 0 0 96
|
right_arm 0 0 96
|
||||||
main_arm 0 0 80
|
right_arm 0 0 80
|
||||||
main_arm 0 0 64
|
right_arm 0 0 64
|
||||||
main_arm 0 0 48
|
right_arm 0 0 48
|
||||||
main_arm 0 0 32
|
right_arm 0 0 32
|
||||||
main_arm 0 0 16
|
right_arm 0 0 16
|
||||||
main_arm 0 0 0
|
right_arm 0 0 0
|
|
@ -6,9 +6,8 @@
|
||||||
"ArmorStandEntityAccessor",
|
"ArmorStandEntityAccessor",
|
||||||
"DataTrackerAccessor",
|
"DataTrackerAccessor",
|
||||||
"EntityAccessor",
|
"EntityAccessor",
|
||||||
|
"EntityEquipmentUpdateS2CPacketAccessor",
|
||||||
"EntityTrackerUpdateS2CPacketAccessor",
|
"EntityTrackerUpdateS2CPacketAccessor",
|
||||||
"MixinEntityTrackerEntry",
|
|
||||||
"MixinLivingEntity",
|
|
||||||
"MixinMobSpawnS2CPacket",
|
"MixinMobSpawnS2CPacket",
|
||||||
"MixinServerPlayerEntity",
|
"MixinServerPlayerEntity",
|
||||||
"MixinServerPlayNetworkHandler",
|
"MixinServerPlayNetworkHandler",
|
||||||
|
|
Reference in New Issue
Block a user