Update to MC 1.14 / Fabric
This commit is contained in:
@@ -12,6 +12,7 @@ import com.replaymod.replaystudio.replay.ReplayFile;
|
||||
import com.replaymod.replaystudio.studio.ReplayStudio;
|
||||
import com.replaymod.replaystudio.studio.protocol.StudioCodec;
|
||||
import com.replaymod.replaystudio.studio.protocol.StudioSession;
|
||||
import de.johni0702.minecraft.gui.utils.EventRegistrations;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
@@ -22,30 +23,44 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.EntityOtherPlayerMP;
|
||||
import net.minecraft.client.gui.GuiDownloadTerrain;
|
||||
import net.minecraft.client.gui.GuiErrorScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.network.*;
|
||||
import net.minecraft.network.EnumConnectionState;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.network.login.server.SPacketLoginSuccess;
|
||||
import net.minecraft.network.play.server.*;
|
||||
import net.minecraft.util.Timer;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.world.EnumDifficulty;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldType;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback;
|
||||
//$$ import net.minecraft.entity.EntityType;
|
||||
//$$ import net.minecraft.text.TranslatableTextComponent;
|
||||
//#else
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.EnumDifficulty;
|
||||
import net.minecraft.world.WorldType;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
//#endif
|
||||
|
||||
//#if MC>=11300
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
//#if MC<11400
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
//#if MC>=11200
|
||||
import com.replaymod.core.utils.WrappedTimer;
|
||||
@@ -56,14 +71,14 @@ import net.minecraft.world.GameType;
|
||||
//$$ import net.minecraft.world.WorldSettings.GameType;
|
||||
//#endif
|
||||
|
||||
//#if MC<10800
|
||||
//#if MC>=10800
|
||||
import net.minecraft.network.EnumPacketDirection;
|
||||
//#else
|
||||
//$$ import org.apache.commons.io.Charsets;
|
||||
//#endif
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -80,6 +95,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
* These packets are ignored completely during replay.
|
||||
*/
|
||||
private static final List<Class> BAD_PACKETS = Arrays.<Class>asList(
|
||||
//#if MC>=11400
|
||||
//$$ OpenWrittenBookS2CPacket.class,
|
||||
//#endif
|
||||
//#if MC>=11200
|
||||
SPacketRecipeBook.class,
|
||||
SPacketAdvancementInfo.class,
|
||||
@@ -215,6 +233,8 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
*/
|
||||
private final File tempResourcePackFolder = Files.createTempDir();
|
||||
|
||||
private final EventHandler events = new EventHandler();
|
||||
|
||||
/**
|
||||
* Create a new replay sender.
|
||||
* @param file The replay file
|
||||
@@ -227,7 +247,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
this.asyncMode = asyncMode;
|
||||
this.replayLength = file.getMetaData().getDuration();
|
||||
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
events.register();
|
||||
|
||||
if (asyncMode) {
|
||||
new Thread(asyncSender, "replaymod-async-sender").start();
|
||||
@@ -293,7 +313,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
*/
|
||||
public void terminateReplay() {
|
||||
terminate = true;
|
||||
MinecraftForge.EVENT_BUS.unregister(this);
|
||||
events.unregister();
|
||||
try {
|
||||
channelInactive(ctx);
|
||||
ctx.channel().pipeline().close();
|
||||
@@ -303,24 +323,31 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onWorldTick(TickEvent.ClientTickEvent event) {
|
||||
// Unfortunately the WorldTickEvent doesn't seem to be emitted on the CLIENT side
|
||||
if (event.phase != TickEvent.Phase.START) return;
|
||||
class EventHandler extends EventRegistrations {
|
||||
//#if MC>=11400
|
||||
//$$ { on(PreTickCallback.EVENT, this::onWorldTick); }
|
||||
//$$ private void onWorldTick() {
|
||||
//#else
|
||||
@SubscribeEvent
|
||||
public void onWorldTick(TickEvent.ClientTickEvent event) {
|
||||
// Unfortunately the WorldTickEvent doesn't seem to be emitted on the CLIENT side
|
||||
if (event.phase != TickEvent.Phase.START) return;
|
||||
//#endif
|
||||
|
||||
// Spawning a player into an empty chunk (which we might do with the recording player)
|
||||
// prevents it from being moved by teleport packets (it essentially gets stuck) because
|
||||
// Entity#addedToChunk is not set and it is therefore not updated every tick.
|
||||
// To counteract this, we need to manually update it's position if it hasn't been added
|
||||
// to any chunk yet.
|
||||
if (mc.world != null) {
|
||||
for (EntityPlayer playerEntity : playerEntities(mc.world)) {
|
||||
if (!playerEntity.addedToChunk && playerEntity instanceof EntityOtherPlayerMP) {
|
||||
// Spawning a player into an empty chunk (which we might do with the recording player)
|
||||
// prevents it from being moved by teleport packets (it essentially gets stuck) because
|
||||
// Entity#addedToChunk is not set and it is therefore not updated every tick.
|
||||
// To counteract this, we need to manually update it's position if it hasn't been added
|
||||
// to any chunk yet.
|
||||
if (mc.world != null) {
|
||||
for (EntityPlayer playerEntity : playerEntities(mc.world)) {
|
||||
if (!playerEntity.addedToChunk && playerEntity instanceof EntityOtherPlayerMP) {
|
||||
//#if MC>=11300
|
||||
playerEntity.livingTick();
|
||||
//#else
|
||||
//$$ playerEntity.onLivingUpdate();
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,9 +387,14 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
|| p instanceof SPacketSpawnPainting
|
||||
|| p instanceof SPacketSpawnExperienceOrb
|
||||
|| p instanceof SPacketDestroyEntities) {
|
||||
World world = mc.world;
|
||||
for (int i = 0; i < world.loadedEntityList.size(); ++i) {
|
||||
Entity entity = loadedEntityList(world).get(i);
|
||||
WorldClient world = mc.world;
|
||||
//#if MC>=11400
|
||||
//$$ // Note: Not sure if it's still required but there's this really handy method anyway
|
||||
//$$ world.finishRemovingEntities();
|
||||
//#else
|
||||
Iterator<Entity> iter = loadedEntityList(world).iterator();
|
||||
while (iter.hasNext()) {
|
||||
Entity entity = iter.next();
|
||||
if (entity.removed) {
|
||||
int chunkX = entity.chunkCoordX;
|
||||
int chunkY = entity.chunkCoordZ;
|
||||
@@ -379,11 +411,12 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
world.getChunk(chunkX, chunkY).removeEntity(entity);
|
||||
}
|
||||
|
||||
world.loadedEntityList.remove(i--);
|
||||
iter.remove();
|
||||
world.onEntityRemoved(entity);
|
||||
}
|
||||
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -433,19 +466,22 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
// Failed to parse options, make sure that under no circumstances further packets are parsed
|
||||
terminateReplay();
|
||||
// Then end replay and show error GUI
|
||||
mc.addScheduledTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
replayHandler.endReplay();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mc.displayGuiScreen(new GuiErrorScreen(
|
||||
I18n.format("replaymod.error.unknownrestriction1"),
|
||||
I18n.format("replaymod.error.unknownrestriction2", unknown)
|
||||
));
|
||||
ReplayMod.instance.runLater(() -> {
|
||||
try {
|
||||
replayHandler.endReplay();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mc.displayGuiScreen(new GuiErrorScreen(
|
||||
//#if MC>=11400
|
||||
//$$ () -> {},
|
||||
//$$ new TranslatableTextComponent("replaymod.error.unknownrestriction1"),
|
||||
//$$ new TranslatableTextComponent("replaymod.error.unknownrestriction2", unknown)
|
||||
//#else
|
||||
I18n.format("replaymod.error.unknownrestriction1"),
|
||||
I18n.format("replaymod.error.unknownrestriction2", unknown)
|
||||
//#endif
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -469,6 +505,8 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
//#else
|
||||
//$$ String channelName = packet.getChannelName();
|
||||
//#endif
|
||||
// On 1.14+ there's a dedicated OpenWrittenBookS2CPacket now
|
||||
//#if MC<11400
|
||||
//#if MC>=11300
|
||||
if (SPacketCustomPayload.BOOK_OPEN.equals(channelName)) {
|
||||
//#else
|
||||
@@ -476,6 +514,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
//#endif
|
||||
return null;
|
||||
}
|
||||
//#endif
|
||||
//#if MC>=10800
|
||||
}
|
||||
|
||||
@@ -510,6 +549,18 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
allowMovement = true;
|
||||
actualID = entId;
|
||||
entId = -1789435; // Camera entity id should be negative which is an invalid id and can't be used by servers
|
||||
//#if MC>=11400
|
||||
//$$ p = new GameJoinS2CPacket(
|
||||
//$$ entId,
|
||||
//$$ GameMode.SPECTATOR,
|
||||
//$$ false,
|
||||
//$$ packet.getDimension(),
|
||||
//$$ 0, // max players (has no getter -> never actually used)
|
||||
//$$ packet.getGeneratorType(),
|
||||
//$$ packet.getChunkLoadDistance(),
|
||||
//$$ packet.hasReducedDebugInfo()
|
||||
//$$ );
|
||||
//#else
|
||||
//#if MC>=10800
|
||||
//#if MC>=11300
|
||||
DimensionType dimension = packet.func_212642_e();
|
||||
@@ -540,10 +591,14 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
//$$ p = new S01PacketJoinGame(entId, GameType.ADVENTURE, false, dimension,
|
||||
//$$ difficulty, maxPlayers, worldType);
|
||||
//#endif
|
||||
//#endif
|
||||
}
|
||||
|
||||
if(p instanceof SPacketRespawn) {
|
||||
SPacketRespawn respawn = (SPacketRespawn) p;
|
||||
//#if MC>=11400
|
||||
//$$ p = new PlayerRespawnS2CPacket(respawn.getDimension(), respawn.getGeneratorType(), GameMode.SPECTATOR);
|
||||
//#else
|
||||
//#if MC>=10809
|
||||
p = new SPacketRespawn(respawn.func_212643_b(),
|
||||
respawn.getDifficulty(), respawn.getWorldType(), GameType.SPECTATOR);
|
||||
@@ -556,6 +611,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
//$$ GameType.ADVENTURE);
|
||||
//#endif
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
allowMovement = true;
|
||||
}
|
||||
@@ -605,7 +661,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void run() {
|
||||
if (mc.world == null || !mc.isCallingFromMinecraftThread()) {
|
||||
if (mc.world == null || !isOnMainThread()) {
|
||||
ReplayMod.instance.runLater(this);
|
||||
return;
|
||||
}
|
||||
@@ -878,10 +934,14 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
|
||||
if(p instanceof SPacketSpawnObject) {
|
||||
SPacketSpawnObject pso = (SPacketSpawnObject)p;
|
||||
//#if MC>=11400
|
||||
//$$ if (pso.getEntityTypeId() == EntityType.FIREWORK_ROCKET) return null;
|
||||
//#else
|
||||
int type = pso.getType();
|
||||
if(type == 76) { // Firework rocket
|
||||
return null;
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
return p;
|
||||
@@ -994,6 +1054,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
World world = mc.world;
|
||||
IChunkProvider chunkProvider = world.getChunkProvider();
|
||||
// Get the chunk that will be unloaded
|
||||
//#if MC>=11400
|
||||
//$$ // FIXME fabric
|
||||
//#else
|
||||
//#if MC>=11300
|
||||
Chunk chunk = chunkProvider.provideChunk(x, z, false, false);
|
||||
//#else
|
||||
@@ -1062,6 +1125,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
|
||||
}
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
return p; // During synchronous playback everything is sent normally
|
||||
}
|
||||
|
||||
@@ -43,7 +43,12 @@ public class InputReplayTimer extends WrappedTimer {
|
||||
|
||||
@Override
|
||||
//#if MC>=11300
|
||||
//#if MC>=11400
|
||||
//$$ // FIXME this should be handled by the preprocessor but there seems to be a bug
|
||||
//$$ public void beginRenderTick(long sysClock) {
|
||||
//#else
|
||||
public void updateTimer(long sysClock) {
|
||||
//#endif
|
||||
super.updateTimer(sysClock);
|
||||
//#else
|
||||
//$$ public void updateTimer() {
|
||||
|
||||
@@ -2,9 +2,8 @@ package com.replaymod.replay;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListenableFutureTask;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import com.replaymod.core.mixin.MinecraftAccessor;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.core.versions.MCVer;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
@@ -18,8 +17,6 @@ import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
@@ -49,7 +46,12 @@ public class NoGuiScreenshot {
|
||||
|
||||
// Render frame without GUI
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.clear(16640);
|
||||
GlStateManager.clear(
|
||||
16640
|
||||
//#if MC>=11400
|
||||
//$$ , true
|
||||
//#endif
|
||||
);
|
||||
mc.getFramebuffer().bindFramebuffer(true);
|
||||
GlStateManager.enableTexture2D();
|
||||
|
||||
@@ -84,7 +86,7 @@ public class NoGuiScreenshot {
|
||||
try {
|
||||
//#if MC>=11300
|
||||
ScreenShotHelper.saveScreenshot(tmpFolder, "tmp", frameWidth, frameHeight, mc.getFramebuffer(), (msg) ->
|
||||
mc.addScheduledTask(() -> mc.ingameGUI.getChatGUI().printChatMessage(msg)));
|
||||
ReplayMod.instance.runLater(() -> mc.ingameGUI.getChatGUI().printChatMessage(msg)));
|
||||
//#else
|
||||
//$$ ScreenShotHelper.saveScreenshot(tmpFolder, "tmp", frameWidth, frameHeight, mc.getFramebuffer());
|
||||
//#endif
|
||||
@@ -121,11 +123,7 @@ public class NoGuiScreenshot {
|
||||
// Make sure we are not somewhere in the middle of the rendering process but always at the beginning
|
||||
// of the game loop. We cannot use the addScheduledTask method as it'll run the task if called
|
||||
// from the minecraft thread which is exactly what we want to avoid.
|
||||
Queue<FutureTask<?>> scheduledTasks = ((MinecraftAccessor) mc).getScheduledTasks();
|
||||
//noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||
synchronized (scheduledTasks) {
|
||||
scheduledTasks.add(ListenableFutureTask.create(runnable, null));
|
||||
}
|
||||
ReplayMod.instance.runLater(runnable);
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import com.github.steveice10.mc.protocol.data.game.chunk.BlockStorage;
|
||||
import com.github.steveice10.mc.protocol.data.game.chunk.Column;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.WorldType;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockChangeRecord;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||
@@ -52,6 +51,7 @@ import com.replaymod.replaystudio.replay.ReplayFile;
|
||||
import com.replaymod.replaystudio.studio.ReplayStudio;
|
||||
import com.replaymod.replaystudio.util.Location;
|
||||
import com.replaymod.replaystudio.util.PacketUtils;
|
||||
import de.johni0702.minecraft.gui.utils.EventRegistrations;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufOutputStream;
|
||||
import io.netty.buffer.Unpooled;
|
||||
@@ -63,9 +63,17 @@ import net.minecraft.network.EnumConnectionState;
|
||||
import net.minecraft.network.EnumPacketDirection;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback;
|
||||
//#else
|
||||
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
|
||||
import static com.replaymod.core.versions.MCVer.FML_BUS;
|
||||
//#endif
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -90,7 +98,6 @@ import java.util.zip.Inflater;
|
||||
import com.replaymod.core.utils.WrappedTimer;
|
||||
//#endif
|
||||
|
||||
import static com.replaymod.core.versions.MCVer.FML_BUS;
|
||||
import static com.replaymod.core.versions.MCVer.getMinecraft;
|
||||
import static com.replaymod.replay.ReplayModReplay.LOGGER;
|
||||
|
||||
@@ -110,6 +117,7 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe
|
||||
|
||||
private final ReplayModReplay mod;
|
||||
private final ReplayFile replayFile;
|
||||
private final EventHandler eventHandler = new EventHandler();
|
||||
private ChannelHandlerContext ctx;
|
||||
|
||||
private int currentTimeStamp;
|
||||
@@ -140,11 +148,11 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe
|
||||
}
|
||||
|
||||
public void register() {
|
||||
FML_BUS.register(this);
|
||||
eventHandler.register();
|
||||
}
|
||||
|
||||
public void unregister() {
|
||||
FML_BUS.unregister(this);
|
||||
eventHandler.unregister();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -205,7 +213,14 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe
|
||||
public void restart() {
|
||||
activeThings.clear();
|
||||
currentTimeStamp = 0;
|
||||
ctx.fireChannelRead(toMC(new ServerRespawnPacket(0, Difficulty.NORMAL, GameMode.SPECTATOR, WorldType.DEFAULT)));
|
||||
ctx.fireChannelRead(toMC(new ServerRespawnPacket(
|
||||
0,
|
||||
//#if MC<11400
|
||||
Difficulty.NORMAL,
|
||||
//#endif
|
||||
GameMode.SPECTATOR,
|
||||
WorldType.DEFAULT
|
||||
)));
|
||||
ctx.fireChannelRead(toMC(new ServerPlayerPositionRotationPacket(0, 0, 0, 0, 0, 0)));
|
||||
}
|
||||
|
||||
@@ -262,16 +277,23 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe
|
||||
sendPacketsTill(value);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onTick(TickEvent.ClientTickEvent event) {
|
||||
if (event.phase != TickEvent.Phase.START) return;
|
||||
if (!asyncMode) return;
|
||||
private class EventHandler extends EventRegistrations {
|
||||
//#if MC>=11400
|
||||
//$$ { on(PreTickCallback.EVENT, this::onTick); }
|
||||
//$$ private void onTick() {
|
||||
//#else
|
||||
@SubscribeEvent
|
||||
public void onTick(TickEvent.ClientTickEvent event) {
|
||||
if (event.phase != TickEvent.Phase.START) return;
|
||||
//#endif
|
||||
if (!asyncMode) return;
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
long realTimePassed = now - lastAsyncUpdateTime;
|
||||
lastAsyncUpdateTime = now;
|
||||
int replayTimePassed = (int) (realTimePassed * replaySpeed);
|
||||
sendPacketsTill(currentTimeStamp + replayTimePassed);
|
||||
long now = System.currentTimeMillis();
|
||||
long realTimePassed = now - lastAsyncUpdateTime;
|
||||
lastAsyncUpdateTime = now;
|
||||
int replayTimePassed = (int) (realTimePassed * replaySpeed);
|
||||
sendPacketsTill(currentTimeStamp + replayTimePassed);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryLoadFromCache(Consumer<Double> progress) throws IOException {
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.core.mixin.MinecraftAccessor;
|
||||
import com.replaymod.core.mixin.TimerAccessor;
|
||||
import com.replaymod.core.utils.Restrictions;
|
||||
@@ -11,8 +12,9 @@ import com.replaymod.core.utils.Utils;
|
||||
import com.replaymod.core.utils.WrappedTimer;
|
||||
import com.replaymod.replay.camera.CameraEntity;
|
||||
import com.replaymod.replay.camera.SpectatorCameraController;
|
||||
import com.replaymod.replay.events.ReplayCloseEvent;
|
||||
import com.replaymod.replay.events.ReplayOpenEvent;
|
||||
import com.replaymod.replay.events.ReplayClosedCallback;
|
||||
import com.replaymod.replay.events.ReplayClosingCallback;
|
||||
import com.replaymod.replay.events.ReplayOpenedCallback;
|
||||
import com.replaymod.replay.gui.overlay.GuiReplayOverlay;
|
||||
import com.replaymod.replay.mixin.EntityLivingBaseAccessor;
|
||||
import com.replaymod.replaystudio.data.Marker;
|
||||
@@ -52,6 +54,8 @@ import net.minecraft.entity.EntityLivingBase;
|
||||
|
||||
//#if MC>=10800
|
||||
import net.minecraft.network.EnumPacketDirection;
|
||||
//#if MC>=11400
|
||||
//#else
|
||||
//#if MC>=11300
|
||||
import net.minecraftforge.fml.network.NetworkHooks;
|
||||
//#else
|
||||
@@ -60,6 +64,7 @@ import net.minecraftforge.fml.network.NetworkHooks;
|
||||
//$$ import net.minecraftforge.fml.client.FMLClientHandler;
|
||||
//$$ import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
|
||||
//#endif
|
||||
//#endif
|
||||
//#else
|
||||
//$$ import cpw.mods.fml.common.Loader;
|
||||
//$$ import cpw.mods.fml.common.network.internal.FMLNetworkHandler;
|
||||
@@ -127,13 +132,11 @@ public class ReplayHandler {
|
||||
private UUID spectating;
|
||||
|
||||
public ReplayHandler(ReplayFile replayFile, boolean asyncMode) throws IOException {
|
||||
Preconditions.checkState(mc.isCallingFromMinecraftThread(), "Must be called from Minecraft thread.");
|
||||
Preconditions.checkState(isOnMainThread(), "Must be called from Minecraft thread.");
|
||||
this.replayFile = replayFile;
|
||||
|
||||
replayDuration = replayFile.getMetaData().getDuration();
|
||||
|
||||
FML_BUS.post(new ReplayOpenEvent.Pre(this));
|
||||
|
||||
markers = replayFile.getMarkers().or(Collections.emptySet());
|
||||
|
||||
fullReplaySender = new FullReplaySender(this, replayFile, false);
|
||||
@@ -146,7 +149,7 @@ public class ReplayHandler {
|
||||
overlay = new GuiReplayOverlay(this);
|
||||
overlay.setVisible(true);
|
||||
|
||||
FML_BUS.post(new ReplayOpenEvent.Post(this));
|
||||
ReplayOpenedCallback.EVENT.invoker().replayOpened(this);
|
||||
|
||||
fullReplaySender.setAsyncMode(asyncMode);
|
||||
}
|
||||
@@ -155,7 +158,7 @@ public class ReplayHandler {
|
||||
channel.close();
|
||||
|
||||
// Force re-creation of camera entity by unloading the previous world
|
||||
mc.addScheduledTask(() -> {
|
||||
ReplayMod.instance.runLater(() -> {
|
||||
//#if MC>=11300
|
||||
mc.mouseHelper.ungrabMouse();
|
||||
//#else
|
||||
@@ -170,13 +173,15 @@ public class ReplayHandler {
|
||||
}
|
||||
|
||||
public void endReplay() throws IOException {
|
||||
Preconditions.checkState(mc.isCallingFromMinecraftThread(), "Must be called from Minecraft thread.");
|
||||
Preconditions.checkState(isOnMainThread(), "Must be called from Minecraft thread.");
|
||||
|
||||
FML_BUS.post(new ReplayCloseEvent.Pre(this));
|
||||
ReplayClosingCallback.EVENT.invoker().replayClosing(this);
|
||||
|
||||
fullReplaySender.terminateReplay();
|
||||
//#if MC>=10904
|
||||
quickReplaySender.unregister();
|
||||
if (quickMode) {
|
||||
quickReplaySender.unregister();
|
||||
}
|
||||
//#endif
|
||||
|
||||
replayFile.save();
|
||||
@@ -209,7 +214,7 @@ public class ReplayHandler {
|
||||
|
||||
mc.displayGuiScreen(null);
|
||||
|
||||
FML_BUS.post(new ReplayCloseEvent.Post(this));
|
||||
ReplayClosedCallback.EVENT.invoker().replayClosed(this);
|
||||
}
|
||||
|
||||
private void setup() {
|
||||
@@ -235,7 +240,9 @@ public class ReplayHandler {
|
||||
channel.pipeline().fireChannelActive();
|
||||
|
||||
networkManager.setNetHandler(new NetHandlerLoginClient(networkManager, mc, null, it -> {}));
|
||||
//#if MC<11400
|
||||
NetworkHooks.registerClientLoginChannel(networkManager);
|
||||
//#endif
|
||||
// FIXME make this work (with vanilla and mods) on all other versions again, now that login phase is included
|
||||
// probably have to change some of the forge handshake calls
|
||||
//#else
|
||||
@@ -572,7 +579,11 @@ public class ReplayHandler {
|
||||
replaySender.jumpToTime(targetTime);
|
||||
} else { // We either have to restart the replay or send a significant amount of packets
|
||||
// Render our please-wait-screen
|
||||
GuiScreen guiScreen = new GuiScreen() {
|
||||
GuiScreen guiScreen = new GuiScreen(
|
||||
//#if MC>=11400
|
||||
//$$ null
|
||||
//#endif
|
||||
) {
|
||||
@Override
|
||||
//#if MC>=11300
|
||||
public void render(int mouseX, int mouseY, float partialTicks) {
|
||||
@@ -590,14 +601,22 @@ public class ReplayHandler {
|
||||
|
||||
// Perform the rendering using OpenGL
|
||||
pushMatrix();
|
||||
clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
|
||||
//#if MC>=11400
|
||||
//$$ , true
|
||||
//#endif
|
||||
);
|
||||
enableTexture2D();
|
||||
mc.getFramebuffer().bindFramebuffer(true);
|
||||
//#if MC>=11400
|
||||
//$$ mc.window.method_4493(true);
|
||||
//#else
|
||||
//#if MC>=11300
|
||||
mc.mainWindow.setupOverlayRendering();
|
||||
//#else
|
||||
//$$ mc.entityRenderer.setupOverlayRendering();
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
//#if MC>=11300
|
||||
MainWindow
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.replaymod.replay.camera;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.core.events.SettingsChangedEvent;
|
||||
import com.replaymod.core.SettingsRegistry;
|
||||
import com.replaymod.core.events.SettingsChangedCallback;
|
||||
import de.johni0702.minecraft.gui.utils.EventRegistrations;
|
||||
import com.replaymod.core.utils.Utils;
|
||||
import com.replaymod.core.versions.MCVer;
|
||||
import com.replaymod.replay.ReplayModReplay;
|
||||
import com.replaymod.replay.Setting;
|
||||
import com.replaymod.replay.events.ReplayChatMessageEvent;
|
||||
import com.replaymod.replay.mixin.FirstPersonRendererAccessor;
|
||||
import com.replaymod.replaystudio.util.Location;
|
||||
import lombok.Getter;
|
||||
@@ -21,6 +21,22 @@ import net.minecraft.entity.item.EntityItemFrame;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ import com.replaymod.core.events.KeyBindingEventCallback;
|
||||
//$$ import com.replaymod.core.events.PreRenderCallback;
|
||||
//$$ import com.replaymod.core.events.PreRenderHandCallback;
|
||||
//$$ import com.replaymod.replay.events.RenderSpectatorCrosshairCallback;
|
||||
//$$ import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback;
|
||||
//$$ import net.fabricmc.fabric.api.util.TriState;
|
||||
//$$ import net.minecraft.client.world.ClientWorld;
|
||||
//$$ import net.minecraft.fluid.Fluid;
|
||||
//$$ import net.minecraft.tag.Tag;
|
||||
//$$ import net.minecraft.util.hit.BlockHitResult;
|
||||
//$$ import net.minecraft.util.hit.HitResult;
|
||||
//#else
|
||||
import com.replaymod.core.versions.MCVer;
|
||||
import com.replaymod.replay.events.ReplayChatMessageEvent;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.world.World;
|
||||
@@ -38,6 +54,7 @@ import net.minecraft.util.math.RayTraceFluidMode;
|
||||
//$$ import net.minecraft.block.material.Material;
|
||||
//$$ import net.minecraft.entity.EntityLivingBase;
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
//#if MC>=10904
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
@@ -104,7 +121,11 @@ public class CameraEntity
|
||||
private final EventHandler eventHandler = new EventHandler();
|
||||
|
||||
//#if MC>=11300
|
||||
//#if MC>=11400
|
||||
//$$ public CameraEntity(MinecraftClient mcIn, ClientWorld worldIn, ClientPlayNetworkHandler netHandlerPlayClient, StatHandler statisticsManager, ClientRecipeBook recipeBookClient) {
|
||||
//#else
|
||||
public CameraEntity(Minecraft mcIn, World worldIn, NetHandlerPlayClient netHandlerPlayClient, StatisticsManager statisticsManager, RecipeBookClient recipeBookClient) {
|
||||
//#endif
|
||||
super(mcIn, worldIn, netHandlerPlayClient, statisticsManager, recipeBookClient);
|
||||
//#else
|
||||
//#if MC>=11200
|
||||
@@ -125,8 +146,7 @@ public class CameraEntity
|
||||
//#endif
|
||||
//#endif
|
||||
//#endif
|
||||
FORGE_BUS.register(eventHandler);
|
||||
FML_BUS.register(eventHandler);
|
||||
eventHandler.register();
|
||||
if (ReplayModReplay.instance.getReplayHandler().getSpectatedUUID() == null) {
|
||||
cameraController = ReplayModReplay.instance.createCameraController(this);
|
||||
} else {
|
||||
@@ -141,7 +161,7 @@ public class CameraEntity
|
||||
* @param z Delta in Z direction
|
||||
*/
|
||||
public void moveCamera(double x, double y, double z) {
|
||||
setCameraPosition(posX + x, posY + y, posZ + z);
|
||||
setCameraPosition(this.posX + x, this.posY + y, this.posZ + z);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,23 +209,27 @@ public class CameraEntity
|
||||
//#else
|
||||
//$$ float yOffset = 1.62f; // Magic value (eye height) from EntityRenderer#orientCamera
|
||||
//#endif
|
||||
prevPosX = to.prevPosX;
|
||||
prevPosY = to.prevPosY + yOffset;
|
||||
prevPosZ = to.prevPosZ;
|
||||
prevRotationYaw = to.prevRotationYaw;
|
||||
prevRotationPitch = to.prevRotationPitch;
|
||||
posX = to.posX;
|
||||
posY = to.posY + yOffset;
|
||||
posZ = to.posZ;
|
||||
rotationYaw = to.rotationYaw;
|
||||
rotationPitch = to.rotationPitch;
|
||||
lastTickPosX = to.lastTickPosX;
|
||||
lastTickPosY = to.lastTickPosY + yOffset;
|
||||
lastTickPosZ = to.lastTickPosZ;
|
||||
this.prevPosX = to.prevPosX;
|
||||
this.prevPosY = to.prevPosY + yOffset;
|
||||
this.prevPosZ = to.prevPosZ;
|
||||
this.prevRotationYaw = to.prevRotationYaw;
|
||||
this.prevRotationPitch = to.prevRotationPitch;
|
||||
this.posX = to.posX;
|
||||
this.posY = to.posY + yOffset;
|
||||
this.posZ = to.posZ;
|
||||
this.rotationYaw = to.rotationYaw;
|
||||
this.rotationPitch = to.rotationPitch;
|
||||
this.lastTickPosX = to.lastTickPosX;
|
||||
this.lastTickPosY = to.lastTickPosY + yOffset;
|
||||
this.lastTickPosZ = to.lastTickPosZ;
|
||||
updateBoundingBox();
|
||||
}
|
||||
|
||||
private void updateBoundingBox() {
|
||||
//#if MC>=11400
|
||||
//$$ float width = getWidth();
|
||||
//$$ float height = getHeight();
|
||||
//#endif
|
||||
//#if MC>=10800
|
||||
//#if MC>=11300
|
||||
setBoundingBox(new AxisAlignedBB(
|
||||
@@ -215,8 +239,8 @@ public class CameraEntity
|
||||
//#else
|
||||
//$$ this.boundingBox.setBB(AxisAlignedBB.getBoundingBox(
|
||||
//#endif
|
||||
posX - width / 2, posY, posZ - width / 2,
|
||||
posX + width / 2, posY + height, posZ + width / 2));
|
||||
this.posX - width / 2, this.posY, this.posZ - width / 2,
|
||||
this.posX + width / 2, this.posY + height, this.posZ + width / 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -226,9 +250,9 @@ public class CameraEntity
|
||||
//$$ public void onUpdate() {
|
||||
//#endif
|
||||
//#if MC>=10800
|
||||
Entity view = getRenderViewEntity(mc);
|
||||
Entity view = getRenderViewEntity(this.mc);
|
||||
//#else
|
||||
//$$ EntityLivingBase view = getRenderViewEntity(mc);
|
||||
//$$ EntityLivingBase view = getRenderViewEntity(this.mc);
|
||||
//#endif
|
||||
if (view != null) {
|
||||
// Make sure we're always spectating the right entity
|
||||
@@ -236,18 +260,18 @@ public class CameraEntity
|
||||
// entity is recreated and we have to spectate a new entity
|
||||
UUID spectating = ReplayModReplay.instance.getReplayHandler().getSpectatedUUID();
|
||||
if (spectating != null && (view.getUniqueID() != spectating
|
||||
|| view.world != world)
|
||||
|| world.getEntityByID(view.getEntityId()) != view) {
|
||||
|| view.world != this.world)
|
||||
|| this.world.getEntityByID(view.getEntityId()) != view) {
|
||||
if (spectating == null) {
|
||||
// Entity (non-player) died, stop spectating
|
||||
ReplayModReplay.instance.getReplayHandler().spectateEntity(this);
|
||||
return;
|
||||
}
|
||||
view = world.getPlayerEntityByUUID(spectating);
|
||||
view = this.world.getPlayerEntityByUUID(spectating);
|
||||
if (view != null) {
|
||||
setRenderViewEntity(mc, view);
|
||||
setRenderViewEntity(this.mc, view);
|
||||
} else {
|
||||
setRenderViewEntity(mc, this);
|
||||
setRenderViewEntity(this.mc, this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -262,15 +286,15 @@ public class CameraEntity
|
||||
@Override
|
||||
public void preparePlayerToSpawn() {
|
||||
// Make sure our world is up-to-date in case of world changes
|
||||
if (mc.world != null) {
|
||||
world = mc.world;
|
||||
if (this.mc.world != null) {
|
||||
this.world = this.mc.world;
|
||||
}
|
||||
super.preparePlayerToSpawn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRotation(float yaw, float pitch) {
|
||||
if (getRenderViewEntity(mc) == this) {
|
||||
if (getRenderViewEntity(this.mc) == this) {
|
||||
// Only update camera rotation when the camera is the view
|
||||
super.setRotation(yaw, pitch);
|
||||
}
|
||||
@@ -288,6 +312,12 @@ public class CameraEntity
|
||||
//$$ }
|
||||
//#endif
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ @Override
|
||||
//$$ public boolean isInFluid(Tag<Fluid> fluid, boolean loadedChunksOnly) {
|
||||
//$$ return falseUnlessSpectating(entity -> entity.isInFluid(fluid, loadedChunksOnly));
|
||||
//$$ }
|
||||
//#else
|
||||
//#if MC>=10800
|
||||
@Override
|
||||
public boolean isInLava() {
|
||||
@@ -304,6 +334,7 @@ public class CameraEntity
|
||||
public boolean isInWater() {
|
||||
return falseUnlessSpectating(Entity::isInWater); // Make sure no water overlay is rendered
|
||||
}
|
||||
//#endif
|
||||
|
||||
@Override
|
||||
public boolean isBurning() {
|
||||
@@ -311,7 +342,7 @@ public class CameraEntity
|
||||
}
|
||||
|
||||
private boolean falseUnlessSpectating(Function<Entity, Boolean> property) {
|
||||
Entity view = getRenderViewEntity(mc);
|
||||
Entity view = getRenderViewEntity(this.mc);
|
||||
if (view != null && view != this) {
|
||||
return property.apply(view);
|
||||
}
|
||||
@@ -342,6 +373,12 @@ public class CameraEntity
|
||||
}
|
||||
//#endif
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ @Override
|
||||
//$$ public boolean shouldRenderFrom(double double_1, double double_2, double double_3) {
|
||||
//$$ return false; // never render the camera otherwise it'd be visible e.g. in 3rd-person or with shaders
|
||||
//$$ }
|
||||
//#else
|
||||
@Override
|
||||
public boolean shouldRenderInPass(int pass) {
|
||||
// Never render the camera
|
||||
@@ -349,10 +386,11 @@ public class CameraEntity
|
||||
// cause any unwanted shadows when rendering with shaders.
|
||||
return false;
|
||||
}
|
||||
//#endif
|
||||
|
||||
@Override
|
||||
public boolean isInvisible() {
|
||||
Entity view = getRenderViewEntity(mc);
|
||||
Entity view = getRenderViewEntity(this.mc);
|
||||
if (view != this) {
|
||||
return view.isInvisible();
|
||||
}
|
||||
@@ -361,7 +399,7 @@ public class CameraEntity
|
||||
|
||||
@Override
|
||||
public ResourceLocation getLocationSkin() {
|
||||
Entity view = getRenderViewEntity(mc);
|
||||
Entity view = getRenderViewEntity(this.mc);
|
||||
if (view != this && view instanceof EntityPlayer) {
|
||||
return Utils.getResourceLocationForPlayerUUID(view.getUniqueID());
|
||||
}
|
||||
@@ -371,7 +409,7 @@ public class CameraEntity
|
||||
//#if MC>=10800
|
||||
@Override
|
||||
public String getSkinType() {
|
||||
Entity view = mc.getRenderViewEntity();
|
||||
Entity view = this.mc.getRenderViewEntity();
|
||||
if (view != this && view instanceof AbstractClientPlayer) {
|
||||
return ((AbstractClientPlayer) view).getSkinType();
|
||||
}
|
||||
@@ -381,7 +419,7 @@ public class CameraEntity
|
||||
|
||||
@Override
|
||||
public float getSwingProgress(float renderPartialTicks) {
|
||||
Entity view = getRenderViewEntity(mc);
|
||||
Entity view = getRenderViewEntity(this.mc);
|
||||
if (view != this && view instanceof EntityPlayer) {
|
||||
return ((EntityPlayer) view).getSwingProgress(renderPartialTicks);
|
||||
}
|
||||
@@ -391,7 +429,7 @@ public class CameraEntity
|
||||
//#if MC>=10904
|
||||
@Override
|
||||
public float getCooldownPeriod() {
|
||||
Entity view = mc.getRenderViewEntity();
|
||||
Entity view = this.mc.getRenderViewEntity();
|
||||
if (view != this && view instanceof EntityPlayer) {
|
||||
return ((EntityPlayer) view).getCooldownPeriod();
|
||||
}
|
||||
@@ -400,7 +438,7 @@ public class CameraEntity
|
||||
|
||||
@Override
|
||||
public float getCooledAttackStrength(float adjustTicks) {
|
||||
Entity view = mc.getRenderViewEntity();
|
||||
Entity view = this.mc.getRenderViewEntity();
|
||||
if (view != this && view instanceof EntityPlayer) {
|
||||
return ((EntityPlayer) view).getCooledAttackStrength(adjustTicks);
|
||||
}
|
||||
@@ -410,7 +448,7 @@ public class CameraEntity
|
||||
|
||||
@Override
|
||||
public EnumHand getActiveHand() {
|
||||
Entity view = mc.getRenderViewEntity();
|
||||
Entity view = this.mc.getRenderViewEntity();
|
||||
if (view != this && view instanceof EntityPlayer) {
|
||||
return ((EntityPlayer) view).getActiveHand();
|
||||
}
|
||||
@@ -419,13 +457,27 @@ public class CameraEntity
|
||||
|
||||
@Override
|
||||
public boolean isHandActive() {
|
||||
Entity view = mc.getRenderViewEntity();
|
||||
Entity view = this.mc.getRenderViewEntity();
|
||||
if (view != this && view instanceof EntityPlayer) {
|
||||
return ((EntityPlayer) view).isHandActive();
|
||||
}
|
||||
return super.isHandActive();
|
||||
}
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ @Override
|
||||
//$$ public HitResult rayTrace(double maxDistance, float tickDelta, boolean fluids) {
|
||||
//$$ HitResult result = super.rayTrace(maxDistance, tickDelta, fluids);
|
||||
//$$
|
||||
//$$ // Make sure we can never look at blocks (-> no outline)
|
||||
//$$ if (result instanceof BlockHitResult) {
|
||||
//$$ BlockHitResult blockResult = (BlockHitResult) result;
|
||||
//$$ result = BlockHitResult.createMissed(result.getPos(), blockResult.getSide(), blockResult.getBlockPos());
|
||||
//$$ }
|
||||
//$$
|
||||
//$$ return result;
|
||||
//$$ }
|
||||
//#else
|
||||
//#if MC>=11300
|
||||
@Override
|
||||
public RayTraceResult rayTrace(double blockReachDistance, float partialTicks, RayTraceFluidMode p_174822_4_) {
|
||||
@@ -451,6 +503,7 @@ public class CameraEntity
|
||||
//$$ return pos;
|
||||
//$$ }
|
||||
//#endif
|
||||
//#endif
|
||||
//#else
|
||||
//$$ @Override
|
||||
//$$ public MovingObjectPosition rayTrace(double p_174822_1_, float p_174822_3_) {
|
||||
@@ -481,8 +534,7 @@ public class CameraEntity
|
||||
//$$ public void setDead() {
|
||||
//$$ super.setDead();
|
||||
//#endif
|
||||
FORGE_BUS.unregister(eventHandler);
|
||||
FML_BUS.unregister(eventHandler);
|
||||
eventHandler.unregister();
|
||||
}
|
||||
|
||||
private void update() {
|
||||
@@ -491,18 +543,7 @@ public class CameraEntity
|
||||
cameraController.update(timePassed / 50f);
|
||||
lastControllerUpdate = now;
|
||||
|
||||
if (mc.gameSettings.keyBindAttack.isPressed() || mc.gameSettings.keyBindUseItem.isPressed()) {
|
||||
if (canSpectate(mc.pointedEntity)) {
|
||||
ReplayModReplay.instance.getReplayHandler().spectateEntity(
|
||||
//#if MC<=10710
|
||||
//$$ (EntityLivingBase)
|
||||
//#endif
|
||||
mc.pointedEntity);
|
||||
// Make sure we don't exit right away
|
||||
//noinspection StatementWithEmptyBody
|
||||
while (mc.gameSettings.keyBindSneak.isPressed());
|
||||
}
|
||||
}
|
||||
handleInputEvents();
|
||||
|
||||
Map<String, KeyBinding> keyBindings = ReplayMod.instance.getKeyBindingRegistry().getKeyBindings();
|
||||
if (keyBindings.get("replaymod.input.rollclockwise").isKeyDown()) {
|
||||
@@ -513,11 +554,26 @@ public class CameraEntity
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInputEvents() {
|
||||
if (this.mc.gameSettings.keyBindAttack.isPressed() || this.mc.gameSettings.keyBindUseItem.isPressed()) {
|
||||
if (canSpectate(this.mc.pointedEntity)) {
|
||||
ReplayModReplay.instance.getReplayHandler().spectateEntity(
|
||||
//#if MC<=10710
|
||||
//$$ (EntityLivingBase)
|
||||
//#endif
|
||||
this.mc.pointedEntity);
|
||||
// Make sure we don't exit right away
|
||||
//noinspection StatementWithEmptyBody
|
||||
while (this.mc.gameSettings.keyBindSneak.isPressed());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateArmYawAndPitch() {
|
||||
prevRenderArmYaw = renderArmYaw;
|
||||
prevRenderArmPitch = renderArmPitch;
|
||||
renderArmPitch = renderArmPitch + (rotationPitch - renderArmPitch) * 0.5f;
|
||||
renderArmYaw = renderArmYaw + (rotationYaw - renderArmYaw) * 0.5f;
|
||||
this.prevRenderArmYaw = this.renderArmYaw;
|
||||
this.prevRenderArmPitch = this.renderArmPitch;
|
||||
this.renderArmPitch = this.renderArmPitch + (this.rotationPitch - this.renderArmPitch) * 0.5f;
|
||||
this.renderArmYaw = this.renderArmYaw + (this.rotationYaw - this.renderArmYaw) * 0.5f;
|
||||
}
|
||||
|
||||
public boolean canSpectate(Entity e) {
|
||||
@@ -529,6 +585,7 @@ public class CameraEntity
|
||||
//#endif
|
||||
}
|
||||
|
||||
//#if MC<11400
|
||||
//#if MC>=11102
|
||||
@Override
|
||||
public void sendMessage(ITextComponent message) {
|
||||
@@ -542,30 +599,50 @@ public class CameraEntity
|
||||
//$$ super.addChatMessage(message);
|
||||
//$$ }
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
//#if MC>=10800
|
||||
private
|
||||
//#else
|
||||
//$$ public // All event handlers need to be public in 1.7.10
|
||||
//#endif
|
||||
class EventHandler {
|
||||
class EventHandler extends EventRegistrations {
|
||||
private final Minecraft mc = getMinecraft();
|
||||
|
||||
private EventHandler() {}
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ { on(PreTickCallback.EVENT, this::onPreClientTick); }
|
||||
//$$ private void onPreClientTick() {
|
||||
//#else
|
||||
@SubscribeEvent
|
||||
public void onPreClientTick(TickEvent.ClientTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.START) {
|
||||
update();
|
||||
updateArmYawAndPitch();
|
||||
}
|
||||
if (event.phase != TickEvent.Phase.START) return;
|
||||
//#endif
|
||||
updateArmYawAndPitch();
|
||||
}
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ { on(PreRenderCallback.EVENT, this::onRenderUpdate); }
|
||||
//$$ private void onRenderUpdate() {
|
||||
//#else
|
||||
@SubscribeEvent
|
||||
public void onRenderUpdate(TickEvent.RenderTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.START) {
|
||||
update();
|
||||
}
|
||||
if (event.phase != TickEvent.Phase.START) return;
|
||||
//#endif
|
||||
update();
|
||||
}
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ { on(KeyBindingEventCallback.EVENT, CameraEntity.this::handleInputEvents); }
|
||||
//#endif
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ { on(RenderSpectatorCrosshairCallback.EVENT, this::shouldRenderSpectatorCrosshair); }
|
||||
//$$ private TriState shouldRenderSpectatorCrosshair() {
|
||||
//$$ return TriState.of(canSpectate(mc.targetedEntity));
|
||||
//$$ }
|
||||
//#else
|
||||
@SubscribeEvent
|
||||
public void preCrosshairRender(RenderGameOverlayEvent.Pre event) {
|
||||
// The crosshair should only render if targeted entity can actually be spectated
|
||||
@@ -577,10 +654,11 @@ public class CameraEntity
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
|
||||
@SubscribeEvent
|
||||
public void onSettingsChanged(SettingsChangedEvent event) {
|
||||
if (event.getKey() == Setting.CAMERA) {
|
||||
{ on(SettingsChangedCallback.EVENT, this::onSettingsChanged); }
|
||||
private void onSettingsChanged(SettingsRegistry registry, SettingsRegistry.SettingKey<?> key) {
|
||||
if (key == Setting.CAMERA) {
|
||||
if (ReplayModReplay.instance.getReplayHandler().getSpectatedUUID() == null) {
|
||||
cameraController = ReplayModReplay.instance.createCameraController(CameraEntity.this);
|
||||
} else {
|
||||
@@ -589,6 +667,18 @@ public class CameraEntity
|
||||
}
|
||||
}
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ { on(PreRenderHandCallback.EVENT, this::onRenderHand); }
|
||||
//$$ private boolean onRenderHand() {
|
||||
//$$ // Unless we are spectating another player, don't render our hand
|
||||
//$$ if (getRenderViewEntity(mc) == CameraEntity.this || !(getRenderViewEntity(mc) instanceof PlayerEntity)) {
|
||||
//$$ return true; // cancel hand rendering
|
||||
//$$ } else {
|
||||
//$$ onRenderHandMonitor();
|
||||
//$$ return false;
|
||||
//$$ }
|
||||
//$$ }
|
||||
//#else
|
||||
@SubscribeEvent
|
||||
public void onRenderHand(RenderHandEvent event) {
|
||||
// Unless we are spectating another player, don't render our hand
|
||||
@@ -596,9 +686,14 @@ public class CameraEntity
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ private void onRenderHandMonitor() {
|
||||
//#else
|
||||
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||
public void onRenderHandMonitor(RenderHandEvent event) {
|
||||
//#endif
|
||||
Entity view = getRenderViewEntity(mc);
|
||||
if (view instanceof EntityPlayer) {
|
||||
EntityPlayer player = (EntityPlayer) view;
|
||||
@@ -628,6 +723,9 @@ public class CameraEntity
|
||||
}
|
||||
}
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ // Moved to MixinCamera
|
||||
//#else
|
||||
//#if MC>=10800
|
||||
@SubscribeEvent
|
||||
public void onEntityViewRenderEvent(EntityViewRenderEvent.CameraSetup event) {
|
||||
@@ -640,9 +738,13 @@ public class CameraEntity
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
private boolean heldItemTooltipsWasTrue;
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ // FIXME fabric
|
||||
//#else
|
||||
@SubscribeEvent
|
||||
public void preRenderGameOverlay(RenderGameOverlayEvent.Pre event) {
|
||||
switch (MCVer.getType(event)) {
|
||||
@@ -684,5 +786,6 @@ public class CameraEntity
|
||||
if (MCVer.getType(event) != RenderGameOverlayEvent.ElementType.ALL) return;
|
||||
mc.gameSettings.heldItemTooltips = heldItemTooltipsWasTrue;
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package com.replaymod.replay.camera;
|
||||
|
||||
import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
|
||||
import javax.vecmath.Vector3f;
|
||||
|
||||
import static com.replaymod.core.versions.MCVer.*;
|
||||
|
||||
// TODO: Marius is responsible for this. Please, someone clean it up.
|
||||
@@ -129,8 +128,7 @@ public class ClassicCameraController implements CameraController {
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3f movement = new Vector3f(direction);
|
||||
movement.normalize();
|
||||
Vector3f movement = direction.normalise(null);
|
||||
double factor = motion * (frac / 1000D);
|
||||
|
||||
camera.moveCamera(movement.x * factor, movement.y * factor, movement.z * factor);
|
||||
@@ -162,8 +160,8 @@ public class ClassicCameraController implements CameraController {
|
||||
Vector3f dbf = direction;
|
||||
|
||||
if(dirBefore != null) {
|
||||
dirBefore.normalize();
|
||||
dirBefore.add(direction);
|
||||
dirBefore.normalise(dirBefore);
|
||||
Vector3f.add(direction, direction, dirBefore);
|
||||
direction = dirBefore;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,11 @@ import net.minecraft.client.settings.KeyBinding;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ import net.minecraft.entity.EquipmentSlot;
|
||||
//#endif
|
||||
|
||||
//#if MC>=11300
|
||||
// FIXME
|
||||
//#else
|
||||
//$$ import org.lwjgl.input.Mouse;
|
||||
//#endif
|
||||
@@ -39,7 +42,7 @@ public class SpectatorCameraController implements CameraController {
|
||||
|
||||
// Prevent mouse movement
|
||||
//#if MC>=11300
|
||||
// FIXME
|
||||
// No longer needed
|
||||
//#else
|
||||
//$$ Mouse.updateCursor();
|
||||
//#endif
|
||||
@@ -53,7 +56,11 @@ public class SpectatorCameraController implements CameraController {
|
||||
// If it's a player, also 'steal' its inventory so the rendering code knows what item to render
|
||||
if (view instanceof EntityPlayer) {
|
||||
EntityPlayer viewPlayer = (EntityPlayer) view;
|
||||
//#if MC>=11400
|
||||
//$$ camera.setEquippedStack(EquipmentSlot.HEAD, viewPlayer.getEquippedStack(EquipmentSlot.HEAD));
|
||||
//#else
|
||||
camera.inventory = viewPlayer.inventory;
|
||||
//#endif
|
||||
//#if MC>=10904
|
||||
EntityPlayerAccessor cameraA = (EntityPlayerAccessor) camera;
|
||||
EntityPlayerAccessor viewPlayerA = (EntityPlayerAccessor) camera;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.replaymod.replay.camera;
|
||||
|
||||
import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
|
||||
@@ -9,8 +10,6 @@ import net.minecraft.client.GameSettings;
|
||||
//$$ import net.minecraft.client.settings.GameSettings;
|
||||
//#endif
|
||||
|
||||
import javax.vecmath.Vector3f;
|
||||
|
||||
/**
|
||||
* Camera controller performing vanilla creative-like camera movements.
|
||||
*/
|
||||
@@ -46,11 +45,11 @@ public class VanillaCameraController implements CameraController {
|
||||
Vector3f direction = new Vector3f(0, 0, 0);
|
||||
for (int i = 0; i < 6; i++) { // First, get movement direction depending on keys pressed
|
||||
if (bindings[i].isKeyDown()) {
|
||||
direction.add(DIRECTIONS[i]);
|
||||
Vector3f.add(direction, DIRECTIONS[i], direction);
|
||||
}
|
||||
}
|
||||
if (direction.length() == 0) return;
|
||||
direction.normalize(); // Normalize, so we don't move quicker if we hold down multiple keys
|
||||
direction.normalise(direction); // Normalize, so we don't move quicker if we hold down multiple keys
|
||||
double yawRadians = Math.toRadians(camera.rotationYaw);
|
||||
float yawSin = (float) Math.sin(yawRadians), yawCos = (float) Math.cos(yawRadians);
|
||||
// Rotate by yaw
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
//#if MC>=11300
|
||||
package com.replaymod.replay.events;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
import net.fabricmc.fabric.api.util.TriState;
|
||||
|
||||
public interface RenderSpectatorCrosshairCallback {
|
||||
Event<RenderSpectatorCrosshairCallback> EVENT = EventFactory.createArrayBacked(
|
||||
RenderSpectatorCrosshairCallback.class,
|
||||
(listeners) -> () -> {
|
||||
for (RenderSpectatorCrosshairCallback listener : listeners) {
|
||||
TriState state = listener.shouldRenderSpectatorCrosshair();
|
||||
if (state != TriState.DEFAULT) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
return TriState.DEFAULT;
|
||||
}
|
||||
);
|
||||
|
||||
TriState shouldRenderSpectatorCrosshair();
|
||||
}
|
||||
//#endif
|
||||
@@ -1,3 +1,4 @@
|
||||
//#if MC<11400
|
||||
package com.replaymod.replay.events;
|
||||
|
||||
import com.replaymod.replay.camera.CameraEntity;
|
||||
@@ -12,3 +13,4 @@ public class ReplayChatMessageEvent extends Event {
|
||||
@Getter
|
||||
private final CameraEntity cameraEntity;
|
||||
}
|
||||
//#endif
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.replaymod.replay.events;
|
||||
|
||||
import com.replaymod.replay.ReplayHandler;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public abstract class ReplayCloseEvent extends Event {
|
||||
@Getter
|
||||
private final ReplayHandler replayHandler;
|
||||
|
||||
public static class Pre extends ReplayCloseEvent {
|
||||
public Pre(ReplayHandler replayHandler) {
|
||||
super(replayHandler);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Post extends ReplayCloseEvent {
|
||||
public Post(ReplayHandler replayHandler) {
|
||||
super(replayHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.replaymod.replay.events;
|
||||
|
||||
import com.replaymod.replay.ReplayHandler;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
public interface ReplayClosedCallback {
|
||||
Event<ReplayClosedCallback> EVENT = EventFactory.createArrayBacked(ReplayClosedCallback.class,
|
||||
(listeners) -> (replayHandler) -> {
|
||||
for (ReplayClosedCallback listener : listeners) {
|
||||
listener.replayClosed(replayHandler);
|
||||
}
|
||||
});
|
||||
|
||||
void replayClosed(ReplayHandler replayHandler);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.replaymod.replay.events;
|
||||
|
||||
import com.replaymod.replay.ReplayHandler;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface ReplayClosingCallback {
|
||||
Event<ReplayClosingCallback> EVENT = EventFactory.createArrayBacked(ReplayClosingCallback.class,
|
||||
(listeners) -> (replayHandler) -> {
|
||||
for (ReplayClosingCallback listener : listeners) {
|
||||
listener.replayClosing(replayHandler);
|
||||
}
|
||||
});
|
||||
|
||||
void replayClosing(ReplayHandler replayHandler) throws IOException;
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package com.replaymod.replay.events;
|
||||
|
||||
import net.minecraftforge.eventbus.api.Cancelable;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
|
||||
public abstract class ReplayDispatchKeypressesEvent extends Event {
|
||||
|
||||
@Cancelable
|
||||
public static class Pre extends ReplayDispatchKeypressesEvent {}
|
||||
}
|
||||
//#if MC<11300
|
||||
//$$ package com.replaymod.replay.events;
|
||||
//$$
|
||||
//$$ import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
//$$ import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
//$$
|
||||
//$$ public abstract class ReplayDispatchKeypressesEvent extends Event {
|
||||
//$$
|
||||
//$$ @Cancelable
|
||||
//$$ public static class Pre extends ReplayDispatchKeypressesEvent {}
|
||||
//$$ }
|
||||
//#endif
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.replaymod.replay.events;
|
||||
|
||||
import com.replaymod.replay.ReplayHandler;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public abstract class ReplayOpenEvent extends Event {
|
||||
@Getter
|
||||
private final ReplayHandler replayHandler;
|
||||
|
||||
public static class Pre extends ReplayOpenEvent {
|
||||
public Pre(ReplayHandler replayHandler) {
|
||||
super(replayHandler);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Post extends ReplayOpenEvent {
|
||||
public Post(ReplayHandler replayHandler) {
|
||||
super(replayHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.replaymod.replay.events;
|
||||
|
||||
import com.replaymod.replay.ReplayHandler;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface ReplayOpenedCallback {
|
||||
Event<ReplayOpenedCallback> EVENT = EventFactory.createArrayBacked(ReplayOpenedCallback.class,
|
||||
(listeners) -> (replayHandler) -> {
|
||||
for (ReplayOpenedCallback listener : listeners) {
|
||||
listener.replayOpened(replayHandler);
|
||||
}
|
||||
});
|
||||
|
||||
void replayOpened(ReplayHandler replayHandler) throws IOException;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.replaymod.replay.gui.overlay;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.core.versions.MCVer.Keyboard;
|
||||
import com.replaymod.replay.ReplayHandler;
|
||||
import com.replaymod.replay.ReplaySender;
|
||||
import de.johni0702.minecraft.gui.GuiRenderer;
|
||||
@@ -14,20 +15,22 @@ import de.johni0702.minecraft.gui.element.GuiTooltip;
|
||||
import de.johni0702.minecraft.gui.element.advanced.IGuiTimeline;
|
||||
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
||||
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
|
||||
import de.johni0702.minecraft.gui.utils.EventRegistrations;
|
||||
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
|
||||
import de.johni0702.minecraft.gui.utils.lwjgl.ReadablePoint;
|
||||
import de.johni0702.minecraft.gui.utils.lwjgl.WritablePoint;
|
||||
import net.minecraft.client.GameSettings;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.InputEvent;
|
||||
|
||||
//#if MC<11300
|
||||
//$$ import org.lwjgl.input.Keyboard;
|
||||
//#if MC>=11300
|
||||
import com.replaymod.core.events.KeyBindingEventCallback;
|
||||
import com.replaymod.core.events.KeyEventCallback;
|
||||
//#else
|
||||
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
//$$ import net.minecraftforge.fml.common.gameevent.InputEvent;
|
||||
//#endif
|
||||
|
||||
import static com.replaymod.core.ReplayMod.TEXTURE_SIZE;
|
||||
import static com.replaymod.core.versions.MCVer.*;
|
||||
|
||||
public class GuiReplayOverlay extends AbstractGuiOverlay<GuiReplayOverlay> {
|
||||
|
||||
@@ -57,6 +60,8 @@ public class GuiReplayOverlay extends AbstractGuiOverlay<GuiReplayOverlay> {
|
||||
public final GuiPanel statusIndicatorPanel = new GuiPanel(this).setSize(100, 20)
|
||||
.setLayout(new HorizontalLayout(HorizontalLayout.Alignment.RIGHT).setSpacing(5));
|
||||
|
||||
private final EventHandler eventHandler = new EventHandler();
|
||||
|
||||
public GuiReplayOverlay(final ReplayHandler replayHandler) {
|
||||
timeline = new GuiMarkerTimeline(replayHandler){
|
||||
@Override
|
||||
@@ -141,32 +146,14 @@ public class GuiReplayOverlay extends AbstractGuiOverlay<GuiReplayOverlay> {
|
||||
public void setVisible(boolean visible) {
|
||||
if (isVisible() != visible) {
|
||||
if (visible) {
|
||||
FML_BUS.register(this);
|
||||
eventHandler.register();
|
||||
} else {
|
||||
FML_BUS.unregister(this);
|
||||
eventHandler.unregister();
|
||||
}
|
||||
}
|
||||
super.setVisible(visible);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onKeyInput(InputEvent.KeyInputEvent event) {
|
||||
GameSettings gameSettings = getMinecraft().gameSettings;
|
||||
while (gameSettings.keyBindChat.isPressed() || gameSettings.keyBindCommand.isPressed()) {
|
||||
if (!isMouseVisible()) {
|
||||
setMouseVisible(true);
|
||||
}
|
||||
}
|
||||
/* FIXME
|
||||
if (Keyboard.getEventKeyState()) {
|
||||
// Handle the F1 key binding while the overlay is opened as a gui screen
|
||||
if (isMouseVisible() && Keyboard.getEventKey() == Keyboard.KEY_F1) {
|
||||
gameSettings.hideGUI = !gameSettings.hideGUI;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
|
||||
// Do not render overlay when user pressed F1 and we are not currently in some popup
|
||||
@@ -182,4 +169,38 @@ public class GuiReplayOverlay extends AbstractGuiOverlay<GuiReplayOverlay> {
|
||||
protected GuiReplayOverlay getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
private class EventHandler extends EventRegistrations {
|
||||
//#if MC>=11300
|
||||
{ on(KeyBindingEventCallback.EVENT, this::onKeyBindingEvent); }
|
||||
private void onKeyBindingEvent() {
|
||||
//#else
|
||||
//$$ @SubscribeEvent
|
||||
//$$ public void onKeyBindingEvent(InputEvent.KeyInputEvent event) {
|
||||
//#endif
|
||||
GameSettings gameSettings = getMinecraft().gameSettings;
|
||||
while (gameSettings.keyBindChat.isPressed() || gameSettings.keyBindCommand.isPressed()) {
|
||||
if (!isMouseVisible()) {
|
||||
setMouseVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#if MC>=11300
|
||||
{ on(KeyEventCallback.EVENT, (int key, int scanCode, int action, int modifiers) -> onKeyInput(key, action)); }
|
||||
private void onKeyInput(int key, int action) {
|
||||
if (action != 0) return;
|
||||
//#else
|
||||
//$$ @SubscribeEvent
|
||||
//$$ public void onKeyInput(InputEvent.KeyInputEvent event) {
|
||||
//$$ if (!Keyboard.getEventKeyState()) return;
|
||||
//$$ int key = Keyboard.getEventKey();
|
||||
//#endif
|
||||
GameSettings gameSettings = getMinecraft().gameSettings;
|
||||
// Handle the F1 key binding while the overlay is opened as a gui screen
|
||||
if (isMouseVisible() && key == Keyboard.KEY_F1) {
|
||||
gameSettings.hideGUI = !gameSettings.hideGUI;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.google.common.base.Supplier;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import com.mojang.realmsclient.gui.ChatFormatting;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.core.SettingsRegistry;
|
||||
import com.replaymod.core.gui.GuiReplaySettings;
|
||||
@@ -37,7 +37,6 @@ import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
|
||||
import de.johni0702.minecraft.gui.utils.lwjgl.ReadablePoint;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.client.gui.GuiErrorScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.crash.ReportedException;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
@@ -57,6 +56,12 @@ import java.util.List;
|
||||
|
||||
import static com.replaymod.replay.ReplayModReplay.LOGGER;
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ import net.minecraft.text.TranslatableTextComponent;
|
||||
//#else
|
||||
import net.minecraft.client.resources.I18n;
|
||||
//#endif
|
||||
|
||||
public class GuiReplayViewer extends GuiScreen {
|
||||
private final ReplayModReplay mod;
|
||||
|
||||
@@ -137,8 +142,14 @@ public class GuiReplayViewer extends GuiScreen {
|
||||
// We failed (might also be their OS)
|
||||
e.printStackTrace();
|
||||
getMinecraft().displayGuiScreen(new GuiErrorScreen(
|
||||
//#if MC>=11400
|
||||
//$$ () -> {},
|
||||
//$$ new TranslatableTextComponent("replaymod.gui.viewer.delete.failed1"),
|
||||
//$$ new TranslatableTextComponent("replaymod.gui.viewer.delete.failed2")
|
||||
//#else
|
||||
I18n.format("replaymod.gui.viewer.delete.failed1"),
|
||||
I18n.format("replaymod.gui.viewer.delete.failed2")
|
||||
//#endif
|
||||
));
|
||||
return;
|
||||
}
|
||||
@@ -159,7 +170,7 @@ public class GuiReplayViewer extends GuiScreen {
|
||||
String name = list.getSelected().name.getText();
|
||||
GuiYesNoPopup popup = GuiYesNoPopup.open(GuiReplayViewer.this,
|
||||
new GuiLabel().setI18nText("replaymod.gui.viewer.delete.linea").setColor(Colors.BLACK),
|
||||
new GuiLabel().setI18nText("replaymod.gui.viewer.delete.lineb", name + ChatFormatting.RESET).setColor(Colors.BLACK)
|
||||
new GuiLabel().setI18nText("replaymod.gui.viewer.delete.lineb", name + TextFormatting.RESET).setColor(Colors.BLACK)
|
||||
).setYesI18nLabel("replaymod.gui.delete").setNoI18nLabel("replaymod.gui.cancel");
|
||||
Futures.addCallback(popup.getFuture(), new FutureCallback<Boolean>() {
|
||||
@Override
|
||||
@@ -393,7 +404,7 @@ public class GuiReplayViewer extends GuiScreen {
|
||||
public GuiReplayEntry(File file, ReplayMetaData metaData, BufferedImage thumbImage) {
|
||||
this.file = file;
|
||||
|
||||
name.setText(ChatFormatting.UNDERLINE + Utils.fileNameToReplayName(file.getName()));
|
||||
name.setText(TextFormatting.UNDERLINE + Utils.fileNameToReplayName(file.getName()));
|
||||
if (StringUtils.isEmpty(metaData.getServerName())
|
||||
|| !ReplayMod.instance.getSettingsRegistry().get(Setting.SHOW_SERVER_IPS)) {
|
||||
server.setI18nText("replaymod.gui.iphidden").setColor(Colors.DARK_RED);
|
||||
|
||||
@@ -1,52 +1,51 @@
|
||||
package com.replaymod.replay.handler;
|
||||
|
||||
import com.replaymod.core.versions.MCVer;
|
||||
import de.johni0702.minecraft.gui.utils.EventRegistrations;
|
||||
import com.replaymod.replay.ReplayModReplay;
|
||||
import com.replaymod.replay.gui.screen.GuiReplayViewer;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiIngameMenu;
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.gui.GuiMultiplayer;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback;
|
||||
//$$ import net.minecraft.client.gui.widget.AbstractButtonWidget;
|
||||
//#else
|
||||
import net.minecraftforge.client.event.GuiScreenEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
//#endif
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static com.replaymod.core.versions.MCVer.*;
|
||||
import static com.replaymod.replay.ReplayModReplay.LOGGER;
|
||||
|
||||
public class GuiHandler {
|
||||
//#if MC>=11300
|
||||
private static final int BUTTON_OPTIONS = 0;
|
||||
//#endif
|
||||
private static final int BUTTON_EXIT_SERVER = 1;
|
||||
private static final int BUTTON_ADVANCEMENTS = 5;
|
||||
private static final int BUTTON_STATS = 6;
|
||||
private static final int BUTTON_OPEN_TO_LAN = 7;
|
||||
|
||||
public class GuiHandler extends EventRegistrations {
|
||||
private static final int BUTTON_REPLAY_VIEWER = 17890234;
|
||||
private static final int BUTTON_EXIT_REPLAY = 17890235;
|
||||
|
||||
private static final Minecraft mc = MCVer.getMinecraft();
|
||||
|
||||
private final ReplayModReplay mod;
|
||||
|
||||
public GuiHandler(ReplayModReplay mod) {
|
||||
this.mod = mod;
|
||||
}
|
||||
|
||||
public void register() {
|
||||
FML_BUS.register(this);
|
||||
FORGE_BUS.register(this);
|
||||
}
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ { on(InitScreenCallback.EVENT, this::injectIntoIngameMenu); }
|
||||
//$$ private void injectIntoIngameMenu(Screen guiScreen, List<AbstractButtonWidget> buttonList) {
|
||||
//#else
|
||||
@SubscribeEvent
|
||||
public void injectIntoIngameMenu(GuiScreenEvent.InitGuiEvent.Post event) {
|
||||
if (!(getGui(event) instanceof GuiIngameMenu)) {
|
||||
GuiScreen guiScreen = getGui(event);
|
||||
List<GuiButton> buttonList = getButtonList(event);
|
||||
//#endif
|
||||
if (!(guiScreen instanceof GuiIngameMenu)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -54,42 +53,82 @@ public class GuiHandler {
|
||||
// Pause replay when menu is opened
|
||||
mod.getReplayHandler().getReplaySender().setReplaySpeed(0);
|
||||
|
||||
GuiButton achievements = null, stats = null, openToLan = null;
|
||||
List<GuiButton> buttonList = getButtonList(event);
|
||||
//#if MC>=11400
|
||||
//$$ final String BUTTON_OPTIONS = I18n.translate("menu.options");
|
||||
//$$ final String BUTTON_EXIT_SERVER = I18n.translate("menu.disconnect");
|
||||
//$$ final String BUTTON_ADVANCEMENTS = I18n.translate("gui.advancements");
|
||||
//$$ final String BUTTON_STATS = I18n.translate("gui.stats");
|
||||
//$$ final String BUTTON_OPEN_TO_LAN = I18n.translate("menu.shareToLan");
|
||||
//#else
|
||||
//#if MC>=11300
|
||||
final int BUTTON_OPTIONS = 0;
|
||||
//#endif
|
||||
final int BUTTON_EXIT_SERVER = 1;
|
||||
final int BUTTON_ADVANCEMENTS = 5;
|
||||
final int BUTTON_STATS = 6;
|
||||
final int BUTTON_OPEN_TO_LAN = 7;
|
||||
//#endif
|
||||
|
||||
|
||||
//#if MC<11300
|
||||
//$$ GuiButton openToLan = null;
|
||||
//#endif
|
||||
//#if MC>=11400
|
||||
//$$ AbstractButtonWidget achievements = null, stats = null;
|
||||
//$$ for(AbstractButtonWidget b : new ArrayList<>(buttonList)) {
|
||||
//#else
|
||||
GuiButton achievements = null, stats = null;
|
||||
for(GuiButton b : new ArrayList<>(buttonList)) {
|
||||
switch (b.id) {
|
||||
//#endif
|
||||
boolean remove = false;
|
||||
//#if MC>=11400
|
||||
//$$ String id = b.getMessage();
|
||||
//#else
|
||||
Integer id = b.id;
|
||||
//#endif
|
||||
if (id.equals(BUTTON_EXIT_SERVER)) {
|
||||
// Replace "Exit Server" button with "Exit Replay" button
|
||||
case BUTTON_EXIT_SERVER:
|
||||
removeButton(event, b);
|
||||
addButton(event, new GuiButton(BUTTON_EXIT_REPLAY, b.x, b.y, b.width, b.height, I18n.format("replaymod.gui.exit")) {
|
||||
//#if MC>=11300
|
||||
@Override
|
||||
public void onClick(double mouseX, double mouseY) {
|
||||
onButton(new GuiScreenEvent.ActionPerformedEvent.Pre(getGui(event), this, new ArrayList<>()));
|
||||
}
|
||||
//#endif
|
||||
});
|
||||
break;
|
||||
remove = true;
|
||||
addButton(guiScreen, new InjectedButton(
|
||||
guiScreen,
|
||||
BUTTON_EXIT_REPLAY,
|
||||
b.x,
|
||||
b.y,
|
||||
width(b),
|
||||
height(b),
|
||||
I18n.format("replaymod.gui.exit"),
|
||||
this::onButton
|
||||
));
|
||||
} else if (id.equals(BUTTON_ADVANCEMENTS)) {
|
||||
// Remove "Advancements", "Stats" and "Open to LAN" buttons
|
||||
case BUTTON_ADVANCEMENTS:
|
||||
removeButton(event, achievements = b);
|
||||
break;
|
||||
case BUTTON_STATS:
|
||||
removeButton(event, stats = b);
|
||||
break;
|
||||
case BUTTON_OPEN_TO_LAN:
|
||||
removeButton(event, openToLan = b);
|
||||
break;
|
||||
//#if MC>=11300
|
||||
case BUTTON_OPTIONS:
|
||||
b.width = 200;
|
||||
break;
|
||||
remove = true;
|
||||
achievements = b;
|
||||
} else if (id.equals(BUTTON_STATS)) {
|
||||
remove = true;
|
||||
stats = b;
|
||||
} else if (id.equals(BUTTON_OPEN_TO_LAN)) {
|
||||
remove = true;
|
||||
//#if MC<11300
|
||||
//$$ openToLan = b;
|
||||
//#endif
|
||||
//#if MC>=11300
|
||||
} else if (id.equals(BUTTON_OPTIONS)) {
|
||||
//#if MC>=11400
|
||||
//$$ width(b, 204);
|
||||
//#else
|
||||
width(b, 200);
|
||||
//#endif
|
||||
//#endif
|
||||
}
|
||||
if (remove) {
|
||||
// Moving the button far off-screen is easier to do cross-version than actually removing it
|
||||
b.x = -1000;
|
||||
b.y = -1000;
|
||||
}
|
||||
}
|
||||
if (achievements != null && stats != null) {
|
||||
moveAllButtonsDirectlyBelowUpwards(buttonList, achievements.y,
|
||||
achievements.x, stats.x + stats.width);
|
||||
achievements.x, stats.x + width(stats));
|
||||
}
|
||||
// In 1.13+ Forge, the Options button shares one row with the Open to LAN button
|
||||
//#if MC<11300
|
||||
@@ -108,17 +147,31 @@ public class GuiHandler {
|
||||
* @param xStart Left x limit of the rectangle
|
||||
* @param xEnd Right x limit of the rectangle
|
||||
*/
|
||||
private void moveAllButtonsDirectlyBelowUpwards(List<GuiButton> buttons, int belowY, int xStart, int xEnd) {
|
||||
for (GuiButton button : buttons) {
|
||||
if (button.y >= belowY && button.x <= xEnd && button.x + button.width >= xStart) {
|
||||
button.y -= 24;
|
||||
}
|
||||
}
|
||||
private void moveAllButtonsDirectlyBelowUpwards(
|
||||
//#if MC>=11400
|
||||
//$$ List<AbstractButtonWidget> buttons,
|
||||
//#else
|
||||
List<GuiButton> buttons,
|
||||
//#endif
|
||||
int belowY,
|
||||
int xStart,
|
||||
int xEnd
|
||||
) {
|
||||
buttons.stream()
|
||||
.filter(button -> button.y >= belowY)
|
||||
.filter(button -> button.x <= xEnd && button.x + width(button) >= xStart)
|
||||
.forEach(button -> button.y -= 24);
|
||||
}
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ { on(InitScreenCallback.EVENT, this::ensureReplayStopped); }
|
||||
//$$ private void ensureReplayStopped(Screen guiScreen, List<AbstractButtonWidget> buttonList) {
|
||||
//#else
|
||||
@SubscribeEvent
|
||||
public void ensureReplayStopped(GuiScreenEvent.InitGuiEvent event) {
|
||||
if (!(getGui(event) instanceof GuiMainMenu || getGui(event) instanceof GuiMultiplayer)) {
|
||||
GuiScreen guiScreen = getGui(event);
|
||||
//#endif
|
||||
if (!(guiScreen instanceof GuiMainMenu || guiScreen instanceof GuiMultiplayer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -137,38 +190,50 @@ public class GuiHandler {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ { on(InitScreenCallback.EVENT, this::injectIntoMainMenu); }
|
||||
//$$ private void injectIntoMainMenu(Screen guiScreen, List<AbstractButtonWidget> buttonList) {
|
||||
//#else
|
||||
@SubscribeEvent
|
||||
public void injectIntoMainMenu(GuiScreenEvent.InitGuiEvent event) {
|
||||
if (!(getGui(event) instanceof GuiMainMenu)) {
|
||||
GuiScreen guiScreen = getGui(event);
|
||||
//#endif
|
||||
if (!(guiScreen instanceof GuiMainMenu)) {
|
||||
return;
|
||||
}
|
||||
GuiButton button = new GuiButton(BUTTON_REPLAY_VIEWER, getGui(event).width / 2 - 100,
|
||||
getGui(event).height / 4 + 10 + 4 * 24, I18n.format("replaymod.gui.replayviewer")) {
|
||||
//#if MC>=11300
|
||||
@Override
|
||||
public void onClick(double mouseX, double mouseY) {
|
||||
onButton(new GuiScreenEvent.ActionPerformedEvent.Pre(getGui(event), this, new ArrayList<>()));
|
||||
}
|
||||
//#endif
|
||||
};
|
||||
button.width = button.width / 2 - 2;
|
||||
addButton(event, button);
|
||||
GuiButton button = new InjectedButton(
|
||||
guiScreen,
|
||||
BUTTON_REPLAY_VIEWER,
|
||||
guiScreen.width / 2 - 100,
|
||||
guiScreen.height / 4 + 10 + 4 * 24,
|
||||
98,
|
||||
20,
|
||||
I18n.format("replaymod.gui.replayviewer"),
|
||||
this::onButton
|
||||
);
|
||||
addButton(guiScreen, button);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onButton(GuiScreenEvent.ActionPerformedEvent.Pre event) {
|
||||
if(!getButton(event).enabled) return;
|
||||
//#if MC>=11300
|
||||
private void onButton(InjectedButton button) {
|
||||
GuiScreen guiScreen = button.guiScreen;
|
||||
//#else
|
||||
//$$ @SubscribeEvent
|
||||
//$$ public void onButton(GuiScreenEvent.ActionPerformedEvent.Pre event) {
|
||||
//$$ GuiScreen guiScreen = getGui(event);
|
||||
//$$ GuiButton button = getButton(event);
|
||||
//#endif
|
||||
if(!button.enabled) return;
|
||||
|
||||
if (getGui(event) instanceof GuiMainMenu) {
|
||||
if (getButton(event).id == BUTTON_REPLAY_VIEWER) {
|
||||
if (guiScreen instanceof GuiMainMenu) {
|
||||
if (button.id == BUTTON_REPLAY_VIEWER) {
|
||||
new GuiReplayViewer(mod).display();
|
||||
}
|
||||
}
|
||||
|
||||
if (getGui(event) instanceof GuiIngameMenu && mod.getReplayHandler() != null) {
|
||||
if (getButton(event).id == BUTTON_EXIT_REPLAY) {
|
||||
getButton(event).enabled = false;
|
||||
if (guiScreen instanceof GuiIngameMenu && mod.getReplayHandler() != null) {
|
||||
if (button.id == BUTTON_EXIT_REPLAY) {
|
||||
button.enabled = false;
|
||||
try {
|
||||
mod.getReplayHandler().endReplay();
|
||||
} catch (IOException e) {
|
||||
@@ -177,4 +242,45 @@ public class GuiHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class InjectedButton extends GuiButton {
|
||||
public final GuiScreen guiScreen;
|
||||
public final int id;
|
||||
private Consumer<InjectedButton> onClick;
|
||||
public InjectedButton(GuiScreen guiScreen, int buttonId, int x, int y, int width, int height, String buttonText,
|
||||
//#if MC>=11300
|
||||
Consumer<InjectedButton> onClick
|
||||
//#else
|
||||
//$$ Consumer<GuiScreenEvent.ActionPerformedEvent.Pre> onClick
|
||||
//#endif
|
||||
) {
|
||||
super(
|
||||
//#if MC<11400
|
||||
buttonId,
|
||||
//#endif
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
buttonText
|
||||
//#if MC>=11400
|
||||
//$$ , self -> onClick.accept((InjectedButton) self)
|
||||
//#endif
|
||||
);
|
||||
this.guiScreen = guiScreen;
|
||||
this.id = buttonId;
|
||||
//#if MC>=11300
|
||||
this.onClick = onClick;
|
||||
//#else
|
||||
//$$ this.onClick = null;
|
||||
//#endif
|
||||
}
|
||||
|
||||
//#if MC>=11300 && MC<11400
|
||||
@Override
|
||||
public void onClick(double mouseX, double mouseY) {
|
||||
onClick.accept(this);
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
|
||||
30
src/main/java/com/replaymod/replay/mixin/MixinCamera.java
Normal file
30
src/main/java/com/replaymod/replay/mixin/MixinCamera.java
Normal file
@@ -0,0 +1,30 @@
|
||||
//#if MC>=11400
|
||||
//$$ package com.replaymod.replay.mixin;
|
||||
//$$
|
||||
//$$ import com.mojang.blaze3d.platform.GlStateManager;
|
||||
//$$ import com.replaymod.replay.camera.CameraEntity;
|
||||
//$$ import net.minecraft.client.render.Camera;
|
||||
//$$ import net.minecraft.entity.Entity;
|
||||
//$$ import net.minecraft.world.BlockView;
|
||||
//$$ import org.spongepowered.asm.mixin.Mixin;
|
||||
//$$ import org.spongepowered.asm.mixin.injection.At;
|
||||
//$$ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
//$$
|
||||
//$$ @Mixin(Camera.class)
|
||||
//$$ public class MixinCamera {
|
||||
//$$ @Inject(
|
||||
//$$ method = "update",
|
||||
//$$ at = @At(
|
||||
//$$ value = "INVOKE",
|
||||
//$$ target = "Lcom/mojang/blaze3d/platform/GlStateManager;rotatef(FFFF)V",
|
||||
//$$ ordinal = 0
|
||||
//$$ )
|
||||
//$$ )
|
||||
//$$ private void applyRoll(BlockView blockView, Entity view, boolean boolean_1, boolean boolean_2, float float_1, CallbackInfo ci) {
|
||||
//$$ if (view instanceof CameraEntity) {
|
||||
//$$ GlStateManager.rotatef(((CameraEntity) view).roll, 0.0F, 0.0F, 1.0F);
|
||||
//$$ }
|
||||
//$$ }
|
||||
//$$ }
|
||||
//#endif
|
||||
@@ -17,7 +17,14 @@ public abstract class MixinGuiSpectator {
|
||||
//#else
|
||||
//$$ @Inject(method = "func_175260_a", at = @At("HEAD"), cancellable = true)
|
||||
//#endif
|
||||
public void isInReplay(int i, CallbackInfo ci) {
|
||||
public void isInReplay(
|
||||
//#if MC>=11400
|
||||
//$$ double i,
|
||||
//#else
|
||||
int i,
|
||||
//#endif
|
||||
CallbackInfo ci
|
||||
) {
|
||||
// Prevent spectator gui from opening while in a replay
|
||||
if (getMinecraft().player instanceof CameraEntity) {
|
||||
ci.cancel();
|
||||
|
||||
22
src/main/java/com/replaymod/replay/mixin/MixinInGameHud.java
Normal file
22
src/main/java/com/replaymod/replay/mixin/MixinInGameHud.java
Normal file
@@ -0,0 +1,22 @@
|
||||
//#if MC>=11400
|
||||
//$$ package com.replaymod.replay.mixin;
|
||||
//$$
|
||||
//$$ import com.replaymod.replay.events.RenderSpectatorCrosshairCallback;
|
||||
//$$ import net.fabricmc.fabric.api.util.TriState;
|
||||
//$$ import net.minecraft.client.gui.hud.InGameHud;
|
||||
//$$ import org.spongepowered.asm.mixin.Mixin;
|
||||
//$$ import org.spongepowered.asm.mixin.injection.At;
|
||||
//$$ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
//$$
|
||||
//$$ @Mixin(InGameHud.class)
|
||||
//$$ public class MixinInGameHud {
|
||||
//$$ @Inject(method = "shouldRenderSpectatorCrosshair", at = @At("HEAD"), cancellable = true)
|
||||
//$$ private void shouldRenderSpectatorCrosshair(CallbackInfoReturnable<Boolean> ci) {
|
||||
//$$ TriState state = RenderSpectatorCrosshairCallback.EVENT.invoker().shouldRenderSpectatorCrosshair();
|
||||
//$$ if (state != TriState.DEFAULT) {
|
||||
//$$ ci.setReturnValue(state.get());
|
||||
//$$ }
|
||||
//$$ }
|
||||
//$$ }
|
||||
//#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
//#if MC>=11300
|
||||
package com.replaymod.replay.mixin;
|
||||
|
||||
import com.replaymod.extras.advancedscreenshots.AdvancedScreenshots;
|
||||
import com.replaymod.replay.ReplayModReplay;
|
||||
import net.minecraft.client.KeyboardListener;
|
||||
import net.minecraft.client.shader.Framebuffer;
|
||||
import net.minecraft.util.ScreenShotHelper;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(KeyboardListener.class)
|
||||
public abstract class MixinKeyboardListener {
|
||||
@Redirect(
|
||||
method = "onKeyEvent",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
//#if MC>=11400
|
||||
//$$ target = "Lnet/minecraft/client/util/ScreenshotUtils;method_1662(Ljava/io/File;Ljava/lang/String;IILnet/minecraft/client/gl/GlFramebuffer;Ljava/util/function/Consumer;)V"
|
||||
//#else
|
||||
target = "Lnet/minecraft/util/ScreenShotHelper;saveScreenshot(Ljava/io/File;IILnet/minecraft/client/shader/Framebuffer;Ljava/util/function/Consumer;)V"
|
||||
//#endif
|
||||
)
|
||||
)
|
||||
private void takeScreenshot(
|
||||
File p_148260_0_,
|
||||
//#if MC>=11400
|
||||
//$$ String something,
|
||||
//#endif
|
||||
int p_148260_1_,
|
||||
int p_148260_2_,
|
||||
Framebuffer p_148260_3_,
|
||||
Consumer<ITextComponent> p_148260_4_
|
||||
) {
|
||||
if (ReplayModReplay.instance.getReplayHandler() != null) {
|
||||
AdvancedScreenshots.take();
|
||||
} else {
|
||||
ScreenShotHelper.saveScreenshot(
|
||||
p_148260_0_,
|
||||
//#if MC>=11400
|
||||
//$$ something,
|
||||
//#endif
|
||||
p_148260_1_,
|
||||
p_148260_2_,
|
||||
p_148260_3_,
|
||||
p_148260_4_
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
@@ -32,9 +32,9 @@ public abstract class MixinParticleManager {
|
||||
@Inject(method = "clearEffects", at = @At("HEAD"))
|
||||
public void replayModReplay_clearParticleQueue(World world, CallbackInfo ci) {
|
||||
//#if MC>=11300
|
||||
queue.clear();
|
||||
this.queue.clear();
|
||||
//#else
|
||||
//$$ queueEntityFX.clear();
|
||||
//$$ this.queueEntityFX.clear();
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,18 @@ import com.replaymod.replay.camera.CameraEntity;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.PlayerControllerMP;
|
||||
import net.minecraft.client.network.NetHandlerPlayClient;
|
||||
import net.minecraft.world.World;
|
||||
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.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
//#if MC>=11400
|
||||
//$$ import net.minecraft.client.world.ClientWorld;
|
||||
//#else
|
||||
import net.minecraft.world.World;
|
||||
//#endif
|
||||
|
||||
//#if MC>=11200
|
||||
//#if MC>=11300
|
||||
import net.minecraft.client.util.RecipeBookClient;
|
||||
@@ -47,32 +52,41 @@ public abstract class MixinPlayerControllerMP {
|
||||
|
||||
//#if MC>=11300
|
||||
@Inject(method = "createPlayer", at=@At("HEAD"), cancellable = true)
|
||||
private void replayModReplay_createReplayCamera(World worldIn, StatisticsManager statisticsManager, RecipeBookClient recipeBookClient, CallbackInfoReturnable<EntityPlayerSP> ci) {
|
||||
private void replayModReplay_createReplayCamera(
|
||||
//#if MC>=11400
|
||||
//$$ ClientWorld worldIn,
|
||||
//#else
|
||||
World worldIn,
|
||||
//#endif
|
||||
StatisticsManager statisticsManager,
|
||||
RecipeBookClient recipeBookClient,
|
||||
CallbackInfoReturnable<EntityPlayerSP> ci
|
||||
) {
|
||||
if (ReplayModReplay.instance.getReplayHandler() != null) {
|
||||
ci.setReturnValue(new CameraEntity(mc, worldIn, connection, statisticsManager, recipeBookClient));
|
||||
ci.setReturnValue(new CameraEntity(this.mc, worldIn, this.connection, statisticsManager, recipeBookClient));
|
||||
//#else
|
||||
//#if MC>=11200
|
||||
//$$ @Inject(method = "func_192830_a", at=@At("HEAD"), cancellable = true)
|
||||
//$$ private void replayModReplay_createReplayCamera(World worldIn, StatisticsManager statisticsManager, RecipeBook recipeBook, CallbackInfoReturnable<EntityPlayerSP> ci) {
|
||||
//$$ if (ReplayModReplay.instance.getReplayHandler() != null) {
|
||||
//$$ ci.setReturnValue(new CameraEntity(mc, worldIn, connection, statisticsManager, recipeBook));
|
||||
//$$ ci.setReturnValue(new CameraEntity(this.mc, worldIn, this.connection, statisticsManager, recipeBook));
|
||||
//#else
|
||||
//#if MC>=10904
|
||||
//$$ @Inject(method = "createClientPlayer", at=@At("HEAD"), cancellable = true)
|
||||
//$$ private void replayModReplay_createReplayCamera(World worldIn, StatisticsManager statisticsManager, CallbackInfoReturnable<EntityPlayerSP> ci) {
|
||||
//$$ if (ReplayModReplay.instance.getReplayHandler() != null) {
|
||||
//$$ ci.setReturnValue(new CameraEntity(mc, worldIn, connection, statisticsManager));
|
||||
//$$ ci.setReturnValue(new CameraEntity(this.mc, worldIn, this.connection, statisticsManager));
|
||||
//#else
|
||||
//#if MC>=10800
|
||||
//$$ @Inject(method = "func_178892_a", at=@At("HEAD"), cancellable = true)
|
||||
//$$ private void replayModReplay_createReplayCamera(World worldIn, StatFileWriter statFileWriter, CallbackInfoReturnable<EntityPlayerSP> ci) {
|
||||
//$$ if (ReplayModReplay.instance.getReplayHandler() != null) {
|
||||
//$$ ci.setReturnValue(new CameraEntity(mc, worldIn, netClientHandler, statFileWriter));
|
||||
//$$ ci.setReturnValue(new CameraEntity(this.mc, worldIn, this.netClientHandler, statFileWriter));
|
||||
//#else
|
||||
//$$ @Inject(method = "createPlayer", at=@At("HEAD"), cancellable = true)
|
||||
//$$ private void replayModReplay_createReplayCamera(World worldIn, StatFileWriter statFileWriter, CallbackInfoReturnable<EntityClientPlayerMP> ci) {
|
||||
//$$ if (ReplayModReplay.instance.getReplayHandler() != null) {
|
||||
//$$ ci.setReturnValue(new CameraEntity(mc, worldIn, mc.getSession(), netClientHandler, statFileWriter));
|
||||
//$$ ci.setReturnValue(new CameraEntity(this.mc, worldIn, this.mc.getSession(), this.netClientHandler, statFileWriter));
|
||||
//#endif
|
||||
//#endif
|
||||
//#endif
|
||||
@@ -88,8 +102,8 @@ public abstract class MixinPlayerControllerMP {
|
||||
//$$ @Inject(method = "isSpectator", at=@At("HEAD"), cancellable = true)
|
||||
//#endif
|
||||
private void replayModReplay_isSpectator(CallbackInfoReturnable<Boolean> ci) {
|
||||
if (mc.player instanceof CameraEntity) { // this check should in theory not be required
|
||||
ci.setReturnValue(mc.player.isSpectator());
|
||||
if (this.mc.player instanceof CameraEntity) { // this check should in theory not be required
|
||||
ci.setReturnValue(this.mc.player.isSpectator());
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
|
||||
@@ -16,7 +16,11 @@ import net.minecraft.util.Util;
|
||||
@Mixin(ItemRenderer.class)
|
||||
public class MixinRenderItem {
|
||||
//#if MC>=11300
|
||||
//#if MC>=11400
|
||||
//$$ @Redirect(method = "renderGlint", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/SystemUtil;getMeasuringTimeMs()J"))
|
||||
//#else
|
||||
@Redirect(method = "renderEffect", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Util;milliTime()J"))
|
||||
//#endif
|
||||
private static long getEnchantmentTime() {
|
||||
//#else
|
||||
//$$ @Redirect(method = "renderEffect", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;getSystemTime()J"))
|
||||
|
||||
@@ -31,7 +31,17 @@ public abstract class MixinRenderLivingBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "renderModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/EntityLivingBase;isInvisibleToPlayer(Lnet/minecraft/entity/player/EntityPlayer;)Z"))
|
||||
@Redirect(
|
||||
method = "renderModel",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
//#if MC>=11400
|
||||
//$$ target = "Lnet/minecraft/entity/LivingEntity;canSeePlayer(Lnet/minecraft/entity/player/PlayerEntity;)Z"
|
||||
//#else
|
||||
target = "Lnet/minecraft/entity/EntityLivingBase;isInvisibleToPlayer(Lnet/minecraft/entity/player/EntityPlayer;)Z"
|
||||
//#endif
|
||||
)
|
||||
)
|
||||
private boolean replayModReplay_shouldInvisibleNotBeRendered(EntityLivingBase entity, EntityPlayer thePlayer) {
|
||||
return thePlayer instanceof CameraEntity || entity.isInvisibleToPlayer(thePlayer);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//#if MC>=10800
|
||||
// Appears to no longer be needed in 1.14+ (maybe not even 1.13?)
|
||||
//#if MC>=10800 && MC<11400
|
||||
package com.replaymod.replay.mixin;
|
||||
|
||||
import net.minecraft.client.GameSettings;
|
||||
|
||||
@@ -10,16 +10,31 @@ import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(ViewFrustum.class)
|
||||
public abstract class MixinViewFrustum {
|
||||
@Redirect(method = "updateChunkPositions", at=@At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/chunk/RenderChunk;setPosition(III)V"))
|
||||
private void replayModReplay_updatePositionAndMarkForUpdate(RenderChunk renderChunk, int x, int y, int z) {
|
||||
@Redirect(
|
||||
method = "updateChunkPositions",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
//#if MC>=10904
|
||||
target = "Lnet/minecraft/client/renderer/chunk/RenderChunk;setPosition(III)V"
|
||||
//#else
|
||||
//$$ target = "Lnet/minecraft/client/renderer/chunk/RenderChunk;setPosition(Lnet/minecraft/util/BlockPos;)V"
|
||||
//#endif
|
||||
)
|
||||
)
|
||||
private void replayModReplay_updatePositionAndMarkForUpdate(
|
||||
RenderChunk renderChunk,
|
||||
//#if MC>=10904
|
||||
int x, int y, int z
|
||||
//#else
|
||||
//$$ BlockPos pos
|
||||
//#endif
|
||||
) {
|
||||
//#if MC>=10904
|
||||
BlockPos pos = new BlockPos(x, y, z);
|
||||
//#endif
|
||||
if (!pos.equals(renderChunk.getPosition())) {
|
||||
//#if MC>=10904
|
||||
//#if MC>=11100
|
||||
renderChunk.setPosition(x, y, z);
|
||||
//#else
|
||||
//$$ renderChunk.setOrigin(x, y, z);
|
||||
//#endif
|
||||
renderChunk.setNeedsUpdate(false);
|
||||
//#else
|
||||
//$$ renderChunk.setPosition(pos);
|
||||
|
||||
@@ -10,6 +10,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@Mixin(WorldClient.class)
|
||||
public abstract class MixinWorldClient {
|
||||
|
||||
// Looks like this has finally been fixed in 1.14 (or been moved somewhere else entirely, guess we'll find out)
|
||||
//#if MC<11400
|
||||
/**
|
||||
* Fixes a bug in vanilla Minecraft that leaves entities remaining in the entityList even after respawn.
|
||||
* The entityList in WorldClient is a Set that assumes that the entity ID of its entities does not change.
|
||||
@@ -28,4 +30,5 @@ public abstract class MixinWorldClient {
|
||||
public void replayModReplay_fix_addEntityToWorld(int entityId, Entity entity, CallbackInfo ci) {
|
||||
entity.setEntityId(entityId);
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user