firtana
This commit is contained in:
@@ -18,8 +18,12 @@ import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreens;
|
||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||
import net.minecraft.client.network.OtherClientPlayerEntity;
|
||||
import net.minecraft.client.option.KeyBinding;
|
||||
import net.minecraft.client.render.entity.EntityRenderer;
|
||||
import net.minecraft.client.render.entity.FlyingItemEntityRenderer;
|
||||
import net.minecraft.client.render.entity.PlayerEntityRenderer;
|
||||
import net.minecraft.client.render.entity.animation.Animation;
|
||||
import net.minecraft.client.render.entity.model.EntityModelLayer;
|
||||
import net.minecraft.client.render.item.BuiltinModelItemRenderer;
|
||||
@@ -33,6 +37,7 @@ import net.minecraft.client.render.*;
|
||||
import net.minecraft.client.util.ModelIdentifier;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
@@ -56,6 +61,7 @@ import static dev.tggamesyt.szar.client.ClientCosmetics.loadTextureFromURL;
|
||||
import static dev.tggamesyt.szar.client.UraniumUtils.updateUranium;
|
||||
|
||||
public class SzarClient implements ClientModInitializer {
|
||||
private static boolean addedFeature = false;
|
||||
private static final Map<KeyBinding, KeyBinding> activeScramble = new HashMap<>();
|
||||
public static final EntityModelLayer PLANE =
|
||||
new EntityModelLayer(
|
||||
@@ -82,6 +88,17 @@ public class SzarClient implements ClientModInitializer {
|
||||
int loopStart = startOffset + startLength;
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
ClientPlayNetworking.registerGlobalReceiver(Szar.PLAY_VIDEO,
|
||||
(client, handler, buf, responseSender) -> {
|
||||
String player = buf.readString();
|
||||
client.execute(() -> {
|
||||
VideoManager.startVideo(player);
|
||||
});
|
||||
|
||||
});
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
VideoManager.tick();
|
||||
});
|
||||
ModelLoadingRegistry.INSTANCE.registerModelProvider((manager, out) -> {
|
||||
ThirdpersonModelRegisterer.getAll().forEach((itemId, modelId) -> {
|
||||
out.accept(new ModelIdentifier(modelId, "inventory"));
|
||||
@@ -424,7 +441,19 @@ public class SzarClient implements ClientModInitializer {
|
||||
(dispatcher, registryAccess) -> PanoramaClientCommand.register(dispatcher)
|
||||
);
|
||||
}
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
if (addedFeature) return; // only run once
|
||||
MinecraftClient mc = MinecraftClient.getInstance();
|
||||
if (mc.getEntityRenderDispatcher() == null) return;
|
||||
|
||||
for (EntityRenderer<?> renderer : mc.getEntityRenderDispatcher().renderers.values()) {
|
||||
if (renderer instanceof PlayerEntityRenderer playerRenderer) {
|
||||
playerRenderer.addFeature(new VideoHeadFeature(playerRenderer));
|
||||
}
|
||||
}
|
||||
|
||||
addedFeature = true; // prevent running again
|
||||
});
|
||||
}
|
||||
private boolean isDebugEnabled() {
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package dev.tggamesyt.szar.client;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.entity.PlayerEntityRenderer;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
public class VideoHeadFeature extends FeatureRenderer<AbstractClientPlayerEntity, PlayerEntityModel<AbstractClientPlayerEntity>> {
|
||||
|
||||
private final PlayerEntityRenderer renderer;
|
||||
|
||||
public VideoHeadFeature(PlayerEntityRenderer renderer) {
|
||||
super(renderer);
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light,
|
||||
AbstractClientPlayerEntity player, float limbAngle, float limbDistance,
|
||||
float tickDelta, float animationProgress, float headYaw, float headPitch) {
|
||||
|
||||
// Only render if the player is playing a video
|
||||
if (!VideoManager.isPlaying(player.getUuid())) return;
|
||||
|
||||
Identifier frame = VideoManager.getCurrentFrame(player.getUuid());
|
||||
if (frame == null) return;
|
||||
|
||||
matrices.push();
|
||||
|
||||
// Rotate to match the head
|
||||
this.getContextModel().head.rotate(matrices);
|
||||
|
||||
// Position quad slightly in front of the face
|
||||
float size = 0.5f;
|
||||
matrices.translate(-size / 2f, -size / 2f, -0.25f);
|
||||
|
||||
// Render the video frame
|
||||
VertexConsumer vc = vertexConsumers.getBuffer(RenderLayer.getEntityCutoutNoCull(frame));
|
||||
Matrix4f matrix = matrices.peek().getPositionMatrix();
|
||||
|
||||
vc.vertex(matrix, 0, 0, 0).texture(0, 1).light(light).next();
|
||||
vc.vertex(matrix, size, 0, 0).texture(1, 1).light(light).next();
|
||||
vc.vertex(matrix, size, size, 0).texture(1, 0).light(light).next();
|
||||
vc.vertex(matrix, 0, size, 0).texture(0, 0).light(light).next();
|
||||
|
||||
matrices.pop();
|
||||
}
|
||||
}
|
||||
169
src/client/java/dev/tggamesyt/szar/client/VideoManager.java
Normal file
169
src/client/java/dev/tggamesyt/szar/client/VideoManager.java
Normal file
@@ -0,0 +1,169 @@
|
||||
package dev.tggamesyt.szar.client;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.client.sound.PositionedSoundInstance;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static dev.tggamesyt.szar.Szar.MOD_ID;
|
||||
|
||||
public class VideoManager {
|
||||
|
||||
private static final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
private static final int TOTAL_FRAMES = 193;
|
||||
private static final int TICKS_PER_FRAME = 1;
|
||||
|
||||
private static final Map<UUID, VideoInstance> activeVideos = new HashMap<>();
|
||||
|
||||
private static final List<Identifier> FRAMES = new ArrayList<>();
|
||||
|
||||
|
||||
/*
|
||||
* Load frames (call once during client init)
|
||||
*/
|
||||
public static void init() {
|
||||
|
||||
if (!FRAMES.isEmpty()) return;
|
||||
|
||||
for (int i = 0; i < TOTAL_FRAMES; i++) {
|
||||
String frame = String.format("textures/video/frame_%03d.png", i);
|
||||
FRAMES.add(new Identifier(MOD_ID, frame));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Start playing the video on a player
|
||||
*/
|
||||
public static void startVideo(String playerUuid) {
|
||||
|
||||
if (client.world == null) return;
|
||||
|
||||
UUID uuid = UUID.fromString(playerUuid);
|
||||
|
||||
activeVideos.put(uuid, new VideoInstance(uuid));
|
||||
|
||||
playSound(uuid);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Tick method (call every client tick)
|
||||
*/
|
||||
public static void tick() {
|
||||
|
||||
if (activeVideos.isEmpty()) return;
|
||||
|
||||
Iterator<Map.Entry<UUID, VideoInstance>> iterator = activeVideos.entrySet().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
|
||||
VideoInstance instance = iterator.next().getValue();
|
||||
|
||||
instance.tick();
|
||||
|
||||
if (instance.finished()) {
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check if a player currently has a video playing
|
||||
*/
|
||||
public static boolean isPlaying(UUID player) {
|
||||
return activeVideos.containsKey(player);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get current frame texture for player
|
||||
*/
|
||||
public static Identifier getCurrentFrame(UUID player) {
|
||||
|
||||
VideoInstance instance = activeVideos.get(player);
|
||||
|
||||
if (instance == null) return null;
|
||||
|
||||
int frameIndex = instance.frame;
|
||||
|
||||
if (frameIndex >= FRAMES.size()) return null;
|
||||
|
||||
return FRAMES.get(frameIndex);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Play sound from the player's location
|
||||
*/
|
||||
private static void playSound(UUID playerUuid) {
|
||||
|
||||
ClientWorld world = client.world;
|
||||
|
||||
if (world == null) return;
|
||||
|
||||
var player = world.getPlayerByUuid(playerUuid);
|
||||
|
||||
if (player == null) return;
|
||||
|
||||
Identifier soundId = new Identifier(MOD_ID, "firtana");
|
||||
SoundEvent soundEvent = SoundEvent.of(soundId);
|
||||
|
||||
client.getSoundManager().play(
|
||||
new PositionedSoundInstance(
|
||||
soundEvent,
|
||||
SoundCategory.PLAYERS,
|
||||
1.0f, // volume
|
||||
1.0f, // pitch
|
||||
player.getRandom(),
|
||||
player.getX(),
|
||||
player.getY(),
|
||||
player.getZ()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Video instance for each player
|
||||
*/
|
||||
private static class VideoInstance {
|
||||
|
||||
UUID player;
|
||||
int frame = 0;
|
||||
int tickCounter = 0;
|
||||
|
||||
VideoInstance(UUID player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
void tick() {
|
||||
|
||||
tickCounter++;
|
||||
|
||||
if (tickCounter >= TICKS_PER_FRAME) {
|
||||
|
||||
frame++;
|
||||
tickCounter = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
boolean finished() {
|
||||
return frame >= TOTAL_FRAMES;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user