Update to MC 1.14 / Fabric

This commit is contained in:
Jonas Herzig
2019-05-04 14:37:00 +02:00
parent 17fe5b345f
commit 3d009e45c7
151 changed files with 3963 additions and 1455 deletions

View File

@@ -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
}

View File

@@ -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() {

View File

@@ -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;
}
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}
}
}

View File

@@ -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);

View File

@@ -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
}
}

View 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

View File

@@ -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();

View 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

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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"))

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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
}