Compare commits

...

1115 Commits

Author SHA1 Message Date
Jonas Herzig
a4c8dafa07 Release 2.6.26 2026-04-14 12:41:25 +02:00
Jonas Herzig
6e64f2acd0 Fix no texture animations when rendering on 1.21.11+ 2026-04-14 12:39:59 +02:00
Jonas Herzig
27d5432fff Update to 26.1 2026-04-14 12:39:59 +02:00
Jonas Herzig
b72fad4055 Update to Gradle 9, Loom 1.15, EGT 0.7 2026-04-06 07:48:51 +02:00
Jonas Herzig
f08607a599 Release 2.6.25 2025-12-16 16:38:50 +01:00
Jonas Herzig
a5dec5db25 Fix hiding of player nametags on 1.21.9+ 2025-12-16 16:35:20 +01:00
Jonas Herzig
dad0ac18a3 Fix missing fabric-resource-loader-v1 dependency 2025-12-16 16:35:20 +01:00
TKD_Kedis
caffd41358 Update to 1.21.11 (#1106)
Co-authored-by: Jonas Herzig <me@johni0702.de>
2025-12-16 16:34:53 +01:00
Jonas Herzig
713db19928 Release 2.6.24 2025-10-20 19:43:35 +02:00
Jonas Herzig
d3929cb6dc Update to 1.21.9/10 2025-10-12 21:26:28 +02:00
Jonas Herzig
e6db9daf80 Update key and mouse handling in preparation for 1.21.9 2025-10-12 20:21:03 +02:00
Jonas Herzig
f299644254 Reimplement runLater without relying on MC's renderTaskQueue
Cause it's gone in 1.21.9, and really not necessary to begin with since
we have our own executor already.
2025-10-12 16:10:29 +02:00
Jonas Herzig
4d644a44c3 Release 2.6.23 2025-07-05 09:40:33 +02:00
Jonas Herzig
85fb0847ee Update to 1.21.7 2025-06-30 18:13:20 +02:00
Jonas Herzig
926f6b6624 Fix depth export on 1.21.5+ 2025-06-14 08:49:46 +02:00
Jonas Herzig
928094bd27 Fix recording in minimal mode on 1.20.6+ 2025-06-13 14:15:03 +02:00
Jonas Herzig
d7b563768f Move replay camera entity creation into dedicated mixin 2025-06-13 14:02:40 +02:00
Jonas Herzig
8246085b84 Fix first person hand missing when shaders are enabled with Iris 1.7+ 2025-06-13 10:49:02 +02:00
Jonas Herzig
55e6044bdd Release 2.6.22 2025-05-13 16:09:25 +02:00
Jonas Herzig
a8c1d19240 Update to 1.21.5 2025-04-28 11:14:37 +02:00
Jonas Herzig
7aad4dcfd9 Update Iris url 2025-04-05 13:10:31 +02:00
Jonas Herzig
b2dde7da97 Release 2.6.21 2024-12-15 10:24:51 +01:00
Jonas Herzig
f21fed031c Update to 1.21.4 2024-12-15 10:24:12 +01:00
Jonas Herzig
7f7b4e1891 Fix camera looking straight down on 1.21.2+ 2024-12-07 17:05:59 +01:00
Jonas Herzig
50cfcbabfb Release 2.6.20 2024-11-03 18:17:58 +01:00
Jonas Herzig
8cf598d781 Fix transfer packet log spam 2024-11-03 17:44:39 +01:00
Jonas Herzig
14229ef1fe Fix LoginHelloS2CPacket being recorded on some servers 2024-11-03 17:44:39 +01:00
Jonas Herzig
17d87faa34 Update to 1.21.2 2024-11-03 17:44:28 +01:00
Jonas Herzig
193e51b3c2 Release 2.6.19 2024-09-09 13:27:52 +02:00
Jonas Herzig
a0c5f25e61 Update ReplayStudio 2024-09-09 13:22:04 +02:00
Jonas Herzig
8503ff0e67 Remove unnecessary manual mappings 2024-09-09 13:22:04 +02:00
Jonas Herzig
73fe633819 Update preprocessor 2024-09-09 13:22:04 +02:00
Jonas Herzig
9f5a8c3d0f Release 2.6.18 2024-07-12 12:42:10 +02:00
Jonas Herzig
5959da8744 Fix LoginSuccess packet being recorded with incorrect id on 1.20.2-4 2024-07-12 12:38:17 +02:00
Jonas Herzig
6de0e37d96 Release 2.6.17 2024-07-10 22:06:28 +02:00
Jonas Herzig
5b766b4fe7 Fix included mod jars being exploded into outer jar
Caused by this stupid behavior of the shadow plugin:
https://github.com/johnrengelman/shadow/issues/111

Fixes #976
2024-07-10 22:04:38 +02:00
Jonas Herzig
203aad687d Release 2.6.16 2024-07-10 19:37:17 +02:00
Jonas Herzig
1836b7fb18 Fix Iris shader animation time on 1.21 2024-07-10 19:07:19 +02:00
Jonas Herzig
ca6ae4b983 Fix ODS export with Iris 1.7 2024-07-10 19:07:00 +02:00
Jonas Herzig
d2cdcb02fc Remove unnecessary isTransitive exclusion
Now that it's using Modrinth maven, there won't be any transitive
dependencies anyway.
2024-07-10 18:20:19 +02:00
Jonas Herzig
b537822d3c Enable Gradle daemon
Now that we no longer have to deal with ForgeGradle, we can actually use
this pretty fundamental Gradle feature again.
2024-07-10 17:36:01 +02:00
Jonas Herzig
6b5993ad64 Fix post-screenshot popup being invisible while HUD is hidden 2024-07-07 11:02:41 +02:00
Jonas Herzig
b4ead9e064 Update ReplayStudio
1e96fda Fix SquashFilter dropping config-phase custom packets
2024-07-07 10:32:55 +02:00
Jonas Herzig
8adb65d724 Move old mapping files to standard location 2024-07-01 12:48:23 +02:00
Jonas Herzig
329530de0e Update ReplayStudio so it works via includeBuild 2024-07-01 12:24:53 +02:00
Jonas Herzig
a04fd5b00b Move ReplayStudio submodule into libs folder 2024-06-30 20:27:59 +02:00
Jonas Herzig
486056de24 Fix recording whith login-phase custom packets 2024-06-25 10:31:12 +02:00
Jonas Herzig
2b2ab2ba8b Fix time keyframe lines rendering below timeline 2024-06-25 10:30:43 +02:00
Jonas Herzig
d70e41006d Add ReplayStudio as submodule instead of JitPack
Because JitPack breaks Gradle variants so we get the Java 17 jar even
when we use the Java 8 variant.

This works for building via Gradle. However it does not work for usage
from IntelliJ, where you must currently publishToMavenLocal ReplayStudio
and then depend on that version. Still looking for a better solution
there.
2024-06-23 21:41:18 +02:00
Jonas Herzig
a4e0abec7f Update to 1.21 2024-06-23 20:33:41 +02:00
Jonas Herzig
1433fccaf1 Update EGT to 0.6.1 2024-06-23 20:24:57 +02:00
Jonas Herzig
310dc90e11 Remove WrappedTimer 2024-06-23 20:24:57 +02:00
Jonas Herzig
454e990849 Replace InputReplayTimer with Mixin 2024-06-23 20:24:57 +02:00
Jonas Herzig
76a68b7867 Prevent pausing in the middle of a bundle packet
Because certain actions (e.g. switching to Quick Mode) will fail in this
state.
2024-06-23 20:24:57 +02:00
Jonas Herzig
5218feb6b6 Update to 1.20.6 2024-06-23 20:24:57 +02:00
Jonas Herzig
3f12413c6b De-duplicate recording channel configuration 2024-06-23 20:07:57 +02:00
Jonas Herzig
675134e6d6 Split outbound handler from FullReplaySender
This because with 1.20.6, MC will require outbound messages to reach its
handlers to switch between protocol versions. So we need our drop
handler two be at the very end of the write processing chain.
2024-06-23 20:07:57 +02:00
Jonas Herzig
4df627029c Fix race condition in PacketListener
The ChannelHandlerContext was only set on the next received packet,
however `save` could be called before that happened.
2024-06-23 20:07:57 +02:00
Jonas Herzig
046a50f326 Target WorldRenderer in Mixin_PostRenderWorldCalback 2024-06-23 20:07:57 +02:00
Jonas Herzig
f388e4af54 Update MixinExtras and include it on all Fabric versions 2024-06-23 20:07:57 +02:00
Jonas Herzig
8900d5a4fb Split MixinGameRenderer into multiple mixins 2024-06-18 14:50:34 +02:00
Jonas Herzig
acd56a7ba3 Remove player list packet entry workaround
No longer using ForgeGradle \o/
2024-05-13 17:33:06 +02:00
Jonas Herzig
c74ef8c0e4 Let Minecraft handle packet decoding during recording
We've done this ourselves only because it was easier at the beginning.
However with 1.20.5, Minecraft's packet decoding became substantially
more sophisticated, to the point that it's probably a bad idea to try
to do it ourselves.

Additionally, getting the packet ids, which we require for identifying
the packets which we want to decode, has becomes significantly more
difficult too, and this way it's a simple instanceof check.
2024-05-13 17:01:03 +02:00
Jonas Herzig
fe0677923c Let Minecraft handle packet decoding during playback
We've done this ourselves only because it was easier at the beginning.
However by now (and especially with 1.20.5), Minecraft's packet decoding
has become substantially more sophisticated, to the point that it's
probably a bad idea to try to do it ourselves.

This commit gives back that responsibility to Minecraft by adding the
standard decoder (and encoder because it's required for proper
connection state management on modern versions) to our channel pipeline,
changes the full and the quick replay sender to send raw `ByteBuf`s into
the front of the channel, and moves the posititon of the full replay
sender in the channel pipeline such that it can see and modify packets
after Minecraft has decoded them.
2024-05-13 15:25:50 +02:00
Jonas Herzig
ad49a69f37 Switch from FG to archloom + essential-gradle-toolkit
- Upgrade Gradle to 8.7
- Increase build daemon max memory to 8GB because archloom can compile a lot
  more projects at the same time.
- Disable Minecraft 1.8 (not 1.8.9) because archloom fails to set up for that
2024-05-12 14:24:43 +02:00
Jonas Herzig
706d46f6a9 Release 2.6.15 2024-03-10 18:05:59 +01:00
Jonas Herzig
c11fffedc1 Update ReplayStudio
95a7c07 Process PlayerPositionRotation packet in SquashFilter
603bdce Create dedicated class for PacketPlayerPositionRotation
88343aa Fix incorrect order of ViaVersion-emitted packets
9ebaa97 Fix 1.20 to 1.20.2 ViaVersion conversion
c490e9f Update ViaVersion
bcccb2c Fix Reconfigure packets not being filtered out
a0df6c9 Fix ConfigFinish being emitted before other config packets
a672023 Separate pre-join-game packets from login-phase packets
a70161c Emit Reconfigure packet when required
074d78d Separate "emit first" list from "login phase" list
20a3bf9 Reorder loginPhase and configurationPhase code
2024-03-10 18:02:19 +01:00
Jonas Herzig
ba6078e080 Update jGui, fixes JPG loading on 1.20.4+ 2024-03-10 16:30:25 +01:00
Jonas Herzig
f8379fa317 Fix thread-unsafe server resource pack playback 2024-03-10 16:29:31 +01:00
Jonas Herzig
61ef87eebe Release 2.6.14 2023-12-12 15:11:49 +01:00
Jonas Herzig
6e5536305b Bump 1.20.2 fabric-api to version 0.92.2 2023-12-09 10:43:26 +01:00
Jonas Herzig
1bf1e0d7be Port to 1.20.4 2023-12-09 10:43:26 +01:00
Jonas Herzig
faebeb525a Port to 1.20.3-rc1 2023-12-03 18:51:37 +01:00
Jonas Herzig
43576efeb3 Convert JPG images to PNG
Minecraft 1.20.3 no longer supports loading JPG images.
2023-12-03 16:28:28 +01:00
Jonas Herzig
b8ab7aa5a7 Port to 1.20.2 2023-11-27 19:40:42 +01:00
Jonas Herzig
e8f9234bf0 Fix EXR rendering failing on Windows on MC 1.20+ 2023-11-27 17:55:13 +01:00
Jonas Herzig
329ac51309 Fix rubber-banding on rotation of entity in vehicle (fixes #846) 2023-11-13 13:51:47 +01:00
Jonas Herzig
f506d5ac65 Fix missing networking-api-v1 on 1.16.4/5
We recently bumped the fabric-api version there, and newer versions of the v0
api just delegate to the v1 one now, so we need to include that there as well.
2023-10-18 12:09:59 +02:00
Jonas Herzig
96dbc54a53 Fix Iris dependency
Seems like it no longer builds on JitPack and their cache has expired.
2023-10-18 12:09:13 +02:00
Jonas Herzig
094ca1ce01 Release 2.6.13 2023-06-20 09:44:55 +02:00
Jonas Herzig
24237557f1 Port to 1.20.1 2023-06-20 09:31:07 +02:00
Jonas Herzig
d8c6ce9b5e Clean up 1.17 .gitkeep file 2023-06-12 11:04:25 +02:00
Jonas Herzig
7726550131 Port to MC 1.20 2023-06-12 10:28:08 +02:00
Jonas Herzig
96a05e256f Add MixinExtras on 1.16.4+
We'll use it in 1.20 mixins.
Unclear what minimal fabric-loader version it requires, so in the interest of
keeping older versions compatible with OptiFabric (old versions of which aren't
compatible with the latest fabric-loader), we'll add it to 1.16.4+ only.
2023-06-12 10:28:08 +02:00
Jonas Herzig
587eff59fe Rewrite main menu button injection code (closes #577, fixes #621)
For 1.16.4+ only because we use parts of fabric-screen-api.
2023-06-12 10:23:21 +02:00
Jonas Herzig
f92d6f5281 Fix overlay gui elements not moving on resize (fixes #841) 2023-06-12 09:07:45 +02:00
Jonas Herzig
fb4ae1b60a Delegate bindTexture to jGui's MCVer 2023-06-12 09:05:42 +02:00
Jonas Herzig
0c5009db8d Drop 1.17 in favor of 1.17.1
Primarily because fabric-api for 1.17 never received any updates, so
fabric-screen-api isn't available for it.
2023-06-12 08:49:15 +02:00
Jonas Herzig
81509a9acf Release 2.6.12 2023-03-28 12:24:16 +02:00
Jonas Herzig
fd740a4af6 Update ReplayStudio 2023-03-28 12:23:18 +02:00
Jonas Herzig
36741b97fa Release 2.6.11 2023-03-26 19:43:21 +02:00
Jonas Herzig
bf32672536 Fix active timeline changes affecting render queue (fixes #814)
The `Timeline` type is mutable, so we need to create a copy before we pass it to
GuiKeyframeRepository because we don't want anything stored in there (or more
specifically in render queue which can also be added to from that gui) to be
affected by subsequent changes.
2023-03-26 19:21:30 +02:00
Jonas Herzig
8037a9ad30 Fix ridden boat missing when joining 1.18+ Spigot server 2023-03-26 18:59:14 +02:00
Jonas Herzig
78bd060249 Port to MC 1.19.4 2023-03-26 18:58:49 +02:00
Jonas Herzig
ae5f893014 Release 2.6.10 2022-12-09 13:16:17 +01:00
Jonas Herzig
043664ab0c Fix multiplayer recording on 1.19.3 (fixes #803) 2022-12-09 13:14:56 +01:00
Jonas Herzig
9a5b88fd48 Release 2.6.9 2022-12-07 16:35:51 +01:00
Jonas Herzig
77ce90b2b0 Disable MixinShaderRenderChunk on 1.18+
It's only required for legacy Optifine doesn't even apply any more as of 1.18,
so we can just disable it on modern versions so it doesn't spam the log.
2022-12-07 16:34:55 +01:00
Jonas Herzig
3816671207 Fix depth export on 1.14.4 2022-12-07 16:34:55 +01:00
Jonas Herzig
000ff19749 Fix depth export while spectating on 1.12.2 and below (fixes #785) 2022-12-07 16:34:55 +01:00
Jonas Herzig
ffcca61b5b Fix running in 1.14.4 dev environment
First version of modmenu in its repo appears to be for 1.15, so we need to
disable it in 1.14.
2022-12-07 16:34:55 +01:00
Jonas Herzig
d571e8fed5 Port to MC 1.19.3
Building against 1.19.3-rc3 for now because 1.19.3 has yet to release.
ReplayStudio/ViaVersion is already targeting the release version though.
2022-12-07 16:34:55 +01:00
Jonas Herzig
e8ea70aabc Port to MC 1.19.2 (fixes #801) 2022-12-07 16:34:50 +01:00
Jonas Herzig
e0a682a5df Fix armor missing after dimension change (fixes #791)
The respawn packet re-creates the player entity, so we need to re-send its
armor (and technically also the riding and sleeping state, though that probably
wouldn't ever have caused issues in practice because a respawn will implicitly
reset those, unlike your inventory which is preserved).
2022-12-06 18:01:07 +01:00
Jonas Herzig
19404032fe Fix jGui resource pack when using per-version run folder 2022-12-06 17:51:55 +01:00
Jonas Herzig
bee13fc9a1 Replace projection matrix Redirect with ModifyArg
Should be better for compatibility because multiple mods can ModifyArg but only
one can Redirect, and will be easier to port to 1.19.3.
2022-12-06 17:37:15 +01:00
Jonas Herzig
3cec8fde9f Release 2.6.8 2022-08-10 14:29:15 +02:00
Jonas Herzig
cce65ec76d Ignore expired player public keys during replay
These would otherwise fail to be initialized and cause the game to disconnect
itself on the first chat message from the corresponding player.
2022-08-10 14:22:21 +02:00
Jonas Herzig
06f1e0c36c Fix chat message validation failure when Show Chat is off on 1.19.1+ 2022-08-10 14:22:21 +02:00
Jonas Herzig
35d1b7f24b Fix game crashing if client disconnects from replay during jump 2022-08-10 13:47:47 +02:00
Jonas Herzig
82d4408567 Add missing MC 1.19.1 .gitkeep file 2022-07-31 14:38:54 +02:00
Jonas Herzig
e8ff8a2066 Release 2.6.7 2022-07-31 13:46:49 +02:00
Jonas Herzig
ff98260216 Fix build on MC 1.8 2022-07-31 13:46:01 +02:00
Jonas Herzig
c34f75d95a Fix item staying visually equipped after being dropped (fixes #658) 2022-07-31 13:03:43 +02:00
Jonas Herzig
62b9cd0538 Use DefaultedList for equipment tracking
Because on 1.11+ a `null` item stack is not something that should exist.
This then also allows us to compare item stacks by value rather than only by
reference, potentially saving a few redundant entity equipment update
packets (but more importantly, also allows us to store a copy instead of the
original, which will be important for the next commit).
2022-07-31 13:03:43 +02:00
Jonas Herzig
42d04d123c Deduplicate code 2022-07-31 12:55:54 +02:00
Jonas Herzig
7550e3dcb7 Fix race conditions in movement packet filtering (fixes #760)
We cannot filter this packet purely on the netty thread because our filter
depends on the current camera position (if it's too far, we do want to teleport
it closer) and accessing the camera is only safe from the main thread.

Previously the second part had not been considered which could lead to race
conditions where the camera may not yet exist on the netty thread at time of
handling. These appear to have gotten the wholly inappropriate "just put a null
check around it" treatment, but that means that the filter sometimes doesn't
work (hence the bug report).

This commit changes handling such that all access to `allowMovement` is always
done on the main thread and then moves the filtering there as well. And
therefore filtering should now work properly.
2022-07-31 12:55:54 +02:00
Jonas Herzig
af3f6ddbe2 Always handle PlayerPositionLookS2CPacket manually 2022-07-31 12:48:39 +02:00
Jonas Herzig
962f08718f Fix "Show Chat" setting on 1.19+ (fixes #757) 2022-07-31 10:38:14 +02:00
Jonas Herzig
a9401a9779 Update ModMenu 2022-07-31 10:38:07 +02:00
Jonas Herzig
400ec6bda5 Port to MC 1.19.1 2022-07-31 10:37:22 +02:00
Jonas Herzig
bdea84b9a2 Remove unused GuiMainMenuAccessor 2022-07-31 10:22:20 +02:00
Jonas Herzig
6db47ee070 Updated broken forge docs link 2022-07-31 10:22:11 +02:00
Jonas Herzig
a95edaa31d Update translations 2022-07-31 09:30:19 +02:00
Kepler-17c
89d771fdbf Updated the compatibility section on shaders 2022-07-17 23:10:24 +02:00
bela333
f0299fed66 Update documentation to include compatible Sodium 2022-07-17 23:06:17 +02:00
bela333
05387b0ac7 Modified FREX notice 2022-07-17 23:05:27 +02:00
Jonas Herzig
738320e896 Update translations 2022-07-17 23:03:44 +02:00
Jonas Herzig
6e3d30e41b Fix thread unsafety in OpenGlToBitmapProcessor
Sharing the temporary `row` and `rowSwap` buffers between different calls to the
processor is not safe because it will be used by multiple threads.
As a result some of the rows in the image could randomly get corrupted.

This commit gets rid of the cached buffers (the value of which questionable
anyway) and simply re-uses the same code which other processors use.
2022-07-17 17:08:03 +02:00
Jonas Herzig
633ac10d89 Fix main hand in first person spectator view (fixes #731) 2022-07-17 17:08:03 +02:00
Jonas Herzig
42aef017c1 Fix skin in Player Overview and first person on 1.8.9 (fixes #749)
No clue why `getResourceLocationForPlayerUUID` was implemented the way it was,
that commit dates back to 2015 (332c36a), but if the skin isn't loaded yet, it
won't load it, so sometimes it just won't show properly in first person and in
the Player Overview.
This commit just calls `AbstractClientPlayer.getSkinTexture` instead.

Unclear which MC versions are affected. At some point before 1.16.4 something
else was introduced which loads the skin for us, hence why modern versions were
not affected.
2022-07-17 16:02:41 +02:00
Jonas Herzig
3526ec526c Release 2.6.6 2022-06-26 14:49:13 +02:00
Jonas Herzig
7457f9c13b Increase maximum camera speed by about an order of magnitude 2022-06-26 13:54:52 +02:00
Jonas Herzig
08c86ce574 Enable compression for OpenEXR if we have the cpu power for it 2022-06-26 13:33:13 +02:00
Jonas Herzig
517591d72a Encode OpenEXR and PNG frames in parallel 2022-06-26 13:32:58 +02:00
Jonas Herzig
a3f4049322 Reduces minimum speed of classic camera controller
Two blocks per second is still quite fast, so this commit reduces the minimum to
a tenth of that, allowing for much finer control.
2022-06-26 12:30:23 +02:00
Jonas Herzig
4f9a730b6d Fix classic camera speed changing way too quickly (fixes #719)
On my system, a single scroll tick results in 120 calls, which is fine for the
vanilla camera controller because it has a range of 2000, but the classic
controller only has a range of 36, making it impossible to select anything but
the extremes.
This commit changes the size of the range to match that of the vanilla controller.
2022-06-26 12:28:07 +02:00
Jonas Herzig
40f07279cf Load tinyexr in its own class loader
That way we can simply use whatever version we want and aren't tied to the
version of lwjgl which MC provides.

This fixes the OpenEXR export on 1.19 crashing either due to the windows
workaround or due to differing lwjgl versions (depending on OS).
And also enables OpenEXR export on MC versions using lwjgl2 (1.12.2 and below).
2022-06-26 11:57:24 +02:00
Jonas Herzig
814d0b7c17 Update ReplayStudio
Fixes fatal QuickMode error introduced with the 1.19 update.
2022-06-15 14:18:23 +02:00
Jonas Herzig
13ac8dcf0a Record raw packets instead of re-encoding decoded packets
Until now, recording worked by injecting right before the vanilla packet
handler. At that point it was receiving packet classes and had to re-encode them
to store them in the replay file. However, not all decoded packets can
necessarily be re-encoded without errors, requiring us to have a bunch of
workarounds.

This commit changes the way recording works by injecting right before the
decoder. It therefore receives the raw bytebufs and no longer has to deal with
the re-encode issue.
2022-06-15 14:18:23 +02:00
Jonas Herzig
df11ba2e36 Port to MC 1.19 2022-06-12 13:47:41 +02:00
Jonas Herzig
9ce25f711f Port to MC 1.19-pre3 2022-05-27 10:05:50 +02:00
Jonas Herzig
9f8957f468 Migrate away from deprecated fabric-api modules 2022-05-26 08:19:34 +02:00
Jonas Herzig
f595d9ca23 Release 2.6.5 2022-05-01 21:25:21 +02:00
Jonas Herzig
716df74893 Fix first person (cross)bow model animation on 1.9+ (fixes #708) 2022-05-01 21:06:24 +02:00
Jonas Herzig
4364347a19 Update ReplayStudio
6fc8e20 Fix incorrect relative packet order in squash filter (fixes #718)
2022-05-01 20:34:26 +02:00
Jonas Herzig
8b2d42f801 Fix broken fog when using Chroma Key with Sodium (fixes #726) 2022-05-01 20:05:00 +02:00
Jonas Herzig
f2c96174bc Fix terrain culling not being updated for omnidirectional rendering
Terrain culling is only updated when the camera position or rotation changes.
For omnidirectional rendering, we don't change the camera directly though, we
rotate way earlier so we can consistently get before any other effects. As a
result, the terrain frustum culling wasn't updated between render passes
resulting in missing terrain.
This was largely masked by the fact that we used to call GameRenderer.onResize
every pass (even when the size hadn't changed) but fixing that made this issue
become apparent.
2022-04-17 12:01:40 +02:00
Jonas Herzig
497b8440ca Call Window.onFramebufferSizeChanged to resize (fixes #705)
Instead of setting the the values via accessor and calling the handler directly.
This allows mods like ResolutionControl+ to properly resize its internal
framebuffers as well.
2022-04-17 12:01:40 +02:00
Jonas Herzig
5be57681af Completely bypass Minecraft when window is resized during rendering
Should fix issues where resizing affects the render result.
2022-04-17 12:01:40 +02:00
Jonas Herzig
fd9be55f79 Remove caching of ScaledResolution from Window shim
It'll become stale if the code holds on to the Window shim object for a longer
duration, and there's no reliable mechanism to invalidate it.
2022-04-17 12:01:40 +02:00
Jonas Herzig
4558793030 Remove unless window size tracking
The only thing we care about is the framebuffer size, cause that will differ
between game and progress gui rendering. The window size will be the same (real)
size for both.
2022-04-17 12:01:40 +02:00
Jonas Herzig
fb36fc2ba8 Fix render progress framebuffer never being deleted 2022-04-10 18:20:26 +02:00
Jonas Herzig
01d37ab2cb Split gui window/framebuffer management code from VideoRenderer 2022-04-10 18:20:16 +02:00
Jonas Herzig
a6c09bcb8a Fix crash when window is minimized on Windows 2022-04-10 15:33:42 +02:00
Jonas Herzig
fb38a20465 Fix path separator in replay name
Would probably have been caught by the write check as well, except in the
specific case where the folder exists, e.g. `../`
2022-04-10 13:52:14 +02:00
Jonas Herzig
d6c6220bdd Fix invalid characters in replay name on Windows (fixes #715) 2022-04-10 13:48:47 +02:00
Jonas Herzig
463b947c2b Suppress fabric-screen-handler-api during playback (fixes #713) 2022-04-10 13:36:50 +02:00
Jonas Herzig
8e140e8d01 Release 2.6.4 2022-03-09 07:09:00 +01:00
Jonas Herzig
c010a437fc Orient camera for ODS in game instead of in vertex shader
This makes it work more like regular 360 mode and is generally more compatible
because it doesn't require the frustum culling workarounds which the GPU
solution needs.
In particular, this fixes frustum culling with newer sodium versions (which no
longer use the vanilla intersection checking method) and fixes the clouds on
modern Iris (which seems to be using a different shader program for clouds).
2022-03-09 07:08:02 +01:00
Jonas Herzig
f2425a693a DRY (Iris)ODSFrameCapturer 2022-03-09 07:08:02 +01:00
Jonas Herzig
9df2035ca9 Update translations 2022-03-09 07:08:02 +01:00
Jonas Herzig
4aa667fe04 Port to MC 1.18.2 (closes #697) 2022-03-09 07:08:02 +01:00
Jonas Herzig
1fa027f362 Enable Quick Mode for 1.8.x 2022-03-06 13:39:49 +01:00
Jonas Herzig
74049dad77 Update ReplayStudio
9c5dec8 Fix writing of empty chunk load packet on 1.8.x (fixes #636)
3d8573f Fix writing of respawn packet on 1.8.x
39a85f7 Fix exception when cache file has invalid gzip header (fixes #535)
2022-03-06 13:39:49 +01:00
Jonas Herzig
c146aa145c Fix stereoscopic eye offset on 1.16+
The mapping between intermediary name on 1.15.2 and yarn on 1.16.1 has already
been added in the previous commit.
2022-03-06 13:39:49 +01:00
Jonas Herzig
ee6b53b247 Fix incorrect FOV and aspect during 360 render on 1.16+ 2022-03-06 13:39:49 +01:00
Jonas Herzig
1efb17e144 Fix ODS rendering on Iris 1.1.3+ (fixes #693) 2022-03-06 13:39:49 +01:00
Jonas Herzig
8573a9b208 Prevent jumping while path is playing (closes #694) 2022-03-06 13:39:49 +01:00
Jonas Herzig
0356fef61d Fix crash when receiving resource pack on 1.8-1.12.2 (fixes #86) 2022-03-06 13:39:49 +01:00
Jonas Herzig
f9c58a1165 Try raw file name before percent encoding it (closes #536) 2022-03-06 13:39:49 +01:00
Jonas Herzig
d178c0980e Log when replays are opened (closes #565) 2022-03-06 13:39:49 +01:00
Jonas Herzig
b8cf7e6df4 Fix scrolling while replay paused on 1.12.2 and below (fixes #590) 2022-03-06 13:39:49 +01:00
Jonas Herzig
2e34a2abd9 Fix render timer breaking when system time changes (fixes #633)
Unlike `currentTimeMillis`, `nanoTime` is guaranteed to be relative to a
fixed point in time, regardless of system or wall-clock time.
2022-03-06 13:39:49 +01:00
Jonas Herzig
e26480f041 Fix "Please wait" when jumping not being centered (fixes #646) 2022-03-06 13:39:49 +01:00
Jonas Herzig
a8d05a2bca Skip mod compat warning screen when in render queue (fixes #653) 2022-03-06 13:39:49 +01:00
Jonas Herzig
7615499cef Add option to preserve alpha channel in export (closes #661)
Default off cause it being on by default had confused quite a few people.
2022-03-06 13:39:49 +01:00
Jochem
d9da2e135c Sync world border animation & movement to Replay speed
Fixes an issue where the world border would move at normal speed when speeding up or slowing down the replay, and also at an incorrect speed when rendering the replay, causing it to get out of sync with the rest of the world.

Co-authored-by: Jonas Herzig <me@johni0702.de>
2022-03-06 13:39:49 +01:00
Jonas Herzig
fe67d7fa14 Link to our docs in the "Missing ffmpeg" screen (closes #663) 2022-03-06 13:39:49 +01:00
Jonas Herzig
fb7900d805 Fix missing hand with Iris 1.1.3 and above (fixes #638) 2022-03-06 13:39:49 +01:00
Jonas Herzig
4a5df2ad6d Use GameRenderer.renderHand boolean field instead of mixin
Should be more compatible with mods which replace the entire renderHand
method (thereby making our mixin non-applicable), at least as long as these mods
check `renderHand` as well (Iris explicitly does).

This will become important once #638 is fixed.
2022-03-06 13:39:10 +01:00
Jonas Herzig
6cc370a117 Workaround Java breaking with symlinks (fixes #660) 2022-03-05 17:21:38 +01:00
Jonas Herzig
abfb3d46f3 Use per-version folder for pack.mcmeta
Comments are not supported here, and depending on the exact environment, that
may break stuff (seems to only happen on fabric in dev).
2022-03-05 17:21:38 +01:00
Jonas Herzig
0b8a2a107c Use separate thread to send packets, even in sync mode (fixes #674) 2022-03-05 17:21:38 +01:00
Andrew S
7e9a1e7c13 Fix Render GUI on Retina Screens (fixes #338)
window.getFramebufferWidth/Height() should be used instead of window.getWidth/Height()

Co-authored-by: Jonas Herzig <me@johni0702.de>
2022-02-27 11:14:57 +01:00
Jonas Herzig
e378ae8f93 Fix entities disappearing on 1.16.1 and 1.15.2 client (fixes #657) 2022-02-27 10:57:49 +01:00
Jonas Herzig
9528a5761c Update old ModMenu versions
To use the new maven group and for compatibility with newer fabric-loader.
2022-02-27 10:54:19 +01:00
Jonas Herzig
39ccea931d Release 2.6.3 2021-12-11 11:19:41 +01:00
Jonas Herzig
841c99148e Fix initial entity rotation getting lost (fixes #619)
This fixes the rotation of already existing entities that just got sent to the
client. Those get spawned with their rotation, which we didn't capture. This
commit fixes that by initializing our tracked rotation to NaN and returning the
original rotation until the tracked one is initialized (we do it this way rather
than initializing during the spawn packet handling because there are many spawn
packets, especially with modded, and we cannot possibly inject into all of
them).
This does not fix the rotation of newly placed entities (cause they seem to get
spawned with 0/0 and then get teleported to their correct rotation). The
previous commit fixed that case by capturing the rotation from the teleport
packet.
2021-12-11 11:00:57 +01:00
Jonas Herzig
e472713d1c Fix rotation from entity teleport getting lost (related to #619)
This fixes the rotation of newly placed entities (cause they seem to get spawned
with 0/0 and then get teleported to their correct rotation, which we didn't
capture).
This does not fix the rotation of already existing entities that just got sent
to the client, those already get spawned with their rotation, which we don't yet
capture. The following commit fixes that.
2021-12-11 10:52:30 +01:00
Jonas Herzig
1d76427a4d Release 2.6.2 2021-12-10 11:52:58 +01:00
Jonas Herzig
f943d11661 Bump to MC 1.18.1 2021-12-10 11:51:25 +01:00
Jonas Herzig
2df9049e6b Fix error when loading old replay on Java 9+ (fixes #578)
By updating the shadow plugin used in ReplayStudio.

java.lang.IncompatibleClassChangeError: Inconsistent constant pool data in classfile for class com/replaymod/replaystudio/lib/viaversion/libs/kyori/adventure/text/Component. Method 'boolean lambda$static$0(com.replaymod.replaystudio.lib.viaversion.libs.kyori.adventure.text.Component, com.replaymod.replaystudio.lib.viaversion.libs.kyori.adventure.text.Component)' at index 1064 is CONSTANT_MethodRef and should be CONSTANT_InterfaceMethodRef
2021-12-08 17:30:36 +01:00
Jonas Herzig
ad62e51ab3 Fix lighting when block is placed in same frame as chunk load 2021-12-08 16:22:06 +01:00
Jonas Herzig
59ac665c81 Disable auto-sync if there is no stable position (closes #488)
Cause not doing anything is better than flickering between different parts of
the timeline every frame.
2021-12-08 16:04:47 +01:00
Jonas Herzig
f4196748f5 Fix recording controls on menu-less pause screen (fixes #575) 2021-12-08 16:04:47 +01:00
Jonas Herzig
3d9d40656e Fix recording of riptide animation (fixes #581)
This code supposedly meant for recording when a player was eating/blocking was
never needed to begin with cause the server echos all data in DataTracker
anyway, and now it broke the riptide animation because that's part of the
living flags as well but wasn't considered here, i.e. unconditionally
overwritten.
2021-12-08 16:04:47 +01:00
Jonas Herzig
bd68a80152 Fix chroma key rendering for 1.12.2 and below (fixes #589)
Forge naming strikes again, there's two different `updateCameraAndRender` in
1.14.4 forge, which lead us to use `updateCameraAndRender` for the older version
as well even though our desired method had a different name back then.
2021-12-08 16:04:47 +01:00
Jonas Herzig
96f7b78a38 Fix spectator hand jittering in 1.12.2 and below 2021-12-08 16:04:47 +01:00
Jonas Herzig
1b18b5c952 Fix spectator hand jumping when rotating across 0 yaw boundary, take 2
The `yaw` value of non-client-players is constraint to [0; 360), so when that
boundary is crossed, the `renderYaw` starts interpolating to its goal the
incorrect way round (instead of crossing the 360 boundary as well).

To fix that, we now add the difference between the current `renderYaw` and the
desired one, modulo 360 (but with range (-180; 180]), to the current
`renderYaw`. That way we always take the short way round.
Additionally, because for rendering MC looks at the difference without modulo,
afterwards (and when a new `yaw` is set) we wrap the result around such that the
actual difference is always less than 180 and therefore rendered as intended.
2021-12-08 16:04:47 +01:00
Jonas Herzig
51aa07e01e Revert "Fix spectator hand jumping when rotating across 0 yaw boundary" (fixes #601)
This reverts commit 411eaa4ca8.

The given solution does not work in old versions because those did not use
`getYaw` for hand rendering. Even worse, their headYaw does wrap around and it
does it in a different way than their yaw value, giving a worse result than
without this commit.
2021-12-08 16:04:47 +01:00
Jonas Herzig
29ef38213f Fix vanilla entity update packet handling (fixes #607) 2021-12-08 16:04:47 +01:00
Jonas Herzig
b10b4fd25a Fix crash when render queue is not saved properly (fixes #617) 2021-12-07 13:35:36 +01:00
Jonas Herzig
9fa5adf395 Bump to MC 1.18 2021-12-07 13:35:36 +01:00
Jonas Herzig
d6cd917d9d Fix passengers getting stuck in unloaded chunks (fixes #606)
We need to update the vehicle before its passengers.
2021-12-07 13:35:36 +01:00
Jonas Herzig
88a23222b6 Fix vanilla 1.18 bug causing entities to get stuck outside sim range
MC uses the client-side position of an entity to determine whether it is inside
the simulation range and therefore whether it will get ticked. For some (most)
entities it interpolates the client-side position to match the server-side one
inside of the tick method... no prices for guessing where this goes wrong.

Somewhat similar to the issue we have with chunk unloads which we work around in
FullReplaySender but worse cause they'll get stuck if they ever leave the sim
range even for a single tick, rather then just when their chunk is unloaded.
2021-12-07 13:35:36 +01:00
Jonas Herzig
ff5c0f594e Fix chunks missing on first frame when rendering without Sodium 2021-12-07 13:35:36 +01:00
Jonas Herzig
58ba590c84 Fix replay being restarted when resuming path playback 2021-12-07 13:35:36 +01:00
Jonas Herzig
549996b270 Fix underwater visibility (fixes #572)
Used to always be super short because that method returns 0 when `isSubmergedIn`
returns false.
2021-12-07 13:35:31 +01:00
Jonas Herzig
bd0dd10942 Ensure we cannot accidentally open a replay file twice
E.g. from the Replay Viewer while it is still being recovered.
Because that would potentially corrupt it.
2021-11-29 17:42:44 +01:00
Jonas Herzig
31817bcf11 Split replay folder and file management into their own classes 2021-11-29 17:42:44 +01:00
Jonas Herzig
ce5886a427 Port to MC 1.18-rc4 2021-11-29 17:42:44 +01:00
Jonas Herzig
b6f623efb8 Update Gradle to 7.3 2021-11-29 16:22:37 +01:00
Jonas Herzig
2ee8fe49c5 Update FG 2.1 to download MCP from Forge maven
Cause the MCP site is now offline.
2021-11-29 16:22:37 +01:00
Jonas Herzig
090778ca63 Fix build for 1.15.x and below 2021-11-29 16:22:37 +01:00
Jonas Herzig
dd055e5c5b Fix build for 1.8 2021-11-29 16:22:37 +01:00
Jonas Herzig
6e1febdab8 Port to MC 1.18-pre1 2021-11-14 17:27:35 +01:00
Jonas Herzig
d2f27e3918 Update Loom to 0.10 2021-11-14 16:09:37 +01:00
Jonas Herzig
55f3a15db6 Release 2.6.1 2021-08-21 15:32:42 +02:00
Jonas Herzig
33328adc9f Fix recording of 4-8 block teleports on 1.8.9 and below (fixes #525) 2021-08-21 15:11:55 +02:00
Jonas Herzig
5f9297b78e Improve lang resource pack injection point (closes #532)
Previously we injected it as a regular builtin resource pack (like the
Programmer Art pack) and hid it on the resource pack screen but this is bad for
several reasons. The most significant one being that it can be re-ordered and
makes the resource pack list ordering weird if you don't know that there is an
invisible pack there.
It also unnecessarily messes with other mods which make certain assumptions
about configurable resource packs (e.g. EBE, though in that case, it merely
triggers an existing bug in EBE).

We now instead inject it into the final resource pack list which gets
constructed from the configured packs, but never as a configurable pack itself.
2021-08-21 15:11:55 +02:00
Jonas Herzig
411eaa4ca8 Fix spectator hand jumping when rotating across 0 yaw boundary
The `yaw` value of non-client-players is constraint to [0; 360), so when that
boundary is crossed, the `renderYaw` starts interpolating to its goal the
incorrect way round (instead of crossing the 360 boundary as well).

Instead we now use the `headYaw` value, which does not wrap around and as such
does not have this issue.
2021-08-21 15:11:55 +02:00
Jonas Herzig
6428416bc4 Fix between-ticks position of hand when spectating (fixes #563) 2021-08-21 15:11:55 +02:00
Jonas Herzig
0e5de6c816 Update ReplayStudio
c9de2f5 Fix incorrect initial version for Combat* packets (fixes #568)
a22df13 Fix off-by-3 in quick mode chunk unloading code
2e2cac4 Guard against bad chunk light masks (fixes #557)
2021-08-21 15:11:41 +02:00
Jonas Herzig
0ceb95a5e2 Abort path preview when opening render screen (fixes #524) 2021-08-21 15:11:41 +02:00
Jonas Herzig
de3f4dab7e Pause path playback while resource pack is loading (closes #540) 2021-08-21 15:11:41 +02:00
Jonas Herzig
612a90681e Reset camera inventory when no longer spectating (fixes #546) 2021-08-21 15:11:29 +02:00
Jonas Herzig
88dece679d Fix scissor state not including scissor bounds (fixes #556)
This caused the bounds to not be relaxed after e.g. lists and as such the scroll
bar and shadows would not render properly.
2021-08-15 17:25:23 +02:00
Jonas Herzig
82c7da8739 Fix advanced screenshot GUI not opening on 1.17.1 (fixes #559) 2021-08-15 16:53:12 +02:00
Jonas Herzig
b243dfc625 Workaround soft-lock when REI screen is closed (fixes #560) 2021-08-15 16:41:50 +02:00
Jonas Herzig
27f365a60a Change skin-caching feature to be fail-safe (fixes #561) 2021-08-15 13:53:31 +02:00
Jonas Herzig
463c51be85 Convert getDefaultRenderSettings into default constructor
Allows us to completely get rid of the custom Gson instance and is more
idiomatic anyway.
2021-08-15 11:45:23 +02:00
Jonas Herzig
9626a4c442 Fix parsing of render queue with chroma key (fixes #564)
By simply replacing the private field with a concrete type, so we do not need to
manually register one when constructing the gson instance (which is evidently
too easy to forget about).
2021-08-15 11:39:10 +02:00
Jonas Herzig
3db8c28505 Fix .no_recover files never being cleaned up (fixes #497) 2021-08-15 11:28:11 +02:00
Jonas Herzig
110199044f Fix nametags not rendering in screenhots (fixes #498)
No clue why this extra hud hiding was even there in the first place, the
renderer already takes care of properly hiding the hud (without hiding the
nametags) as it does for videos as well.
2021-08-15 11:19:52 +02:00
Jonas Herzig
4a587eed74 Workaround crash with REI and MainMenuScale (fixes #501, fixes #473) 2021-08-15 11:07:19 +02:00
Jonas Herzig
e2b0422965 Fix timeline not saving when completely overwritten (fixes #505)
Either when it is cleared or when it is loaded from the keyframe repository, if
you exit the replay without any further changes, this used to not be saved.
2021-08-15 10:47:34 +02:00
Jonas Herzig
a793cbee0d Remove RM 2.6+ for MC 1.7.10 from versions.json 2021-08-01 16:59:51 +02:00
Jonas Herzig
f95a943589 Release 2.6.0 2021-07-31 16:01:48 +02:00
Jonas Herzig
c88b4c1e76 Add missing .gitkeep files 2021-07-31 16:01:11 +02:00
Jonas Herzig
a457bccf12 Fix Java 9+ ABI being used for Java 8 versions 2021-07-31 15:31:43 +02:00
Jonas Herzig
3cba99068e Increase default bitrate to from 10 to 20mbps 2021-07-31 14:37:10 +02:00
Jonas Herzig
e9bf75b4d6 Remove ModCore
That was never actually finished and we do not need to keep it around anymore.
Whether we add its successor once that is ready for production use remains to be
seen.
2021-07-24 19:15:08 +02:00
Jonas Herzig
5bede327f3 Update jGui (fixes textures with Sodium) 2021-07-24 17:09:16 +02:00
Jonas Herzig
0cb14a9106 Re-introduce entity-in-wrong-chunk-at-unload workaround (fixes #548)
Nope, this was not fixed, they just changed where the chunkCoords are stored but
the interpolation issue remains.
2021-07-24 17:06:46 +02:00
Jonas Herzig
35fef5176d Fix skins of server-only NPCs being unreliable (fixes #486) 2021-07-24 14:43:38 +02:00
Jonas Herzig
3ef355a267 Failure to hide cache folder should never be fatal (closes #512) 2021-07-24 13:17:14 +02:00
Jonas Herzig
4090e7b540 Search for homebrew in /opt as well (fixes #496) 2021-07-24 13:14:23 +02:00
Jonas Herzig
2891c4e8fa Remove MP4 Default Quality preset (closes #475)
Similar to High Quality, it is too unpredictable, sometimes giving bad quality
and sometimes being unbearably slow. We should just encourage everyone to set
their bitrate manually.
2021-07-24 12:59:06 +02:00
Jonas Herzig
83cb459957 Fix keyframes being required to open render queue window
Half the reason we swapped the render queue / settings parent relationship was
so we don't need to go through the settings screen to access the queue. But for
some reason I stopped half way through and didn't also move the "You need at
last two keyframes." popup. This commit rectifies that.
2021-07-24 12:46:13 +02:00
Jonas Herzig
3f4dae05db Fix missing preprocessor comments 2021-07-24 11:30:34 +02:00
Jonas Herzig
2f4360a2a1 Fix Mixin_PreserveDepthDuringGuiRendering for 1.14-16 2021-07-24 11:29:27 +02:00
Jonas Herzig
2415a886e2 Update to 1.17.1 2021-07-24 11:05:39 +02:00
Jonas Herzig
927db36baa Use same fabric-loader version across all MC versions 2021-07-24 11:05:00 +02:00
Jonas Herzig
d0620091d2 Add support for FREX Flawless Frames API (fixes #150) 2021-07-24 09:11:34 +02:00
Jonas Herzig
96bb1abc1d Update ReplayStudio
0e72e36 Add workaround for lack of way to determine global palette size
872bc75 Update vanilla global palette size
19d3dab Fix OOB when converting local palette storage to global palette (fixes #509)
c93a370 Fix incorrect packet release during SquashFilter.flush (fixes #490, fixes #492)
2021-07-01 14:05:52 +02:00
Jonas Herzig
7a52a29ef3 Fix race condition in resource pack recording (fixes #521)
If the server sends the resource pack right on connect (rather than when
switching to a sub-server), then `mc.getNetworkHandler()` will be null.
2021-07-01 14:05:52 +02:00
Jonas Herzig
7ab2edd738 Implement ODS rendering via Iris Shader for MC 1.17 2021-07-01 14:05:52 +02:00
Jonas Herzig
f462a5b391 Fix 1.12 shim Window.getScaledHeight 2021-07-01 14:05:52 +02:00
Jonas Herzig
e85618a27c Change frame time (used by Iris) to be based on replay or video time
Iris derives that one from the frameStartNanos argument passed to the render
method and shaders usually use it to do animations. Prior to this commit we
always pass 0 which effectively froze any shader animations.

With this commit, we now compute the frameStartNanos based on the
FPS of the video we are rendering (so animations will happen in real time when
watching the video) or based on the time in the replay (so animations will
be influenced by playback speed / be frozen if the replay is frozen).
We default to the video time based approach because the replay time one may
produce undesirable results when it comes to things like motion blur and TAA.
2021-07-01 14:05:52 +02:00
Jonas Herzig
3f2456ba65 Use GameRenderer.render instead of renderWorld, improves compat
In particular, Iris updates its frame counter and timer in the outer method, so
if we only call the inner one, then its shadows and sky will not update
properly.
Since the render method also renders the GUI, we set the current screen to null
and cancel the HUD during rendering. MC also clears the depth before rendering
the HUD, which we don't want because it breaks the depth map export, so we
cancel that as well.

This also allows Vanilla post-processing (aka Super Secret Settings, aka Vanilla
Shaders) as well as entity outlines to function properly cause those are applied
in that method as well.
Should have done this a long time ago but better late than never.

Closes #321
2021-07-01 14:05:52 +02:00
Jonas Herzig
ed99e240ec Bundle missing transitive fabric-api dependency 2021-06-28 19:06:26 +02:00
Jonas Herzig
0fcb27c6b2 Fix keyPressed/keyReleased injection targets 2021-06-28 19:06:26 +02:00
Jonas Herzig
5289026313 Bump MC to 1.17 proper 2021-06-28 19:06:26 +02:00
Jonas Herzig
2be47e9810 Change ReplayButton icon to be white with shadow for better contrast
The previous one, blue with no shadow, had horrible contrast with the button
background and did not fit well with any of the other buttons.
Now it does (except that it's not yet in the 20-pixel width/height style).
2021-06-28 19:06:26 +02:00
Jonas Herzig
1af4add932 Update ReplayStudio
- MC 1.17
- Updated ViaVersion
- Quick Mode supports multiple worlds now (and no longer needs a manual Respawn)
2021-06-28 19:06:26 +02:00
Jonas Herzig
8d3d705fed Switch to commons-lang Pair instead of the ViaVersion one
Cause that one will be removed in a future version, and the lang one is just
fine.
2021-06-28 14:35:57 +02:00
Jonas Herzig
766d3346ee Pin FG5 version because its maintainers cannot be trusted
Versions after 5.0.5 emit tsrg2 instead of tsrg, breaking anything which reads
those files (e.g. Mixin and the preprocessor), later versions even bump the
required Gradle version.
2021-06-27 14:44:16 +02:00
Jonas Herzig
08165252d5 Switch to new Quick Mode backend 2021-06-06 10:42:16 +02:00
Jonas Herzig
1802b1a7d0 Port to 1.17-pre1 2021-06-06 10:42:16 +02:00
Jonas Herzig
5f2dca08d1 Fix "Cannot register receiver while client is not logging in!"
Since MC provides no reliable way to get the connection while still in the login
phase, Fabric API tries to determine it either from MinecraftClient's connection
field (for the integrated server) or from the ConnectScreen (for multiplayer).
However, neither is present during a replay, leading to the aforementioned
error.

To fix this, we store our ClientConnection in MinecraftClient's connection
field. This should have no significant effect on vanilla behavior.

Also remove the dead Forge 1.14 code which was in the same place.
2021-06-05 23:01:16 +02:00
Jonas Herzig
25a6cdc502 Fix RenderSettings (de)serialization with Java 16 (fixes #520)
Turns out we were relying on the implementation detail of the File class, and
Java 16 ensures we cannot do that.
2021-06-05 23:01:16 +02:00
Jonas Herzig
9d3583293b Bundle Gson on 1.11.2 and below (fixes #421)
Decided to go with 1.11.2 because the Gson from that version is the first to not
have the JsonAdapter annotiation, which we want for fixing #520.
2021-06-05 23:01:16 +02:00
Jonas Herzig
e380907334 Switch preprocessor config to flat style 2021-06-05 23:01:16 +02:00
Jonas Herzig
4cdbfb7c46 Update Gradle to 7.0.2 2021-06-05 23:01:16 +02:00
Jonas Herzig
59fb58c6fc Disable 1.7.10 for now
Continued support would require porting FG1.2 to Gradle 7 / Java 16.
2021-06-05 22:57:46 +02:00
Jonas Herzig
f5af283492 Update for new forge maven repo 2021-04-22 14:09:58 +02:00
Jonas Herzig
3440b8d8a8 Update loom to 0.6 2021-03-14 12:13:06 +01:00
Jonas Herzig
537795f9ca Backport contextual key bindings to 1.12.2 and below (closes #478) 2021-03-14 12:12:53 +01:00
Jonas Herzig
dda6bd41b6 Implement ffmpeg-independent PNGWriter (closes #476)
Creates a dedicated folder for each video and does not depend on ffmpeg, just
like the EXRWriter (but supporting all MC versions).

Also does 32 bit depth export by chunking the 32-bit float into the 8-bit BGRA
component channels.
2021-03-14 12:12:53 +01:00
Jonas Herzig
8ff27437af Add configurable, small Replay Viewer button (closes #471) 2021-03-14 12:12:53 +01:00
Jonas Herzig
c6b41d76fa Document valid values for MultipleChoiceSettings in config file 2021-03-14 12:12:53 +01:00
Jonas Herzig
4ca4f2def6 Auto-reload config file on changes (Fabric only) 2021-03-14 12:12:53 +01:00
Jonas Herzig
61d67a5e80 Remove OpenEye (closes #465)
It is not available for Fabric and we stopped using it.
2021-03-14 12:12:53 +01:00
Jonas Herzig
b7309283e9 Rename MixinRendererLivingEntity -> Mixin_HideNameTags_LivingEntity 2021-03-14 12:12:53 +01:00
Jonas Herzig
a97190de1e Move MixinRendererLivingEntity into 1.8.9 project 2021-03-14 12:12:53 +01:00
Jonas Herzig
c17fc79ab2 Rename MixinRender -> Mixin_HideNameTags 2021-03-14 12:12:53 +01:00
Jonas Herzig
1924963d75 Move MixinOpenGlHelper into 1.7.10 project 2021-03-14 12:12:53 +01:00
Jonas Herzig
aba34d6c6f Rename Mixin_CubicRotation -> Mixin_Omnidirectional_Rotation 2021-03-14 12:12:53 +01:00
Jonas Herzig
db5708f338 Rename MixinFrustum -> Mixin_Omnidirectional_DisableFrustumCulling 2021-03-14 12:12:53 +01:00
Jonas Herzig
6974f8e60c Rename MixinCamera -> Mixin_StabilizeCamera 2021-03-14 12:12:53 +01:00
Jonas Herzig
3ec81d5c35 Split MixinEntityRenderer into multiple, more focused files 2021-03-14 12:12:53 +01:00
Jonas Herzig
fad89626e5 Move 1.7.10 code from MixinEntityRenderer to Mixin_ForceChunkLoading 2021-03-14 12:12:53 +01:00
Jonas Herzig
e7a1fafdf9 Extract Mixin_ChromaKeyDisableFog from other mixins 2021-03-14 12:12:53 +01:00
Jonas Herzig
cf1d7537e8 Move MixinEffectRenderer into 1.8.9 project 2021-03-14 12:12:53 +01:00
Jonas Herzig
10426f9d39 Move MixinChunkRenderWorker into 1.14.4 project 2021-03-14 12:12:53 +01:00
Jonas Herzig
2fb4f73ae4 Move ChunkRenderDispatcherAccessor into 1.14.4 project 2021-03-14 12:12:53 +01:00
Jonas Herzig
6289545d84 Remove forge/fml event bus from MCVer 2021-03-14 12:12:53 +01:00
Jonas Herzig
cfb9e15b8a Make use of new @Pattern feature to centralize version-aware code
That is, most of the business code should not be aware that it is being compiled
to multiple versions even when it heavily interacts with MC, preprocessor
statements should be an escape hatch, not the norm.
Similarly, code should not be forced to do `MCVer.getWindow(mc)` instead of the
much more intuitive `mc.getWindow()`, and a new preprocessor (technically remap)
feature makes this possible by defining "search and replace"-like patterns (but
smarter in that they are type-aware) in one or more central places (the
"Patterns.java" files) which then are applied all over the code base.

In a way, this is another step in the automatic back-porting process where
preprocessor statements are used when we cannot yet do something automatically.
Previously we "merely" automatically converted between different mapping, this
new feature now also allows us to automatically perform simple refactoring
tasks like changing field access to a getter+setter (e.g. `mc.getWindow()`), or
changing how a method is called (e.g. `BufferBuilder.begin`), or changing a
method call chain (e.g. `dispatcher.camera.getYaw()`), or most other
search-and-replace-like changes and any combination of those.
The only major limitation is that the replacement itself is not smart, so
arguments must be kept in same order (or be temporarily assigned to local
variables which then can be used in any order).
2021-03-14 12:12:51 +01:00
Jonas Herzig
06a46e6f38 Use callback-style events for crosshair and hotbar render events 2021-02-28 09:52:19 +01:00
Jonas Herzig
da16b0fb78 Add 1.14.4 <> 1.12.2 mapping for Option <> GameSettings.Options 2021-02-28 09:52:19 +01:00
Jonas Herzig
f34b88cf7e Move MixinShader into 1.7.10 project 2021-02-28 09:52:19 +01:00
Jonas Herzig
d7dde42add Move HideInvisibleEntities into 1.12.2 project 2021-02-28 09:52:19 +01:00
Jonas Herzig
5f652ec7f2 Move DisableBetterSprinting into 1.12.2 project 2021-02-28 09:52:19 +01:00
Jonas Herzig
05d7971332 Move mapwriter.MixinMinecraft into 1.12.2 project 2021-02-28 09:52:19 +01:00
Jonas Herzig
4eeaca5af1 Use MainWindowAccessor across all versions 2021-02-28 09:52:19 +01:00
Jonas Herzig
e4da7f331b DRY main MC window resizing 2021-02-28 09:52:19 +01:00
Jonas Herzig
3fbb4b50ea Rename ChunkLoadingRenderGlobal → ForceChunkLoadingHook
More descriptive, less MCP.
2021-02-28 09:52:19 +01:00
Jonas Herzig
ab5b101f96 Add stub ChunkLoadingRenderGlobal for 1.7.10
Allows us to get rid of all preprocessor guards around its usages.
2021-02-28 09:52:19 +01:00
Jonas Herzig
c729654f04 Split off 1.14.4 overwrite from ChunkLoadingRenderGlobal 2021-02-28 09:52:19 +01:00
Jonas Herzig
f19ee8ba63 Split off 1.14.4 overwrite from Mixin_ForceChunkLoading 2021-02-28 09:52:19 +01:00
Jonas Herzig
90bbc68443 Replace reflection in ChunkLoadingRenderGlobal with mixin 2021-02-28 09:52:19 +01:00
Jonas Herzig
4b4d18026b Move GLStateTracker into 1.7.10 project 2021-02-28 09:52:19 +01:00
Jonas Herzig
74580e6649 Remove redundant preprocessor statements 2021-02-28 09:52:19 +01:00
Jonas Herzig
87b55e187c Replace a few //#if statements with mapping file entries 2021-02-28 09:52:19 +01:00
Jonas Herzig
026bc1fdcb Move MixinWorldClient into 1.12.2 project 2021-02-28 09:52:19 +01:00
Jonas Herzig
470669b1f7 Move MixinRenderManager into 1.12.2 project 2021-02-23 01:21:44 +01:00
Jonas Herzig
b8bcb4967f Move MixinFMLClientHandler into 1.7.10 project 2021-02-23 01:05:48 +01:00
Jonas Herzig
6fa746a2e3 Move MixinEntityRenderer into 1.7.10 project 2021-02-23 01:01:55 +01:00
Jonas Herzig
01d47279fd Split off 1.12.2 overwrite from MixinCamera 2021-02-23 00:59:56 +01:00
Jonas Herzig
06db2ebb92 Move MixinS26PacketMapChunkBulk into 1.7.10 project 2021-02-23 00:47:01 +01:00
Jonas Herzig
6068aabea7 Move MixinPlayerControllerMP into 1.12.2 project 2021-02-23 00:45:12 +01:00
Jonas Herzig
6bc130312a Move MixinNetworkDispatcher into 1.12.2 project 2021-02-23 00:41:22 +01:00
Jonas Herzig
ba7c478da1 Split off 1.12.2 overwrite from MixinNetHandlerLoginClient 2021-02-23 00:41:22 +01:00
Jonas Herzig
25247a2371 Move MixinGuiScreen into 1.7.10 project 2021-02-23 00:41:22 +01:00
Jonas Herzig
22d1048999 Move FMLHandshakeFilter into 1.12.2 project 2021-02-23 00:41:22 +01:00
Jonas Herzig
6094422792 Split off highly version-dependent code from ModCompat 2021-02-23 00:41:22 +01:00
Jonas Herzig
029b228b26 Move ReplayModTweaker into 1.12.2 project 2021-02-23 00:41:22 +01:00
Jonas Herzig
9bde5fae49 Move ResourcePackRepositoryAccessor into 1.7.10 project 2021-02-23 00:41:22 +01:00
Jonas Herzig
f15eaf95c1 Split off 1.12.2 overwrite from MixinKeyboardListener 2021-02-23 00:41:22 +01:00
Jonas Herzig
9e152f2655 Move GLStateTrackerTransformer into 1.7.10 project 2021-02-23 00:41:22 +01:00
Jonas Herzig
1329f2d703 Move GLErrorTransformer into 1.7.10 project 2021-02-23 00:41:22 +01:00
Jonas Herzig
66c1f63219 Move GuiFactory into 1.12.2 project 2021-02-23 00:41:22 +01:00
Jonas Herzig
633bc19650 Use callback-style events throughout all versions
Removes the need for //#if statements on each and every event handler.
Instead we now always use the equivalent Callback and have one central 1.12.2
class which forwards Forge events to the callbacks.
2021-02-23 00:41:22 +01:00
Jonas Herzig
0be2082fe7 Split off highly version dependent code from ReplayMod 2021-02-20 00:43:49 +01:00
Jonas Herzig
bc9d8cb3d1 Split off highly version dependent code from SettingsRegistry 2021-02-20 00:43:46 +01:00
Jonas Herzig
9a67a64555 Drop server-side restrictions implementation
I don't think this sees sufficient use to justify updating.
Especially because it's non-trivial with forge's network changes.
Ping me if you actually used this.
2021-02-20 00:43:46 +01:00
Jonas Herzig
1a35234b0a Move LoadingPlugin into 1.12.2 project 2021-02-19 23:02:39 +01:00
Jonas Herzig
9d81265213 Update preprocessor plugin 2021-02-19 23:01:43 +01:00
Jonas Herzig
bcde675775 Update jGui 2021-02-19 17:32:41 +01:00
Jonas Herzig
8c2d7d096c Merge branch 'stable' into develop 2021-02-19 11:58:28 +01:00
Jonas Herzig
ff47174fd6 Release 2.5.2 2021-02-17 21:56:30 +01:00
Jonas Herzig
c0a95d278e Add toString implementation to RenderSettings
We print them to the log in a few places, that's fairly useless without a
toString implementation.
2021-02-17 21:53:07 +01:00
Jonas Herzig
fed90b5597 Update ReplayStudio
a1f82a7 Properly handle same-dimension respawns in squash and quick mode (fixes #139, fixes #455)
7b84461 Fix NPE if there is a block change at time 0 (fixes #446)
ee9d7d5 Switch to LGPLv3+ as primary license
2021-02-17 18:20:48 +01:00
Jonas Herzig
51a4ade37e Fix slow drifting in FullReplaySender replay time (fixes #451) 2021-02-17 15:16:33 +01:00
Jonas Herzig
2f0160c4f6 Update loom to 0.5 (closes #453) 2021-02-17 11:39:57 +01:00
Jonas Herzig
56e5df65d5 Use vanilla sound engine to play render success sound (fixes #286) 2021-02-17 11:27:09 +01:00
Jonas Herzig
5f0218929b Process sub-selection of render jobs in displayed order (fixes #488) 2021-02-17 03:33:14 +01:00
Jonas Herzig
6d0d50f5b3 Fix "Render All" button in render queue (fixes #447) 2021-02-17 03:06:52 +01:00
Jonas Herzig
c54638db30 Update ReplayStudio (fixes #368)
e7d5bf5 Fix wrap around for LinearInterpolator
2021-02-17 02:57:10 +01:00
Jonas Herzig
cdb93a1716 Fix spectating via clicking on forge (fixes #432) 2021-02-17 02:55:49 +01:00
Jonas Herzig
02a731e018 Update jGui (fixes #429)
3596f15 Improve timeline time indicators for really long (1h+) timelines
2021-02-17 01:39:38 +01:00
Jonas Herzig
ae0b0e3f13 Allow any entity to be spectated on 1.8+ (fixes #382)
Idk why this was restricted in the first place, ask Marius: 163faddd
2021-02-17 01:19:29 +01:00
Jonas Herzig
a9a0c2ddc3 Update jGui (fixes #428)
e3cd741 Re-open GuiOverlay if externally closed while `!closeable`
5a90b8b Fix GuiOverlay.closeable not being respected on 1.14+
2021-02-17 01:19:29 +01:00
Jonas Herzig
72d5d43ad2 Suppress CancellationException when stopping camera path 2021-02-17 01:19:29 +01:00
Jonas Herzig
a5f874e571 Fix crash with certain render output file values (fixes #396) 2021-02-17 01:19:29 +01:00
Jonas Herzig
9dfdfd6fe3 Update bundled mixin version (fixes #438) 2021-02-17 01:19:29 +01:00
Jonas Herzig
d8cae487c2 Rename build scripts: build -> root and common -> build
This way it's easier for people not familiar with the preprocessor setup to find
what they are looking for.
2021-02-17 00:13:42 +01:00
Jonas Herzig
7e5734067f Remove jcenter repo, it will be shutting down
We have only been using it for the shadow plugin which is also available in the
plugins.gradle.org repo.
2021-02-17 00:13:42 +01:00
Daniel N. Werner
159f0e259f Update common.gradle
Stable and develop are returning 520 from CloudFlare, looks like they've switched the maven repository to use https.
2021-02-16 22:43:55 +01:00
Jonas Herzig
19ff1ef38b Do not bother recovering useless replays (fixes #444)
Useless replays being those for which auto-recording was disabled and Start
never pressed.
2021-02-16 22:38:39 +01:00
Jonas Herzig
57c7362e34 Merge branch 'stable' into develop 2020-11-22 17:10:27 +01:00
Jonas Herzig
dabb64340e Release 2.5.1 2020-11-22 16:19:28 +01:00
Jonas Herzig
99b1528dcc Update doRelease task for current branching model 2020-11-22 16:18:22 +01:00
Jonas Herzig
673964ea6a Hide Saving Replay popup when no output is produced (fixes #420)
I.e. if the had Auto-Recording disabled and never pressed start, there won't be
any replays and it would just be the Done button, which is pointless.
2020-11-22 16:04:14 +01:00
Jonas Herzig
c3c59ec1c0 Trim video file extension from glb file name (fixes #422) 2020-11-22 15:18:41 +01:00
Jonas Herzig
d06ef47f1c Update ReplayStudio (fixes #426) 2020-11-22 15:15:41 +01:00
Jonas Herzig
68ca92e8a2 Update changelog URL 2020-11-22 15:06:28 +01:00
Jonas Herzig
f7f20ee6cb Add setting to disable Saving Replay rename dialog (closes #423) 2020-11-22 15:03:24 +01:00
Jonas Herzig
f895a13b61 Apply Saving Replay dialog when pressing Enter (closes #424) 2020-11-22 14:55:07 +01:00
Jonas Herzig
4739d2278b Fix render settings not saving when rendering (fixes #425)
Clicking Cancel or Add to Queue does save them but clicking Render does not.

This is caused by the fact that the GuiRenderSettings are now a popup and no
longer their own screen, so to close them, we need to call its close method, not
close the entire screen.
2020-11-22 14:53:40 +01:00
Jonas Herzig
d4b7fdf949 Update remap (fixes #414)
Support remapping of mixin targets declared in static fields (specifically
`core.MixinKeyboardListener:ON_KEY_PRESSED`).

String literals in annotations can be specified in a static final field instead
of inline (so you can e.g. use the same literal in multiple places).
This commit adds support for remapping those external literals.
2020-11-22 14:31:03 +01:00
Jonas Herzig
ee02944391 Fix crash when rendering ODS without depth export (fixes #418) 2020-11-22 13:00:37 +01:00
Jonas Herzig
36276d32b6 Fix camera path export roll being inverted (fixes #427) 2020-11-22 09:14:51 +01:00
Jonas Herzig
6879729633 Fix OpenEXR export option throwing UnsatisfiedLinkError on Windows 2020-11-15 13:17:00 +01:00
Jonas Herzig
4a5d971be5 Release 2.5.0 2020-11-14 10:01:46 +01:00
Jonas Herzig
bcaf946f13 Move .gitkeep from 1.16.3 to 1.16.4 folder (fixup c620e2c) 2020-11-14 09:55:36 +01:00
Jonas Herzig
514c4fb30d Merge pull request #412 from LindaJuffermans/docs-201110-labymod370
LabyMod update 3.7.x has been tested with ReplayMod and works.
2020-11-10 13:35:55 +01:00
LindaJuffermans
6552fc68c0 LabyMod update 3.7.x has been tested with ReplayMod and works. 2020-11-10 09:32:32 +01:00
Jonas Herzig
0f67ba157e Merge pull request #408 from LindaJuffermans/docs-201107-direct-ffmpeg-link
Update ffmpeg link to the essential release ZIP file directly.
2020-11-08 10:15:42 +01:00
Jonas Herzig
1b4e68e4b2 Merge pull request #410 from LindaJuffermans/docs-201107-quickmode-194
Quick Mode is only available for MC 1.9.4 and up.
2020-11-08 10:13:24 +01:00
LindaJuffermans
f1e197b830 Quick Mode is only available for MC 1.9.4 and up. 2020-11-07 20:34:37 +01:00
Jonas Herzig
d3f1ce92b9 Merge pull request #407 from LindaJuffermans/docs-201107-resourceloader
Resource Loader is not compatible
2020-11-07 16:02:27 +01:00
LindaJuffermans
3cc2a90b64 Update ffmpeg link to the essential release ZIP file directly. 2020-11-07 15:55:09 +01:00
LindaJuffermans
28b2f87324 Resource Loader is not compatible 2020-11-07 15:49:59 +01:00
Jonas Herzig
ec862f0596 Update jGui 2020-11-07 13:18:10 +01:00
Jonas Herzig
6308b8a859 Add line between time keyframes and replay timeline (closes #351) 2020-11-06 18:54:55 +01:00
Jonas Herzig
3911ff4058 Fix crash when jumping to 00:00 (closes #227) 2020-11-06 18:54:55 +01:00
Jonas Herzig
c620e2cf9e Update to MC 1.16.4 (closes #406) 2020-11-06 18:54:55 +01:00
Jonas Herzig
4bff201307 Show warning if first keyframe is not placed at 00:00 (closes #352) 2020-11-06 18:54:55 +01:00
Jonas Herzig
577e59fd41 Add undo/redo to keyframe timeline (closes #305) 2020-11-06 18:54:55 +01:00
Jonas Herzig
28facc430e Allow raw key handlers to cancel keybindings (required for #305)
So that when you press e.g. Ctrl+Z, it doesn't trigger the keybinding bound to
Z (currently full brightness).
2020-11-06 18:54:54 +01:00
Jonas Herzig
ccb08d37a7 Store server name (in addition to address) in replays (closes #324) 2020-11-06 18:54:54 +01:00
Jonas Herzig
6e6af1dcbb Allow keyframe timeline cursor sync to be toggled (closes #290) 2020-11-06 18:54:54 +01:00
Jonas Herzig
214100840e Auto-scroll keyframe timeline to cursor where possible (closes #291) 2020-11-06 18:54:54 +01:00
Jonas Herzig
e7eef08512 When tabbing into text field, select all its text (closes #211) 2020-11-06 18:54:54 +01:00
Jonas Herzig
fa8266f71c Fix sync not working when triggered via hotkey buttons (fixes #399) 2020-11-06 18:54:54 +01:00
Jonas Herzig
dd5935649d Do not rely on error handling popup for sodium info (fixes #392)
Instead we now disable all the Render buttons and give them a tooltip. Much more
user-friendly.
2020-11-06 18:54:54 +01:00
Jonas Herzig
76bec31cd8 Move cache folders into central (hidden) location (closes #343) 2020-11-06 18:54:54 +01:00
Jonas Herzig
3ce10d4855 Get rid of thumb magic (closes #237) 2020-11-06 18:54:54 +01:00
Jonas Herzig
4402650971 Split hotkey button text over two lines if necessary (fixes #353) 2020-11-06 18:54:53 +01:00
Jonas Herzig
6016ebece7 Fix label of non-letter keys in hotkey buttons 2020-11-06 18:54:53 +01:00
Jonas Herzig
f51f6032ca Use empty hotkey button when key is unbound across all versions
This happened to already be the case in 1.16.3 (because of another bug), this
commit makes it intentional and consistent across all versions.
Using the empty label over NONE or another label because it doesn't change the
width of the button and therefore fits nicer with all the other buttons.
2020-11-06 18:54:53 +01:00
Jonas Herzig
e86a583558 Fix crash when clicking hotkey button; introduced in 83690f4 2020-11-06 18:54:53 +01:00
Jonas Herzig
6fc7b8fb0f Fix incorrect layering of vanilla gui additions (fixes #385) 2020-11-06 18:54:53 +01:00
Jonas Herzig
8f094000fe Fix camera FOV not matching configured FOV
This is because the camera is considered flying which causes MC to increase its
FOV slightly.
2020-11-06 18:54:52 +01:00
Jonas Herzig
d3230e1e38 Add camera path export (closes #391) 2020-11-06 18:54:52 +01:00
Jonas Herzig
d8135d9038 Add depth map export (closes #371) 2020-11-06 11:41:38 +01:00
Jonas Herzig
a7d424679b Remove duplicate code between Simple and MultiFrame PBO capturer 2020-11-06 11:41:38 +01:00
Jonas Herzig
2b6d1b2359 Add OpenEXR export option
In preparation for depth map export.
2020-11-06 11:41:38 +01:00
Jonas Herzig
f57286043d Merge pull request #401 from LindaJuffermans/docs-201028-modlinks
Removed links to other mods which may trigger Chrome's safe browsing block.
2020-10-28 21:54:26 +01:00
LindaJuffermans
57900edf31 Fixed linebreak after Lunar Client 2020-10-28 19:49:33 +01:00
LindaJuffermans
3b428c7574 Removed links to other mods which may trigger Chrome's safe browsing block. 2020-10-28 19:47:22 +01:00
Jonas Herzig
5bd85e4c09 Merge pull request #400 from LindaJuffermans/docs-201026-futureclient
Future Client crashes on the Mixin
2020-10-28 19:15:04 +01:00
LindaJuffermans
d9ba1d24f5 Future Client crashes on the Mixin 2020-10-26 16:40:27 +01:00
Jonas Herzig
ad6c2aa3d9 Merge pull request #394 from LindaJuffermans/docs-1021-17animations
1.7 Animations w/shaders can cause floating glass and water
2020-10-21 18:30:42 +02:00
Jonas Herzig
45922acbc1 Merge pull request #393 from LindaJuffermans/docs-1021-ffmpeg43
Removed old issue from zeranoe's ffmpeg 4.3 missing libx264
2020-10-21 18:30:32 +02:00
LindaJuffermans
d7e309bca4 Removed old issue from zeranoe's ffmpeg 4.3 missing libx264 2020-10-21 15:55:04 +02:00
LindaJuffermans
716ec321ca 1.7 Animations w/shaders can cause floating glass and water 2020-10-21 15:52:25 +02:00
Jonas Herzig
17e554b67c Rename VideoWriter -> FFmpegWriter 2020-10-03 14:52:58 +02:00
Jonas Herzig
aee486c4f3 Stop assuming that our render pipeline will only process RGB frames
For one, we have already switched to RGBA some time ago, so the name was
technically incorrect already.
But the main reason is that we'll want to use them for depth maps as well (and
potentially maybe even for HDR images if that's possible with canvas?).
2020-10-03 14:50:44 +02:00
Jonas Herzig
4c4c052d8a Record into separate folder so replays only show once fully saved 2020-10-03 12:30:44 +02:00
Jonas Herzig
1486fe7fd0 Refresh ReplayViewer list after replay is saved (closes #379) 2020-10-03 10:58:17 +02:00
Jonas Herzig
b488e0b059 Fix render queue not being persisting after edit (fixes #362) 2020-10-03 10:38:08 +02:00
Jonas Herzig
094b20d69a Merge pull request #381 from LindaJuffermans/Branch_docs-0930-liteloader (closes #263)
Added LiteLoader compatibility information and workaround steps.
2020-09-30 11:41:48 +02:00
LindaJuffermans
41390b02e7 Added LiteLoader compatibility information and workaround steps. 2020-09-30 11:20:02 +02:00
Jonas Herzig
9af562957f Merge branch 'stable' into develop 2020-09-27 18:48:54 +02:00
Jonas Herzig
9cf8ec4e06 Release 2.4.5 2020-09-27 18:26:06 +02:00
Jonas Herzig
d7788b675a Fix missing blocks pre-1.14 in Quick Mode and Edit (fixes #374) 2020-09-27 17:28:29 +02:00
Jonas Herzig
5721b6f8c9 Fix realms notification icon offsets (fixes #373) 2020-09-27 15:58:43 +02:00
Jonas Herzig
a55320030f Fix thread-unsafe mc method call in FullReplaySender (fixes #370) 2020-09-27 15:28:08 +02:00
Jonas Herzig
1382e9fb31 Fix VanillaGuiScreen not resetting when resized (fixes #369) 2020-09-27 15:17:24 +02:00
Jonas Herzig
a62100071f Fix camera getting stuck spectating itself (fixes #300)
This bug was introduced when we started to record the login phase because it
contains the UUID of the local player. In the replay case this will be the UUID
of the camera entity but also the one of the recording player, so if the
recording player despawns while it is being spectated (e.g. because of a
backwards jump), then the camera snaps onto itself and gets stuck in place until
one presses Shift.
2020-09-27 14:41:10 +02:00
Jonas Herzig
afd0c27af9 Fix incorrect rotation when jumping to marker (fixes #310) 2020-09-27 14:16:58 +02:00
Jonas Herzig
49b0cbe4f8 Fix jumping to marker position when time already matches 2020-09-27 14:14:49 +02:00
Jonas Herzig
85ea757253 Fix incorrect jump behavior when jumping small distances beyond 5s 2020-09-27 14:08:39 +02:00
Jonas Herzig
fb447dc252 Fix incorrect extension for custom screenshot file name (fixes #337) 2020-09-27 13:45:03 +02:00
Jonas Herzig
d9e3622254 Fix crash when screenshots folder does not yet exist (fixes #377)
Happens when you open the output file dialog for the first time and haven't
taken any screenshots before.
2020-09-27 13:27:06 +02:00
Jonas Herzig
12a49a4a5e Fix crash due to double-close after ODS rendering (fixes #376) 2020-09-27 13:13:39 +02:00
Jonas Herzig
2c2af8a6a6 Fix outer skin layer when spectating in first person (fixes #363) 2020-09-27 13:11:57 +02:00
Jonas Herzig
f42f4d468d Fix editing a replay twice with the same name (fixes #342) 2020-09-27 12:36:16 +02:00
Jonas Herzig
e24c4cd860 Fix incorrect latest version in minimal mode popup (fixes #375)
Also clean up the `1.7.6-1.7.10` to just `1.7.10`.
2020-09-27 12:31:05 +02:00
Jonas Herzig
9abbea7fb9 Merge branch 'mc-1.16.3' into release-2.4.5 2020-09-27 12:01:25 +02:00
Jonas Herzig
39a2fba921 Merge pull request #372 from LindaJuffermans/docs-0804-ffmpeg-431
Updated location of windows binaries for ffmpeg now that zeranoe is discontinued.
2020-09-25 15:41:07 +02:00
LindaJuffermans
ba4bffda2a Updated location of windows binaries for ffmpeg now that zeranoe is discontinued. 2020-09-25 14:53:45 +02:00
Jonas Herzig
cff6034079 Merge pull request #366 from altrisi/patch-1
Don't create an empty directory with no modcore available
2020-09-20 08:00:56 +02:00
altrisi
0561a9f53c Don't create an empty directory with no modcore...
...version available for the current MCVersion.
2020-09-19 15:10:23 +02:00
Jonas Herzig
3db25abe48 Merge branch 'mc-1.16.3' into develop 2020-09-10 17:34:48 +02:00
Jonas Herzig
efd1cebff3 Update to MC 1.16.3 2020-09-10 17:32:21 +02:00
Jonas Herzig
83690f4024 Refactor key binding registrations to be more easily expandable 2020-09-06 11:45:37 +02:00
Jonas Herzig
f623bb3ee7 Add reset button to export command settings (closes #356) 2020-09-06 11:45:37 +02:00
Jonas Herzig
00cb2b43a8 Rewrite main menu button offset to be more compatible (closes #341)
In particular, we now position it relative to the realms (fallback to
multiplayer) button.
This removes the need for special-casing ModMenu and fixes compatibility with
Better Mod Button.
2020-09-06 11:45:37 +02:00
Jonas Herzig
e5c0ca501b Add option to process multiple render queues in on go (closes #349) 2020-09-06 11:45:37 +02:00
Jonas Herzig
fcd1224fa0 Allow replay to be started in sync mode (required for #349) 2020-09-06 11:45:37 +02:00
Jonas Herzig
76a8623531 Show content of replay's render queue in Replay Viewer
As part of #349.
2020-09-06 11:45:37 +02:00
Jonas Herzig
9eb69375bd Add multi-select to Replay Viewer list (closes #354) 2020-09-06 11:45:37 +02:00
Jonas Herzig
6878cefadc Add type-to-filter functionality to Replay Viewer list 2020-09-06 11:45:37 +02:00
Jonas Herzig
29653c7ccc Render border of focused text field in white to match vanilla 2020-09-06 11:45:37 +02:00
Jonas Herzig
b54645e5b7 Replace "Settings" button with textured button in top left corner
The texture of this button is based on the settings button of the ModMenu mod
and was originally under the MIT license "Copyright (c) 2018-2020 Prospector".
The derived version is licensed as any other file in this repository.
2020-09-06 11:45:37 +02:00
Jonas Herzig
000048cc8f Support 1.15 button hover style for textured buttons 2020-09-04 20:56:05 +02:00
Jonas Herzig
8fac84bfe9 Merge branch 'release-2.4.4' into develop 2020-09-04 12:01:56 +02:00
Jonas Herzig
ebcf2bfa7b Release 2.4.4 2020-09-04 11:47:02 +02:00
Jonas Herzig
8ef3ab8647 Stop relying on fabric-api internals to inject resource packs
Fixes compatibility with fabric-api 0.20+
2020-09-04 11:37:25 +02:00
Jonas Herzig
d039009a9f Workaround Optifine breaking charTyped events 2020-09-01 12:54:30 +02:00
Jonas Herzig
9211fb524c Persist render queue in replay file (closes #317) 2020-08-29 21:21:34 +02:00
Jonas Herzig
4a6c0acc8b Add "Add to Queue" button to keyframe repository (closes #168) 2020-08-29 19:13:59 +02:00
Jonas Herzig
a92aa9cbbd Add Edit button to render queue 2020-08-29 19:13:04 +02:00
Jonas Herzig
f13e8834d6 Have render job name be determined directly by output file name 2020-08-29 19:13:04 +02:00
Jonas Herzig
1188ce4360 Swap parent relation between render settings and queue
Previously you'd access the render queue from the render settings screen which
was arguably the wrong way around (e.g. you weren't able to access the queue
when your current keyframes were incorrect even if you only wanted to render
those in the queue).

Now the render button opens the queue which can open a new settings popup. To
save people who don't need the queue from always having to go through it, the
queue will immediately open a new settings popup if does not yet have any jobs.
2020-08-29 19:13:04 +02:00
Jonas Herzig
ae63b32268 Allow rendering of selected entries in render queue gui 2020-08-29 19:13:04 +02:00
Jonas Herzig
fbed279e34 Add multi-select to render queue gui 2020-08-29 14:46:04 +02:00
Jonas Herzig
d95af541c7 Default render queue job name to output file name (closes #267) 2020-08-29 14:27:07 +02:00
Jonas Herzig
db9db0280b Find ffmpeg.exe anywhere in .minecraft folder (closes #347)
Thanks to Lucky56 for testing!
2020-08-29 14:27:07 +02:00
Jonas Herzig
098300f0db Stop blocking all UI during path playback (closes #269)
Instead, just copy the timeline before playback.
2020-08-29 14:27:07 +02:00
Jonas Herzig
9314eab7ff Make video timeline length configurable (closes #261) 2020-08-29 14:27:07 +02:00
Jonas Herzig
c9b57dbcd7 Handle Ctrl+A, Ctrl+C and Ctrl+V in the keyframe repository 2020-08-29 14:27:07 +02:00
Jonas Herzig
9f590e93ce Add copy/paste buttons to keyframe repository (closes #318) 2020-08-29 14:27:07 +02:00
Jonas Herzig
e294ebe8c9 Add multi-select to keyframe repository (see #318) 2020-08-29 14:27:07 +02:00
Jonas Herzig
fbf53d3842 Add option to use night vision for full brightness (closes #315) 2020-08-29 10:34:12 +02:00
Jonas Herzig
9a27138e78 Fix crash when config is missing a value 2020-08-29 10:19:01 +02:00
Jonas Herzig
9c6f040364 Change F1 while replay gui is focused to only hide it (closes #259)
Previously pressing F1 while the replay gui is focused (i.e. while the mouse is
visible) would toggle the global hudHidden state.
Now it only toggles the hidden state for the replay itself, allowing the
remainder to still be recorded with e.g. OBS where a full render isn't needed.
2020-08-29 09:32:18 +02:00
Jonas Herzig
39f958a7bb Fix F1 not functioning on 1.14+ while replay gui is focused 2020-08-29 09:30:57 +02:00
Jonas Herzig
103d2204d6 Load replays in order of last modified (closes #346) 2020-08-29 09:09:10 +02:00
Jonas Herzig
c2d4ac20dc Add rename/discard options to "Replay Saving" gui (closes #319) 2020-08-28 21:21:25 +02:00
Jonas Herzig
ab2b89f838 Add per-server overwrite for auto-recording setting (closes #313) 2020-08-28 18:31:25 +02:00
Jonas Herzig
ebe6da28fb Run recovery in background with progress indicator (closes #326) 2020-08-28 16:34:09 +02:00
Jonas Herzig
26f3c3639c Add progress bar to "Saving Replay" indicator (closes #325) 2020-08-28 16:15:39 +02:00
Jonas Herzig
739d5b2807 Add key hints to buttons which have corresponding keybindings 2020-08-28 15:58:02 +02:00
Jonas Herzig
fd48e56238 Add keybindings for the two keyframe buttons (closes #312)
And one to add a position keyframe even when spectating.
And one to press both buttons with a single key.
2020-08-28 15:45:34 +02:00
Jonas Herzig
c2f51d41fa ./gradlew :1.16.2:setCoreVersion 2020-08-28 14:55:40 +02:00
Jonas Herzig
9001fdc9de Cleanup 1.15.2 <-> 1.16.2 conversion 2020-08-28 14:50:28 +02:00
Jonas Herzig
16c759f1dd Drop lombok, it has been causing too much confusion
Basically the result of the Delombok function, except we use IntelliJ's equals,
hashCode and toString and don't re-organize imports (cause that breaks the
preprocessor) and a bunch of manual cleanup was necessary (and half the classes
weren't even converted).
2020-08-28 14:06:31 +02:00
Jonas Herzig
23e51d7099 Release 2.4.3 2020-08-22 17:17:40 +02:00
Jonas Herzig
1208fb92a1 Add .gitkeep file to 1.16.2 folder 2020-08-22 17:12:32 +02:00
Jonas Herzig
27edfcb4f3 Fix incompatibility with mods which mixin into Main (fixes #327) 2020-08-22 14:04:05 +02:00
Jonas Herzig
34b0369775 Merge branch 'mc-1.16.2' into release-2.4.3 2020-08-22 13:40:43 +02:00
Jonas Herzig
0edebdc8d3 Merge pull request #279 from LindaJuffermans:docs-0721-quickmode-icon 2020-08-22 13:40:02 +02:00
Jonas Herzig
7c229c0216 Enable git's autocrlf 2020-08-22 13:36:16 +02:00
Jonas Herzig
2a8c802d43 Merge pull request #257 from LindaJuffermans:develop 2020-08-22 13:33:18 +02:00
Jonas Herzig
8ffb98efd1 Fix recording of client-triggered world events in 1.16+ (fixes #333) 2020-08-16 10:03:55 +02:00
Jonas Herzig
da275a6080 Update to 1.16.2 2020-08-11 18:16:08 +02:00
Jonas Herzig
0e77235ef9 Update to MC 1.16.2-rc1 2020-08-09 13:55:00 +02:00
Jonas Herzig
3ba37ab05c Merge pull request #308 from LindaJuffermans/docs-0804-ffmpeg-431
ffmpeg 4.3.1 supports h264/h265
2020-08-04 16:08:09 +02:00
LindaJuffermans
6537c30d6b Removed mentioning of an ffmpeg version 2020-08-04 16:03:18 +02:00
LindaJuffermans
17f5771906 ffmpeg 4.3.1 supports h264/h265 2020-08-04 15:17:01 +02:00
Jonas Herzig
d065868abb Release 2.4.2 2020-08-03 10:31:36 +02:00
LindaJuffermans
9c3c76e70d Added NULL check for missing encodingPreset (fixes #288) 2020-08-03 10:23:50 +02:00
Jonas Herzig
eb2c2f2e6b Merge pull request #306 from LindaJuffermans/docs-0801-sodium
Sodium cannot be enable during rendering.
2020-08-01 21:33:36 +02:00
LindaJuffermans
d26c9e508b Sodium cannot be enable during rendering. 2020-08-01 20:51:13 +02:00
Jonas Herzig
9dc5e62b64 Merge pull request #297 from LindaJuffermans/docs-0730-screens
Updated screenshots to latest version of ReplayMod
2020-07-30 16:27:17 +02:00
Jonas Herzig
21dbafb860 Merge pull request #298 from LindaJuffermans/docs-0730-camera-symbol
Path preview icon is not shown when the path is shown.
2020-07-30 16:24:58 +02:00
LindaJuffermans
d54c1c2be2 Path preview icon is not shown when the path is shown. 2020-07-30 13:51:59 +02:00
LindaJuffermans
8ccffb9bd3 Updated screenshots to latest version of RM 2020-07-30 13:32:44 +02:00
Jonas Herzig
bd5af16e1e Merge pull request #293 from LindaJuffermans/docs-0728-randompatches
Crash using ReplayMod with RandomPatches
2020-07-29 11:06:37 +02:00
LindaJuffermans
0295257fc0 Crash using ReplayMod with RandomPatches 2020-07-28 15:44:36 +02:00
Jonas Herzig
335eb93858 Merge pull request #285 from LindaJuffermans/docs-0726-baritone
Crash using ReplayMod with Baritone
2020-07-26 11:01:10 +02:00
LindaJuffermans
cc3e950d6a Crash using ReplayMod with Baritone 2020-07-26 10:55:59 +02:00
Jonas Herzig
621587c65e Release 2.4.1 2020-07-25 22:40:32 +02:00
Jonas Herzig
fd7b6030f9 Fix keybinding conflicts on 1.14+ (fixes #268)
This fixes both, replay-exclusive keybindings blocking vanilla ones as well as
vanilla keybindings blocking replay-exclusive ones.

The magic happens in Mixin_ContextualKeyBindings.
2020-07-25 21:40:02 +02:00
Jonas Herzig
063657af4c Fix DELETE keybinding on 1.14+ (fixes #270) 2020-07-25 19:52:18 +02:00
Jonas Herzig
8d82953c0b Fix hands always rendering with 1.16 OF shaders (fixes #280) 2020-07-25 19:33:19 +02:00
Jonas Herzig
a4b6e92627 Position recording control buttons relative to Exit (fixes #281) 2020-07-25 18:43:33 +02:00
Jonas Herzig
35cc78c70c Fix crash due to invalid characters in video file name (fixes #265)
037d54f Prevent FileChooserPopup from selecting invalid file names
2020-07-25 17:19:38 +02:00
Jonas Herzig
5983d99354 Fix jittering once a tick during rendering pre-1.16 (fixes #264)
The fetching of the ticks variable was accidentally moved to before the timer
update while updating to 1.16, this caused the interpolation to be off by one
tick each frame in which the timer advances to the next tick.
2020-07-25 17:02:56 +02:00
Jonas Herzig
fc1ae0e109 Hide unsupported render methods in settings gui (fixes #284) 2020-07-25 17:02:24 +02:00
Jonas Herzig
34a7465b8e Merge pull request #283 from LindaJuffermans/docs-0722-oldanimations
Crash using ReplayMod with OldAnimationsMod
2020-07-22 21:38:48 +02:00
Jonas Herzig
2957f46ade Merge branch 'stable' into docs-0722-oldanimations 2020-07-22 21:38:29 +02:00
Jonas Herzig
83cc4a035a Merge pull request #282 from LindaJuffermans/docs-0722-patchermod
Crash using ReplayMod with Patcher
2020-07-22 21:37:37 +02:00
LindaJuffermans
3981fa3ada Removed extra empty lines 2020-07-22 21:24:19 +02:00
LindaJuffermans
bc5182f98b Removed extra empty lines 2020-07-22 21:23:45 +02:00
LindaJuffermans
fda09358da Crash using ReplayMod with OldAnimationsMod 2020-07-22 21:22:31 +02:00
LindaJuffermans
e177333af4 Crash using ReplayMod with Patcher 2020-07-22 21:18:50 +02:00
Jonas Herzig
f578f0df20 Merge pull request #277 from LindaJuffermans/docs-0721-accounts
Added Accounts section to explain discontinuing and new Discord support structure.
2020-07-21 21:53:34 +02:00
LindaJuffermans
a2342071b3 Updated to fixed Discord link from the main site 2020-07-21 21:52:24 +02:00
Jonas Herzig
7510f717a4 Merge pull request #278 from LindaJuffermans/docs-0721-quickmode
Added Quick Mode section and reference from timeline jumping
2020-07-21 21:50:10 +02:00
LindaJuffermans
3d7d51e2e0 Added Quick Mode section and reference from timeline jumping; including clock icon 2020-07-21 21:49:56 +02:00
LindaJuffermans
a0e9f0b61b Added Quick Mode section and reference from timeline jumping 2020-07-21 21:47:48 +02:00
LindaJuffermans
d49b06856f Added Accounts section to explain discontinuing and new Discord support structure. 2020-07-21 21:44:27 +02:00
Jonas Herzig
72bc8c87ee Merge pull request #276 from LindaJuffermans/docs-0721-thumbnails
Removed Replay Center reference in Thumbnails
2020-07-21 21:44:05 +02:00
LindaJuffermans
70494f3c6a Removed Replay Center reference in Thumbnails 2020-07-21 21:42:21 +02:00
Jonas Herzig
3273b3c239 Merge pull request #275 from LindaJuffermans/docs-0721-ffmpeg-notes3
Added ffmpeg details
2020-07-21 21:38:40 +02:00
LindaJuffermans
f61bfc4648 Added ffmpeg details 2020-07-21 21:35:53 +02:00
LindaJuffermans
169c4857b3 Fixed order of methods in quickmode change; no longer relying on local variable, instead pulling current state from ReplayHandler before updating. 2020-07-17 17:23:02 +02:00
LindaJuffermans
b79848936b Implemented review changes 2020-07-17 16:32:12 +02:00
LindaJuffermans
3aea7cdca4 Tweaked the indicator positions 2020-07-15 21:44:48 +02:00
LindaJuffermans
a94f417822 Fixed for 1.15.2 2020-07-15 21:07:30 +02:00
LindaJuffermans
2dcfbd6435 Changed Replay Viewer panel button (from play button to hamburger)
Added quickmode indicator (bottom-right with night vision indicator)
2020-07-15 15:49:44 +02:00
Jonas Herzig
2ab92f554f Release 2.4.0 2020-07-14 13:59:13 +02:00
Jonas Herzig
d3ad55eb79 Add run directory to gitignore 2020-07-14 13:57:49 +02:00
Jonas Herzig
9ea52eadc7 Move .gitkeep from 1.16 to 1.16.1 2020-07-14 13:57:10 +02:00
Jonas Herzig
a04ef22945 Fix broken frame after teleport during rendering (fixes #225) 2020-07-13 20:23:21 +02:00
Jonas Herzig
294f24c71e Fix jGui resources in 1.16 dev env 2020-07-13 20:23:21 +02:00
Jonas Herzig
b8618b6165 Fix dead-lock when rendering outside of loaded chunks (fixes #197) 2020-07-13 19:22:28 +02:00
Jonas Herzig
d8e4b89413 Fix forge handshake being reordered by MarkerProcessor (fixes #253)
For one, the forge handshake takes place *after* login phase (but before the
JoinGame packet), so we must ensure that the SquashFilter does not reorder
those.
Secondly, we were ignoring the initial packet (timestamp = 0) in marker
processor when it should have been passed to the SquashFilter. This was not an
issue before cause the SquashFilter did not rely on it. Now however the
SquashFilter needs to be able to see a login phase packet, so it knows that the
following packets till the JoinGame packet are part of the forge handshake.

In ReplayStudio:
20b5183 Fix forge handshake being reordered to after the JoinGame packet
2020-07-13 19:04:32 +02:00
Jonas Herzig
88fab6a91d Fix fastutil being relocated in 1.14+ (fixes #248) 2020-07-13 19:04:32 +02:00
Jonas Herzig
da59c75f8b Update jGui (fixes #249)
20e11e0 Remove length limit from GuiFileChooserPopup text field
2020-07-13 19:04:32 +02:00
Jonas Herzig
e090e8f4f3 Fix crash when video file name contains whitespace (fixes #250) 2020-07-13 19:04:32 +02:00
Jonas Herzig
f1885ece41 Fix non-player entity freezing on chunk unload in 1.14+ (fixes #203) 2020-07-13 19:03:41 +02:00
Jonas Herzig
dc31605b29 Change forge run dir from "eclipse" to "run"
I don't even know why it was at "eclipse" in the first place.
2020-07-13 16:07:48 +02:00
Jonas Herzig
f83216ab91 Include only the mod meta data file for the respective loader
Also clean up the entire processResources block in the process cause it was a
mere coincidence that it has worked properly.
2020-07-13 16:07:48 +02:00
Jonas Herzig
ecee63491c Remove mods.toml (modlauncher was never supported anyway) 2020-07-13 16:07:48 +02:00
Jonas Herzig
9c49fdf4d1 Remove explicit FAPI dep and instead bundle the required modules
Also need to update ModMenu because the version we depended on still bundled the
snapshot FAPI and that was only fine because we overwrote it with our version.
2020-07-13 16:07:48 +02:00
Jonas Herzig
62bbf0efd6 Update IDEA setup instructions
Configuring the annotation processor is done automatically as of IDEA 2020.1.

Run configs for 1.14+ versions should now be generated automatically once the
referenced PR is merged (or when using a local build of it).
2020-07-13 16:07:48 +02:00
Jonas Herzig
e83805bee6 Remove MP4_HIGH preset (fixes #254)
It results in unreasonably high bit rates which regularly confuses users.
The Custom preset should generally be preferred.
2020-07-13 16:04:39 +02:00
Jonas Herzig
f1f1f5dde2 Fix tests failing because they cannot access jGui classes 2020-07-13 16:01:28 +02:00
Jonas Herzig
9b98575c0b Get rid of preshadow plugin, it doesn't play nice with recent IDEA 2020-07-13 16:01:28 +02:00
Jonas Herzig
ffa66dd905 Remove long broken reprod gradle setup 2020-07-13 16:01:28 +02:00
Jonas Herzig
54b515fd2b Merge remote-tracking branch 'origin/develop' into snapshot 2020-07-13 16:01:01 +02:00
Jonas Herzig
23849bc8c4 Merge pull request #247 from LindaJuffermans/develop
Minor doc changes
2020-07-04 19:36:54 +02:00
Linda Juffermans
e27c19f781 Rephrased tickrate mod incompatibility 2020-07-03 09:42:25 +02:00
Linda Juffermans
faf9b454d2 Fixed FFmpeg path in Windows 2020-07-03 09:20:39 +02:00
Linda Juffermans
241b086ec4 Added some known issues, unsupported launchers and incompatible mods. 2020-07-03 09:16:43 +02:00
Jonas Herzig
5bf6773655 Merge remote-tracking branch 'origin/develop' into snapshot 2020-06-28 22:07:49 +02:00
Jonas Herzig
7118d55d62 Update to 1.16.1 2020-06-28 21:57:45 +02:00
Jonas Herzig
a4af8c2610 Release 2.3.2 2020-06-28 21:31:47 +02:00
Jonas Herzig
bc05566d2e Update ReplayStudio
fc8a66d Fix handling of view pos/dist packets in MC 1.14+ quick mode
2828174 Fix reading and writing of unload chunk packets pre-1.9 (fixes #210)
42bd0fe Fix map data being swallowed by squash filter (fixes #232)
2020-06-28 21:12:12 +02:00
Jonas Herzig
0ab1db9517 Improve handling of CrashException in runLater (fixes #205) 2020-06-28 21:12:12 +02:00
Jonas Herzig
a6f5931e7e Fix output file render setting not being saved (fixes #229) 2020-06-28 21:12:12 +02:00
Jonas Herzig
513f53f1ee Open output file popup in folder and with name of current file 2020-06-28 21:12:12 +02:00
Jonas Herzig
6038d3c4df [1.14+] Fix resource pack loading during rendering (fixes #182) 2020-06-28 21:12:12 +02:00
Jonas Herzig
72b44c368b [1.8] Fix incorrect event bus for deferred runLater (fixes #206) 2020-06-28 21:12:12 +02:00
Jonas Herzig
058346d247 Workaround a bug in MC where light is not updated (fixes #209)
MC stores server light data and only applies it during the next frame.
Therefore, if there is no frame between receiving the chunk and block changes in
it (like when jumping in replays), then the light update from the block change
gets lost.
2020-06-28 21:12:12 +02:00
Jonas Herzig
0ba651d19c Fix recording of client player's metadata after respawn (fixes #212)
1.15 removed the data tracker syncing from the spawn packet, so we now need to
send that explicitly.
2020-06-28 21:12:12 +02:00
Jonas Herzig
8e1f9f5a9c Fix quick mode sending async-mode packets when paused
This wasn't much of on issue because no tick events are fired normally while
paused. When seeking we do however manually run a tick for better result, and
this manual tick would cause this async sending code to run and seek wildly into
the future.
2020-06-28 21:12:12 +02:00
Jonas Herzig
c04f3ab185 Fix shift+play camera path requiring time keyframes (fixes #218) 2020-06-28 21:12:12 +02:00
Jonas Herzig
bad79ab286 Throw IOException when ImageIO.read return null (fixes #201) 2020-06-28 21:12:12 +02:00
Jonas Herzig
9f3808f0ff Render gui overlay even when event was cancelled (fixes #170)
Cause Lunatrius' InGame-Info-XML mod cancels it and we don't actually care about the event, just about when it's called.
2020-06-28 21:12:12 +02:00
Jonas Herzig
5f284fcd3d Fix spectating when clicking with unlocked cursor (fixes #224)
> If you misclick the add keyframe button or something, you end up specating
instead and you have to find the camera angle again
2020-06-28 21:12:12 +02:00
Jonas Herzig
04c902a792 [1.8.9] Fix launching in development environment 2020-06-28 21:12:12 +02:00
Jonas Herzig
33ec18ad1e Merge pull request #240 from ThomasBerends/feature/docs-upgrade
Overall upgrade of documentation
2020-06-25 20:47:01 +02:00
Thomas Berends
5c446bbb8d Processed feedback 2020-06-25 20:41:09 +02:00
Thomas Berends
d79c66cdd1 Update docs/content.md
Co-authored-by: Jonas Herzig <me@johni0702.de>
2020-06-25 20:27:20 +02:00
Thomas Berends
175efa55fe Update docs/content.md
Co-authored-by: Jonas Herzig <me@johni0702.de>
2020-06-25 20:27:07 +02:00
Thomas Berends
b79c835d53 Overall upgrade of documentation 2020-06-25 19:07:57 +02:00
Jonas Herzig
dc9fcb11cd Update to 1.16-rc1 2020-06-21 15:29:07 +02:00
Jonas Herzig
82200a7c34 Update to 1.16-pre6 2020-06-15 21:12:06 +02:00
Jonas Herzig
30aa992ddb Update to 1.16-pre5 2020-06-15 11:14:30 +02:00
Jonas Herzig
2ffde14c60 Update to 1.16-pre1 2020-06-15 09:44:37 +02:00
Jonas Herzig
14b84c5e1b Fix remapping of jGui using incorrect mappings
We used to include the raw jGui source in our jar and then had the main remapJar
task remap both of them to intermediary. This however does not work properly
when jGui needs additional mapping (e.g. because of mixin), resulting in
non-remapped mixins with fail to apply at runtime.

With this commit, we no longer include jGui in our raw jar and instead now have
shadowJar depend on jGui's remapJar task.
2020-06-15 08:58:02 +02:00
Jonas Herzig
88be6b3935 Update to 20w22a (minimal mode only) 2020-06-04 13:03:34 +02:00
Jonas Herzig
6210cb09aa Fix recording in minimal mode 2020-06-04 11:44:54 +02:00
Jonas Herzig
20b410f963 Release 2.3.1 2020-05-24 14:08:45 +02:00
Jonas Herzig
ef13d020a2 Fix incorrect screen and crash when encountering replay restrictions 2020-05-24 13:39:15 +02:00
Jonas Herzig
fabe4783c8 Make Replay Viewer button work with CustomMainMenu (fixes #195) 2020-05-24 13:38:10 +02:00
Jonas Herzig
ef79331037 Remove online features, they're no longer available 2020-05-24 12:38:57 +02:00
Jonas Herzig
244aeb244f Fix incorrect 1.14.4-forge to 1.12.2 mapping
This causes the reverse conversion to incorrect results again but I cannot
currently be bothered to fix that.
2020-05-23 23:24:24 +02:00
Jonas Herzig
ea95863b4a Update ReplayStudio (fixes #173) 2020-05-23 22:54:11 +02:00
Jonas Herzig
3c526a6cd4 Support MM1 in addition to MM2 (fixes #162)
Cause the latest OptiFabric on 1.14.4 still ships that and it has no support for
entrypoints.
2020-05-23 22:31:01 +02:00
Jonas Herzig
363a8d595c Apply OF chunk building bug fix only during rendering (fixes #164) 2020-05-23 22:05:42 +02:00
Jonas Herzig
d1ff98c76a Fix 1.12.2 to 1.14.4-forge conversion 2020-05-23 20:13:54 +02:00
Jonas Herzig
1123341182 Fix RM not loading another mod loads mixin first (fixes #181) 2020-05-23 20:06:18 +02:00
Jonas Herzig
a23f18d92e Fix fabric dependency declaration (fixes #187) 2020-05-23 14:37:44 +02:00
Jonas Herzig
154952a8ac Change ModCore messages cause people keep thinking those are errors 2020-05-23 14:37:44 +02:00
Jonas Herzig
b68d077b38 Update preprocess plugin and enable parallel builds by default 2020-05-23 13:25:37 +02:00
Jonas Herzig
c0be8da65b Release 2.3.0 2020-05-08 13:09:42 +02:00
Jonas Herzig
b534d1395d Update ReplayStudio, fixes squashing of empty columns (fixes #151) 2020-05-08 12:23:35 +02:00
Jonas Herzig
4e5122db5d Close packet output stream before saving replay
Aside from being best practice, this is necessary for the recording CRC to be
written to the replay file (cause that only happens on close).

Also potentially fixes https://github.com/ReplayMod/ReplayMod/issues/144 though
that should already be covered by ZipReplayFile tracking and closing all of its
`OutputStream`s before saving.
2020-05-08 11:38:12 +02:00
Jonas Herzig
8193006aea Update ReplayStudio, fixes cache invalidation when recording changes 2020-05-08 11:29:33 +02:00
Jonas Herzig
4aa256d53b Cleanup raw and cache files after some time (fixes #143) 2020-05-08 10:57:34 +02:00
Jonas Herzig
62c6b36f08 Fix crash when minimizing on Windows during rendering (fixes #140)
Hopefully, haven't actually tried it cause, you know, Windows (and minimizing
with just xfwm4 doesn't exhibit the same behavior).
2020-05-08 10:17:49 +02:00
Jonas Herzig
a1cee391fb Render GuiOverlays before (i.e. behind) debug overlay
Also fixes https://github.com/ReplayMod/ReplayMod/issues/155
2020-05-08 09:45:06 +02:00
Jonas Herzig
d4192b354c [1.15] Fix dead-lock due to data race during rendering (fixes #156) 2020-05-08 09:45:06 +02:00
Jonas Herzig
d24800160b Improve MarkerProcessor output generation (fixes multiple issues)
In particular:
- No longer generate any replays when auto-recording is off and recording is
never enabled from the ingame menu (fixes #138)
- Do not generate an additional empty replay file when recording was stopped in
ingame menu (fixes #147)
- only do squash if there are further output replays (fixes #142)
- Use the input file name as output file name even if there was a split (as long
as it's the only output file, e.g. because recording was never un-paused after
the split)
2020-05-08 09:45:06 +02:00
Jonas Herzig
9fb4dce367 Reset export arguments when upgrading from old version (fixes #148) 2020-05-08 09:45:06 +02:00
Jonas Herzig
811f52dc17 Throw helpful error message when rendering with sodium (see #150) 2020-05-08 09:45:06 +02:00
Jonas Herzig
72ce522813 Ensure task queue is not locked during rendering (fixes #157)
Similar to 3fedc22 in effect and cause. However tasks are executed, they just
cannot be submitted pre-1.14 because MC would continuously hold the lock on the
scheduledTasks queue for the entire renderVideo call.
2020-05-07 14:11:02 +02:00
Jonas Herzig
316f4e2c3c Prevent keyframe time from being set out of bounds (fixes #152) 2020-05-07 11:45:01 +02:00
Jonas Herzig
0962f1895e Fix 1.14.4 forge and fabric jars having the same name (fixes #149)
This caused one of them to be deployed at random, e.g. forge for 2.3.0-b1,
obviously resulting in an unusable build.
2020-05-07 11:20:20 +02:00
Jonas Herzig
8e05a67c5e Pre-release 1 of 2.3.0 2020-04-22 10:48:44 +02:00
Jonas Herzig
715bd8d366 Fix doRelease gradle task 2020-04-22 10:48:07 +02:00
Jonas Herzig
195942cd62 Add .gitkeep files to versions/{1.14.4,1.15.2} 2020-04-22 10:38:58 +02:00
Jonas Herzig
9dfd25c3fd Update README 2020-04-22 10:10:01 +02:00
Jonas Herzig
3d71f7c526 [Pre-1.12] Include less-outdated netty library for ReplayStudio
On 1.12+ MC's bundled version is sufficiently up-to-date but before that it
didn't have e.g. `ByteBuf.retainedSlice`.
2020-04-21 23:08:04 +02:00
Jonas Herzig
05f617a885 Use ReplayOutputStream for packet writing
We didn't used to do that because it would have required us to serialize and
then de-serialize as MCProtocolLib only to re-serialize each packet.
With ReplayStudio v2, we only have to convert to from MC's ByteBuf types to
ReplayStudio's ByteBuf (fairly trivial).

This also allows us to automatically make use of ReplayStudio's backwards
compatibility features: We didn't used to record the login phase pre-1.14 and we
still don't, so we now would have to inject a fake login packet (because we're
no longer generating legacy-version replay files) but ReplayOutputStream can
do that for us.
Without this commit, any pre-1.14 replays generated are unplayable due to the
missing LoginSuccess packet.
2020-04-21 22:58:55 +02:00
Jonas Herzig
c8b7e5b213 [Forge] Fix saving of CustomPayload packets 2020-04-21 22:04:01 +02:00
Jonas Herzig
1249ca4167 Add ModCore integration 2020-04-21 21:30:24 +02:00
Jonas Herzig
b852a1787d Downgrade pre-1.12 back to Mixin 0.7.10 2020-04-21 21:11:31 +02:00
Jonas Herzig
a733d301fd Update preview gui framebuffer size regardless of performance mode
This used to be more of an issue in the past but `displaySizeChanged` has gotten
pretty cheap by now and not updating it will basically make the rendering GUI
useless once you resize even once.
2020-04-17 13:56:19 +02:00
Jonas Herzig
059063430c Update ReplayStudio (fixes #134)
9117411 ReplayOutputStream must not change ByteBuf reader index of packet
2020-04-17 01:24:46 +02:00
Jonas Herzig
7c35e1c7d1 Set CameraEntity.noClip depending on spectator state (fixes #136)
This field is used to decide whether or not to render the inside-block overlay,
as such we want it to be set while we're in spectator mode).

This wasn't a problem before 1.15 because we also cancel the renderHand call
while we're in spectator mode and the same method which renders your hand also
renders the overlay, so we were inadvertently canceling that at the same time.
With 1.15, that's still the case except when using OF, which splits the method
apart by adding three boolean arguments indicating which part to execute.
2020-04-16 23:59:00 +02:00
Jonas Herzig
3b72a67d2b Persist gradle (and loom) cache between Jenkins jobs 2020-04-16 18:51:01 +02:00
Jonas Herzig
808793a121 Switch from Drone to Jenkins 2020-04-16 18:50:59 +02:00
Jonas Herzig
023a1bcf0f Fix :1.7.10:setup{CI,Decomp}Workspace
For details see the referenced FG commit.
Related commit for 1.8+: 190210f
2020-04-16 18:50:51 +02:00
Jonas Herzig
5953435dc5 [1.14+] Fix reading of lang files with CRLFs (mitigates #132) 2020-04-16 14:55:46 +02:00
Jonas Herzig
0d3a689f17 [1.14+] Fix "Player Overview" title
We used to remap the old language key layout for inputs to the one used by
fabric but didn't consider that we might still be directly referencing the old
key somewhere else (e.g. for the Player Overview title).

With this commit, we retain the original and add the new mapping.
2020-04-16 14:48:23 +02:00
Jonas Herzig
f8b22d449c [1.14] Work around bug in mixin causing Accessors to not resolve
This intentionally breaks the mixin in a development environment but makes the
compiled jar work in a live environment (which is probably more useful given the
primary version is 1.15 now).
2020-04-15 19:47:12 +02:00
Jonas Herzig
f96ed03f12 Update loom: 0.2.2 → 0.2.6 2020-04-15 19:41:21 +02:00
Jonas Herzig
3fedc22899 Execute task queue even when rendering a paused replay (fixes #129)
The task queue is executed by MC each frame, not just each tick, so we should do
so as well. Most async actions also rely on it to re-synchronize with the
rendering thread, e.g. skins won't load if we never poll the task queue.
2020-04-15 18:42:39 +02:00
Jonas Herzig
a514e53d11 [1.7.10] Disable tests for now 2020-04-15 18:34:25 +02:00
Jonas Herzig
4586cb5382 Only update timeline when default iterp type changed (fixes #127) 2020-04-15 17:40:26 +02:00
Jonas Herzig
6ccb576637 Update lombok (see #127) 2020-04-15 17:26:53 +02:00
Jonas Herzig
82f86122c8 Handle third-party buttons without text in ingame menu (see #120) 2020-04-15 16:56:16 +02:00
Jonas Herzig
39ccf60f15 Update ReplayStudio
6990c48 SquashFilter: Fix leaking of MapData packets
2020-04-08 23:49:13 +02:00
Jonas Herzig
f5afeb918c Fixup mixin config changes of c119392
- Remove MixinRenderGlobal, it's now called Mixin_ForceChunkLoading
- Re-add MixinChunkRenderWorker (1.8-1.14) which was accidentally removed
2020-04-08 23:26:02 +02:00
Jonas Herzig
dafbeb34d4 Workaround a bug in OF which incorrectly queues chunks (fixes #123) 2020-04-08 22:43:02 +02:00
Jonas Herzig
5aa1d7be53 Update 1.14.4 fabric-api version to 0.4.3 (fixes #101) 2020-04-08 17:46:01 +02:00
Jonas Herzig
c5476025ec Fix terrain not rendering with OF shaders enabled (fixes #122)
This was caused by us setting `needsTerrainUpdate` to false during the shadow
pass in order to break out of the ForceChunkLoading loop (cause OF doesn't
update chunks during the shadow pass). However, this inadvertently caused the
chunk updates to be skipped during the normal pass as well if there didn't
happen to be another reasons for updating.

To fix this, we simply move the shadow pass check into the ForceChunkLoading
mixin and skip the entire loop during the shadow pass.
2020-04-08 17:45:06 +02:00
Jonas Herzig
8f7d263ad9 Fix livelock caused by OF not properly resetting ChunkVisibility
This can lead to a livelock when rendering with shaders after exiting a
singleplayer world (3/4 chance of breakage on each exit).
2020-04-08 14:18:25 +02:00
Jonas Herzig
97f901408e Reduce mixin plugin log message verbosity to debug level 2020-04-08 12:59:59 +02:00
Jonas Herzig
1d7a49907c Fix compilation with Mixin 0.8 on ForgeGradle 2020-04-07 17:20:04 +02:00
Jonas Herzig
9970ac798a Update 1.14.4 fabric-loader (for Mixin 0.8) 2020-04-07 15:40:42 +02:00
Jonas Herzig
5d0ea19c72 Fix rendering not being cancelled until unpaused (fixes #125) 2020-04-07 15:30:40 +02:00
Jonas Herzig
7613fdd4c3 Abort rendering when window receives close request even when paused
Previously we'd get stuck in the paused render loop even when window close was
requested.
2020-04-07 15:26:07 +02:00
Jonas Herzig
31caa68b34 Fix hover pos not respecting gui scale in render gui (fixes #124) 2020-04-07 15:25:19 +02:00
Jonas Herzig
b6ff3855a1 Fix rendering gui framebuffer size when not paused (fixes #126) 2020-04-07 15:10:29 +02:00
Jonas Herzig
3be3072082 Run video rendering from runLater
Prevents any issues arising from the fact that we would otherwise be somewhere
deep in the GUI lib button handling call stack.
2020-04-07 14:51:16 +02:00
Jonas Herzig
3f4156b91b Stop using interrupts to abort the rendering process (fixes #119)
They ended up lingering around and breaking any further blocking operations,
resulting in random errors afterwards. And using them was really unnecessary
anyway.
2020-04-06 20:56:22 +02:00
Jonas Herzig
e3f621b86a Work around the fact that our mixins may be loaded before Optifabric 2020-04-06 20:39:15 +02:00
Jonas Herzig
27bdc78688 Give up on end portal animation mixin when OF is installed 2020-04-06 20:38:53 +02:00
Jonas Herzig
ed6ba740bb Workaround OF breaking spectator hand mixin 2020-04-06 20:37:45 +02:00
Jonas Herzig
4c577c4559 Update non-fabric versions to Mixin 0.8 2020-04-06 20:33:44 +02:00
Jonas Herzig
51e10d890a Update ReplayStudio (fixes #121) 2020-04-06 15:21:39 +02:00
Jonas Herzig
b4a2c1b266 Fix race condition between inbound and injected packets (fixes #118)
In the case of #118, this was resulting in the EntityTrackerUpdate packet (which
contains info on which skin layers should be visible) sometimes ending up before
the SpawnPlayer packet, hence the players outer skin layers being invisible at
the start of the recording.
2020-04-06 15:14:47 +02:00
Jonas Herzig
ee68a63233 Fix Redirect target in MixinRenderLivingBase for 1.15 (see #120)
For some reason this applied fine in a development environment (even though the
method signature changed significantly), hence why I didn't notice it being
broken. It did not work (just like one would expect) in a live environment.
2020-04-06 13:19:11 +02:00
Jonas Herzig
b119d2d127 ./gradlew :1.15.2:setCoreVersion
Also `./gradlew :jGui:1.15.2:setCoreVersion`.
2020-04-06 13:18:37 +02:00
Jonas Herzig
f3c4092c72 Update preprocessor 2020-04-06 12:14:05 +02:00
Jonas Herzig
065d713e94 Update ReplayStudio
338c5a8 RandomAccessReplay: Handle light packets arriving after chunk packet
1658b5e SquashFilter: Fix entity delta position not being reset on teleport
2020-04-02 15:34:56 +02:00
Jonas Herzig
de40b5aa47 Fix spectating via point&click on fabric 2020-04-02 15:31:59 +02:00
Jonas Herzig
c119392c92 Implement chunk forcing during rendering for 1.15 2020-04-02 14:15:05 +02:00
Jonas Herzig
4ea13051fd Disable Blend render mode on 1.15 for now 2020-04-02 10:54:19 +02:00
Jonas Herzig
6113336c37 Disable ContainerLocalRenderInformationAccessor in 1.15 for now
It appears to suffer from https://github.com/SpongePowered/Mixin/issues/390 and
since we don't yet support the ChunkExporter, it's not yet needed anyway.
2020-04-02 10:51:14 +02:00
Jonas Herzig
724c236524 Cache configureRelocation output so we can do up-to-date checks
Saves us from having to run it every time even if the shadowJar task would be
up-to-date anyway.
2020-04-02 10:12:02 +02:00
Jonas Herzig
0b31e8c9df Implement MCVer.getProtocolVersion() for MC<11400 2020-04-02 02:00:18 +02:00
Jonas Herzig
8ce84e39e2 Fix shadowJar task using incorrect jar with loom 2020-04-02 01:59:32 +02:00
Jonas Herzig
c0e27634f4 Fix particle orientation during omnidirectional rendering in 1.15 2020-04-02 00:11:06 +02:00
Jonas Herzig
bf6f71ef89 Fix packet reference counting in MarkerProcessor 2020-04-02 00:11:06 +02:00
Jonas Herzig
2dbd5cde02 Update ReplayStudio 2020-04-02 00:11:06 +02:00
Jonas Herzig
c9285ab4a1 Fix end portal texture animation while replay is paused
Figured out where they moved it.
2020-04-02 00:11:06 +02:00
Jonas Herzig
d5fcdfb8c2 Fix ODS rendering in 1.15 2020-04-02 00:11:06 +02:00
Jonas Herzig
ad523009b4 Fix entity rendering with larger/smaller than actual resolution 2020-04-02 00:11:06 +02:00
Jonas Herzig
4116a3a7c9 Fix path preview rendering in 1.15 2020-04-02 00:11:06 +02:00
Jonas Herzig
b11b9db548 Fix frustum culling during non-ODS omnidirectional rendering
Not sure when this changed (probably with 1.14 update) but it definitely was
before the 1.15 update.
2020-04-02 00:11:06 +02:00
Jonas Herzig
2c3697c2ec Fix cubic rendering orientation 2020-04-02 00:11:06 +02:00
Jonas Herzig
d6559a21fc Get all 1.15 mixins applying 2020-04-02 00:11:06 +02:00
Jonas Herzig
a3e1792fe7 More 1.15 mapping fixes 2020-04-02 00:11:06 +02:00
Jonas Herzig
5315c66943 Cleanup 1.15.2 → 1.14.4 remapping 2020-04-02 00:11:06 +02:00
Jonas Herzig
9e7dc61d20 #ifdef DEV_ENV is no longer applicable since 8bc0b0a
There is no longer a dedicated "core" project where DEV_ENV would be defined,
instead whichever is the currently selected version automatically becomes the
main project using the main src folder.
2020-04-02 00:11:06 +02:00
Jonas Herzig
b69cd9fb81 Fix mode of various files
None of these should be executable, I blame Marius.
2020-04-02 00:11:06 +02:00
Jonas Herzig
527562549b Update 1.14.4 yarn 2020-04-02 00:11:02 +02:00
Jonas Herzig
ba83aa97b3 Update preprocessor plugin, enable configure-on-demand 2020-04-02 00:10:25 +02:00
Jonas Herzig
b3b73609cb Migrate 1.15.1 project to 1.15.2 2020-03-31 14:04:50 +02:00
Jonas Herzig
78ba9bd55e Fix misc preprocessor directives 2020-03-30 15:30:22 +02:00
Jonas Herzig
190210f950 Fix setupCIWorkspace/setupDecompWorkspace
See the linked commits in our FG fork for details.

`:1.8:setupDecompWorkspace` (and only that one) still fails with an unrelated
NPE which I can't be bothered to fix.
2020-03-30 12:46:36 +02:00
Jonas Herzig
9107485c14 Fix compilation for 1.7.10 2020-03-30 12:40:07 +02:00
Jonas Herzig
823e04a858 Fix compilation of 1.9.4 2020-03-30 03:20:13 +02:00
Jonas Herzig
4c6684236b Fix compilation of 1.11.2 2020-03-30 03:18:00 +02:00
Jonas Herzig
8b7ef8d1e3 1.13 is dead (followup to 8bc0b0a) 2020-03-30 02:52:47 +02:00
Jonas Herzig
49ea1ae40a Fix compilation of 1.12.2 2020-03-30 02:52:21 +02:00
Jonas Herzig
13283fb5d2 Fix compilation of 1.14.4-forge 2020-03-30 02:52:13 +02:00
Jonas Herzig
eb1fbed0d8 Fix compilation of 1.15.1 2020-03-30 01:05:26 +02:00
Jonas Herzig
5c13995e59 Fix compilation of 1.14.4 2020-03-30 01:03:46 +02:00
Jonas Herzig
82bbf7b495 Fix ReplayStudio dependency group id 2020-03-29 21:32:44 +02:00
Jonas Herzig
af8803d6b5 WIP 1.15 and ReplayStudio v2 update 2020-03-13 14:18:19 +01:00
Jonas Herzig
8bc0b0a4df Update preprocessor and replace 1.13.2 subproject with 1.14.4-forge
The new preprocessor version brings first-party support for fabric, in
particular for automatically fetching mappings loom and for
automatically remapping between MC versions via intermediary mappings.
This will come in handy when updating to 1.15.

It also supports automatic remapping between fabric and forge on the
same MC version (by going mcp<->srg<->mojang<->intermediary<->yarn).
Therefore this commit replaces the previous 1.13.2 (forge) subproject
with a 1.14.4-forge one. Instead of manually providing full mappings for
1.14.4-fabric to 1.13.2-forge and partial (classes) for 1.13.2-forge to
1.12.2-forge, we now only need partial (classes) for 1.12.2-forge to
1.14.4-forge and preprocessor will take care of the forge to fabric
step (in fact, our mapping file for that is currently completely empty).

In an attempt to write an IDE (IntelliJ) plugin for quicker and easier
working with the preprocessor (e.g. immediately mapping single files
from within the IDE, jumping between different versions for the same
file), the preprocessor gradle plugin declaration now requires you to
explicitly specify variables in the common.gradle and the overall
relationship between projects in the build.gradle (latter is required
anyway, so the plugin can know where it should map between forge and
fabric and which subprojects are which versions).
Since that necessitated some changes to the build.gradle file, I took
the opportunity to convert it to Kotlin. As such we now also use
Gradle's newer plugin-block with the pluginManagement-block instead of
manually declaring buildScript (not for the common.gradle though), which
imo is nicer anyway and comes with various advantages (see gradle docs).

There were also some remapping bugs fixed and some new ones
introduced (e.g. manually declared inner class mappings seem to no
longer function properly under certain conditions).
There's also support for remapping Kotlin now. Just saying.
2020-01-12 23:34:10 +01:00
Jonas Herzig
f51298e2a3 Update Mixin (fixes GH-66) 2019-08-04 17:16:52 +02:00
Jonas Herzig
d8ce4275af Update ReplayStudio for misc MCProtocolLib fixes 2019-08-04 17:13:56 +02:00
Jonas Herzig
c7b0780111 Fix playback once end has been reached on 1.8 (and some above) 2019-08-04 15:06:27 +02:00
Jonas Herzig
94d6e7cb4b Fix mouse wheel speed outside of gui screen on 1.13+ 2019-07-27 11:51:39 +02:00
Jonas Herzig
ea6e452dd0 Pre-release 7 of 2.2.0 2019-07-19 22:44:05 +02:00
Jonas Herzig
7d6c263ce0 Update MCProtocolLib for modded entity attribute types on 1.12.2
E.g. "forge.swimSpeed" introduced in some later 1.12.2 Forge
2019-07-19 21:49:10 +02:00
Jonas Herzig
9c25396016 Gracefully handle incomplete QuickMode cache 2019-07-19 21:49:10 +02:00
Jonas Herzig
1245f38267 Fix 360 camera stabilization on 1.13+ 2019-07-19 21:49:10 +02:00
Jonas Herzig
5bd9b0cb6b Fix LoginCompressionS2CPacket being recorded in replay file on 1.13+ 2019-07-19 21:49:10 +02:00
Jonas Herzig
08f09dca6e Update MCProtocolLib to fix certain chunk unload packets on 1.8(.9) 2019-07-19 19:34:25 +02:00
Jonas Herzig
3cd21b8a78 Guard against corrupted config files on 1.14 2019-07-19 14:48:00 +02:00
Jonas Herzig
67d7af2dc3 Update to MC 1.14.4 2019-07-19 14:25:42 +02:00
Jonas Herzig
c4c4b75022 Pre-release 6 of 2.2.0 2019-07-12 21:06:27 +02:00
Jonas Herzig
4a115cd1a5 Fix NoSuchMethodError due to OpenNBT binary incompatibility on MC<1.12 2019-07-12 19:50:47 +02:00
Jonas Herzig
06fe165249 Fix toString call which breaks due to Windows not defaulting to UFT8 2019-07-12 19:18:32 +02:00
Jonas Herzig
aea222d176 Fix deadlock when jumping backwards in 1.7.10 under certain conditions
Not entirely sure how to fulfill those conditions but the fix should be
fairly self-explanatory anyway.
2019-07-08 14:52:42 +02:00
Jonas Herzig
ac60e58da2 Fix nested runLater on 1.7.10 2019-07-08 11:58:55 +02:00
Jonas Herzig
45ef15359e Fix replay not properly starting during rendering on 1.7.10 2019-07-08 11:30:15 +02:00
Jonas Herzig
6ca1d037c1 Update ReplayStudio (fixes LIGHTNING_BOLT mappings on 1.14) 2019-07-08 10:35:03 +02:00
Jonas Herzig
c4d2be9e89 Make thread requirements of ReplayHandler#setup explicit and fix illegal usage 2019-07-08 09:53:47 +02:00
Jonas Herzig
8261767657 Pre-release 5 of 2.2.0 2019-07-06 22:16:53 +02:00
Jonas Herzig
cdf6ff4419 Update ReplayStudio 2019-07-06 21:36:54 +02:00
Jonas Herzig
a0e397d1d5 Add support for camera roll on 1.7.10 2019-07-06 21:24:26 +02:00
Jonas Herzig
8a75edb218 Fix vanilla keys being handled by VanillaGuiScreen's internal screen
This becomes an issue once e.g. Esc is overwritten to return to the
parent screen instead of no screen (e.g. pressing Esc in JEI recipe).
2019-07-06 20:28:52 +02:00
Jonas Herzig
e497e5930b Fix event dispatching between layered VanillaGuiScreen on MC<=1.12.2 2019-07-06 20:00:22 +02:00
Jonas Herzig
989a54b067 Fix stack overflow after entity tracker popup has been shown
Failure to load the entity tracker usually (not always) results in
`entityTracker` remaining to be `null`, so there has to be an additional
condition for aborting the thenRun-loadEntityTracker-…-recursion.
2019-07-06 17:37:28 +02:00
Jonas Herzig
31d327efc7 Fix entity tracker loading error popup never being shown 2019-07-06 17:35:10 +02:00
Jonas Herzig
d47c899ef8 Fix advanced screenshot writer (switch from rgb to bgra) 2019-07-06 13:59:46 +02:00
Jonas Herzig
55924c1d46 Fix serialization of settings on Fabric 2019-07-06 13:05:20 +02:00
Jonas Herzig
731ea1ab9f Fix NPE when adding marker during recording before player is spawned
Can happen e.g. when auto-recording is disabled
2019-07-06 12:56:39 +02:00
Jonas Herzig
67e300bcff Fix NPE in MarkerProcessor when unnamed markers are present 2019-07-06 12:50:31 +02:00
Jonas Herzig
dc86da7a20 Pre-release 4 of 2.2.0 2019-06-30 22:20:38 +02:00
Jonas Herzig
7eecb2664d Fix rendering of sky (or anything with textures disabled) during ODS 2019-06-30 20:32:54 +02:00
Jonas Herzig
7299ecd0ce Fix main/offhand items of spectated player not being updated 2019-06-30 15:46:52 +02:00
Jonas Herzig
4fe2fee456 Fix constant equip sound when spectating player with head gear in replay 2019-06-30 15:46:09 +02:00
Jonas Herzig
b2b0ca1cd1 Fix recording of certain mobs on Hypixel
For some reason hypixel is sending duplicate entity meta data entries
in their spawn packets.
We'll now be ignoring all but the last one for each id (should match
how vanilla handles these).
2019-06-30 13:14:47 +02:00
Jonas Herzig
7241036e61 AWT is forbidden on 1.13+ (this includes BufferedImage)
Instead use NativeImage on 1.13+ via newly introduced Image class.
See Image docs for details.

Also fixes an issue with thumbnail taking on 1.13+: The original
ScreenshotHelper method is now async, luckily there's a sync
variant and as a bonus it directly returns a NativeImage so we can
skip having to read the screenshot from disk.
2019-06-30 12:12:13 +02:00
Jonas Herzig
732e1ab32e Update ReplayStudio to fix illegal reflection issue on JDK12 2019-06-29 15:09:31 +02:00
Jonas Herzig
954052aaa0 Pre-release 3 of 2.2.0 2019-06-28 18:28:23 +02:00
Jonas Herzig
c051b0ba3b Fix crash when quickly double-clicking the "Load"-replay button
This has previously been fixed for quadruple-clicking on the replay
itself but for some reason has not been fixed for simply double-clicking
the "Load" button.
2019-06-28 17:38:55 +02:00
Jonas Herzig
801f0871d5 Fix framebuffer resizing for rendering on 1.13+ 2019-06-28 17:23:07 +02:00
Jonas Herzig
fcb8cc329b Fix second column of RM settings being displaced by long dropdown labels 2019-06-28 16:57:25 +02:00
Jonas Herzig
a9f7e09e64 Fix RM settings being shown in random order 2019-06-28 16:56:15 +02:00
Jonas Herzig
2351698b66 Show popup when replay saving/postprocessing fails
because asking people for logs turned out to not be a viable strategy
when they can figure out how to get back their replay on their own…
2019-06-28 16:43:13 +02:00
Jonas Herzig
94d2e523ab Fix crash when converting position for newly appended element
E.g. happens when clicking on newly added elements in a resource loading
list before those were rendered at least once.
2019-06-28 16:10:33 +02:00
Jonas Herzig
9320bd931b Fix container GUIs opening in 1.14+
Not sure why MC has yet another packet for those now but tbh idc.
2019-06-28 15:29:40 +02:00
Jonas Herzig
654a640a60 Fix tracking of enabled state for primary texture 2019-06-28 15:01:45 +02:00
Jonas Herzig
214da6ba59 Update to MC 1.14.3 2019-06-24 18:36:12 +02:00
Jonas Herzig
1f547f92ce Fix core module not being included in 1.7.10
Probably a remnant of when we used a different gradle version for it.
2019-06-24 17:15:33 +02:00
Jonas Herzig
862c8d9b36 Update preprocessor
- Switch from ECJ to IDEA (with potential for kotlin)
- Can pull SRG mappings from FG, reducing amount of manual mappings (basically just class mappings and fixing errors in SRG mappings)
2019-06-24 17:15:33 +02:00
Jonas Herzig
b846d5308e Fix FullBrightness having no effect during rendering 2019-06-21 22:20:45 +02:00
Jonas Herzig
e7deed73b5 Fix NPE when jumping to beginning of replay (before player is spawned) 2019-06-21 22:14:22 +02:00
Jonas Herzig
4213d37c76 Fix race-condition-induced dead lock on replay restart in 1.14+
MC clears it scheduled tasks on disconnect. If we don't wait for
that to have happened on the async sender, then we might loose
some of the initial handshake packets (resulting in a dead lock in
fabric's registry syncing code).
2019-06-21 22:06:04 +02:00
Jonas Herzig
25ec311c86 Pre-release 2 of 2.2.0 2019-06-21 15:01:51 +02:00
Jonas Herzig
4ec5ef75a1 Fix various replay editor issues caused by shadow plugin bug 2019-06-21 15:00:08 +02:00
Jonas Herzig
75c4c7213f Fix NPE applying camera keyframes when camera entity is not yet loaded
Still not sure when this can happen but users are reporting it:
https://www.replaymod.com/forum/thread/2548#post10627
2019-06-21 12:05:05 +02:00
Jonas Herzig
f1f760a0e9 [1.14] Fix ingame menu buttons with ModMenu installed 2019-06-21 07:34:22 +02:00
Jonas Herzig
b8d319eba9 Skip world during video rendering if it has not yet been loaded 2019-06-21 07:34:22 +02:00
Jonas Herzig
de0f40f4dd [1.14] Allow opening of replay settings via ModMenu 2019-06-20 18:44:38 +02:00
Jonas Herzig
5305352b77 [1.14] Mark mod as client-side-only in ModMenu 2019-06-20 18:44:26 +02:00
Jonas Herzig
44a70c8ecf [1.14] Fix invalid mod icon (icons on fabric must be square) 2019-06-20 18:44:26 +02:00
Jonas Herzig
481b7b4c9d [1.14] Fix ModMenu buttons clashing with RM buttons on main menu 2019-06-20 18:44:10 +02:00
Jonas Herzig
b7136e6d70 [1.14] Fix camera entity after restarting replay (same as 1eafc3f) 2019-06-20 18:44:10 +02:00
Jonas Herzig
70acd79431 Allow continued use of most of pathing even if entity tracker fails
The failing entity tracker really only breaks spectator keyframes.
This is also very desirable for minimal mode where entity tracker
failure is highly likely.
2019-06-20 18:44:10 +02:00
Jonas Herzig
af55951f42 Introduce minimal mode (allows RM to run on unsupported MC versions)
by disabling various version-specific features (i.e. everything which
requires the ReplayStudio).
2019-06-20 18:44:10 +02:00
Jonas Herzig
357501e5db Qualify some (remapped) field references which the preprocesser ignored
The preprocessor should have complained about these but it didn't for
some reason. This commit isn't fixing any imminent bug, it's just
precautionary (and required to compile once the preprocessor is fixed).
2019-06-17 12:04:51 +02:00
Jonas Herzig
679e4805a0 Fix error popup in replay editor being off-screen 2019-06-17 12:01:39 +02:00
Jonas Herzig
e59b5db859 Fix the replay editor now showing non-IO exceptions during processing
Instead it just froze which is unhelpful if people don't look at the log.
2019-06-17 11:52:47 +02:00
Jonas Herzig
d417c58d00 Pre-release 1 of 2.2.0 2019-06-14 22:35:44 +02:00
Jonas Herzig
bf2d72976c Fix rendering with OF F1_pre13 (via OptiFabric) installed
Note that to run it in dev env, one must switch back fabric-api to 0.2.
2019-06-14 22:16:18 +02:00
Jonas Herzig
d02b239e74 Fix incorrect RM config location
While I might wish it was `configs`, the world (forge) has settled on
`config`.
2019-06-14 22:09:56 +02:00
Jonas Herzig
73723ed9e2 Guard against broken render settings file 2019-06-14 22:09:56 +02:00
Jonas Herzig
8112c852ef [1.14] Fix NPE in FullBrightness
Turns out fabric's init runs earlier than forge so mc.options is still
null.
Instead we just store mc and access the options when needed (thanks to
the preprocessor that's even shorter than before).
2019-06-14 22:09:56 +02:00
Jonas Herzig
a76268138a [1.14] Fix recording player's hand not swinging 2019-06-14 22:09:56 +02:00
Jonas Herzig
1eafc3fadf [1.14] Fix closing of replay not actually fully shutting down the world 2019-06-14 22:09:56 +02:00
Jonas Herzig
4dd02f8299 [1.14] Fix recording not always being stopped 2019-06-14 22:09:56 +02:00
Jonas Herzig
d15fa6a3f9 Fix notice screen back buttons not being hooked up 2019-06-14 22:09:56 +02:00
Jonas Herzig
a840cadfb7 Fix camera event handler staying registered leading to lack of HUD
When unloading the camera without killing it first (e.g. jumping back
in time), the event handler wouldn't ever get unregistered.
2019-06-14 22:09:56 +02:00
Jonas Herzig
2a08c11598 [1.7.10] Fix dead lock and NPE when jumping backwards in replays
The deadlock is a regression due to login phase inclusion.
Not sure about the NPE, it might have always existed.
2019-06-14 22:09:56 +02:00
Jonas Herzig
c72392fb62 Fix various NPE while in replay on 1.8.9 or below
Nulling the world and calling runTick proved to be too volatile, so
instead let's try performing an early return from runTick via mixin.
2019-06-14 14:49:54 +02:00
Jonas Herzig
560982a14a Fix NPE when replay is closed but camera entity is still being rendered 2019-06-14 14:09:42 +02:00
Jonas Herzig
047f216f73 [1.7.10] Fix event handler visibility 2019-06-14 14:04:52 +02:00
Jonas Herzig
898e29d7a1 [1.7.10] Fix crash when opening replay
Looks to be two regressions, one due to login phase inclusion and one
due to simplification of InputReplayTimer.
2019-06-14 13:35:53 +02:00
Jonas Herzig
208b9c1b60 Update to MC 1.14.2 2019-05-28 11:55:58 +02:00
Jonas Herzig
d89655e69a Remove some more preprocessor statements in favor of remap 2019-05-28 11:25:46 +02:00
Jonas Herzig
f3acf8cde7 Fix realms icon offsets in main menu on 1.14+ 2019-05-25 20:07:27 +02:00
Jonas Herzig
e7d96fca2a Fix lack of hand when spectating player in replay on 1.13+ 2019-05-25 19:45:53 +02:00
Jonas Herzig
cfdc4b9713 Remove workaround for super-super-class remapping bug 2019-05-25 18:57:32 +02:00
Jonas Herzig
26d8c97136 Switch to custom FG fork for Gradle 5 compatibility
Also drop MixinGradle since it supports neither Gradle 5 nor FG1 nor FG3
2019-05-24 16:26:01 +02:00
Jonas Herzig
a57ce21ebb Update Gradle Wrapper to 5.4.1 2019-05-24 16:26:01 +02:00
Jonas Herzig
5f57f3a1e2 Fix incompatible OpenNBT version on 1.12.2 and below 2019-05-24 16:25:24 +02:00
Jonas Herzig
62c673f4bc Update jGui to fix NPE in file chooser gui on windows
Regression introduced in 213ac13627178f49ce9671b29b6a542cb0e4c922
2019-05-24 10:59:55 +02:00
Jonas Herzig
05aec482c9 Fix classic camera movement (regression from switching to lwjgl vecs) 2019-05-22 11:04:10 +02:00
Jonas Herzig
5e407cc9aa Fix translations in replay recovery gui 2019-05-22 10:41:41 +02:00
Jonas Herzig
41251a1e18 Update ReplayStudio to remove ViaVersion server plugin classes 2019-05-21 20:43:28 +02:00
Jonas Herzig
cc9f2828c1 Fix world being set to null on replay restart when in sync mode 2019-05-21 11:04:38 +02:00
Jonas Herzig
8627867b62 Fix render preview (broken due to BGRA changes)
Also de-duplicates some code by combining >=1.13 and <1.13
2019-05-21 10:37:39 +02:00
Jonas Herzig
cf30f39b0e Be explicit about when we expect a login phase and when we don't 2019-05-20 18:57:20 +02:00
Jonas Herzig
2d02948203 Remove old replay editor gui screens 2019-05-20 18:55:07 +02:00
Jonas Herzig
993cdeab73 Work around mixin bug where a non-@Shadow field is treated as @Shadow
Note: Happens on 1.12.2 (different mappings than 1.14.1) and probably
only in dev env.
2019-05-20 18:37:40 +02:00
Jonas Herzig
fc1d99f985 Fix mouse input to overlays while the replay is paused in 1.8-1.12.2 2019-05-20 17:34:07 +02:00
Jonas Herzig
3a45147974 Move Mixins which exist specifically for jGui from RM to jGui repo 2019-05-20 17:18:12 +02:00
Jonas Herzig
1ef4f605d7 Fix accidental relocating of guava, commons-io and apache-logging (all provided by MC) 2019-05-20 17:08:19 +02:00
Jonas Herzig
e5ee6a3d94 Update to MC 1.14.1
The ReplayStudio update also fixes an issue with reading the
PlayerListEntryPacket leading to NPEs during Quick Mode.
2019-05-20 14:59:31 +02:00
Jonas Herzig
0e086d91a6 Use own event distribution system instead abusing fabric's one 2019-05-20 14:59:13 +02:00
Jonas Herzig
7cbf7f7c94 Switch core to 1.14 (generated via ./gradlew :1.14:setCoreVersion) 2019-05-10 14:09:22 +02:00
Jonas Herzig
7f7d33def8 Fail hard if versions/core/mcVersion is missing 2019-05-10 14:06:40 +02:00
Jonas Herzig
5f37ba48ff Reduce amount of 'relocate' statements for far better build times 2019-05-09 18:47:45 +02:00
Jonas Herzig
69e80fb3f4 Update Preprocessor to fix parallel builds 2019-05-09 17:45:26 +02:00
Jonas Herzig
7b97d9ea85 Use FG1.2 fork with Gradle 4.9 fixes so we can build everything at once 2019-05-08 14:00:46 +02:00
Jonas Herzig
362f61a337 Sign .drone.yml
Forgot to do it in f1527c51
2019-05-07 13:29:58 +02:00
Jonas Herzig
f1527c51fe Fix -dirty suffix of 1.7.10 build on CI 2019-05-07 12:49:53 +02:00
Jonas Herzig
d54905713f Fix mouse scroll and screenshot mixin targets 2019-05-07 12:48:36 +02:00
Jonas Herzig
6ba05f3d99 Fix resource pack recorder mixin
The old targets weren't inside the method but inside an inner class.
2019-05-07 11:59:06 +02:00
Jonas Herzig
2463e5dbf0 Work around bug in fabric's mapping provider (or Mixin itself?)
See https://github.com/FabricMC/fabric-mixin-compile-extensions/issues/1
2019-05-07 11:21:33 +02:00
Jonas Herzig
0f9150d7ce Fix modifier of scroll handler method 2019-05-07 10:30:20 +02:00
Jonas Herzig
2c843f4b45 Fix spectated player hand swinging 2019-05-06 23:31:35 +02:00
Jonas Herzig
6b9b9c2131 Get rid of annotation workaround (by not referencing affected classes) 2019-05-06 23:31:35 +02:00
Jonas Herzig
bd91d0d3bd Get rid of all the ATs in favor of Mixins 2019-05-06 22:46:21 +02:00
Jonas Herzig
2094c518a0 Fix :shadowJar task. Take 2.
This time, wait for the subprojects to be evaluated before trying
to get their shadowJar tasks (otherwise they won't be there).
2019-05-06 13:31:50 +02:00
Jonas Herzig
1d21002eb0 Run shadowJar and setCoreVersion in same gradle invocation on CI 2019-05-06 11:33:40 +02:00
Jonas Herzig
b55dce280c Fix :shadowJar task
It now copies any shadowed jar in any configured subprojects
instead of requiring all subprojects
2019-05-06 11:05:33 +02:00
Jonas Herzig
a65f3efbc5 Fix fetching of remap in jGui 2019-05-05 13:33:23 +02:00
Jonas Herzig
a02fe4e985 More FG build classpath workarounds
Though this one seems to have a different cause from the previous
one.
2019-05-05 13:26:53 +02:00
Jonas Herzig
2b4bee84f0 Fix preprocessor version in jGui 2019-05-04 20:41:25 +02:00
Jonas Herzig
08ff063a3b Fix 1.7.10 jar not being archived after drone build 2019-05-04 20:31:53 +02:00
Jonas Herzig
220b22869a Fix replay initialization with login phase on 1.11.2 and below
While this commit also considerably simplifies/cleans the setup
method, the actual fix is that the networkManager is now added
to the channel pipeline with under the "packet_handler" key,
whereas before it was unnamed causing issues when transitioning
to the play state.
2019-05-04 19:22:41 +02:00
Jonas Herzig
af86faeaf9 Fix webm encoding preset (caused by BGRA changes) 2019-05-04 15:27:03 +02:00
Jonas Herzig
3d009e45c7 Update to MC 1.14 / Fabric 2019-05-04 15:27:03 +02:00
Jonas Herzig
17fe5b345f Replace all ATs with Mixin on 1.13+ in preparation for Fabric 2019-04-26 12:04:33 +02:00
Jonas Herzig
d5b9e60c4d Workaround class loader errors by loading single guava in the root scope
Possibly related to gradle/gradle#4823 as it only appeared after
using evaluationDependsOn (via The Preprocessor and on jGui).
2019-04-25 09:17:07 +02:00
Jonas Herzig
2d572f6740 Get restrictions module "compiling" on 1.13 2019-04-24 19:26:43 +02:00
Jonas Herzig
6f15df8081 Get compat module compiling on 1.13 2019-04-24 19:26:43 +02:00
Jonas Herzig
df6f744d51 Update preprocessor to fix encoding issues 2019-04-24 17:17:53 +02:00
Jonas Herzig
7cff2e0cf3 Get 1.7.10 working with source remapping
Requires changing the 'core' version to 1.8 before compiling
2019-04-24 17:17:53 +02:00
Jonas Herzig
2ee91515f7 Make use of the source remapping feature of The Preprocessor plugin 2019-04-24 15:38:34 +02:00
Jonas Herzig
6127e0a027 Replace dev-only reflection with access transformer entry 2019-04-24 14:03:17 +02:00
Jonas Herzig
fa8f8f52aa Stop using @SneakyThrows since it breaks the JDT used for source remap 2019-04-24 13:41:06 +02:00
Jonas Herzig
9968f81073 Split source preprocessor into separate gradle plugin 2019-04-21 01:40:39 +02:00
Jonas Herzig
73597dd031 Fix camera being reset to 0/0/0 when jumping in quick mode in 1.13 2019-03-27 11:04:41 +01:00
Jonas Herzig
b8c892fcd4 Fix initialization of quick mode with login phase
Replay is always already past the login phase when quick mode is
enabled, hence the LoginSuccess packet must not be sent.
2019-03-27 10:58:37 +01:00
Jonas Herzig
2c0ae426de Fix drone build 2019-03-15 19:04:54 +01:00
Jonas Herzig
cf592bdedb Skip netty when shading libs (MC already provides it) 2019-03-15 17:50:22 +01:00
Jonas Herzig
2997d3e8f6 Update ReplayStudio for ViaVersion 1.12.2 and 1.13.2 support 2019-03-15 17:12:15 +01:00
Jonas Herzig
44151876cd Add task which collects shadowed jars in root project build/libs folder 2019-03-15 14:50:56 +01:00
Jonas Herzig
f795b27251 Use shadow gralde plugin on 1.8+ and enable its minimize option
Cuts RM jar sizes in half.
2019-03-15 13:43:05 +01:00
Jonas Herzig
fc0f070721 Make our non-shading of Mixin's deps explicit 2019-03-15 10:51:15 +01:00
Jonas Herzig
2e29632fab Merge branch 'johni/blend' into johni/1.13-pre 2019-03-15 10:49:38 +01:00
Jonas Herzig
1e1104f4d3 Add blend export to GuiRenderSettings 2019-03-14 18:20:17 +01:00
Jonas Herzig
7cc62b13c1 Fix blend compilation on pre-1.13 2019-03-14 18:20:17 +01:00
Jonas Herzig
3cb1d8189b Preshadow lwjgl_util instead of copying source of specific classes 2019-03-14 18:20:17 +01:00
Jonas Herzig
dc6de5bd5f Apply rotation and scale to entity (livingbase), not its parts
Reduces amount of keyframes per entity and makes it easier to work with.
2019-03-14 11:30:40 +01:00
Jonas Herzig
cd16e014d1 Vastly improve performance of major block name generation 2019-03-13 22:03:03 +01:00
Jonas Herzig
22ab39c2db Get blend export running on 1.13 2019-03-13 19:10:44 +01:00
Jonas Herzig
4eb5d2d9cf Preshadow lwjgl_util instead of copying source of specific classes 2019-03-13 18:32:05 +01:00
Jonas Herzig
106f14d8c7 Merge branch 'johni/1.13-pre' into johni/blend 2019-03-13 16:07:32 +01:00
Jonas Herzig
443c1ca2af Render to BGRA instead of RGB format for better performance on most GPUs 2019-03-13 15:27:53 +01:00
Jonas Herzig
27efc3c717 Fix pre-1.13 imports 2019-03-13 14:52:11 +01:00
Jonas Herzig
d7f2cba214 Update ReplayStudio to fix SquashFilter as used by MarkerProcessor 2019-03-13 13:55:28 +01:00
Jonas Herzig
2d7696b09e Fix NPE in MarkerProcessor when done 2019-03-13 12:06:35 +01:00
Jonas Herzig
1db94b7871 Fix timestamp of squashed packets in MarkerProcessor 2019-03-13 11:50:18 +01:00
Jonas Herzig
681e803d44 Update ReplayStudio for custom entity attribs and binary tracker cache 2019-03-13 11:46:12 +01:00
Jonas Herzig
1d88ca044d Add "Edit" button to replay viewer gui 2019-03-12 20:11:07 +01:00
Jonas Herzig
51c073012e Re-work Replay Editor UI 2019-03-12 19:44:34 +01:00
Jonas Herzig
eb6e7b79d0 Add start/stop/pause/resume recording functionality
Using automatically applied, ReplayStudio-based post processing.
2019-03-12 13:29:21 +01:00
Jonas Herzig
fe68f76bd1 Remove accidentally added mixin-hack subproject inclusion 2019-03-11 18:52:00 +01:00
Jonas Herzig
9d315134fc Fix packet re-encoding in pre-1.13 versions 2019-03-11 18:16:23 +01:00
Jonas Herzig
32de147ae2 Update ReplayStudio for dedicated replay cache
Also change artifact back from localMaven to jitpack
2019-03-11 17:51:53 +01:00
Jonas Herzig
fde807f8ff Fix pack.mcmeta for pre-1.13 versions 2019-03-11 17:29:22 +01:00
Jonas Herzig
79f02b5dfb Fix regression in MixinRenderItem redirect method signature 2019-03-11 15:48:11 +01:00
Jonas Herzig
8526264dab Disable reproducible builds for now since people keep breaking it
Need to re-enable it before 1.13 release since it's required for sigs.
2019-03-11 15:24:55 +01:00
Jonas Herzig
4da57dceb0 Fix GSON dependency configuration for FG3 2019-03-11 15:13:31 +01:00
Jonas Herzig
0f3a6253e0 Complete all currently actionable 1.13.2 FIXMEs 2019-03-11 15:13:31 +01:00
Jonas Herzig
e9ca1bb47e Fix FOV during 360 rendering 2019-03-11 15:13:31 +01:00
Jonas Herzig
5f0bd1cf5d Only update uniforms when ODS shader is bound (fixes GL errors) 2019-03-11 15:13:31 +01:00
Jonas Herzig
cdcd6f6893 Get render module mostly working 2019-03-10 16:59:59 +01:00
Jonas Herzig
f8fc3462e8 Get recording and replay working 2019-03-10 14:15:14 +01:00
Jonas Herzig
8705bbad9a Re-enable and fix building for older MC versions 2019-03-09 13:08:47 +01:00
Jonas Herzig
528791c91f fixup snapshot 2019-03-02 15:10:15 +01:00
Jonas Herzig
f13f2dda1c Get extras module compiling on 1.13
Remove LocalizationExtra (too much update work for too little gain)
2019-03-02 09:59:57 +01:00
Jonas Herzig
c8cf4d66c5 Get editor module compiling on 1.13 2019-03-01 17:22:50 +01:00
Jonas Herzig
cae970ec6b Get online module compiling on 1.13 2019-03-01 17:22:50 +01:00
Jonas Herzig
1727702de4 Get simplepathing module compiling on 1.13 2019-03-01 17:22:50 +01:00
Jonas Herzig
344a550dc1 Get render module compiling on 1.13 2019-03-01 17:22:50 +01:00
Jonas Herzig
641014b0d1 Get pathing module compiling 2019-03-01 17:22:50 +01:00
Jonas Herzig
c1fefdeb3c Get core, recording and replay modules compiling on 1.13.2 2019-03-01 17:22:50 +01:00
Jonas Herzig
b6a4206816 Update FG3 and Forge from git version to first official snapshots 2019-03-01 17:22:50 +01:00
Jonas Herzig
1e584769af Misc 1.13 progress 2019-03-01 17:22:50 +01:00
Jonas Herzig
1470123ec9 Get replay module compiling on 1.13 2019-03-01 17:22:50 +01:00
Jonas Herzig
9655677972 Start update to 1.13 2019-03-01 17:22:50 +01:00
Jonas Herzig
65295b311e Merge branch 'spherical-fov' into develop 2018-12-19 10:20:23 +01:00
Jonas Herzig
3bc9bb32b9 Merge branch 'fix-bitrate-label' into develop 2018-12-19 10:18:01 +01:00
Jonas Herzig
c575049bd9 Merge branch 'johni/quick-mode' into develop 2018-12-19 10:17:45 +01:00
Jonas Herzig
3f7818aeec Auto-save the current timeline after changes and on exit
This auto-saved timeline is loaded when the replay is opened the next time.
2018-12-18 15:04:21 +01:00
Jonas Herzig
c1b4964978 Handle entity position interpolation when jumping in quick mode 2018-12-18 13:32:26 +01:00
Jonas Herzig
1da7060bb2 Fix entity head rotation in quick mode 2018-12-18 12:55:51 +01:00
Jonas Herzig
5366758cf6 Compress packets to reduce quick mode memory usage by ~80% 2018-12-18 12:43:39 +01:00
Jonas Herzig
60ef8df523 Add Quick Mode keybinding translation key 2018-12-18 10:48:31 +01:00
Jonas Herzig
2737077828 Retain camera position when switching to and from quick mode 2018-12-18 10:44:57 +01:00
Jonas Herzig
1670ed4e80 Fix dead lock when switching from async to quick mode 2018-12-18 10:44:42 +01:00
Jonas Herzig
c30520ad3d Fix previous block state of BlockChange being loaded incorrectly 2018-12-18 10:04:46 +01:00
Jonas Herzig
e989b60ea8 Properly handle non-full chunks in QuickReplaySender 2018-12-18 10:04:46 +01:00
Jonas Herzig
c8ecd17fe9 Re-write QuickReplaySender caching to be significantly more memory efficient 2018-12-18 10:04:46 +01:00
Jonas Herzig
3319d4263c Ensure replay has ended when MP GUI is opened (fixes #134) 2018-12-17 15:01:01 +01:00
Jonas Herzig
c94f5d17f4 Fix packet data being trashed by Restore Replay GUI (fixes #129) 2018-12-17 14:42:03 +01:00
Jonas Herzig
d791eedae9 Replace dropdown replay selection with popup in ReplayEditor (fixes #132) 2018-12-17 14:00:44 +01:00
CrushedPixel
2f44d5f380 GuiRenderSettings: Fix bitrate label 2018-12-06 14:47:29 +01:00
CrushedPixel
7c3fcd4e42 Adjustments for consistency 2018-12-06 14:18:55 +01:00
CrushedPixel
a7ec6524b7 Add FOV slider for spherical render methods
Before uploading to YouTube, convert all spherical non-mp4 files to mp4 to be able to inject metadata
Properly re-throw errors during the rendering pipeline
2018-12-06 01:29:31 +01:00
Jonas Herzig
ef368254cd Merge branch 'stable' into johni/quick-mode 2018-08-31 12:44:00 +02:00
Jonas Herzig
20dfebbc2a Release 2.1.4 2018-08-25 14:23:32 +02:00
Jonas Herzig
8e2b0c304c Merge branch 'johni/fix-optifine-e1' into develop 2018-08-25 13:48:05 +02:00
Jonas Herzig
a9e32a53ea Update jGui (fixes "Cannot convert pos unless rendered at least once.") 2018-08-25 13:47:31 +02:00
Jonas Herzig
85a167a0d5 Fix camera position being able to become NaN with classic controls
To reproduce, hold A for about a second, then release A and press D in the same frame.
2018-08-25 11:06:24 +02:00
Jonas Herzig
73c52b5cf0 Backport quick mode to 1.9.4+ and disable below 2018-08-22 17:40:57 +02:00
Jonas Herzig
b6a7d3bcda Disable maven artifact checksum verification because Mojang keeps breaking it
(and so do some maven repos) and I can't be bothered to constantly fix it.
2018-08-22 14:07:48 +02:00
Jonas Herzig
34343a809f Update ReplayStudio (fixes #131) 2018-08-22 13:32:42 +02:00
Jonas Herzig
3db9d58f8f Handle Respawn packet in QuickReplaySender 2018-07-28 13:07:57 +02:00
Jonas Herzig
ec5ffe3e02 Add caching to the quick replay sender 2018-07-28 12:59:58 +02:00
Jonas Herzig
42a2ae35ed fixup quick weather 2018-07-27 21:26:55 +02:00
Jonas Herzig
12605f51de Add GUI popup for initializing quick mode and signaling failures 2018-07-27 19:50:40 +02:00
Jonas Herzig
6cb207fd47 Also track weather and time during quick replay mode 2018-07-27 18:49:06 +02:00
Jonas Herzig
ad9c82c991 Fix compatibility with Optifine 1.12.2 E1
Optifine has changed some package names, this commit deals with that.
2018-07-20 11:05:21 +02:00
Jonas Herzig
edc54ce6d4 Add quick replay mode
Allows very quick forwards and backwards jumping at the cost of only
replaying entity positions and block updates.

Still needs to be backported from 1.12.2 and contains FIXMEs
2018-07-18 21:55:03 +02:00
Jonas Herzig
8314803cda Use "-dirty" for marking dirty builds because Windows doesn't like "*" 2018-06-12 22:24:57 +02:00
Jonas Herzig
832413dda0 Set default memory for gradle JVM (fixes #32)
See: https://github.com/MinecraftForge/MinecraftForge/pull/3361
2018-06-12 22:24:05 +02:00
Jonas Herzig
c48187e784 Disable .blend export for 1.7.10 2018-06-11 00:31:50 +02:00
Jonas Herzig
c5229628e3 Merge branch 'stable' into blend 2018-06-11 00:31:25 +02:00
Jonas Herzig
f96e715b0b Release 2.1.3 2018-06-10 17:59:22 +02:00
Jonas Herzig
16b40a5725 Only try to sign jars if the current call built any 2018-06-10 17:59:22 +02:00
Jonas Herzig
38892026c5 Add .gitkeep to versions/1.7.10 directory
This is required for it to be included in the versions.json
on the master branch for the next release.
2018-06-10 16:43:37 +02:00
Jonas Herzig
ab4153f375 Update ReplayStudio to fix custom potion effects (fixes #126) 2018-06-10 16:06:45 +02:00
Jonas Herzig
5e6a85d475 Update dependency checksums 2018-06-10 13:39:21 +02:00
Jonas Herzig
1b9d430176 Handle unbalanced quotes in ffmpeg arguments (fixes #119) 2018-06-10 13:12:42 +02:00
Jonas Herzig
62d2ce4b37 Fix crash when in replay with Optifine 1.12.2 DX (fixes #120)
Re-creating the RenderChunk lost any custom data Optifine had in them which
resulted in NPEs.
The reason we re-create the RenderChunks is because otherwise, once it's
assigned an empty chunk once, it's not getting any further update even when
moving back to filled chunks. Since just calling setNeedsUpdate works as well,
this commit changes the whole mixin to doing that instead.
2018-06-09 23:55:39 +02:00
Jonas Herzig
efaa5b7c41 Shouldn't release jars be final..
Well, looks like the jcenter repo doesn't care because the hash for
one of its jars has changed (a few bits in the jar were flipped).
Maven Central is still serving the original version, so we have to allow
both hashes.
2018-04-03 16:17:33 +02:00
Jonas Herzig
fb1254ce12 Merge branch 'johni/1.7.10' into johni/develop 2018-04-02 11:53:06 +02:00
Jonas Herzig
277e55a241 [1.7.10] Workaround for crash when loading replay with TCNodeTracker (fixes #118) 2018-04-02 11:52:11 +02:00
Jonas Herzig
3f00c1f977 [1.7.10] Update ReplayStudio to fix custom entity types (fixes #117) 2018-04-02 11:51:42 +02:00
Jonas Herzig
feb39f02ec Fix Optifine language data missing when localization extra is enabled (fixes #109) 2018-03-22 14:52:12 +01:00
Jonas Herzig
65e3d45c9b Switch submodules from ssh to https 2018-03-16 17:34:24 +01:00
Jonas Herzig
8b044b344a [1.7.10] Remove unnecessary pre-MixinGradle configuring in common.gradle 2018-03-16 16:59:15 +01:00
Jonas Herzig
9631f1cf5f [1.7.10] Fix recording player y position 2018-03-16 16:57:08 +01:00
Jonas Herzig
63b2f3abcc Add transformer exclusion for transformers and fix transforming of null classes 2018-03-16 16:57:08 +01:00
Jonas Herzig
0b262d1a74 [1.7.10] Fix reobf task missing fields due to incorrect classpath
The reobf task was not handling certain fields because it was missing
the respective classes on its classpath because we removed MC&deps
from the compile configuration.
2018-03-16 16:55:19 +01:00
Jonas Herzig
75a14a7488 Catch _all_ errors during recording setup 2018-03-16 16:55:19 +01:00
Jonas Herzig
031582957f Merge branch 'stable' into develop-1.7.10 2018-03-16 13:03:22 +01:00
Jonas Herzig
e32dab8749 Add 1.7.10 to reprod / drone build 2018-03-16 13:01:33 +01:00
Jonas Herzig
3e23826c8d [1.7.10] Fix recording of chunk packets in MP (fixes #98) 2018-03-16 13:01:33 +01:00
Jonas Herzig
eb04eb47dc Add 1.7.10 version 2018-03-16 13:01:33 +01:00
Jonas Herzig
0a26f59c9c Release 2.1.2 2018-03-15 23:12:53 +01:00
Jonas Herzig
9cdd1bbca8 Sign jars based on current commit instead of tag 2018-03-15 22:56:40 +01:00
Jonas Herzig
31a9e4eaf6 Fix preprocessor not processing ifdef 2018-03-15 22:17:51 +01:00
Jonas Herzig
221991bf2c Do not shade gson lib (fixes #115)
The gson lib is provided by MC anyway.
Additionally, by shading it, we relocate the lib via the FG reobfJar
task which doesn't properly handle annotations causing the Mixin
lib's MixinConfig to no longer parse properly.
2018-03-15 22:17:28 +01:00
Jonas Herzig
48b39fe551 Update MCProtocolLib (via ReplayStudio)
Primarily because of
1728e10 Default to no team color when receiving unknown values.
63e06fa Remove hard bitsPerEntry limit, enforce minimum of 4.
6de0593 Add CustomStatistic as fallback for custom or unimplemented statistic IDs.
2018-03-11 20:57:00 +01:00
Jonas Herzig
76be6c1d2e Fix dead lock when jumping backwards in time during rendering
A jump backwards in time entails unloading the current world and with it
the ChunkRenderDispatcher that the ChunkLoadingRenderGlobal has locked.
2018-03-11 13:45:19 +01:00
Jonas Herzig
13d5586583 Fix trimming of replays not actually removing any packets (fixes #113)
The init method of the Squash filter has never been called therefore it had
never registered its packets and was never able to properly function.
2018-03-11 12:29:51 +01:00
Jonas Herzig
34172cd737 Fix race condition due to ReplaySender in async mode during setup()
The ReplaySender used to be started in async mode even before the call
to setup(). If the ReplaySender restarts the replay before the setup()
call finishes, that call may instead produce a NPE in
clientToServerHandshake().
To fix this race condition, the ReplaySender is always started in sync
mode and only switched to async after the setup() call.
2018-03-11 12:17:18 +01:00
Jonas Herzig
fbbca76099 Remove :versions prefix from gradle projects and remove duplicated build code 2018-03-06 12:39:24 +01:00
Jonas Herzig
8ed9c75ba1 Release 2.1.1 2018-03-05 12:12:07 +01:00
Jonas Herzig
e7b5ba9e72 Update blend export for all remaining MC versions 2018-03-04 16:28:35 +01:00
Jonas Herzig
40da0d10c8 Parse raw buffer instead of intercepting all BufferBuilder calls 2018-03-04 16:28:35 +01:00
Jonas Herzig
1bdf7da525 Update blend export to 1.12.2 2018-03-04 16:28:29 +01:00
Jonas Herzig
6794b58524 Add .blend export 2018-03-04 15:30:50 +01:00
Jonas Herzig
78ad02bc84 Change from tag-based versioning to commit/file based 2018-03-03 12:33:50 +01:00
Jonas Herzig
9c76f0fcc0 Unload old world when restarting replay, fixes floating heads 2018-03-03 09:50:13 +01:00
Jonas Herzig
5d9dc9eb95 Fix half-despawned non-player entities if they are inside an unloading chunk (see #111) 2018-03-03 09:11:16 +01:00
Jonas Herzig
66312e4d40 Fix half-despawned player entities if they are inside an unloading chunk (fixes #111) 2018-03-02 15:54:21 +01:00
Jonas Herzig
180fda20d7 Do not shade lombok 2018-03-02 10:40:45 +01:00
Jonas Herzig
94c33df308 Exclude guava from ReplayStudio deps 2018-03-02 10:40:45 +01:00
Jonas Herzig
598827f074 Do not relocate javax package 2018-02-28 23:06:46 +01:00
Jonas Herzig
49c756b97d Fix version replacement in source and resources 2018-02-28 22:53:41 +01:00
Jonas Herzig
5ce08874d6 Do not relocate mixin lib 2018-02-28 21:56:57 +01:00
Jonas Herzig
da6d9e8167 Only replace FG2.1 when not a reprod build 2018-02-28 21:15:37 +01:00
Jonas Herzig
2fa2d2f745 Remove superfluous opening of MainMenu on replay exit (fixes #110) 2018-02-28 20:16:09 +01:00
Jonas Herzig
e508ac40cf Fix formatting/typos in README 2018-02-28 19:33:03 +01:00
Jonas Herzig
f0d4d93936 Replace FG 2.1 with custom fork for Gradle 3 compatibility 2018-02-28 19:20:48 +01:00
Jonas Herzig
95877be3e6 Replace FG 2.0 with custom fork for Gradle 3 compatibility 2018-02-28 11:55:59 +01:00
Jonas Herzig
d9f318623c Update README for single tree 2018-02-28 11:55:59 +01:00
Jonas Herzig
dd26163a7c Update .drone.yaml for single tree build 2018-02-28 11:55:59 +01:00
Jonas Herzig
5f4c15de2b Update proxy-witness and disable its cache 2018-02-28 08:36:02 +01:00
Jonas Herzig
7546d421b0 Use https for downloading gradle wrapper 2018-02-28 08:36:02 +01:00
Jonas Herzig
943fa45bbc Change project version to partially depend on the MC version 2018-02-28 08:36:02 +01:00
Jonas Herzig
ad6345de88 Re-write reprod to support all versions in one tree 2018-02-28 08:36:02 +01:00
Jonas Herzig
aabc3b52fe Replace reprod patched mixingradle with specific upstream version 2018-02-22 18:25:36 +01:00
Jonas Herzig
2f96694a73 Replace reprod patched mixin with upstream + gradle task for fixing refmap 2018-02-22 18:25:36 +01:00
Jonas Herzig
c5ad912a79 Relocate shaded libs 2018-02-22 18:25:36 +01:00
Jonas Herzig
aa1900bee6 Remove unused lombok dependency 2018-02-22 18:25:36 +01:00
Jonas Herzig
748b9da443 Combine all versions into a single tree 2018-02-22 18:25:36 +01:00
Jonas Herzig
ec50efec10 Merge branch '1.12.1-dev' into 1.12.2-dev 2018-01-19 19:50:18 +01:00
Jonas Herzig
d7e3c4d242 Merge branch '1.12-dev' into 1.12.1-dev 2018-01-19 19:48:36 +01:00
Jonas Herzig
b176dd9879 Manually repack jar file after reobfJar task for reproducibility 2018-01-19 19:45:57 +01:00
Jonas Herzig
a090a00360 Merge branch '1.12.1-dev' into 1.12.2-dev 2018-01-19 13:17:31 +01:00
Jonas Herzig
ddeaf37e8e Merge branch '1.12-dev' into 1.12.1-dev 2018-01-19 13:16:56 +01:00
Jonas Herzig
d0e4475b40 Merge branch '1.11.2-dev' into 1.12-dev 2018-01-19 13:15:40 +01:00
Jonas Herzig
00adf7f083 Merge branch '1.11-dev' into 1.11.2-dev 2018-01-19 13:10:55 +01:00
Jonas Herzig
7458e46e07 Merge branch '1.10.2-dev' into 1.11-dev 2018-01-19 13:09:31 +01:00
Jonas Herzig
ed6e11f106 Merge branch '1.9.4-dev' into 1.10.2-dev 2018-01-19 13:06:15 +01:00
Jonas Herzig
178c6b21a1 Fix member info of WorldClient.playSound mixin 2018-01-19 13:00:44 +01:00
Jonas Herzig
5f2366e49d Merge branch '1.12.1-dev' into 1.12.2-dev 2018-01-17 20:46:34 +01:00
Jonas Herzig
f6b4ea015d Merge branch '1.12.2-reprod' into 1.12.2-dev 2018-01-17 20:13:05 +01:00
Jonas Herzig
638cc59097 Merge branch '1.12-dev' into 1.12.1-dev 2018-01-17 20:02:27 +01:00
Jonas Herzig
3a2abf05cb Merge branch '1.12.1-reprod' into 1.12.1-dev 2018-01-17 19:49:37 +01:00
Jonas Herzig
0f004537af Whitelist version.json checksum
Why is there even a sha1 value in the URL if the file can change?
2018-01-17 19:37:34 +01:00
Jonas Herzig
dc1bc1ee8e Merge branch '1.11.2-dev' into 1.12-dev 2018-01-17 00:18:04 +01:00
Jonas Herzig
87335cd243 Add lombok-1.16.4.jar to checksums list 2018-01-17 00:13:40 +01:00
Jonas Herzig
06bebda557 Merge branch '1.11-dev' into 1.11.2-dev 2018-01-16 23:28:46 +01:00
Jonas Herzig
430a5044f5 Merge branch '1.11.2-reprod' into 1.11.2-dev 2018-01-16 23:25:23 +01:00
Jonas Herzig
e7ce03e85f Merge branch '1.10.2-dev' into 1.11-dev 2018-01-16 23:15:31 +01:00
Jonas Herzig
bab1d3463e Merge branch '1.11-reprod' into 1.11-dev 2018-01-16 22:45:52 +01:00
Jonas Herzig
2dce4eb54a Merge branch '1.9.4-dev' into 1.10.2-dev 2018-01-16 22:31:31 +01:00
Jonas Herzig
0ed9a5533e Merge branch '1.10.2-reprod' into 1.10.2-dev 2018-01-16 22:28:17 +01:00
Jonas Herzig
c148076a40 Merge branch '1.8.9-dev' into 1.9.4-dev 2018-01-16 22:22:05 +01:00
Jonas Herzig
e11f8f9e9d Merge branch '1.9.4-reprod' into 1.9.4-dev 2018-01-16 21:56:01 +01:00
Jonas Herzig
604d33d846 Merge branch '1.8-dev' into 1.8.9-dev 2018-01-16 21:52:50 +01:00
Jonas Herzig
ea2427a73c Create screenshot folder it it does not yet exist 2018-01-16 21:52:05 +01:00
Jonas Herzig
1ca91d7ee9 Merge branch '1.8.9-reprod' into 1.8.9-dev 2018-01-16 21:04:12 +01:00
Jonas Herzig
22e4ce4584 Make sure the replay is stopped if the main menu is opened (fixes #95) 2018-01-16 16:14:03 +01:00
Jonas Herzig
d7368d8c87 Remove 5 character restriction from user names (fixes #97) 2018-01-16 16:05:08 +01:00
Jonas Herzig
eb916c395b Add forge server mod for ReplayRestrictions (fixes #102) 2018-01-16 16:03:19 +01:00
Jonas Herzig
23c5df5aaa Allow the mod to be loaded in a dedicated server environment 2018-01-16 16:01:59 +01:00
Jonas Herzig
5a1e893a45 Deselect marker when selecting keyframe (and vice versa) (fixes #104) 2018-01-16 15:08:42 +01:00
Jonas Herzig
e854635a34 Allow hiding of server IPs in replay viewer by pressing F1 (fixes #105) 2018-01-16 14:52:48 +01:00
Jonas Herzig
5bc5ef5fb8 Add buttons in SP/MP menu for quick en-/disabling of recording 2018-01-16 14:21:38 +01:00
Jonas Herzig
08e0d65685 Remove preshadowJar steps from README.md (no longer required as of a8f2c74) 2018-01-16 14:02:17 +01:00
Jonas Herzig
c654d7bd2f Merge branch '360-screenshots' into 1.8-dev 2018-01-16 13:51:25 +01:00
Jonas Herzig
f8aa97405a Merge branch '1.8-viaversion' into 1.8-dev 2018-01-16 13:46:57 +01:00
Jonas Herzig
38f69c52d9 Merge branch '1.8-reprod' into 1.8-dev 2018-01-16 12:40:20 +01:00
Jonas Herzig
2e62cdf838 Fix dead lock when rendering without immediate jump in time
setupTerrain will loop until (among other conditions) the chunksToUpdate set is
empty. However its size is never decreased during setupTerrain.
Having a (backwards) jump in time right before rendering the first frame would
reset the RenderGlobal due to the world change, leaving the chunksToUpdate set
empty to begin with and due to other changes, chunks are never inserted into it
during rendering (because they're always updated immediately).
The new screenshot feature and rendering a path that's in the future will not
trigger any world change, leaving the render process stuck in a life lock.
2018-01-16 11:42:28 +01:00
CrushedPixel
650cc1036d Fix GuiUploadScreenshot showOnDiskButton crashing the game on Windows 2017-12-22 15:14:20 +01:00
Jonas Herzig
c07080650a Fix realms notifications not being offset with button (fixes #22 GH) 2017-11-03 09:24:57 +01:00
CrushedPixel
666a3611bb Actually hide the GUI when exporting a screenshot 2017-11-01 15:43:49 +01:00
CrushedPixel
a4a9473111 Hide GUI when exporting screenshot
Workaround not all chunks being loaded in screenshot
Fix wrong RenderSettings being exposed in ScreenshotRenderer
Update Language submodule
2017-11-01 15:36:15 +01:00
CrushedPixel
2ebec358e0 Added Screenshot export settings GUI 2017-11-01 13:24:52 +01:00
CrushedPixel
7d380e770a Properly handle OOMExceptions when creating a 360° screenshot 2017-10-31 17:28:21 +01:00
Jonas Herzig
434efd16d1 Fix BetterSprinting compat class not actually functioning (fixes #103) 2017-10-31 11:11:33 +01:00
Jonas Herzig
bfbaec44ba Add logging to BetterSprinting compat class 2017-10-31 11:11:03 +01:00
Jonas Herzig
4ac418cdd5 Update reprod to 1.12.2 2017-10-28 21:13:01 +02:00
Jonas Herzig
42aa0d9b61 Merge branch '1.12.2-dev' into 1.12.2-reprod 2017-10-28 19:52:54 +02:00
Jonas Herzig
117dc6191f Update reprod to 1.12.1 2017-10-28 19:51:02 +02:00
Jonas Herzig
903762f042 Merge branch '1.12.1-dev' into 1.12.1-reprod 2017-10-28 19:34:38 +02:00
Jonas Herzig
f9b6fd1ced Update reprod to 1.12 2017-10-28 19:32:26 +02:00
Jonas Herzig
9592c6b8ea Merge branch '1.12-dev' into 1.12-reprod 2017-10-28 18:28:19 +02:00
Jonas Herzig
5f7e4fd9dd Update reprod to 1.11.2 2017-10-28 18:25:22 +02:00
Jonas Herzig
e70ef7a601 Merge branch '1.11.2-dev' into 1.11.2-reprod 2017-10-28 18:06:00 +02:00
Jonas Herzig
b0a65b1103 Update reprod to 1.11 2017-10-28 18:04:27 +02:00
Jonas Herzig
134c10f39e Merge branch '1.11-dev' into 1.11-reprod 2017-10-28 17:44:35 +02:00
Jonas Herzig
fd7da227a0 Update reprod to 1.10.2 2017-10-28 17:42:58 +02:00
Jonas Herzig
701e8e8bba Merge branch '1.10.2-dev' into 1.10.2-reprod 2017-10-28 17:26:43 +02:00
Jonas Herzig
4ea0da3fe6 Update reprod to 1.9.4 2017-10-28 17:18:57 +02:00
Jonas Herzig
4f413e34fc Merge branch '1.9.4-dev' into 1.9.4-reprod 2017-10-28 16:15:38 +02:00
Jonas Herzig
45cc789add Update reprod to 1.8.9 2017-10-28 15:52:49 +02:00
Jonas Herzig
24e1f7b9fb Merge branch '1.8.9-dev' into 1.8.9-reprod 2017-10-28 15:27:41 +02:00
Jonas Herzig
6c0f63c4d2 Enable reproducible builds on drone 2017-10-28 15:16:02 +02:00
Jonas Herzig
faf5c681de Add script for online-cache building 2017-10-28 15:13:40 +02:00
Jonas Herzig
c8dc70af56 Merge branch 1.12.1-dev into 1.12.2-dev
db1717f Merge branch 1.12-dev into 1.12.1-dev
d7dc2ba Merge branch 1.11.2-dev into 1.12-dev
b1c6098 Merge branch 1.11-dev into 1.11.2-dev
caf6051 Merge branch 1.9.4-dev into 1.11-dev
263e080 Merge branch 1.8.9-dev into 1.9.4-dev
8fad02c Merge branch 1.8-dev into 1.8.9-dev
1c888aa Add minVersion to mixin configs and bump bundled mixin version
10ce71e Fix mapwriter crash when opening replay for <MC1.12 (fixes #96)
5fb1cf3 Fix half-despawned player entities (see #93) when the entity is moved greater distances
adfe6a2 Fix NPE when spectated non-player entity despawns (fixes #94)
b27af27 Fix player entities being half-despawned after jumping in time (fixes #93)
2017-10-28 12:50:29 +02:00
Jonas Herzig
db1717ffdd Merge branch 1.12-dev into 1.12.1-dev
d7dc2ba Merge branch 1.11.2-dev into 1.12-dev
b1c6098 Merge branch 1.11-dev into 1.11.2-dev
caf6051 Merge branch 1.9.4-dev into 1.11-dev
263e080 Merge branch 1.8.9-dev into 1.9.4-dev
8fad02c Merge branch 1.8-dev into 1.8.9-dev
1c888aa Add minVersion to mixin configs and bump bundled mixin version
10ce71e Fix mapwriter crash when opening replay for <MC1.12 (fixes #96)
5fb1cf3 Fix half-despawned player entities (see #93) when the entity is moved greater distances
adfe6a2 Fix NPE when spectated non-player entity despawns (fixes #94)
b27af27 Fix player entities being half-despawned after jumping in time (fixes #93)
2017-10-28 12:47:13 +02:00
Jonas Herzig
d7dc2badf8 Merge branch 1.11.2-dev into 1.12-dev
b1c6098 Merge branch 1.11-dev into 1.11.2-dev
caf6051 Merge branch 1.9.4-dev into 1.11-dev
263e080 Merge branch 1.8.9-dev into 1.9.4-dev
8fad02c Merge branch 1.8-dev into 1.8.9-dev
1c888aa Add minVersion to mixin configs and bump bundled mixin version
10ce71e Fix mapwriter crash when opening replay for <MC1.12 (fixes #96)
5fb1cf3 Fix half-despawned player entities (see #93) when the entity is moved greater distances
adfe6a2 Fix NPE when spectated non-player entity despawns (fixes #94)
b27af27 Fix player entities being half-despawned after jumping in time (fixes #93)
2017-10-28 12:28:58 +02:00
Jonas Herzig
b1c6098205 Merge branch 1.11-dev into 1.11.2-dev
caf6051 Merge branch 1.9.4-dev into 1.11-dev
263e080 Merge branch 1.8.9-dev into 1.9.4-dev
8fad02c Merge branch 1.8-dev into 1.8.9-dev
1c888aa Add minVersion to mixin configs and bump bundled mixin version
10ce71e Fix mapwriter crash when opening replay for <MC1.12 (fixes #96)
5fb1cf3 Fix half-despawned player entities (see #93) when the entity is moved greater distances
adfe6a2 Fix NPE when spectated non-player entity despawns (fixes #94)
b27af27 Fix player entities being half-despawned after jumping in time (fixes #93)
2017-10-28 12:13:04 +02:00
Jonas Herzig
caf6051ab7 Merge branch 1.9.4-dev into 1.11-dev
263e080 Merge branch 1.8.9-dev into 1.9.4-dev
8fad02c Merge branch 1.8-dev into 1.8.9-dev
1c888aa Add minVersion to mixin configs and bump bundled mixin version
10ce71e Fix mapwriter crash when opening replay for <MC1.12 (fixes #96)
5fb1cf3 Fix half-despawned player entities (see #93) when the entity is moved greater distances
adfe6a2 Fix NPE when spectated non-player entity despawns (fixes #94)
b27af27 Fix player entities being half-despawned after jumping in time (fixes #93)
2017-10-28 11:43:25 +02:00
Jonas Herzig
b8b4f167ef Merge branch 1.9.4-dev into 1.10.2-dev
263e080 Merge branch 1.8.9-dev into 1.9.4-dev
8fad02c Merge branch 1.8-dev into 1.8.9-dev
1c888aa Add minVersion to mixin configs and bump bundled mixin version
10ce71e Fix mapwriter crash when opening replay for <MC1.12 (fixes #96)
5fb1cf3 Fix half-despawned player entities (see #93) when the entity is moved greater distances
adfe6a2 Fix NPE when spectated non-player entity despawns (fixes #94)
b27af27 Fix player entities being half-despawned after jumping in time (fixes #93)
2017-10-28 11:35:58 +02:00
Jonas Herzig
263e080401 Merge branch 1.8.9-dev into 1.9.4-dev
8fad02c Merge branch 1.8-dev into 1.8.9-dev
1c888aa Add minVersion to mixin configs and bump bundled mixin version
10ce71e Fix mapwriter crash when opening replay for <MC1.12 (fixes #96)
5fb1cf3 Fix half-despawned player entities (see #93) when the entity is moved greater distances
adfe6a2 Fix NPE when spectated non-player entity despawns (fixes #94)
b27af27 Fix player entities being half-despawned after jumping in time (fixes #93)
2017-10-28 11:24:47 +02:00
Jonas Herzig
8fad02cae7 Merge branch 1.8-dev into 1.8.9-dev
1c888aa Add minVersion to mixin configs and bump bundled mixin version
10ce71e Fix mapwriter crash when opening replay for <MC1.12 (fixes #96)
5fb1cf3 Fix half-despawned player entities (see #93) when the entity is moved greater distances
adfe6a2 Fix NPE when spectated non-player entity despawns (fixes #94)
b27af27 Fix player entities being half-despawned after jumping in time (fixes #93)
2017-10-28 11:12:22 +02:00
Jonas Herzig
4ad7d61280 Update reprod mixin dep 2017-10-27 18:54:56 +02:00
Jonas Herzig
f4f42f7257 Merge branch '1.8-dev' into 1.8-reprod 2017-10-27 16:32:19 +02:00
Jonas Herzig
1c888aadc2 Add minVersion to mixin configs and bump bundled mixin version 2017-10-27 16:27:28 +02:00
Jonas Herzig
f82d0e9f9f Skip pom generation for root project 2017-10-27 15:53:19 +02:00
Jonas Herzig
cfee84acbc Manually re-pack FG jar 2017-10-27 15:52:41 +02:00
Jonas Herzig
10ce71efe3 Fix mapwriter crash when opening replay for <MC1.12 (fixes #96) 2017-10-27 14:21:12 +02:00
Jonas Herzig
5fb1cf34e2 Fix half-despawned player entities (see #93) when the entity is moved greater distances 2017-10-16 11:29:15 +02:00
Jonas Herzig
ba4aaa3654 Produce pom.xml instead of shading deps of deps 2017-10-03 18:00:24 +02:00
Jonas Herzig
c07e08386d Fetch pre-built artifact if available 2017-10-03 14:36:51 +02:00
Jonas Herzig
cceed1258d Apply externally generated signature to replaymod.jar if requested 2017-10-03 14:04:03 +02:00
Jonas Herzig
c34b059ed9 Replace manual shade patch for FG with reproducible builds plugin 2017-10-03 11:18:42 +02:00
Jonas Herzig
a45dda3169 Update reproducible builds plugin 2017-10-03 11:18:15 +02:00
CrushedPixel
98098ea2ed Update language submodule 2017-09-27 13:13:49 +02:00
CrushedPixel
d2d7a36139 Added post-screenshot GUI 2017-09-27 13:13:20 +02:00
CrushedPixel
9671ee605d Add 360° screenshot feature when pressing Ctrl + Screenshot Keybind 2017-09-27 00:16:39 +02:00
Jonas Herzig
f2755f6e1f Update to 1.12.2 2017-09-19 10:37:19 +02:00
Jonas Herzig
cfb990ad43 Remove ReplayStudio submodule and depend on it via maven instead 2017-09-19 10:21:07 +02:00
Jonas Herzig
c18644a208 Use gradle-ecj-plugin to make reproducible builds JDK-independent 2017-09-03 21:32:55 +02:00
Jonas Herzig
5be2f36a78 Use gradle-reproducible-builds-plugin instead of configuring Gradle manually 2017-09-03 17:22:12 +02:00
Jonas Herzig
c21408a9d0 Rebase reprod changes on 1.8 2017-09-03 17:22:12 +02:00
Jonas Herzig
a976d8c58f Whitelist forge json in proxy-witness 2017-09-02 19:25:29 +02:00
Jonas Herzig
a8f2c742e5 Remove ReplayStudio submodule and depend on it via maven instead 2017-09-02 19:25:28 +02:00
Jonas Herzig
25df4f181d Whitelist mcp versions.json in proxy-witness 2017-09-02 19:25:28 +02:00
Jonas Herzig
8b86253103 Replace manually built shadow and gitpatcher plugins with upstream 2017-09-02 19:25:28 +02:00
Jonas Herzig
93b8e52e8b Update checksums 2017-09-02 19:25:28 +02:00
Jonas Herzig
6ef61f0878 Manually build ReplayStudio dep 2017-09-02 19:25:28 +02:00
Jonas Herzig
c44de2b22a Add http proxy for artifact verification, remove gradle-witness 2017-09-02 19:25:26 +02:00
Jonas Herzig
25823e1081 Patch FG to work with proxy-witness 2017-09-02 14:19:36 +02:00
Jonas Herzig
ad3ff3e8ef Move gradle config for reproducible builds into init.gradle file 2017-09-02 14:19:36 +02:00
Jonas Herzig
95fc9a5248 Build FG SNAPSHOT deps manually 2017-09-02 14:19:36 +02:00
Jonas Herzig
acd03c0ee3 OSX has neither "xargs -r" nor "sha256sum" 2017-09-02 14:19:36 +02:00
Jonas Herzig
c561a3fa5a Remove further sources of nondeterminism and update SNAPSHOT hashes 2017-09-02 14:15:51 +02:00
Jonas Herzig
ebbe363954 Allow for reproducible builds
REPRODUCIBLE_BUILD=1 ./gradlew clean :build
2017-09-02 14:15:42 +02:00
Jonas Herzig
adfe6a2bfc Fix NPE when spectated non-player entity despawns (fixes #94) 2017-08-28 10:58:04 +02:00
Jonas Herzig
b27af2781b Fix player entities being half-despawned after jumping in time (fixes #93) 2017-08-28 10:56:37 +02:00
Jonas Herzig
b1a2826cb4 Merge branch 1.12 into 1.12.1
0d6c1ca Merge branch 1.11.2 into 1.12
13bb0bd Merge branch 1.11-staging into 1.11.2-staging
5257a41 Merge branch 1.10.2 into 1.11
689f897 Merge branch 1.9.4 into 1.10.2
0aed9c3 Merge branch 1.8.9 into 1.9.4
f36ebf1 Merge branch 1.8 into 1.8.9
08170b3 Downgrade FG to 2.1 because FG 2.2 is 1.9+ only
41d2547 Update translations
00e999f Fix replay not being closed when opened via URI scheme handler (fixes #92)
767ea29 Fix book gui not being suppressed during replay (fixes #90)
5b04edb Hide ReplayMod app entry from menus on Linux
6aff99d Fix livelock during netty write to embedded channel (fixes #85)
703805f Fix infinite loop in mc.scheduledTasks (fixes #86)
922c039 Fix server with RM installed refusing clients without RM (fixes #76)
7a4440c Update ReplayStudio
0b9c56c Fix resource packs not working after first time jumping back in time
933ee5f [Compat] Fix camera entity with BetterSprinting prior to 2.0.0 (fixes #78)
83b1090 Fix hotbar being visible while spectating player (fixes #83)
5c73117 [Compat] Fix invisible entities with Orange's 1.7 Animations (fixes #78)
4704b29 Replace the RenderPlayer hook (used subclassing) with a mixin (fixes #79)
0c226b0 Fix path at end of replay resulting in constant reloading (fixes #56)
1b9b13e Rename render success sound to all lowercase (required for 1.11) (fixes #66)
c2000b3 Fix only front-facing chunks visible for ODS rendering (fixes #67)
aafeecc Fix initial login gui not closing on success (fixes #68)
9292add Use percent-encoding for replay file names (fixes #71)
8499c0f Fix name of invis armor stand with CustomNameVisible not rendering (fixes #72)
b9ea572 Try to handle invalid ffmpeg arguments more gracefully (fixes #77)
a2f8c88 Fix compression packets being recorded (fixes #80)
19629c3 Replace usages of System.out with logger
fe1d9b8 Stop Forge from allowing the mod to load on other MC versions (fixes #82)
d56fa9b Update ReplayStudio/MCProtocolLib (Fixes missing ARMOR_STAND MobType)
7c719e0 Update ReplayStudio/MCProtocolLib (Fixes missing ARMOR_STAND MobType)
1a1e96c Fix server with RM installed refusing clients without RM (fixes #76)
35eb9ca Replace usage of FMLLog with the mod logger
2017-08-26 14:53:36 +02:00
Jonas Herzig
6a7147b401 Use ReplayInputStream to support loading older replays on newer MC 2017-08-23 20:31:08 +02:00
Jonas Herzig
0b462280fc Update to 1.12.1 2017-08-04 09:10:48 +02:00
633 changed files with 31971 additions and 11386 deletions

View File

@@ -1,19 +0,0 @@
pipeline:
clone:
image: plugins/git
tags: true
build:
image: maven:3.3.9-jdk-8
commands:
- curl --fail --create-dirs -o $HOME/.gradle/init.d/mirror.gradle https://maven.johni0702.de/config/gradle
- curl --fail --create-dirs -o $HOME/.m2/settings.xml https://maven.johni0702.de/config/maven
- ./gradlew :build
archive:
image: plugins/s3
acl: public-read
region: "us-east-1"
bucket: "replaymod"
path_style: true
source: build/libs/*
strip_prefix: build/libs/
target: /

View File

@@ -1 +0,0 @@
eyJhbGciOiJIUzI1NiJ9.cGlwZWxpbmU6CiAgY2xvbmU6CiAgICBpbWFnZTogcGx1Z2lucy9naXQKICAgIHRhZ3M6IHRydWUKICBidWlsZDoKICAgIGltYWdlOiBtYXZlbjozLjMuOS1qZGstOAogICAgY29tbWFuZHM6CiAgICAgIC0gY3VybCAtLWZhaWwgLS1jcmVhdGUtZGlycyAtbyAkSE9NRS8uZ3JhZGxlL2luaXQuZC9taXJyb3IuZ3JhZGxlIGh0dHBzOi8vbWF2ZW4uam9obmkwNzAyLmRlL2NvbmZpZy9ncmFkbGUKICAgICAgLSBjdXJsIC0tZmFpbCAtLWNyZWF0ZS1kaXJzIC1vICRIT01FLy5tMi9zZXR0aW5ncy54bWwgaHR0cHM6Ly9tYXZlbi5qb2huaTA3MDIuZGUvY29uZmlnL21hdmVuCiAgICAgIC0gLi9ncmFkbGV3IDpidWlsZAogIGFyY2hpdmU6CiAgICBpbWFnZTogcGx1Z2lucy9zMwogICAgYWNsOiBwdWJsaWMtcmVhZAogICAgcmVnaW9uOiAidXMtZWFzdC0xIgogICAgYnVja2V0OiAicmVwbGF5bW9kIgogICAgcGF0aF9zdHlsZTogdHJ1ZQogICAgc291cmNlOiBidWlsZC9saWJzLyoKICAgIHN0cmlwX3ByZWZpeDogYnVpbGQvbGlicy8KICAgIHRhcmdldDogLwo.Z6rpaLplJKQ4pzB8AjCnplgci42qEu7L4LeS0fGm4SY

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
* text=auto

BIN
.gitignore vendored

Binary file not shown.

7
.gitmodules vendored
View File

@@ -2,10 +2,9 @@
path = jGui path = jGui
url = https://github.com/ReplayMod/jGui url = https://github.com/ReplayMod/jGui
[submodule "ReplayStudio"]
path = ReplayStudio
url = https://github.com/ReplayMod/ReplayStudio
[submodule "src/main/resources/assets/replaymod/lang"] [submodule "src/main/resources/assets/replaymod/lang"]
path = src/main/resources/assets/replaymod/lang path = src/main/resources/assets/replaymod/lang
url = https://github.com/ReplayMod/Translations url = https://github.com/ReplayMod/Translations
[submodule "ReplayStudio"]
path = libs/ReplayStudio
url = ../ReplayStudio

30
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,30 @@
pipeline {
agent {
docker { image 'openjdk:8-jdk' }
}
stages {
stage('Build') {
environment {
GRADLE_USER_HOME = '.gradle/user_home'
}
steps {
cache(maxCacheSize: 4096, caches: [
[$class: 'ArbitraryFileCache', excludes: 'modules-2/modules-2.lock,*/plugin-resolution/**', includes: '**/*', path: '.gradle/user_home/caches'],
[$class: 'ArbitraryFileCache', excludes: '', includes: '**/*', path: '.gradle/user_home/wrapper'],
[$class: 'ArbitraryFileCache', excludes: '', includes: '**/*', path: '.gradle/loom-cache'],
]) {
// sh './gradlew :jGui:1.7.10:setupCIWorkspace :1.7.10:setupCIWorkspace'
sh './gradlew --parallel'
}
archiveArtifacts 'versions/*/build/libs/*.jar'
}
}
stage('Deploy') {
steps {
withAWS(endpointUrl: 'https://minio.johni0702.de', credentials: 'minio') {
s3Upload bucket: 'replaymod', includePathPattern: '*.jar', workingDir: 'build/libs', acl: 'PublicRead', pathStyleAccessEnabled: true
}
}
}
}
}

View File

@@ -4,46 +4,38 @@ A Minecraft mod to record game sessions and replay them afterwards from any pers
## Building ## Building
Make sure your sub-projects are up-to-date: `git submodule update --init --recursive` Make sure your sub-projects are up-to-date: `git submodule update --init --recursive`
For each branch you visit the first time, running `./gradlew setupDecompWorkspace` is necessary. For compiling 1.7.10, you must run `./gradlew :jGui:1.7.10:setupDecompWorkspace :1.7.10:setupDecompWorkspace` once after the initial clone. This may take quite some time.
This will also be necessary if the `replaymod_at.cfg` file has been changed (getting errors about code that is trying
to access private fields is a good indication that this has happened).
### No IDE ### No IDE
You can build the mod by running `./gradlew :build`. You can then find the final jar files in `build/libs/`. You can build the mod by running `./gradlew build` (or just `./gradlew bundleJar`). You can then find the final jar files in `versions/$MCVERSION/build/libs/`.
You can also build single versions by running `./gradlew :1.8:build` (or just `./gradlew :1.8:bundleJar`) (builds the MC 1.8 version).
### IntelliJ ### IntelliJ
For the initial setup run `./gradlew preshadowJar idea genIntellijRuns`. Ensure you have at least IDEA 2020.1.
You also need to enable the Mixin annotation processor: Build the mod via Gradle as explained above at least once (`./gradlew compileJava` should be sufficient). This will ensure that the sources for all MC versions are generated.
1. Go to File -> Settings -> Build, Execution, Deployment -> Compiler -> Annotation Processors Then import the Gradle project from within IDEA: File -> Open -> build.gradle -> Open as Project
2. Tick "Enable annotation processing" Finally configure IDEA to build everything by itself instead of delegating it to Gradle (cause that is slow): File -> Settings -> Build, Execution, Deployment -> Build Tools -> Gradle -> Build and run using: IntelliJ IDEA
3. Add a new entry to the "Annotation Processor options"
4. Set the name to "reobfSrgFile" and the value to "$path/build/mcp-srg.srg" where you replace $path with the full
path to the folder containing the gradlew file
Whenever you switch to another branch, you can either just run `./gradlew preshadowJar idea` or instead run
`./gradlew preshadowJar copySrg` and then refresh the gradle project from within IntelliJ.
### Eclipse ### Eclipse
## Development ## Development
### Branches ### Branches
New features are developed on the `1.8` branch and merged upwards for release. Larger features are developed on their Loosely based on [this branching model](http://nvie.com/posts/a-successful-git-branching-model/) with `stable` instead of `master`.
own branch that is based on `1.8` and then merged back once it's finished.
Features or bug fixes that apply only to a specific Minecraft version are fixed on the branch corresponding to that TL;DR:
version and reverted when merging upwards. Main development happens on the `develop` branch, snapshots are built from this branch.
The `stable` branch contains the most recent release.
Both subprojects follow a similar branching model.
The user documentation (`docs` folder) is only committed to on the current development branch. Any changes committed on
a branch for a more recent Minecraft version are not kept up to date on the website and should only be
of importance once support for the previous Minecraft version is dropped.
The `master` branch is solely to be used for the `version.json` file that contains a list of all versions The `master` branch is solely to be used for the `version.json` file that contains a list of all versions
used by the clients to check for updates of this mod. used by the clients to check for updates of this mod.
### The Preprocessor
To support multiple Minecraft versions with the ReplayMod, a [JCP](https://github.com/raydac/java-comment-preprocessor)-inspired preprocessor is used.
It has by now acquired a lot more sophisticated features to make it as noninvasive as possible.
Please read the [preprocessor's README](https://github.com/ReplayMod/preprocessor/blob/master/README.md) to understand how it works.
### Versioning ### Versioning
The ReplayMod uses the versioning scheme outlined [here](http://mcforge.readthedocs.io/en/latest/conventions/versioning/) The ReplayMod uses the versioning scheme outlined [here](https://docs.minecraftforge.net/en/1.12.x/conventions/versioning/)
with three changes: with three changes:
- No `MAJORAPI`, the ReplayMod does not provide any external API - No `MAJORAPI`, the ReplayMod does not provide any external API
- "Updating to a new Minecraft version" should not increment `MAJORMOD`, we maintain one version of the ReplayMod - "Updating to a new Minecraft version" should not increment `MAJORMOD`, we maintain one version of the ReplayMod
@@ -52,19 +44,18 @@ keep the version name the same for all of them (with the exception of `MCVERSION
"Multiple Minecraft Version" section does not apply. "Multiple Minecraft Version" section does not apply.
- For pre-releases the shorter `-bX` is used instead of `-betaX` - For pre-releases the shorter `-bX` is used instead of `-betaX`
When a new version is (pre-)release, a new annotated tag should be added with the name of the version and the When a new version is (pre-)release, a new commit modifying the `version.txt` file should be added and the
`versions.json` file in the `master` branch should be updated. To simplify this process the gradle task `doRelease` can `versions.json` file in the `master` branch should be updated. To simplify this process the gradle task `doRelease` can
be used: `./gradlew -PreleaseVersion=1.8-2.0.0-rc1 doRelease`. It will create the tag and update the version.json be used: `./gradlew -PreleaseVersion=2.0.0-rc1 doRelease`. It will create the commit and update the version.json
accordingly. accordingly.
Care should be taken that the updated `version.json` is not pushed before a jar file is available on the Care should be taken that the updated `version.json` is not pushed before a jar file is available on the
download page (or Jenkins) as it will inform the users of the update. download page (or Jenkins) as it will inform the users of the update.
### Bugs ### Bugs
Bugs in the mod are tracked via [Bugzilla](https://bugs.replaymod.com/). GitHub should generally be used to report bugs.
GitHub should only be used for issues that are generally not likely to affect any end users.
Bug numbers in commits such as `(fixes #42)` refer to Bugzilla unless noted otherwise. In the past, bugs were tracked via [Bugzilla](https://bugs.replaymod.com/), so bug numbers in commits prior to 2020 such as `(fixes #42)` generally referred to Bugzilla unless noted otherwise.
## License ## License
The ReplayMod is provided under the terms of the GNU General Public License Version 3 or (at your option) any later version. The ReplayMod is provided under the terms of the GNU General Public License Version 3 or (at your option) any later version.

Submodule ReplayStudio deleted from 11b6ad7cb9

View File

@@ -1,344 +0,0 @@
import groovy.json.JsonOutput
buildscript {
repositories {
mavenCentral()
maven {
name = "forge"
url = "http://files.minecraftforge.net/maven"
}
maven {
name = "sponge"
url = "https://repo.spongepowered.org/maven"
}
maven {
name = "sonatype"
url = "https://oss.sonatype.org/content/repositories/snapshots/"
}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
classpath 'org.spongepowered:mixingradle:0.4-SNAPSHOT'
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
apply plugin: 'org.spongepowered.mixin'
sourceCompatibility = 1.8
targetCompatibility = 1.8
version = gitDescribe()
group= "com.replaymod"
archivesBaseName = "replaymod"
minecraft {
coreMod = 'com.replaymod.core.LoadingPlugin'
version = '1.12-14.21.1.2387'
runDir = "eclipse"
mappings = "snapshot_20170615"
replace '@MOD_VERSION@', project.version
// Includes intentional whitespace to stop Forge from declaring the mod to be compatible with
// a newer srg-compatible MC version (that may be using a different protocol version)
replace '@MC_VERSION@', "[ ${project.minecraft.version} ]"
}
repositories {
maven {
name = "SpongePowered Repo"
url = "http://repo.spongepowered.org/maven/"
}
}
configurations {
shade
compile.extendsFrom shade
}
dependencies {
compile 'org.projectlombok:lombok:1.16.4'
compile('org.spongepowered:mixin:0.6.11-SNAPSHOT') {
exclude group: 'org.apache.logging.log4j'
}
shade 'com.googlecode.mp4parser:isoparser:1.1.7'
shade 'org.apache.commons:commons-exec:1.3'
shade 'com.google.apis:google-api-services-youtube:v3-rev178-1.22.0'
shade 'com.google.api-client:google-api-client-gson:1.20.0'
shade 'com.google.api-client:google-api-client-java6:1.20.0'
shade 'com.google.oauth-client:google-oauth-client-jetty:1.20.0'
shade 'org.aspectj:aspectjrt:1.8.2'
compile project(':ReplayStudio')
testCompile 'junit:junit:4.11'
}
tasks['idea'].dependsOn ':ReplayStudio:preshadowJar'
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
dependsOn configurations.compile
dependsOn configurations.shade
dependsOn ':ReplayStudio:shadowJar'
def shade = {files(
configurations.compile.findAll {it.name.startsWith 'mixin-'}
+ configurations.shade
+ getTasks().getByPath(':ReplayStudio:shadowJar').outputs.files
)}
def noticeDir = file("$buildDir/NOTICE")
doFirst {
noticeDir.deleteDir()
noticeDir.mkdirs()
shade().collect { it.isDirectory() ? fileTree(it) : zipTree(it) }.each {
it.matching { include '**/NOTICE*' }.each {
new File(noticeDir, 'NOTICE.txt') << it.getText('UTF-8') + '\n'
}
}
}
from noticeDir
from ({shade().collect { it.isDirectory() ? it : zipTree(it) }}) {
exclude '**/NOTICE*'
// exclude everything taken in from jGui for running the mod in a dev environment
exclude { new File(file('jGui/src/main/resources'), it.relativePath.pathString).exists() }
eachFile {
if (getName() == 'LICENSE.txt') {
setName(getFile().getParentFile().getName().split('-')[0] + '-LICENSE.txt')
}
}
}
manifest {
attributes 'TweakClass': 'org.spongepowered.asm.launch.MixinTweaker',
'TweakOrder': '0',
'FMLCorePluginContainsFMLMod': 'true',
'FMLAT': 'replaymod_at.cfg'
}
}
def gitDescribe() {
try {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'describe', '--always', '--dirty=*'
standardOutput = stdout
}
return stdout.toString().trim()
} catch (e) {
return "unknown"
}
}
processResources
{
// this will ensure that this task is redone when the versions change.
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
// replace stuff in mcmod.info, nothing else
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
// replace version and mcversion
expand 'version': project.version, 'mcversion': project.minecraft.version
}
// copy everything else, thats not the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
}
}
sourceSets {
main {
// Directly include jGui into main build
// This could also be done by including it as a gradle subproject, however
// doing so caused classpath issues on some IntelliJ versions.
java {
srcDir 'jGui/src/main/java'
}
resources {
srcDir 'jGui/src/main/resources'
}
refMap = "mixins.replaymod.refmap.json"
}
integrationTest {
compileClasspath += main.runtimeClasspath + main.output
java {
srcDir file('src/integration-test/java')
}
resources.srcDir file('src/integration-test/resources')
}
}
task copySrg(type: Copy, dependsOn: 'genSrgs') {
from {project.tasks.genSrgs.mcpToSrg}
into 'build'
}
setupDecompWorkspace.dependsOn copySrg
setupDevWorkspace.dependsOn copySrg
project.tasks.idea.dependsOn copySrg
import org.objectweb.asm.*
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream
import static org.objectweb.asm.Opcodes.ASM5
// MC binaries were complied with a java version that produces invalid class files under certain circumstances
// This causes setupCIWorkspace to be insufficient for compiling.
// Related JDK bug: https://bugs.openjdk.java.net/browse/JDK-8066725
// As a workaround, to use setupCIWorkspace on Drone, we modify the bin jar in-place and remove all parameter annotations.
// WARNING: This piece of code ignores any and all gradle conventions and will probably fail horribly when run outside
// of a single-use environment (e.g. Drone). Use setupDecompWorkspace for normal use.
tasks.deobfMcMCP.doLast {
println "Applying RuntimeInvisibleParameterAnnotations workaround..."
File jar = getOutJar()
File tmp = new File((File) getTemporaryDir(), "workaround.jar")
tmp.withOutputStream {
new ZipOutputStream(it).withStream { dst ->
new ZipFile(jar).withCloseable { src ->
src.entries().each {
if (it.name.startsWith("net/minecraft/") && it.name.endsWith(".class")) {
def cw = new ClassWriter(0)
def cv = new ClassVisitor(ASM5, cw) {
@Override
MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
return new MethodVisitor(ASM5, cv.visitMethod(access, name, desc, signature, exceptions)) {
@Override
AnnotationVisitor visitParameterAnnotation(int parameter, String pdesc, boolean visible) {
return null // Strip all parameter annotations
}
}
}
}
new ClassReader(src.getInputStream(it)).accept(cv, 0)
dst.putNextEntry(new ZipEntry(it.name))
dst.write(cw.toByteArray())
} else {
dst.putNextEntry(it)
dst.write(src.getInputStream(it).bytes)
}
}
}
}
}
jar.delete()
tmp.renameTo(jar)
}
task runIntegrationTest(type: JavaExec, dependsOn: ["makeStart", "jar"]) {
main = 'GradleStart'
standardOutput = System.out
errorOutput = System.err
workingDir file(minecraft.runDir)
def testDir = new File(minecraft.runDir, "integration-test")
doFirst {
testDir.deleteDir()
testDir.mkdirs()
}
doLast {
testDir.deleteDir()
}
afterEvaluate {
def runClient = tasks.getByName("runClient")
runIntegrationTest.jvmArgs = runClient.jvmArgs + "-Dfml.noGrab=true"
runIntegrationTest.args = runClient.args + "--gameDir" + testDir.canonicalPath
runIntegrationTest.classpath runClient.classpath + sourceSets.integrationTest.output
}
}
def generateVersionsJson() {
// List all tags
def stdout = new ByteArrayOutputStream()
project.exec {
commandLine 'git', 'for-each-ref', '--sort=taggerdate', '--format=%(refname:short)', 'refs/tags'
standardOutput = stdout
}
def versions = stdout.toString().tokenize('\n').reverse()
def mcVersions = versions.collect {it.substring(0, it.indexOf('-'))}.unique().reverse()
def root = [
homepage: 'https://www.replaymod.com/download/',
promos: [:]
]
mcVersions.forEach { mcVersion ->
def mcVersionRoot = [:]
def latest
def recommended
versions.forEach {
def (thisMcVersion, modVersion, preVersion) = it.tokenize('-')
if (thisMcVersion == mcVersion) {
mcVersionRoot[it] = "See https://github.com/ReplayMod/ReplayMod/releases/$it"
if (latest == null) latest = it
if (preVersion == null) {
if (recommended == null) recommended = it
}
}
}
root[mcVersion] = mcVersionRoot
root.promos[mcVersion + '-latest'] = latest
if (recommended != null) {
root.promos[mcVersion + '-recommended'] = recommended
}
}
root
}
task doRelease() {
doLast {
// Parse version
def version = project.releaseVersion as String
if (project.version.endsWith('*')) {
throw new InvalidUserDataException('Git working tree is dirty. Make sure to commit all changes.')
}
def (mcVersion, modVersion, preVersion) = version.tokenize('-')
preVersion = preVersion != null && preVersion.startsWith('b') ? preVersion.substring(1) : null
// Create new tag
if (preVersion != null) {
project.exec {
commandLine 'git', 'tag',
'-m', "Pre-release $preVersion of $modVersion for Minecraft $mcVersion",
"$mcVersion-$modVersion-b$preVersion"
}
} else {
project.exec {
commandLine 'git', 'tag',
'-m', "Release $modVersion for Minecraft $mcVersion",
"$mcVersion-$modVersion"
}
}
// Switch to master branch to update versions.json
project.exec { commandLine 'git', 'checkout', 'master' }
// Generate versions.json content
def versionsRoot = generateVersionsJson()
def versionsJson = JsonOutput.prettyPrint(JsonOutput.toJson(versionsRoot))
// Write versions.json
new File('versions.json').write(versionsJson)
// Commit changes
project.exec { commandLine 'git', 'add', 'versions.json' }
project.exec { commandLine 'git', 'commit', '-m', "Update versions.json for $version" }
// Return to previous branch
project.exec { commandLine 'git', 'checkout', '-' }
}
}
defaultTasks 'build'

377
build.gradle.kts Normal file
View File

@@ -0,0 +1,377 @@
import com.replaymod.gradle.preprocess.PreprocessTask
import gg.essential.gradle.util.*
import net.fabricmc.loom.task.RemapJarTask
plugins {
java
id("com.gradleup.shadow") apply false
id("gg.essential.multi-version")
id("gg.essential.defaults.repo")
id("gg.essential.defaults.java")
id("gg.essential.defaults.loom")
}
val mcVersion = platform.mcVersion
var jGuiVersion = project.name
if (jGuiVersion in listOf("1.10.2", "1.11", "1.11.2")) jGuiVersion = "1.9.4"
if (jGuiVersion in listOf("1.12.1", "1.12.2")) jGuiVersion = "1.12"
val jGui = project.evaluationDependsOn(":jGui:$jGuiVersion")
version = "${project.name}-${rootProject.version}"
base.archivesName.set("replaymod")
java.withSourcesJar()
loom {
noServerRunConfigs()
}
if (!platform.isUnobfuscated) {
loom.mixin.useLegacyMixinAp = true
loom.mixin.defaultRefmapName.set("mixins.replaymod.refmap.json")
}
if (platform.isLegacyForge) {
loom.runs.named("client") {
property("fml.coreMods.load", "com.replaymod.core.LoadingPlugin")
}
}
repositories {
mavenLocal()
maven("https://repo.spongepowered.org/maven/")
maven("https://maven.terraformersmc.com/releases/") {
content {
includeGroup("com.terraformersmc")
}
}
maven("https://jitpack.io") {
content {
includeGroupByRegex("com\\.github\\..*")
}
}
exclusiveContent {
forRepository {
maven("https://api.modrinth.com/maven")
}
filter {
includeGroup("maven.modrinth")
}
}
}
// Include dep in fat jar without relocation and, when forge supports it, without exploding (TODO)
val shade by configurations.creating
// Include dep in fat jar with relocation and minimization
val shadow by configurations.creating {
exclude(group = "net.fabricmc", module = "fabric-loader")
exclude(group = "com.google.guava", module = "guava-jdk5")
exclude(group = "com.google.guava", module = "guava") // provided by MC
exclude(group = "com.google.code.gson", module = "gson") // provided by MC (or manually bundled for 1.11.2 and below)
}
dependencies {
if (platform.isFabric) {
val fabricApiVersion = when (mcVersion) {
11404 -> "0.4.3+build.247-1.14"
11502 -> "0.5.1+build.294-1.15"
11601 -> "0.14.0+build.371-1.16"
11603 -> "0.17.1+build.394-1.16"
11604 -> "0.42.0+1.16"
11701 -> "0.46.1+1.17"
11800 -> "0.43.1+1.18"
11801 -> "0.43.1+1.18"
11802 -> "0.47.9+1.18.2"
11900 -> "0.55.3+1.19"
11901 -> "0.58.5+1.19.1"
11902 -> "0.68.0+1.19.2"
11903 -> "0.68.1+1.19.3"
11904 -> "0.76.0+1.19.4"
12001 -> "0.83.1+1.20.1"
12002 -> "0.91.2+1.20.2"
12004 -> "0.91.2+1.20.4"
12006 -> "0.98.0+1.20.6"
12100 -> "0.100.3+1.21"
12102 -> "0.106.1+1.21.2"
12104 -> "0.111.0+1.21.4"
12105 -> "0.119.9+1.21.5"
12107 -> "0.128.1+1.21.7"
12110 -> "0.135.0+1.21.10"
12111 -> "0.139.5+1.21.11"
26_01_00 -> "0.144.3+26.1"
else -> throw UnsupportedOperationException()
}
val fabricApiModules = mutableListOf(
"api-base",
"networking-v0",
"keybindings-v0",
"resource-loader-v0",
)
if (mcVersion >= 11600) {
fabricApiModules.remove("keybindings-v0")
fabricApiModules.add("key-binding-api-v1")
}
if (mcVersion >= 11604) {
fabricApiModules.add("screen-api-v1")
fabricApiModules.add("networking-api-v1")
}
if (mcVersion >= 11700) {
fabricApiModules.remove("networking-v0")
}
if (mcVersion >= 12109) {
fabricApiModules.add("resource-loader-v1")
}
if (mcVersion >= 26_01_00) {
fabricApiModules.remove("key-binding-api-v1")
fabricApiModules.add("key-mapping-api-v1")
}
for (module in fabricApiModules) {
val dep = fabricApi.module("fabric-$module", fabricApiVersion)
modImplementation(dep)
"include"(dep)
}
}
if (!platform.isFabric) {
// Mixin 0.8 is no longer compatible with MC 1.11.2 or older
val mixinVersion = if (mcVersion >= 11200) "0.8.2" else "0.7.11-SNAPSHOT"
compileOnly("org.spongepowered:mixin:$mixinVersion")
implementation(shade("org.spongepowered:mixin:$mixinVersion") {
isTransitive = false // deps should all be bundled with MC
})
}
if (platform.isFabric) {
"include"(implementation(annotationProcessor("io.github.llamalad7:mixinextras-fabric:0.3.6")!!)!!)
}
implementation(shadow("com.googlecode.mp4parser:isoparser:1.1.7")!!)
implementation(shadow("org.apache.commons:commons-exec:1.3")!!)
implementation(shadow("com.google.apis:google-api-services-youtube:v3-rev178-1.22.0")!!)
implementation(shadow("com.google.api-client:google-api-client-gson:1.20.0")!!)
implementation(shadow("com.google.api-client:google-api-client-java6:1.20.0")!!)
implementation(shadow("com.google.oauth-client:google-oauth-client-jetty:1.20.0")!!)
val lwjgl by configurations.creating
for (suffix in listOf("", ":natives-linux", ":natives-windows", ":natives-macos", ":natives-macos-arm64")) {
lwjgl("org.lwjgl:lwjgl:3.3.1$suffix")
lwjgl("org.lwjgl:lwjgl-tinyexr:3.3.1$suffix")
}
compileOnly("org.lwjgl:lwjgl-tinyexr:3.3.1")
shadow(prebundle(lwjgl, "com/replaymod/render/utils/lwjgl.jar"))
if (mcVersion < 11200) {
// The version which MC ships is too old, we'll need to ship our own
implementation(shadow("com.google.code.gson:gson:2.8.7")!!)
}
implementation(shadow("com.github.javagl.JglTF:jgltf-model:3af6de4")!!)
if (platform.isFabric) {
implementation(shadow("org.apache.maven:maven-artifact:3.6.1")!!)
}
implementation(shadow("org.aspectj:aspectjrt:1.8.2")!!)
implementation(shadow("com.github.ReplayMod.JavaBlend:2.79.0:a0696f8")!!)
implementation(shadow("com.github.ReplayMod:ReplayStudio")!!)
// FIXME hack because I don't know how to get this to be inherited properly
implementation(rootProject.files("libs/ReplayStudio/.gradle/prebundled-jars/viaVersion.jar"))
implementation(project(path = jGui.path, configuration = if (platform.isUnobfuscated) null else "namedElements"))
implementation(shadow("com.github.ReplayMod:lwjgl-utils:27dcd66")!!)
if (platform.isFabric) {
val modMenuVersion = when {
mcVersion >= 26_01_00 -> "18.0.0-alpha.8"
mcVersion >= 12111 -> "17.0.0-alpha.1"
mcVersion >= 12110 -> "16.0.0-rc.1"
mcVersion >= 12107 -> "15.0.0-beta.3"
mcVersion >= 12105 -> "14.0.0-rc.2"
mcVersion >= 12104 -> "13.0.0-beta.1"
mcVersion >= 12102 -> "12.0.0-beta.1"
mcVersion >= 12100 -> "11.0.0-rc.4"
mcVersion >= 12006 -> "10.0.0-beta.1"
mcVersion >= 12003 -> "9.0.0-pre.1"
mcVersion >= 12002 -> "8.0.0"
mcVersion >= 12000 -> "7.0.1"
mcVersion >= 11904 -> "6.1.0-rc.4"
mcVersion >= 11903 -> "5.0.0-alpha.4"
mcVersion >= 11901 -> "4.0.5"
mcVersion >= 11900 -> "4.0.4"
mcVersion >= 11802 -> "3.1.0"
mcVersion >= 11800 -> "3.0.0"
mcVersion >= 11700 -> "2.0.0-beta.7"
mcVersion >= 11602 -> "1.16.8"
mcVersion >= 11600 -> null // maven doesn't have one for this version (only 1.16.5)
mcVersion >= 11500 -> "1.10.6"
else -> null
}
if (modMenuVersion != null) {
modCompileOnly("com.terraformersmc:modmenu:$modMenuVersion")
} else {
// Oldest modmenu on their maven is 1.10.5 for MC 1.15.2; for older versions we won't run it in dev
modCompileOnly("com.terraformersmc:modmenu:1.10.6")
}
// Lacks maven dependencies
if (mcVersion == 12006) {
//modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:0.98.0+1.20.6")
}
}
val irisVersion = when {
mcVersion >= 26_01_00 -> "1.10.8+26.1-fabric"
mcVersion >= 12000 -> "1.7.2+1.20.1"
mcVersion >= 11600 -> "1.18.x-v1.2.0"
else -> null
}
if (irisVersion != null) {
modCompileOnly("maven.modrinth:iris:$irisVersion")
}
testImplementation("junit:junit:4.11")
}
preprocess {
keywords.set(mapOf(
".java" to PreprocessTask.DEFAULT_KEYWORDS,
".kt" to PreprocessTask.DEFAULT_KEYWORDS,
".json" to PreprocessTask.DEFAULT_KEYWORDS,
".mcmeta" to PreprocessTask.DEFAULT_KEYWORDS,
".cfg" to PreprocessTask.CFG_KEYWORDS,
".vert" to PreprocessTask.DEFAULT_KEYWORDS,
".frag" to PreprocessTask.DEFAULT_KEYWORDS,
))
patternAnnotation.set("com.replaymod.gradle.remap.Pattern")
}
tasks.jar {
archiveClassifier.set("raw")
if (!platform.isFabric) {
manifest {
attributes(
"TweakClass" to "com.replaymod.core.tweaker.ReplayModTweaker",
"TweakOrder" to "0",
"FMLCorePluginContainsFMLMod" to "true",
"FMLCorePlugin" to "com.replaymod.core.LoadingPlugin",
"FMLAT" to "replaymod_at.cfg",
)
}
}
}
if (!platform.isUnobfuscated) {
tasks.named<RemapJarTask>("remapJar") {
if (platform.isFabric) {
addNestedDependencies.set(true)
}
archiveClassifier.set("obf")
}
}
val configureRelocationOutput = project.layout.buildDirectory.file("configureRelocation")
val configureRelocation by tasks.registering {
dependsOn(tasks.jar)
dependsOn(shadow)
outputs.file(configureRelocationOutput)
doLast {
val pkgs = files(shadow).filter { it.exists() }.map {
val tree = if (it.isDirectory) fileTree(it) else zipTree(it)
val pkgs = mutableSetOf<String>()
tree.visit {
val file = this
if (!file.isDirectory && file.name.endsWith(".class") && file.path.contains("/")) {
val pkg = file.path.substring(0, file.path.lastIndexOf("/")) + "/"
if (pkg.startsWith("com/")) {
if (pkg.startsWith("com/google/")) {
if (!pkg.startsWith("com/google/common")) {
pkgs += pkg.substring(0, pkg.indexOf("/", "com/google/".length))
}
} else if (!pkg.startsWith("com/replaymod")) {
pkgs += pkg.substring(0, pkg.indexOf("/", 4))
}
} else if (pkg.startsWith("net/")) {
if (!pkg.startsWith("net/minecraft")
&& !pkg.startsWith("net/fabric")) {
pkgs += pkg.substring(0, pkg.indexOf("/", "net/".length))
}
} else if (pkg.startsWith("org/")) {
if (pkg.startsWith("org/apache/")) {
if (pkg.startsWith("org/apache/commons/")) {
if (!pkg.startsWith("org/apache/commons/io")) {
pkgs += pkg.substring(0, pkg.indexOf("/", "org/apache/commons/".length))
}
} else if (!pkg.startsWith("org/apache/logging")) {
pkgs += pkg.substring(0, pkg.indexOf("/", "org/apache/".length))
}
} else if (pkg.startsWith("org/lwjgl")) {
return@visit // either bundled with MC or uses natives which we can't relocate
} else if (!pkg.startsWith("org/spongepowered")) {
pkgs += pkg.substring(0, pkg.indexOf("/", 4))
}
} else if (pkg.startsWith("it/unimi/dsi/fastutil") && mcVersion >= 11400) {
return@visit // MC uses this as well
} else if (!pkg.startsWith("javax/")) {
// Note: we cannot just use top level packages as those will be too generic and we'll run
// into this long standing bug: https://github.com/johnrengelman/shadow/issues/232
val i = pkg.indexOf("/")
val i2 = pkg.indexOf("/", i + 1)
if (i2 > 0) {
pkgs += pkg.substring(0, i2)
}
}
}
}
pkgs
}.flatten().toSortedSet()
configureRelocationOutput.get().asFile.writeText(pkgs.joinToString("\n"))
}
}
val bundleJar by tasks.registering(com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar::class) {
from((if (platform.isUnobfuscated) tasks.jar else tasks.named<RemapJarTask>("remapJar")).flatMap { it.archiveFile }.map { zipTree(it) })
from((if (platform.isUnobfuscated) jGui.tasks.jar else jGui.tasks.named<RemapJarTask>("remapJar")).flatMap { it.archiveFile }.map { zipTree(it) }) {
filesMatching("mixins.jgui.json") {
filter { it.replace("de.johni0702", "com.replaymod.lib.de.johni0702") }
}
filesMatching("mixins.jgui.refmap.json") {
filter { it.replace("de/johni0702", "com/replaymod/lib/de/johni0702") }
}
}
relocate("de.johni0702", "com.replaymod.lib.de.johni0702")
manifest.from(tasks.jar.get().manifest)
from(shade.elements.map { it.map { zipTree(it) } })
configurations = listOf(shadow)
exclude("META-INF/INDEX.LIST", "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "module-info.class")
dependsOn(configureRelocation)
inputs.file(configureRelocationOutput)
doFirst {
configureRelocationOutput.get().asFile.forEachLine { pkg ->
val pkgName = pkg.replace("/", ".")
relocate(pkgName, "com.replaymod.lib.$pkgName")
}
}
// No need to shadow netty, MC provides it
// (actually, pre-1.12 ships a netty which is too old, so we need to shade it there anyway)
if (mcVersion >= 11200) {
relocate("com.github.steveice10.netty", "io.netty")
exclude("com/github/steveice10/netty/**")
}
if (mcVersion >= 11400) {
// MC ships this
exclude("it/unimi/dsi/fastutil/**")
}
minimize {
exclude(dependency(".*spongepowered:mixin:.*"))
}
}
tasks.assemble { dependsOn(bundleJar) }

385
docs/content.md Normal file → Executable file
View File

@@ -1,16 +1,14 @@
# Installation [installing] # Installation [installing]
## Installing the Replay Mod [replaymod] ## Installing the Replay Mod [replaymod]
The **ReplayMod** requires **Minecraft Forge** to be installed. ### Minecraft 1.14 and above
The **ReplayMod** for Minecraft 1.14 and above requires **Fabric** to be installed.
Depending on your **Replay Mod** version we recommend the following **Forge** versions: You can find Fabric and the installation instructions [here](https://fabricmc.net/use/).
- Replay Mod 2.0.0 or later for Minecraft 1.11: Forge [1.11-13.19.1.2189](https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.11.html) After installing Fabric, simply put the downloaded ReplayMod .jar file into the `/mods` folder of your Minecraft directory.
- Replay Mod 2.0.0 or later for Minecraft 1.10.2: Forge [1.10.2-12.18.2.2099](https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.10.2.html)
- Replay Mod 2.0.0 or later for Minecraft 1.9.4: Forge [1.9.4-12.17.0.1976](https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.9.4.html)
- Replay Mod 2.0.0 or later for Minecraft 1.8: Forge [1.8-11.14.4.1563](https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.8.html)
- Replay Mod 1.0.8 or older for Minecraft 1.8: Forge [1.8-11.14.3.1450](http://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.8.html)
Other Forge Versions might, but don't necessarily work. ### Minecraft 1.12.2 and below
For Minecraft 1.12.2 and below it requires **Minecraft Forge** to be installed.
If you don't know how to install Forge, follow [this tutorial](https://www.youtube.com/watch?v=4i7-RystzC4). If you don't know how to install Forge, follow [this tutorial](https://www.youtube.com/watch?v=4i7-RystzC4).
@@ -19,63 +17,44 @@ After installing Forge, simply put the downloaded `ReplayMod.jar` file in the `/
> **Note:** The **Replay Mod** is entirely client side and can not be installed on the servers you play on. > **Note:** The **Replay Mod** is entirely client side and can not be installed on the servers you play on.
## Installing FFmpeg [ffmpeg] ## Installing FFmpeg [ffmpeg]
To use the **Replay Mod**'s [Rendering Feature](#replaying-render), you need to have FFmpeg installed. To render your creations with **Replay Mod** you will need to have FFmpeg installed.
### Windows [windows] ### Windows [windows]
Download the latest **FFmpeg Static Build** for your architecture from <http://ffmpeg.zeranoe.com/builds/>. Download the latest FFmpeg release from https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip.
Then, extract the downloaded `.7z` file in the folder you want to install FFmpeg in.
Next, download this **Batch Script** to quickly install FFmpeg: <https://replaymod.com/files/ffmpeg-path-installer.bat> Extract the downloaded .zip file into your `.minecraft` folder.
> **Note:** If your browser warns you about the download, dismiss the message. It's a simple Batch Script which won't damage your computer. Historically the exact location inside the `.minecraft` folder was important, this is no longer the case.
It is sufficient for the `ffmpeg.exe` to be anywhere inside your `.minecraft` folder.
Put the downloaded script into the folder where you extracted FFmpeg and run itt by double-clicking it. **Notes for alternative launchers**
If you see a success message in the console, you've sucessfully installed **FFmpeg**! - Twitch launcher by default installs Minecraft instances in C:\\Users\\*username*\\Twitch\\Minecraft\\Instances\\*instancename*\\
- GD Launcher by default installs Minecraft instances in C:\\Users\\*username*\\AppData\\Roaming\\gdlauncher_next\\instances\\*instancename*\\
- MultiMC by default installs Minecraft instances in C:\\Program Files (x86)\\MultiMC\\instances\\*Instancename*\\.minecraft\\
Alternatively, starting with ReplayMod 2.0.0-b5, you can also extract the downloaded `.7z` file into a `ffmpeg` folder For these launchers, make sure FFmpeg exists inside the corresponding folder.
(you have to create it, it doesn't exist by default) in your `.minecraft` folder. No need to run any **Batch Script**.
The FFmpeg executable should end up at `.minecraft/ffmpeg/bin/ffmpeg.exe`.
### Mac OSX [mac] ### Mac OSX [mac]
On OSX, you can install **FFmpeg** with **[Homebrew](http://brew.sh/)** using `brew install ffmpeg`. On OSX, you can install **FFmpeg** with **[Homebrew](http://brew.sh/)** using `brew install ffmpeg`.
Alternatively, you can download the latest static build from <https://ffmpeg.org/> and copy the ffmpeg executable to `/usr/local/bin`. Alternatively, you can download the latest static build from <https://ffmpeg.org/> and copy the FFmpeg executable to `/usr/local/bin`.
### Linux [linux] ### Linux [linux]
On Linux, you can install **FFmpeg** using your system's package manager, for example using `apt install ffmpeg`. On Linux, you can install **FFmpeg** using your system's package manager, for example using `apt install ffmpeg`.
If in doubt, consult the documentation of your distribution. If in doubt, consult the documentation of your distribution.
## Compatibility with other Mods [compatibility]
### General information [general]
In General, the Replay Mod _should_ be compatible with most Forge Mods.
### Shaders Mod [shaders]
[Karyonix' Shaders Mod](http://www.minecraftforum.net/forums/mapping-and-modding/minecraft-mods/1286604-shaders-mod-updated-by-karyonix)
is no longer compatible with Minecraft Forge starting with 1.9.4. As such it is not compatible with the Replay Mod either.
Please use [Optifine](https://optifine.net/) instead.
### Custom Main Menu [custom-main-menu]
The [Custom Main Menu](https://mods.curse.com/mc-mods/minecraft/226406-custom-main-menu) mod is often used in mod packs to customize their Main Menu with a button layout fitting the background image, links to their website / bug tracker and similar.
If you are familiar with it, the button ids for the Replay Mod are: **17890234** (text: `replaymod.gui.replayviewer`), **17890237** (text: `replaymod.gui.replayeditor`) and **17890236** (text: `replaymod.gui.replaycenter`)
Due to the nature of this Custom Main Menu mod, buttons added to the Main Menu by 3rd party mods like the **Replay Mod** will not show up by default.
Thus, to access the Replay Viewer/Editor/Center, you need to manually configure the position for those buttons.
To do so, you need to modify the Custom Main Menu configuration file.
Usually, you can find it at `.minecraft/config/CustomMainMenu/mainmenu.json` (if you're using a mod pack launcher, it normally has its own .minecraft folder).
For an explanation of this config file, have a look at Custom Main Menu's page.
You can find a list of already modified config files [here](https://gist.github.com/Johni0702/3f3fab81dbf7ada83d045d9fe8f345aa).
## Troubleshooting [troubleshooting]
If you need help installing the **Replay Mod** or **FFmpeg**, please read [this forum thread](https://www.replaymod.com/forum/thread/220)
by [bela333](https://www.replaymod.com/user/bela333) - it covers most of the problems that users encountered so far.
## Settings [settings] ## Settings [settings]
To access the **Replay Mod Settings** from the Main Menu click the **"Mods"** button, select the **Replay Mod** from the list and To access the **Replay Mod Settings** from the Main Menu click the **"Replay Viewer"** button and click the **Settings** button.
the click the **"Config"** button.
While playing, you can click the 'Mods' button in the Pause screen to reach **Replay Mod Settings** if you use Minecraft 1.12.2 and below, or have the mod _Mod Menu_ installed.
When in a Replay, you can either bind a hotkey to the **Replay Mod Settings** in Minecraft's Control settings When in a Replay, you can either bind a hotkey to the **Replay Mod Settings** in Minecraft's Control settings
or use the hotkey GUI by clicking on the arrow button in the lower left corner. or use the hotkey GUI by clicking on the hamburger button in the lower left corner.
## Accounts [accounts]
In previous versions of ReplayMod we used accounts to deliver videos to the **Replay Center**. This has since been discontinued and with that, so have the accounts.
Instead of the forum, you can join our [Discord server](https://discord.gg/5GR7RSb) to get support and answers.
# Recording [recording] # Recording [recording]
![](img/recording-indicator.jpg) ![](img/recording-indicator.jpg)
@@ -143,15 +122,13 @@ The minimum Speed value is **0.1 times** the normal Minecraft Tick Speed, and th
To the right of the Speed Slider, there is the **Replay Timeline**. To the right of the Speed Slider, there is the **Replay Timeline**.
On the Replay Timeline, you see a yellow cursor indicating your current position in the Replay. On the Replay Timeline, you see a yellow cursor indicating your current position in the Replay.
By clicking somewhere on this Timeline, you will travel in time towards the specified point in time. By clicking somewhere on this Timeline, you will travel in time towards the specified point in time.
Please note that it takes longer to do larger steps in time or to jump backwards in time. Please note that it takes longer to do larger steps in time or to jump backwards in time (see also [Quick Mode](#replaying-quickmode)).
## Camera Paths [paths] ## Camera Paths [paths]
### Introduction [intro] ### Introduction [intro]
While in a Replay, you can create controlled **Camera Movements** using the Mods's **Keyframe System**. While in a Replay, you can create controlled **Camera Movements** using the Mods's **Keyframe System**.
Those Camera Paths can be rendered to a video later (see [Rendering](#replaying-render)). Those Camera Paths can be rendered to a video later (see [Rendering](#replaying-render)).
Camera Paths are inspired by the [PixelCam Mod](http://www.minecraftforum.net/forums/mapping-and-modding/minecraft-mods/2327429-pixelcam-camera-studio-for-minecraft-1-8) which is based on the Camera Studio Mod.
The **Replay Mod Keyframe System** is similar to many Video Editing Software's Keyframe Systems. The **Replay Mod Keyframe System** is similar to many Video Editing Software's Keyframe Systems.
If you're new to Keyframe Systems, try reading [this Wikipedia article](https://en.wikipedia.org/wiki/Key_frame). If you're new to Keyframe Systems, try reading [this Wikipedia article](https://en.wikipedia.org/wiki/Key_frame).
@@ -170,6 +147,8 @@ If two Keyframes are 5 seconds apart, the Camera Path will take 5 seconds to int
You can drag Keyframes on the **Keyframe Timeline** by left-clicking them, holding the mouse button and moving your mouse. You can drag Keyframes on the **Keyframe Timeline** by left-clicking them, holding the mouse button and moving your mouse.
> **Hint:** Made a mistake? You can use `Ctrl+Z` to undo your changes to the keyframe timeline. Changed you mind? Press `Ctrl+Y` (or `Ctrl+Shift+Z`) to redo them.
### Position Keyframes [place] ### Position Keyframes [place]
The basic components of a Camera Path are **Position Keyframes**. The basic components of a Camera Path are **Position Keyframes**.
A Position Keyframe stores a **Camera Position** (x, y, z, yaw, pitch, roll). A Position Keyframe stores a **Camera Position** (x, y, z, yaw, pitch, roll).
@@ -200,9 +179,6 @@ If you wish to disable smooth interpolation and want to make the Path follow str
You can easily toggle between **Linear** and **Cubic Interpolation** using the `O` key. You can easily toggle between **Linear** and **Cubic Interpolation** using the `O` key.
#### Path Preview [preview] #### Path Preview [preview]
![](img/path-preview-icon.jpg)
While the **Path Preview** is enabled, this camera symbol is displayed in the lower right corner of the screen.
![](img/path-preview.jpg) ![](img/path-preview.jpg)
A normal **Path Preview** A normal **Path Preview**
@@ -278,60 +254,6 @@ You can change a Preset's name, select it from the list and click the **"Rename"
To load a Keyframe Preset, select a Preset from the list and click the **"Load"** button. To load a Keyframe Preset, select a Preset from the list and click the **"Load"** button.
Using the **"Remove"** button, you can permanently delete a Keyframe Preset from the **Keyframe Repository**. Using the **"Remove"** button, you can permanently delete a Keyframe Preset from the **Keyframe Repository**.
## Custom Objects [objects]
> Custom Objects are not available in the 2.0.0 versions. They are expected to return eventually.
[YouTube](_Xdpg828fbE)
### Introduction [introduction]
**Custom Objects** are mainly meant for **video creators**. They allow you to add any image into the Replay World and animate its Position, Opacity and much more.
Instead of using [Motion Tracking](https://en.wikipedia.org/wiki/Match_moving) to add text or pictures to a video, you can directly add these to the rendered file.
### Adding Assets [assets]
![](img/asset-manager.jpg)
The **Asset Manager** with an example Asset
In order to create **Custom Objects**, you first have to add **Assets** to your Replay File.
Therefore, open the **Asset Manager** using the `G` key.
In the **Asset Manager**, you can add **Image Files (.png, .jpg and more)**, so-called **Assets**, to the Replay.
When clicking the **"Add"** button, a File Chooser will show up. Select the image file you want to use.
You can give the Asset a custom name using the Text Input Field in the top right corner.
All of the Assets you added can be used by **Custom Objects**.
### Creating Custom Objects [creating]
![](img/object-manager.jpg)
The **Object Manager** with some **Animation Keyframes**
Using the `F` key, you can open the **Object Manager**. Initially there won't be any Objects in the **Object List**, but you can simply add an Object using the **"Add"** button.
After doing so, you can name the newly created **Custom Object** using the Text Field in the upper right corner.
To define which **Asset File** (i.e. image) the **Custom Object** should use, select the desired **Asset** from the dropdown beneath the Name Input.
If you leave the **Object Manager**, you should see the image in the World somwhere near your position.
### Animating Custom Objects [animating]
![](img/custom-object-animated.gif)
An animated **Custom Image Object**.
Of course, you don't want the image to stay at that position.
herefore, open the **Object Manager** again and select the **Custom Object** you want to modify.
On the lower half of the screen you will see mutliple **Input Fields**, using which you can modify various settings
(so-called **Transformations**), for example the Object's **Position**, **Scale**, **Orientation** and **Opacity**.
When editing these values, you'll notice that on the TImeline to the right, Keyframes appear.
You can set and remove Keyframes for specific settings using its "Add Keyframe" button on the very left of the screen.
The **Object Manager's Keyframe System** is very similar to the **Position Keyframe** and **Time Keyframe** System.
During a **Camera Path**, the **Custom Objects** will interpolate their **Transformation Values** like **Position Keyframes** are interpolated.
While outside the **Object Manager** you can preview the Objects' position by moving the cursor on the **Keyframe Timeline** - the Objects will interpolate to the position they'll be at that timestamp during the **Camera Path**.
Once you got the hang of it, you'll be able to quickly animate **Custom Objects**.
## Rendering [render] ## Rendering [render]
With the **Replay Mod**, you can render **Camera Paths** to videos **without** using a screen recording tool like Fraps. With the **Replay Mod**, you can render **Camera Paths** to videos **without** using a screen recording tool like Fraps.
To get started, first [set up your Camera Path](#replaying-paths) as described in the previous chapters. To get started, first [set up your Camera Path](#replaying-paths) as described in the previous chapters.
@@ -436,7 +358,14 @@ There are **7 Encoding Presets** you can choose from:
While these video files are of perfect quality, most **non-FFmpeg-based video players and video editing software** (e.g. QuickTime Player, Sony Vegas and Adobe Premiere) can't play these videos. Therefore, you should instead use the **MP4 - High Quality** preset in most cases. While these video files are of perfect quality, most **non-FFmpeg-based video players and video editing software** (e.g. QuickTime Player, Sony Vegas and Adobe Premiere) can't play these videos. Therefore, you should instead use the **MP4 - High Quality** preset in most cases.
- **PNG Sequence** - **PNG Sequence**
Exports the sequence as individual frames in the **PNG Format**. Exports the sequence as individual frames in the **PNG Format**.
**Warning:** This can create a huge amount of files, so make sure to save them in a separate folder. The images are of perfect quality.
Depth map images are 32-bit float encoded in the 8-bit components in BGRA order and will need some kind of post-processing to be useful in most editors.
- **OpenEXR Sequence** (Minecraft 1.14 and above)
Exports the sequence as individual frames in the **OpenEXR Format**.
The images are of perfect quality and may contain
additional image layers beyond the visible one (e.g. [depth](#replaying-render-advanced-depth-map)).
As such, this format is a good choice if you have plenty of disk space to spare and want to perform additional editing
on the video in a third-party video editor.
### Advanced Settings [advanced] ### Advanced Settings [advanced]
![](img/rendersettings-advanced.jpg) ![](img/rendersettings-advanced.jpg)
@@ -463,6 +392,21 @@ Using a **Video Editing Software** like **Adobe After Effects** or **Sony Vegas*
> **Note:** For best results, you should **disable clouds** before rendering, as they are transparent. > **Note:** For best results, you should **disable clouds** before rendering, as they are transparent.
#### Depth Map [depth-map]
![](img/depthmapsuzanne.jpg)
"Suzanne" model added into a scene using Blender
This setting causes depth information to be recorded and included in video formats which support it
(currently only [OpenEXR](#replaying-render-settings-quality)).
Using a video editor which supports it (e.g. [Blender](https://www.blender.org/)), you can then for example (among many
other effects) add arbitrary geometry onto your rendered video in such a way that foreground objects in the
video will still occlude background geometry as if it actually was part of the world.
> **Note:** For best results, avoid semi-transparent blocks in front of your geometry, as they cannot be accurately represented in the depth map.
> **Note:** Anti-aliasing is not supported when exporting depth. Instead simply render and edit your video at a higher resolution and scale it down at the very end.
### Command Line Settings [commandline] ### Command Line Settings [commandline]
![](img/rendersettings-commandline.jpg) ![](img/rendersettings-commandline.jpg)
The **Command Line Render Settings** The **Command Line Render Settings**
@@ -475,7 +419,7 @@ The **Replay Mod** runs [FFmpeg](http://ffmpeg.org/) via the **Command Line** to
You can customize both the **executed Command** and the **Command Line Arguments** in the **Command Line Settings** part of the **Render Settings Screen**. You can customize both the **executed Command** and the **Command Line Arguments** in the **Command Line Settings** part of the **Render Settings Screen**.
#### Custom Command [command] #### Custom Command [command]
If you leave the left input field blank, `ffmpeg` will be used as **command**. If you haven't set your **PATH variable** to link to your FFmpeg distribution, simply enter the full path to your FFmpeg executable (e.g. `C:/ffmpeg/ffmpeg.exe` or `/usr/local/bin/ffmpeg`). If you leave the left input field blank, `ffmpeg` will be used as **command**. If you haven't set your **PATH variable** to link to your FFmpeg distribution, simply enter the full path to your FFmpeg executable (e.g. `C:\ffmpeg\ffmpeg.exe` or `/usr/local/bin/ffmpeg`).
#### Command Line Arguments [arguments] #### Command Line Arguments [arguments]
In the right input field, you can input custom **Command Line Arguments** to be used in the console. In the right input field, you can input custom **Command Line Arguments** to be used in the console.
@@ -510,29 +454,6 @@ To use **High Performance Rendering**, hold down the `Ctrl` key (`Cmd` key on M
but only after one rendered seconds (e.g. every 60 frames when rendering with 60fps) but only after one rendered seconds (e.g. every 60 frames when rendering with 60fps)
- Resizing the Minecraft Window does not update the Rendering Gui - Resizing the Minecraft Window does not update the Rendering Gui
### Troubleshooting [troubleshooting]
> If you have trouble with rendering, please first consult the Documentation before asking for help in the Forums.
#### No FFmpeg installation found [ffmpeg]
![](img/ffmpeg-missing.jpg)
The error screen that is displayed when no FFmpeg installation could be found
If the **Replay Mod** tells you to install FFmpeg even though you already have, you have to manually tell the **Replay Mod** where your FFmpeg executable is located.
First, get the full path to your `ffmpeg.exe` (on Windows) or `ffmpeg` executable (on Mac/Linux).
On Windows, this path might look like `C:/ffmpeg/ffmpeg.exe`.
Then, open the **"Command Line Settings" Tab** in the Render Settings and paste this path into the **left input field** and retry rendering.
#### Crash while rendering [crash]
If Minecraft crashes after a few frames of rendering, it most likely means the **FFmpeg** didn't like the **Command Line Arguments** you passed.
If you customized the Command Line Arguments manually, re-check them - it's probably your own fault.
> **Hint:** In your .minecraft folder, you'll find a file called `export.log` which contains information about FFmpeg's rendering process.
If you did **not** customize the **Command Line Arguments**, you might have entered some insanely high (or low) values e.g. for Bitrate or Video Resolution. Try again with other, more reasonable values.
## Ambient Lighting [lighting] ## Ambient Lighting [lighting]
![](img/ambient-lighting-comparison.jpg) ![](img/ambient-lighting-comparison.jpg)
The same setting, onace with **Ambient Lighting** enabled, once with **Ambient Lighting** disabled The same setting, onace with **Ambient Lighting** enabled, once with **Ambient Lighting** disabled
@@ -544,6 +465,14 @@ If you have a Replay in a dark setting (for example at nighttime, or in a cave)
This works as a replacement for the **Night Vision Potion Effect**, without the side effect of a weird sky color. This works as a replacement for the **Night Vision Potion Effect**, without the side effect of a weird sky color.
## Quick Mode [quickmode]
![](img/quickmode-icon.jpg)
In **Quick Mode**, this clock symbol is displayed in the lower right corner of the screen.
When you first enable **Quick Mode** in a replay, an internal reference of certain entity and block properties is stored for quick access, allowing for faster navigation in the **Replay Timeline**.
As a side effect, certain features like particles and second skin layers will not be rendered in the preview.
By default, **Quick Mode** is toggled with `Q`.
## Player Overview [overview] ## Player Overview [overview]
![](img/player-overview.jpg) ![](img/player-overview.jpg)
The **Player Overview** Screen The **Player Overview** Screen
@@ -567,11 +496,9 @@ The **Default Thumbnail** which is used if no Thumbnail was created
While in a Replay, you can use the `N` key to create a **Thumbnail** of the current Replay. While in a Replay, you can use the `N` key to create a **Thumbnail** of the current Replay.
A **Thumbnail** is a Screenshot which should give the viewer a good impression of your Replay's content. A **Thumbnail** is a Screenshot which should give the viewer a good impression of your Replay's content.
**Thumbnails** are important when uploading a Replay to the **Replay Center**, **Thumbnails** help keeping your **Replay Viewer** clear and structured.
as other users are much more likely to download your Replay if they can see a preview of it.
They also help keeping your **Replay Viewer** clear and structured.
If no **Thumbnail** is set for a Replay, the **Default Thumbnail** will be displayed in the **Replay Viewer** and in the **Replay Center**. If no **Thumbnail** is set for a Replay, the **Default Thumbnail** will be displayed in the **Replay Viewer**.
## Event Markers [markers] ## Event Markers [markers]
![](img/marker-timeline.jpg) ![](img/marker-timeline.jpg)
@@ -594,84 +521,8 @@ This way, it's even simpler to add structure to your Replays.
You can **delete an Event Marker** by clicking it once to select it and then pressing the `DELETE` key. You can **delete an Event Marker** by clicking it once to select it and then pressing the `DELETE` key.
# Replay Center [center]
The **Replay Center** is where you can **share** your **Minecraft Moments** with others and discover awesome **Replays by other Users**.
To be able to use the **Replay Center**, you need an **account on ReplayMod.com**.
## Authentication [auth]
![](img/auth-login.jpg)
The **Login Screen** which is displayed upon startup
![](img/auth-register.jpg)
The **Register Screen**
When starting Minecraft with the **Replay Mod** installed, you will be asked to login to **ReplayMod.com**.
If you don't want to use the **Replay Center**, you can click the **"Skip" Button** to continue without logging in.
If you want to browse other users' **Replays** and **share your own Replays** however, you need to **Register an account**.
> **Note:** By registering an Account on **ReplayMod.com**, you agree to the Website's [Terms of Service](https://www.replaymod.com/legal/terms)
Please note that you can only create **one ReplayMod.com Account per Minecraft Account**, so choose your username wisely.
Once you've registered, you're automatically going to be logged in. The Mod **remembers your login** until you manually log out from the **Replay Center**, so it won't ask you upon every startup if you logged in once.
## Replay Files [files]
![](img/replay-center.jpg)
The **Replay Center** in the Mod
Once you've logged in, you can use the **"Replay Center" Button** in the Main Menu to access the **Replay Center**.
In the upper half of the screen, there are **5 Buttons** for **5 Tabs** of the **Replay Center**:
- **Recent**
Shows the most recently uploaded Replays in the **Replay Center**
- **Best**
Shows the Replays with the **best rating and most downloads**
- **Downloaded**
Shows all of the Replays you've downloaded locally
- **Favorited**
Shows all of the Replays you favorited
- **Search**
Allows you to search for specific Replays
When you've found an insteresting looking Replay, you can download it using the **"Download" Button** in the lower left corner.
After downloading, you'll automatically join the Replay.
After you've downloaded a Replay, you can rate and favorite it in the **Replay Center** using the respective buttons.
> You are encouraged to rate Replays after you downloaded them to help promoting the best Replays.
## Upload Replays [upload]
![](img/replay-upload.jpg)
The **Replay Upload Screen**
You can share your own **Replay Files** with other users in the **Replay Center**.
Therefore, click the **"Upload" Button** in the **Replay Viewer** after selecting a Replay.
In the **Replay Upload Screen** there are **6 input fields**:
- **Replay Name**
The Replay's Name in the Replay Center
- **Replay Description**
A description of what happens in the Replay. Try to give the user a good impression why your Replay is worth downloading.
- **Category**
The Replay's Category, one of the following: **Survival**, **Build**, **Minigame**, **Miscellaneous**. If none of the other categories fit, use **Miscellaneous**.
- **Tags**
One or more tags that fit your replay, spearated by comma. **Example tags:** pvp,battle,redstone,creative
- **Hide Server IP**
If you've recorded a Replay on a private Server, you can remove the Server IP by checking the respective checkbox.
- **Thumbnail**
While you can't directly edit the Thumbnail when uploading, it is highly recommended that
you [create a Thumbnail](#replaying-thumbnail) before sharing your Replay.
Replays without a Thumbnail are much less likely to be downloaded by other users.
When uploading a Replay File, make sure to follow the [Replay Center Rules](https://www.replaymod.com/rules).
# Frequently Asked Questions [faq] # Frequently Asked Questions [faq]
### Do I need a ReplayMod.com Account to use the mod?
You only need a ReplayMod.com Account to access the [Replay Center](#center).
All of the other features are also available offline.
### For how long can I record? ### For how long can I record?
Theoretically, a Replay File can be up to **24 days, 20 hours, 30 minutes and 23 seconds** long - which is a timespan you'll probably never reach. Theoretically, a Replay File can be up to **24 days, 20 hours, 30 minutes and 23 seconds** long - which is a timespan you'll probably never reach.
@@ -694,3 +545,113 @@ A Replay in which you travelled around and discovered a lot of terrain is signif
An average Replay File of **10 Minutes duration** usually is between **2MB and 10MB large**. An average Replay File of **10 Minutes duration** usually is between **2MB and 10MB large**.
Replays recorded on **Minigame Servers** with lots of particle effects and world changes might be larger. Replays recorded on **Minigame Servers** with lots of particle effects and world changes might be larger.
# Troubleshooting [troubleshooting]
> If you have trouble with rendering, please first consult the Documentation before asking for help in the Discord.
## No FFmpeg installation found [ffmpeg]
![](img/ffmpeg-missing.jpg)
The error screen that is displayed when no FFmpeg installation could be found
If you have not installed FFmpeg, please follow the steps provided [here](#installing-ffmpeg)
If already have installed FFmpeg, you have to manually tell the **Replay Mod** where your FFmpeg executable is located.
First, get the full path to your `ffmpeg.exe` (on Windows) or `ffmpeg` executable (on Mac/Linux).
On Windows, this path might look like `C:\ffmpeg\ffmpeg.exe`.
Then, open the **"Command Line Settings" Section** in the Render Settings and paste this path into the **left input field** and retry rendering.
## Crash while rendering [crash]
If Minecraft crashes after a few frames of rendering, it most likely means the **FFmpeg** didn't like the **Command Line Arguments** you passed.
If you customized the Command Line Arguments manually, re-check them - it's probably your own fault.
> **Hint:** In your .minecraft folder, you'll find a file called `export.log` which contains information about FFmpeg's rendering process.
- If you did **not** customize the **Command Line Arguments**, you might have entered some insanely high (or low) values e.g. for Bitrate or Video Resolution. Try again with other, more reasonable values.
- Make sure the camera doesn't move below Y=0 or above Y=255
## Unsupported Launchers [launchers]
_Future Client_ is not compatible with the Mixin required by ReplayMod.
_Lunar Client_ does not support ReplayMod.
_Badlion Client_ offers a different ReplayMod that is not the same as this one.
## Compatibility with other Mods [compatibility]
### General information [general]
In General, the Replay Mod _should_ be compatible with most Forge and Fabric Mods.
### Shaders Mod [shaders]
_Karyonix' Shaders Mod_ is no longer compatible with Minecraft Forge starting with 1.9.4. As such it is not compatible with the Replay Mod either.
Below Minecraft 1.16 you can try _Optifine_ instead. Note however, that official support has ended and many versions break ReplayMod.
On Minecraft 1.16.5 and up you can use _Iris_, which is fully supported. For the time being, you will have to use it with the custom _Sodium_ provided on our download page. The fix it includes is pending for the official version.
### Custom Main Menu [custom-main-menu]
The _Custom Main Menu_ mod is often used in mod packs to customize their Main Menu with a button layout fitting the background image, links to their website / bug tracker and similar.
If you are familiar with it, the button id for the Replay Mod is: **17890234** (text: `replaymod.gui.replayviewer`).
Due to the nature of this Custom Main Menu mod, buttons added to the Main Menu by 3rd party mods like the **Replay Mod** will not show up by default.
Thus, to access the Replay Viewer/Editor/Center, you need to manually configure the position for those buttons.
To do so, you need to modify the Custom Main Menu configuration file.
Usually, you can find it at `.minecraft/config/CustomMainMenu/mainmenu.json` (if you're using a mod pack launcher, it normally has its own .minecraft folder).
For an explanation of this config file, have a look at Custom Main Menu's page.
You can find a list of already modified config files [here](https://gist.github.com/Johni0702/3f3fab81dbf7ada83d045d9fe8f345aa).
### Tickrate Changer [tickrate-changer]
The _Tickrate Changer_ mod may cause minecraft to freeze when you try to use the Replay Viewer UI.
### LabyMod [labymod]
_LabyMod_ v3.7.x has been reported to be compatible with ReplayMod and other Forge mods.
Lower versions are not compatible.
### OldAnimationsMod [oldanimationsmod]
In case your Minecraft crashes when you are using both ReplayMod and _OldAnimationsMod_, try removing OldAnimationsMod.
### Orange's 1.7 Animations [17animations]
If you use ReplayMod with shaders and _1.7 Animations_ you may see floating water and glass. Remove 1.7 Animations to resolve this.
### Sk1er Club: Patcher [patcher]
We have seen reports of crashes that were related to _Patcher_; in case of crashes try removing Patcher.
### Baritone [baritone]
The _Baritone_ mod can cause a crash when you're trying to load a replay. If you experience such problems, try running without Baritone.
### RandomPatches [randompatches]
Minecraft may crash if you try to use _RandomPatches_ together with ReplayMod. Try removing RandomPatches if Minecraft crashes on startup.
### Sodium [sodium]
ReplayMod can record when _Sodium_ is installed, but currently lacks the FREX Flawless Frames API to render. A modified build of _Sodium_, that supports this API, is available from the ReplayMod downloads, by clicking the `Click to show compatible Sodium versions` button.
### Resource Loader [resourceloader]
The _Resource Loader_ mod is not compatible with ReplayMod.
### LiteLoader [liteloader]
![](img/mutlimc-liteloader.jpg)
The MultiMC interface to place ReplayMod above LiteLoader.
![](img/multimc-addempty.jpg)
The properties for the new *Empty*.
_LiteLoader_ is known to cause issues due to the mixin version it contains.
You can use MultiMC to workaround this problem.
> The MultiMC `Edit` function requires that your computer has a default editor for json files associated.
1: Create your instance then edit the instance
2: Click `Install Forge`
3: Click `Install LiteLoader`
4: Click `Add Empty`; use `ReplayMod` as name and `com.replaymod` as uid
5: Select the new *ReplayMod* and click `Edit`
6: Replace the contents with one of the below snippets
7: Save and close the text editor
8: Move *ReplayMod* up until it is **above** *LiteLoader*
9: Remove the ReplayMod jar from the mods folder if you installed it previously.
** Snippet for 1.8.9 **
`{ "formatVersion": 1, "name": "ReplayMod", "uid": "com.replaymod", "version": "1.8.9-2.4.5", "libraries": [{ "name": "com.replaymod:replaymod:1.8.9-2.4.5", "MMC-absoluteUrl": "https://minio.replaymod.com/replaymod/replaymod-1.8.9-2.4.5.jar" }]}`
** Snippet for 1.12.2 **
`{ "formatVersion": 1, "name": "ReplayMod", "uid": "com.replaymod", "version": "1.12.2-2.4.5", "libraries": [{ "name": "com.replaymod:replaymod:1.12.2-2.4.5", "MMC-absoluteUrl": "https://minio.replaymod.com/replaymod/replaymod-1.12.2-2.4.5.jar" }]}`

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 299 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 KiB

After

Width:  |  Height:  |  Size: 439 KiB

BIN
docs/img/quickmode-icon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
docs/img/quickmode-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 598 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 255 KiB

23
docs/package-lock.json generated Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "replaymod-docs",
"version": "0.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"array-findindex-polyfill": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/array-findindex-polyfill/-/array-findindex-polyfill-0.1.0.tgz",
"integrity": "sha1-w2JmW+x2RfItejw6rJeT9xw2Iu8="
},
"md-jml": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/md-jml/-/md-jml-2.0.1.tgz",
"integrity": "sha1-th99rTm1JPVKCmpthnMcTRLOCDo="
},
"string.prototype.endswith": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/string.prototype.endswith/-/string.prototype.endswith-0.2.0.tgz",
"integrity": "sha1-oZwg3uUamHd+mkfhDwm+OTubunU="
}
}
}

10
gradle.properties Normal file
View File

@@ -0,0 +1,10 @@
essential.defaults.loom=0
essential.defaults.loom.fabric-loader=net.fabricmc:fabric-loader:0.18.5
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx8G
org.gradle.parallel=true
org.gradle.configureondemand=true
loom.ignoreDependencyLoomVersionValidation=true

Binary file not shown.

View File

@@ -1,6 +1,5 @@
#Sun May 10 21:57:58 CEST 2015
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-2.11-all.zip

126
gradlew vendored
View File

@@ -1,4 +1,20 @@
#!/usr/bin/env bash #!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
############################################################################## ##############################################################################
## ##
@@ -6,47 +22,6 @@
## ##
############################################################################## ##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" PRG="$0"
@@ -61,9 +36,49 @@ while [ -h "$PRG" ] ; do
fi fi
done done
SAVED="`pwd`" SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&- cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`" APP_HOME="`pwd -P`"
cd "$SAVED" >&- cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -90,7 +105,7 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n` MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -114,6 +129,7 @@ fi
if $cygwin ; then if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath # We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -154,11 +170,19 @@ if $cygwin ; then
esac esac
fi fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules # Escape application args
function splitJvmOpts() { save () {
JVM_OPTS=("$@") for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
} }
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS APP_ARGS=$(save "$@")
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" # Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

30
gradlew.bat vendored
View File

@@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem http://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@@ -8,14 +24,14 @@
@rem Set local scope for the variables with windows NT shell @rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,10 +62,9 @@ echo location of your Java installation.
goto fail goto fail
:init :init
@rem Get command-line arguments, handling Windowz variants @rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args :win9xME_args
@rem Slurp the command line arguments. @rem Slurp the command line arguments.
@@ -60,11 +75,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%* set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute :execute
@rem Setup the command line @rem Setup the command line

2
jGui

Submodule jGui updated: e5fcc65032...b0e068383c

1
libs/ReplayStudio Submodule

Submodule libs/ReplayStudio added at ca00f8101b

288
root.gradle.kts Executable file
View File

@@ -0,0 +1,288 @@
import groovy.json.JsonOutput
import java.io.ByteArrayOutputStream
import org.gradle.kotlin.dsl.support.serviceOf
import org.gradle.process.ExecOperations
plugins {
id("gg.essential.multi-version.root")
id("gg.essential.loom") version "1.15.48" apply false
kotlin("jvm") version "2.3.20" apply false
id("com.github.hierynomus.license") version "0.15.0"
}
val latestVersion = file("version.txt").readLines().first()
var releaseCommit = providers.exec {
commandLine("git", "blame", "-p", "-l", "version.txt")
}.standardOutput.asText.map { it.trim().split("/n").first().split(" ").first() }.get()
if (latestVersion == "2.1.0") { // First version since change from tag-based
releaseCommit = "35ac26e91689ac9bdf12dbb9902c452464a75108" // git rev-parse 1.12.2-2.1.0
}
val currentCommit = providers.exec {
commandLine("git", "rev-parse", "HEAD")
}.standardOutput.asText.map { it.trim().split("/n").first() }.get()
if (releaseCommit == currentCommit) {
version = latestVersion
} else {
val diff = providers.exec {
commandLine("git", "log", "--format=oneline", "$releaseCommit..$currentCommit")
}.standardOutput.asText.map { it.trim().split("/n").size }.get()
version = "$latestVersion-$diff-g${currentCommit.substring(0, 7)}"
}
val dirty = providers.exec {
commandLine("git", "describe", "--always", "--dirty=*")
}.standardOutput.asText.map { it.trim().endsWith("*") }.get()
if (dirty) {
version = "$version-dirty"
}
group = "com.replaymod"
val bundleJar by tasks.registering(Copy::class) {
into("$buildDir/libs")
}
subprojects {
buildscript {
repositories {
maven("https://jitpack.io")
}
}
if (name == "jGui" || name == "ReplayStudio") {
return@subprojects
}
val (major, minor, patch) = name.split("-")[0].split(".") + listOf("0")
val mcVersion = major.toInt() * 10000 + minor.toInt() * 100 + patch.toInt()
val fabric = mcVersion >= 1_14_00 && !name.endsWith("-forge")
extra.set("loom.platform", if (fabric) "fabric" else "forge")
afterEvaluate {
val projectBundleJar = project.tasks.findByName("bundleJar")
if (projectBundleJar != null && projectBundleJar.hasProperty("archivePath") && project.name != "core") {
bundleJar.configure {
dependsOn(projectBundleJar)
from(projectBundleJar.withGroovyBuilder { getProperty("archivePath") })
}
}
}
}
fun ExecOperations.command(vararg cmd: String): List<String> {
val stdout = ByteArrayOutputStream()
exec {
commandLine(*cmd)
standardOutput = stdout
}
return stdout.toString().trim().split("\n")
}
fun generateVersionsJson(execOps: ExecOperations): Map<String, Any> {
fun command(vararg cmd: String): List<String> =
execOps.command(*cmd)
val versionComparator = compareBy<String>(
{ (it.split(".").getOrNull(0) ?: "0").toInt() },
{ (it.split(".").getOrNull(1) ?: "0").toInt() },
{ (it.split(".").getOrNull(2) ?: "0").toInt() }
)
// Find all tag-style releases by listing all tags
val tagVersions = command("git", "for-each-ref", "--sort=taggerdate", "--format=%(refname:short)", "refs/tags")
// Find all commit-style releases
// List all commits
val releaseCommits =
command("git", "log", "--format=%H", "--date-order", "-E",
"--grep", "Pre-release [0-9]+ of [0-9]+\\.[0-9]+\\.[0-9]+",
"--grep", "Release [0-9]+\\.[0-9]+\\.[0-9]+")
// Find version string and MC versions for each commit hash
val commitVersions = releaseCommits.map { commit ->
val version = command("git", "show", "$commit:version.txt").first()
val mcVersions = command("git", "ls-tree", "-d", "--name-only", "$commit:versions")
// In the past (early days of preprocessor) we used to have an internal "core" project
.filter { it != "core" }
// Internal project used to automatically remap from Forge 1.12.2 to Fabric 1.14.4
.filter { it != "1.14.4-forge" }
// We dropped 1.8 with the switch to archloom but still kept its source in case someone
// volunteers to make it build again
.filterNot { it == "1.8" && versionComparator.compare(version, "2.6.16") >= 0 }
// We dropped 1.7.10 with the Gradle 7 update but still kept its source in case someone
// volunteers to ~~update FG 1.2 to Gradle 7~~ make it work with archloom.
.filterNot { it == "1.7.10" && versionComparator.compare(version, "2.6.0") >= 0 }
val versions = mcVersions.map { "$it-$version" }.toMutableList()
when (version) {
"2.6.7" -> versions.add("1.19.1-2.6.7") // forgot to add the .gitkeep file before merging
}
versions
}.flatten()
val versions = commitVersions + tagVersions.reversed()
val mcVersions = versions
.map {it.substring(0, it.indexOf("-"))}
.distinct()
.sortedWith(versionComparator)
val promos = mutableMapOf<String, String>()
val root = mutableMapOf<String, Any>(
"homepage" to "https://www.replaymod.com/download/",
"promos" to promos
)
mcVersions.forEach { mcVersion ->
var mcVersionRoot = mutableMapOf<String, String>()
var latest: String? = null
var recommended: String? = null
versions.forEach {
val (thisMcVersion, modVersion, preVersion) = it.split("-") + listOf(null, null)
if (thisMcVersion == mcVersion) {
mcVersionRoot[it] = "See https://www.replaymod.com/changelog.txt"
if (latest == null) latest = it
if (preVersion == null) {
if (recommended == null) recommended = it
}
}
}
root[mcVersion] = mcVersionRoot
promos[mcVersion + "-latest"] = latest!!
if (recommended != null) {
promos[mcVersion + "-recommended"] = recommended!!
}
}
return root
}
val writeVersionsJson by tasks.registering {
val execOps = project.serviceOf<ExecOperations>()
doLast {
val versionsRoot = generateVersionsJson(execOps)
val versionsJson = JsonOutput.prettyPrint(JsonOutput.toJson(versionsRoot))
File("versions.json").writeText(versionsJson)
}
}
val doRelease by tasks.registering {
val execOps = project.serviceOf<ExecOperations>()
doLast {
fun command(vararg cmd: String): List<String> =
execOps.command(*cmd)
// Parse version
val version = project.extra["releaseVersion"] as String
if (command("git", "describe", "--always", "--dirty=*").first().endsWith("*")) {
throw InvalidUserDataException("Git working tree is dirty. Make sure to commit all changes.")
}
val (modVersion, preVersion) = if ("-b" in version) {
version.split("-b")
} else {
listOf(version, null)
}
// Merge release branch into stable but do not yet commit (we need to update the version.txt first)
command("git", "checkout", "stable")
command("git", "merge", "--no-ff", "--no-commit", "release-$version")
// Update version.txt
file("version.txt").writeText("$version\n")
command("git", "add", "version.txt")
// Finallize the merge. The message is what is later used to identify releses for building the version.json tree
val commitMessage = if (preVersion != null)
"Pre-release $preVersion of $modVersion"
else
"Release $modVersion"
command("git", "commit", "-m", commitMessage)
// Generate versions.json content
val versionsRoot = generateVersionsJson(execOps)
val versionsJson = JsonOutput.prettyPrint(JsonOutput.toJson(versionsRoot))
// Switch to master branch to update versions.json
command("git", "checkout", "master")
// Write versions.json
File("versions.json").writeText(versionsJson)
// Commit changes
command("git", "add", "versions.json")
command("git", "commit", "-m", "Update versions.json for $version")
// Return to previous branch
command("git", "checkout", "-")
}
}
defaultTasks("bundleJar")
preprocess {
strictExtraMappings.set(true)
val mc26_01_00 = createNode("26.1", 26_01_00, "yarn")
val mc12111 = createNode("1.21.11", 12111, "yarn")
val mc12110 = createNode("1.21.10", 12110, "yarn")
val mc12107 = createNode("1.21.7", 12107, "yarn")
val mc12105 = createNode("1.21.5", 12105, "yarn")
val mc12104 = createNode("1.21.4", 12104, "yarn")
val mc12102 = createNode("1.21.2", 12102, "yarn")
val mc12100 = createNode("1.21", 12100, "yarn")
val mc12006 = createNode("1.20.6", 12006, "yarn")
val mc12004 = createNode("1.20.4", 12004, "yarn")
val mc12002 = createNode("1.20.2", 12002, "yarn")
val mc12001 = createNode("1.20.1", 12001, "yarn")
val mc11904 = createNode("1.19.4", 11904, "yarn")
val mc11903 = createNode("1.19.3", 11903, "yarn")
val mc11902 = createNode("1.19.2", 11902, "yarn")
val mc11901 = createNode("1.19.1", 11901, "yarn")
val mc11900 = createNode("1.19", 11900, "yarn")
val mc11802 = createNode("1.18.2", 11802, "yarn")
val mc11801 = createNode("1.18.1", 11801, "yarn")
val mc11701 = createNode("1.17.1", 11701, "yarn")
val mc11604 = createNode("1.16.4", 11604, "yarn")
val mc11601 = createNode("1.16.1", 11601, "yarn")
val mc11502 = createNode("1.15.2", 11502, "yarn")
val mc11404 = createNode("1.14.4", 11404, "yarn")
val mc11404Forge = createNode("1.14.4-forge", 11404, "srg")
val mc11202 = createNode("1.12.2", 11202, "srg")
val mc11201 = createNode("1.12.1", 11201, "srg")
val mc11200 = createNode("1.12", 11200, "srg")
val mc11102 = createNode("1.11.2", 11102, "srg")
val mc11100 = createNode("1.11", 11100, "srg")
val mc11002 = createNode("1.10.2", 11002, "srg")
val mc10904 = createNode("1.9.4", 10904, "srg")
val mc10809 = createNode("1.8.9", 10809, "srg")
val mc10800 = createNode("1.8", 10800, "srg")
val mc10710 = createNode("1.7.10", 10710, "srg")
mc26_01_00.link(mc12111, file("versions/mapping-fabric-26.1-1.21.11.txt"))
mc12111.link(mc12110, file("versions/mapping-fabric-1.21.11-1.21.10.txt"))
mc12110.link(mc12107, file("versions/mapping-fabric-1.21.10-1.21.7.txt"))
mc12107.link(mc12105)
mc12105.link(mc12104, file("versions/mapping-fabric-1.21.5-1.21.4.txt"))
mc12104.link(mc12102)
mc12102.link(mc12100)
mc12100.link(mc12006)
mc12006.link(mc12004)
mc12004.link(mc12002, file("versions/mapping-fabric-1.20.4-1.20.2.txt"))
mc12002.link(mc12001)
mc12001.link(mc11904, file("versions/mapping-fabric-1.20.1-1.19.4.txt"))
mc11904.link(mc11903, file("versions/mapping-fabric-1.19.4-1.19.3.txt"))
mc11903.link(mc11902, file("versions/mapping-fabric-1.19.3-1.19.2.txt"))
mc11902.link(mc11901)
mc11901.link(mc11900)
mc11900.link(mc11802)
mc11802.link(mc11801)
mc11801.link(mc11701, file("versions/mapping-fabric-1.18.1-1.17.1.txt"))
mc11701.link(mc11604, file("versions/mapping-fabric-1.17.1-1.16.4.txt"))
mc11604.link(mc11601)
mc11601.link(mc11502)
mc11502.link(mc11404, file("versions/mapping-fabric-1.15.2-1.14.4.txt"))
mc11404.link(mc11404Forge)
mc11404Forge.link(mc11202, file("versions/mapping-forge-1.14.4-1.12.2.txt"))
mc11202.link(mc11201)
mc11201.link(mc11200)
mc11200.link(mc11102)
mc11102.link(mc11100)
mc11100.link(mc11002)
mc11002.link(mc10904)
mc10904.link(mc10809, file("versions/mapping-forge-1.9.4-1.8.9.txt"))
mc10809.link(mc10800, file("versions/mapping-forge-1.8.9-1.8.txt"))
mc10800.link(mc10710, file("versions/mapping-forge-1.8-1.7.10.txt"))
}

View File

@@ -1 +0,0 @@
include 'ReplayStudio'

112
settings.gradle.kts Normal file
View File

@@ -0,0 +1,112 @@
pluginManagement {
repositories {
mavenLocal()
gradlePluginPortal()
mavenCentral()
google()
maven("https://jitpack.io")
maven("https://maven.fabricmc.net")
maven("https://maven.architectury.dev/")
maven("https://maven.minecraftforge.net")
maven("https://repo.essential.gg/repository/maven-public")
}
plugins {
id("gg.essential.multi-version.root") version "0.7.0-alpha.4"
id("com.gradleup.shadow") version "9.4.1"
}
}
val jGuiVersions = listOf(
// "1.7.10",
// "1.8",
"1.8.9",
"1.9.4",
"1.12",
"1.14.4-forge",
"1.14.4",
"1.15.2",
"1.16.1",
"1.16.4",
"1.17.1",
"1.18.1",
"1.18.2",
"1.19",
"1.19.1",
"1.19.2",
"1.19.3",
"1.19.4",
"1.20.1",
"1.20.2",
"1.20.4",
"1.20.6",
"1.21",
"1.21.2",
"1.21.4",
"1.21.5",
"1.21.7",
"1.21.10",
"1.21.11",
"26.1",
)
val replayModVersions = listOf(
// "1.7.10",
// "1.8",
"1.8.9",
"1.9.4",
"1.10.2",
"1.11",
"1.11.2",
"1.12",
"1.12.1",
"1.12.2",
"1.14.4-forge",
"1.14.4",
"1.15.2",
"1.16.1",
"1.16.4",
"1.17.1",
"1.18.1",
"1.18.2",
"1.19",
"1.19.1",
"1.19.2",
"1.19.3",
"1.19.4",
"1.20.1",
"1.20.2",
"1.20.4",
"1.20.6",
"1.21",
"1.21.2",
"1.21.4",
"1.21.5",
"1.21.7",
"1.21.10",
"1.21.11",
"26.1",
)
rootProject.buildFileName = "root.gradle.kts"
includeBuild("libs/ReplayStudio")
include(":jGui")
project(":jGui").apply {
projectDir = file("jGui")
buildFileName = "root.gradle.kts"
}
jGuiVersions.forEach { version ->
include(":jGui:$version")
project(":jGui:$version").apply {
projectDir = file("jGui/versions/$version")
buildFileName = "../../build.gradle.kts"
}
}
replayModVersions.forEach { version ->
include(":$version")
project(":$version").apply {
projectDir = file("versions/$version")
buildFileName = "../../build.gradle.kts"
}
}

View File

@@ -1,29 +1,37 @@
package com.replaymod.compat; package com.replaymod.compat;
import com.replaymod.compat.bettersprinting.DisableBetterSprinting;
import com.replaymod.compat.optifine.DisableFastRender; import com.replaymod.compat.optifine.DisableFastRender;
import com.replaymod.compat.oranges17animations.HideInvisibleEntities; import com.replaymod.core.Module;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
//#if MC<11400
//$$ import com.replaymod.compat.oranges17animations.HideInvisibleEntities;
//#endif
//#if MC<11400
//$$ import com.replaymod.compat.bettersprinting.DisableBetterSprinting;
//#endif
//#if MC>=10800
import com.replaymod.compat.shaders.ShaderBeginRender; import com.replaymod.compat.shaders.ShaderBeginRender;
import net.minecraftforge.common.MinecraftForge; //#endif
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.EventBus;
@Mod(modid = ReplayModCompat.MOD_ID, public class ReplayModCompat implements Module {
version = "@MOD_VERSION@", public static Logger LOGGER = LogManager.getLogger();
acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*",
useMetadata = true)
public class ReplayModCompat {
public static final String MOD_ID = "replaymod-compat";
@Mod.EventHandler @Override
public void init(FMLInitializationEvent event) { public void initClient() {
EventBus bus = MinecraftForge.EVENT_BUS; //#if MC>=10800
bus.register(new ShaderBeginRender()); new ShaderBeginRender().register();
bus.register(new DisableFastRender()); //#endif
bus.register(new HideInvisibleEntities()); new DisableFastRender().register();
DisableBetterSprinting.register(); //#if MC<11400
//$$ new HideInvisibleEntities().register();
//#endif
//#if MC<11400
//$$ DisableBetterSprinting.register();
//#endif
} }
} }

View File

@@ -1,102 +1 @@
package com.replaymod.compat.bettersprinting; // 1.12.2 and below
import com.replaymod.replay.ReplayModReplay;
import com.replaymod.replay.events.ReplayChatMessageEvent;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.PlayerControllerMP;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorldEventListener;
import net.minecraft.world.World;
import net.minecraftforge.client.event.GuiOpenEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion;
import net.minecraftforge.fml.common.versioning.Restriction;
import net.minecraftforge.fml.common.versioning.VersionRange;
import javax.annotation.Nullable;
import java.util.Collections;
/**
* Old Better Sprinting versions replace the vanilla player with their own, overridden instance (replacing the camera entity).
*
* See: https://github.com/chylex/Better-Sprinting/blob/1.8/src/main/java/chylex/bettersprinting/client/player/impl/LogicImplOverride.java
*/
public class DisableBetterSprinting {
private static final VersionRange OLD_VERSION = VersionRange.newRange(null,
Collections.singletonList(new Restriction(null, false, new DefaultArtifactVersion("2.0.0"), false)));
private static final String LOGIC_CLASS_NAME = "chylex.bettersprinting.client.player.impl.LogicImplOverride";
private static final String CONTROLLER_OVERRIDE_CLASS_NAME = LOGIC_CLASS_NAME + ".PlayerControllerMPOverride";
public static void register() {
Loader.instance().getModList().stream()
.filter(mod -> mod.getModId().equalsIgnoreCase("bettersprinting"))
.findFirst()
.map(ModContainer::getProcessedVersion).filter(OLD_VERSION::containsVersion)
.ifPresent($_ -> MinecraftForge.EVENT_BUS.register(new DisableBetterSprinting()));
}
private DisableBetterSprinting() {}
private final Minecraft mc = Minecraft.getMinecraft();
private PlayerControllerMP originalController;
private BetterSprintingWorldAccess worldAccessHook = new BetterSprintingWorldAccess();
@SubscribeEvent(priority = EventPriority.HIGH)
public void beforeGuiOpenEvent(GuiOpenEvent event) {
if (ReplayModReplay.instance.getReplayHandler() != null && mc.world != null) {
// During replay, get ready to revert BetterSprinting's overwritten playerController
originalController = mc.playerController;
mc.world.addEventListener(worldAccessHook);
}
}
@SubscribeEvent(priority = EventPriority.LOW)
public void afterGuiOpenEvent(GuiOpenEvent event) {
if (ReplayModReplay.instance.getReplayHandler() != null && mc.world != null) {
mc.world.addEventListener(worldAccessHook);
}
}
@SubscribeEvent
public void onReplayChatMessage(ReplayChatMessageEvent event) {
// Suppress this message if it's the Better Sprinting warning message
for (StackTraceElement elem : Thread.currentThread().getStackTrace()) {
if (LOGIC_CLASS_NAME.equals(elem.getClassName())) {
event.setCanceled(true);
return;
}
}
}
private class BetterSprintingWorldAccess implements IWorldEventListener {
@Override
public void onEntityRemoved(Entity entityIn) {
if (mc.playerController != null && mc.playerController.getClass().getName().equals(CONTROLLER_OVERRIDE_CLASS_NAME)) {
// Someone has secretly swapped out the player controller and is about to substitute their own player entity.
// This is the right time to destroy their plan.
mc.playerController = originalController;
}
}
@Override public void notifyBlockUpdate(World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) {}
@Override public void notifyLightSet(BlockPos pos) {}
@Override public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {}
@Override public void playSoundToAllNearExcept(@Nullable EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) {}
@Override public void playRecord(SoundEvent soundIn, BlockPos pos) {}
@Override public void spawnParticle(int p_180442_1_, boolean p_180442_2_, double p_180442_3_, double p_180442_5_, double p_180442_7_, double p_180442_9_, double p_180442_11_, double p_180442_13_, int... p_180442_15_) {}
@Override public void spawnParticle(int p_190570_1_, boolean p_190570_2_, boolean p_190570_3_, double p_190570_4_, double p_190570_6_, double p_190570_8_, double p_190570_10_, double p_190570_12_, double p_190570_14_, int... p_190570_16_) {}
@Override public void onEntityAdded(Entity entityIn) {}
@Override public void broadcastSound(int p_180440_1_, BlockPos p_180440_2_, int p_180440_3_) {}
@Override public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data) {}
@Override public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) {}
}
}

View File

@@ -0,0 +1 @@
// 1.12.2 and below

View File

@@ -1,34 +1,34 @@
package com.replaymod.compat.optifine; package com.replaymod.compat.optifine;
import com.replaymod.render.events.ReplayRenderEvent; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import net.minecraft.client.Minecraft; import com.replaymod.core.versions.MCVer;
import net.minecraftforge.fml.client.FMLClientHandler; import com.replaymod.render.events.ReplayRenderCallback;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraft.client.MinecraftClient;
public class DisableFastRender { public class DisableFastRender extends EventRegistrations {
private final Minecraft mc = Minecraft.getMinecraft(); private final MinecraftClient mc = MinecraftClient.getInstance();
private boolean wasFastRender = false; private boolean wasFastRender = false;
@SubscribeEvent { on(ReplayRenderCallback.Pre.EVENT, renderer -> onRenderBegin()); }
public void onRenderBegin(ReplayRenderEvent.Pre event) { private void onRenderBegin() {
if (!FMLClientHandler.instance().hasOptifine()) return; if (!MCVer.hasOptifine()) return;
try { try {
wasFastRender = (boolean) OptifineReflection.gameSettings_ofFastRender.get(mc.gameSettings); wasFastRender = (boolean) OptifineReflection.gameSettings_ofFastRender.get(mc.options);
OptifineReflection.gameSettings_ofFastRender.set(mc.gameSettings, false); OptifineReflection.gameSettings_ofFastRender.set(mc.options, false);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
@SubscribeEvent { on(ReplayRenderCallback.Post.EVENT, renderer -> onRenderEnd()); }
public void onRenderEnd(ReplayRenderEvent.Post event){ private void onRenderEnd() {
if (!FMLClientHandler.instance().hasOptifine()) return; if (!MCVer.hasOptifine()) return;
try { try {
OptifineReflection.gameSettings_ofFastRender.set(mc.gameSettings, wasFastRender); OptifineReflection.gameSettings_ofFastRender.set(mc.options, wasFastRender);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@@ -1,8 +1,9 @@
package com.replaymod.compat.optifine; package com.replaymod.compat.optifine;
import net.minecraft.client.settings.GameSettings; import net.minecraft.client.options.GameOptions;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class OptifineReflection { public class OptifineReflection {
@@ -14,7 +15,7 @@ public class OptifineReflection {
// this throws an ignored ClassNotFoundException if Optifine isn't installed // this throws an ignored ClassNotFoundException if Optifine isn't installed
Class.forName("Config"); Class.forName("Config");
gameSettings_ofFastRender = GameSettings.class.getDeclaredField("ofFastRender"); gameSettings_ofFastRender = GameOptions.class.getDeclaredField("ofFastRender");
gameSettings_ofFastRender.setAccessible(true); gameSettings_ofFastRender.setAccessible(true);
} catch (ClassNotFoundException ignore) { } catch (ClassNotFoundException ignore) {
// no optifine installed // no optifine installed
@@ -24,4 +25,20 @@ public class OptifineReflection {
} }
} }
public static void reloadLang() {
try {
Class<?> langClass;
try {
langClass = Class.forName("Lang"); // Pre Optifine 1.12.2 E1
} catch (ClassNotFoundException ignore) {
langClass = Class.forName("net.optifine.Lang"); // Post Optifine 1.12.2 E1
}
langClass.getDeclaredMethod("resourcesReloaded").invoke(null);
} catch (ClassNotFoundException ignore) {
// no optifine installed
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
} }

View File

@@ -1,28 +1 @@
package com.replaymod.compat.oranges17animations; // 1.12.2 and below
import com.replaymod.replay.camera.CameraEntity;
import net.minecraft.client.Minecraft;
import net.minecraftforge.client.event.RenderLivingEvent;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
/**
* Orange seems to have copied vast parts of the RendererLivingEntity into their ArmorAnimation class which cancels the RenderLivingEvent.Pre and calls its own code instead.
* This breaks our mixin which assures that, even though the camera is in spectator mode, it cannot see invisible entities.
*
* To fix this issue, we simply cancel the RenderLivingEvent.Pre before it gets to ArmorAnimation if the entity is invisible.
*/
public class HideInvisibleEntities {
private final Minecraft mc = Minecraft.getMinecraft();
private final boolean modLoaded = Loader.isModLoaded("animations");
@SubscribeEvent(priority = EventPriority.HIGH)
public void preRenderLiving(RenderLivingEvent.Pre event) {
if (modLoaded) {
if (mc.player instanceof CameraEntity && event.getEntity().isInvisible()) {
event.setCanceled(true);
}
}
}
}

View File

@@ -1,39 +1,44 @@
//#if MC>=10800
package com.replaymod.compat.shaders; package com.replaymod.compat.shaders;
import com.replaymod.core.events.PreRenderCallback;
import com.replaymod.render.hooks.EntityRendererHandler; import com.replaymod.render.hooks.EntityRendererHandler;
import net.minecraft.client.Minecraft; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraft.client.MinecraftClient;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
public class ShaderBeginRender { public class ShaderBeginRender extends EventRegistrations {
private final Minecraft mc = Minecraft.getMinecraft(); private final MinecraftClient mc = MinecraftClient.getInstance();
/** /**
* Invokes Shaders#beginRender when rendering a video, * Invokes Shaders#beginRender when rendering a video,
* as this would usually get called by EntityRenderer#renderWorld, * as this would usually get called by EntityRenderer#renderWorld,
* which we're not calling during rendering. * which we're not calling during rendering.
*/ */
@SubscribeEvent { on(PreRenderCallback.EVENT, this::onRenderTickStart); }
public void onRenderTickStart(TickEvent.RenderTickEvent event) { private void onRenderTickStart() {
if (event.phase != TickEvent.Phase.START) return;
if (ShaderReflection.shaders_beginRender == null) return; if (ShaderReflection.shaders_beginRender == null) return;
if (ShaderReflection.config_isShaders == null) return; if (ShaderReflection.config_isShaders == null) return;
try { try {
// check if video is being rendered // check if video is being rendered
if (((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler() == null) if (((EntityRendererHandler.IEntityRenderer) mc.gameRenderer).replayModRender_getHandler() == null)
return; return;
// check if Shaders are enabled // check if Shaders are enabled
if (!(boolean) (ShaderReflection.config_isShaders.invoke(null))) return; if (!(boolean) (ShaderReflection.config_isShaders.invoke(null))) return;
ShaderReflection.shaders_beginRender.invoke(null, mc, mc.timer.renderPartialTicks, 0); ShaderReflection.shaders_beginRender.invoke(null, mc,
//#if MC>=11400
mc.gameRenderer.getCamera(),
//#endif
mc.getTickDelta(), 0);
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
} }
//#endif

View File

@@ -1,6 +1,11 @@
//#if MC>=10800
package com.replaymod.compat.shaders; package com.replaymod.compat.shaders;
import net.minecraft.client.Minecraft; import net.minecraft.client.MinecraftClient;
//#if MC>=11400
import net.minecraft.client.render.Camera;
//#endif
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -24,16 +29,23 @@ public class ShaderReflection {
static { static {
try { try {
shaders_frameTimeCounter = Class.forName("shadersmod.client.Shaders") Class<?> shadersClass;
.getDeclaredField("frameTimeCounter"); try {
shadersClass = Class.forName("shadersmod.client.Shaders"); // Pre Optifine 1.12.2 E1
} catch (ClassNotFoundException ignore) {
shadersClass = Class.forName("net.optifine.shaders.Shaders"); // Post Optifine 1.12.2 E1
}
shaders_frameTimeCounter = shadersClass.getDeclaredField("frameTimeCounter");
shaders_frameTimeCounter.setAccessible(true); shaders_frameTimeCounter.setAccessible(true);
shaders_isShadowPass = Class.forName("shadersmod.client.Shaders") shaders_isShadowPass = shadersClass.getDeclaredField("isShadowPass");
.getDeclaredField("isShadowPass");
shaders_isShadowPass.setAccessible(true); shaders_isShadowPass.setAccessible(true);
shaders_beginRender = Class.forName("shadersmod.client.Shaders") shaders_beginRender = shadersClass.getDeclaredMethod("beginRender", MinecraftClient.class,
.getDeclaredMethod("beginRender", Minecraft.class, float.class, long.class); //#if MC>=11400
Camera.class,
//#endif
float.class, long.class);
shaders_beginRender.setAccessible(true); shaders_beginRender.setAccessible(true);
renderGlobal_chunksToUpdateForced = Class.forName("net.minecraft.client.renderer.RenderGlobal") renderGlobal_chunksToUpdateForced = Class.forName("net.minecraft.client.renderer.RenderGlobal")
@@ -51,3 +63,4 @@ public class ShaderReflection {
} }
} }
} }
//#endif

View File

@@ -0,0 +1,32 @@
//#if MC>=11500
package com.replaymod.compat.shaders.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
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.CallbackInfo;
@Pseudo
@Mixin(targets = "net/optifine/render/ChunkVisibility", remap = false)
public abstract class MixinChunkVisibility {
@Shadow
private static int counter;
/**
* OF doesn't properly reset the counter when exiting a world.
* It'll only be reset when getMaxChunkY is called which only happens for
* SP worlds (i.e. not in a replay or MP).
* As a result, it may end up in a non-0 state, which will cause isFinished
* to unconditionally return false, therefore unconditionally setting
* needsTerrainUpdate to true on each call to WorldRenderer.setupTerrain,
* therefore unnecessarily consuming resources and live-locking when
* rendering the shader pass.
*/
@Inject(method = "reset", at = @At("HEAD"), remap = false)
private static void replayModCompat_fixImproperReset(CallbackInfo ci) {
MixinChunkVisibility.counter = 0;
}
}
//#endif

View File

@@ -1,18 +1,27 @@
//#if MC>=10800
package com.replaymod.compat.shaders.mixin; package com.replaymod.compat.shaders.mixin;
import com.replaymod.compat.shaders.ShaderReflection; import com.replaymod.compat.shaders.ShaderReflection;
import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplayHandler;
import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.ReplayModReplay;
import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.client.render.GameRenderer;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(EntityRenderer.class) @Mixin(GameRenderer.class)
public abstract class MixinShaderEntityRenderer { public abstract class MixinShaderEntityRenderer {
@Inject(method = "renderWorldPass", at = @At("HEAD")) //#if MC>=11400
@Inject(method = "renderWorld", at = @At("HEAD"))
//#else
//#if MC>=11400
//$$ @Inject(method = "updateCameraAndRender(FJ)V", at = @At("HEAD"))
//#else
//$$ @Inject(method = "renderWorldPass", at = @At("HEAD"))
//#endif
//#endif
private void replayModCompat_updateShaderFrameTimeCounter(CallbackInfo ignore) { private void replayModCompat_updateShaderFrameTimeCounter(CallbackInfo ignore) {
if (ReplayModReplay.instance.getReplayHandler() == null) return; if (ReplayModReplay.instance.getReplayHandler() == null) return;
if (ShaderReflection.shaders_frameTimeCounter == null) return; if (ShaderReflection.shaders_frameTimeCounter == null) return;
@@ -26,3 +35,4 @@ public abstract class MixinShaderEntityRenderer {
} }
} }
} }
//#endif

View File

@@ -1,29 +1,71 @@
//#if MC>=10800 && MC<11800
package com.replaymod.compat.shaders.mixin; package com.replaymod.compat.shaders.mixin;
import com.replaymod.render.hooks.EntityRendererHandler; import com.replaymod.render.hooks.EntityRendererHandler;
import net.minecraft.client.Minecraft; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.renderer.chunk.RenderChunk;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(RenderChunk.class) //#if MC>=11500
import org.spongepowered.asm.mixin.Shadow;
//#endif
//#if MC>=11500
@Mixin(net.minecraft.client.render.chunk.ChunkBuilder.BuiltChunk.class)
//#else
//$$ @Mixin(net.minecraft.client.render.chunk.ChunkRenderer.class)
//#endif
public abstract class MixinShaderRenderChunk { public abstract class MixinShaderRenderChunk {
private final Minecraft mc = Minecraft.getMinecraft(); private final MinecraftClient mc = MinecraftClient.getInstance();
//#if MC>=11500
@Shadow private int rebuildFrame;
@Shadow public abstract boolean shouldBuild();
/**
* So, for some reason OF though it'd be a good idea to drop the `shouldBuild` check from the chunk traversal in
* the setupTerrain method (see the innermost if of the "iteration" profiler section).
* Hint: It's not a good idea. It'll cause chunks to be queued for building which should not be built. And because
* they don't know any better, they'll even re-queue themselves (which looks like a race condition in vanilla
* MC) causing a live-lock when we try to force-build all chunks (or at least it would cause a lockup if it
* wasn't for the vanilla race condition which slowly causes some of the rebuild tasks to get lost over time,
* eventually, potentially all of them).
* This is the most convenient place to re-introduce the check (setRebuildFrame would normally be called right after
* shouldBuild, if it returns true).
*/
@Inject(method = "setRebuildFrame", at = @At("HEAD"), cancellable = true)
private void replayModCompat_OFHaveYouConsideredWhetherThisChunkShouldEvenBeBuilt(int rebuildFrame, CallbackInfoReturnable<Boolean> ci) {
if (this.rebuildFrame == rebuildFrame) {
// want to keep the fast path
ci.setReturnValue(false);
} else if (!this.shouldBuild()) {
// this is the check which OF removed
// So, I think I figured out the reason why optifine applies this change: It's so chunks which are outside
// the server view distance are still rendered if they've previously compiled. The bug still stands but
// fixing it breaks OF's broken feature, so to reduce the impact of our fix, we only apply it during
// rendering where it affects us the most.
if (((EntityRendererHandler.IEntityRenderer) mc.gameRenderer).replayModRender_getHandler() == null) return;
ci.setReturnValue(false);
}
}
//#endif
/** /**
* Changes the RenderChunk#isPlayerUpdate method that Optifine adds * Changes the RenderChunk#isPlayerUpdate method that Optifine adds
* to always return true while rendering so no chunks are being added * to always return true while rendering so no chunks are being added
* to a separate rendering queue * to a separate rendering queue
*/ */
@Inject(method = "isPlayerUpdate", at = @At("HEAD"), cancellable = true) @Inject(method = "isPlayerUpdate", at = @At("HEAD"), cancellable = true, remap = false)
private void replayModCompat_disableIsPlayerUpdate(CallbackInfoReturnable<Boolean> ci) { private void replayModCompat_disableIsPlayerUpdate(CallbackInfoReturnable<Boolean> ci) {
// TODO: Update to 1.12 once optifine is available if (((EntityRendererHandler.IEntityRenderer) mc.gameRenderer).replayModRender_getHandler() == null) return;
if (((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler() == null) return;
ci.setReturnValue(true); ci.setReturnValue(true);
} }
} }
//#endif

View File

@@ -1,40 +0,0 @@
package com.replaymod.compat.shaders.mixin;
import com.replaymod.compat.shaders.ShaderReflection;
import com.replaymod.render.hooks.EntityRendererHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.culling.ICamera;
import net.minecraft.entity.Entity;
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.CallbackInfo;
@Mixin(RenderGlobal.class)
public abstract class MixinShaderRenderGlobal {
private final Minecraft mc = Minecraft.getMinecraft();
@Shadow
public boolean displayListEntitiesDirty;
@Inject(method = "setupTerrain", at = @At("HEAD"), cancellable = true)
public void replayModCompat_setupTerrain(Entity viewEntity, double partialTicks, ICamera camera,
int frameCount, boolean playerSpectator, CallbackInfo ci) {
if (((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler() == null) return;
if (ShaderReflection.shaders_isShadowPass == null) return;
// when called by the shadow pass, displayListEntitiesDirty can't be set to false, as no chunk updates
// are being processed. As it's being set to true by ChunkLoadingRenderGlobal#updateChunks, we have to
// set it to false manually to exit the loop imposed by MixinRenderGlobal#replayModRender_setupTerrain.
try {
if ((boolean) ShaderReflection.shaders_isShadowPass.get(null) == true) {
displayListEntitiesDirty = false;
}
} catch (IllegalAccessException ignore) {}
}
}

View File

@@ -0,0 +1 @@
// 1.7.10 and below

View File

@@ -1,20 +1,52 @@
package com.replaymod.compat.shaders.mixin; package com.replaymod.compat.shaders.mixin;
import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.client.render.GameRenderer;
import net.minecraftforge.client.ForgeHooksClient;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=11600
import net.minecraft.client.render.Camera;
import net.minecraft.client.util.math.MatrixStack;
//#endif
//#if MC>=11400
import com.replaymod.core.events.PreRenderHandCallback;
//#else
//$$ import com.replaymod.core.versions.MCVer;
//$$ import net.minecraftforge.client.ForgeHooksClient;
//#endif
@Pseudo @Pseudo
@Mixin(targets = "shadersmod/client/ShadersRender", remap = false) @Mixin(targets = {
"shadersmod/client/ShadersRender", // Pre Optifine 1.12.2 E1
"net/optifine/shaders/ShadersRender" // Post Optifine 1.12.2 E1
}, remap = false)
public abstract class MixinShadersRender { public abstract class MixinShadersRender {
@Inject(method = "renderHand0", at = @At("HEAD"), cancellable = true) @Inject(method = { "renderHand0", "renderHand1" }, at = @At("HEAD"), cancellable = true, remap = false)
private static void replayModCompat_disableRenderHand0(EntityRenderer er, float partialTicks, int renderPass, CallbackInfo ci) { private static void replayModCompat_disableRenderHand0(
if (ForgeHooksClient.renderFirstPersonHand(er.mc.renderGlobal, partialTicks, renderPass)) { GameRenderer er,
//#if MC>=11600
MatrixStack stack,
Camera camera,
//#endif
float partialTicks,
//#if MC<11600
//$$ int renderPass,
//#endif
CallbackInfo ci) {
//#if MC>=11400
if (PreRenderHandCallback.EVENT.invoker().preRenderHand()) {
//#else
//#if MC>=11400
//$$ if (ForgeHooksClient.renderFirstPersonHand(MCVer.getMinecraft().renderGlobal, partialTicks)) {
//#else
//$$ if (ForgeHooksClient.renderFirstPersonHand(MCVer.getMinecraft().renderGlobal, partialTicks, renderPass)) {
//#endif
//#endif
ci.cancel(); ci.cancel();
} }
} }

View File

@@ -0,0 +1,18 @@
//#if FABRIC>=1
package com.replaymod.core;
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
// Required for ReplayModMMLauncher.
//
// Chain-loading mixin configurations only works when the first class that is loaded doesn't have any mixins which
// target it. The first class would ordinarily be MC's Main but there are valid use cases for targeting it, see
// e.g. https://github.com/ReplayMod/ReplayMod/issues/327
// So, instead of relying on the bad assumption that Main doesn't have any mixins, we'll instead register this
// dummy pre-launch entry point which is practically guaranteed to not have any mixins and gets called before Main.
public class DummyChainLoadEntryPoint implements PreLaunchEntrypoint {
@Override
public void onPreLaunch() {
}
}
//#endif

View File

@@ -2,107 +2,221 @@ package com.replaymod.core;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import net.minecraft.client.settings.KeyBinding; import com.replaymod.core.events.PreRenderCallback;
import net.minecraft.crash.CrashReport; import com.replaymod.core.mixin.KeyBindingAccessor;
import net.minecraft.crash.CrashReportCategory; import de.johni0702.minecraft.gui.function.KeyInput;
import net.minecraft.util.ReportedException; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import net.minecraftforge.fml.client.registry.ClientRegistry; import com.replaymod.core.events.KeyBindingEventCallback;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import com.replaymod.core.events.KeyEventCallback;
import net.minecraftforge.fml.common.gameevent.InputEvent; import net.minecraft.client.options.KeyBinding;
import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraft.util.crash.CrashReport;
import org.lwjgl.input.Keyboard; import net.minecraft.util.crash.CrashReportSection;
import net.minecraft.util.crash.CrashException;
//#if FABRIC>=1
import com.replaymod.core.versions.LangResourcePack;
//#if MC>=11600
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
//#else
//$$ import net.fabricmc.fabric.api.client.keybinding.FabricKeyBinding;
//#endif
import net.minecraft.client.util.InputUtil;
import net.minecraft.util.Identifier;
import static com.replaymod.core.ReplayMod.MOD_ID;
import static de.johni0702.minecraft.gui.versions.MCVer.identifier;
//#else
//$$ import net.minecraftforge.fml.client.registry.ClientRegistry;
//#endif
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
public class KeyBindingRegistry { public class KeyBindingRegistry extends EventRegistrations {
private Map<String, KeyBinding> keyBindings = new HashMap<String, KeyBinding>(); //#if MC>=12109
private Multimap<KeyBinding, Runnable> keyBindingHandlers = ArrayListMultimap.create(); //$$ private static final KeyBinding.Category CATEGORY = KeyBinding.Category.create(identifier(MOD_ID, "general"));
private Multimap<KeyBinding, Runnable> repeatedKeyBindingHandlers = ArrayListMultimap.create(); //#else
private Multimap<Integer, Runnable> rawHandlers = ArrayListMultimap.create(); private static final String CATEGORY = "replaymod.title";
//#if FABRIC>=1 && MC<11600
//$$ static { net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry.INSTANCE.addCategory(CATEGORY); }
//#endif
//#endif
public void registerKeyBinding(String name, int keyCode, Runnable whenPressed) { private final Map<String, Binding> bindings = new HashMap<>();
keyBindingHandlers.put(registerKeyBinding(name, keyCode), whenPressed); private Set<KeyBinding> onlyInReplay = new HashSet<>();
private Multimap<Integer, Function<KeyInput, Boolean>> rawHandlers = ArrayListMultimap.create();
public Binding registerKeyBinding(String name, int keyCode, Runnable whenPressed, boolean onlyInRepay) {
Binding binding = registerKeyBinding(name, keyCode, onlyInRepay);
binding.handlers.add(whenPressed);
return binding;
} }
public void registerRepeatedKeyBinding(String name, int keyCode, Runnable whenPressed) { public Binding registerRepeatedKeyBinding(String name, int keyCode, Runnable whenPressed, boolean onlyInRepay) {
repeatedKeyBindingHandlers.put(registerKeyBinding(name, keyCode), whenPressed); Binding binding = registerKeyBinding(name, keyCode, onlyInRepay);
binding.repeatedHandlers.add(whenPressed);
return binding;
} }
private KeyBinding registerKeyBinding(String name, int keyCode) { private Binding registerKeyBinding(String name, int keyCode, boolean onlyInRepay) {
KeyBinding keyBinding = keyBindings.get(name); Binding binding = bindings.get(name);
if (keyBinding == null) { if (binding == null) {
keyBinding = new KeyBinding(name, keyCode, "replaymod.title"); //#if FABRIC>=1
keyBindings.put(name, keyBinding); if (keyCode == 0) {
ClientRegistry.registerKeyBinding(keyBinding); keyCode = -1;
}
Identifier id = identifier(MOD_ID, name.substring(LangResourcePack.LEGACY_KEY_PREFIX.length()));
//#if MC>=11600
String key = String.format("key.%s.%s", id.getNamespace(), id.getPath());
KeyBinding keyBinding = new KeyBinding(key, InputUtil.Type.KEYSYM, keyCode, CATEGORY);
KeyBindingHelper.registerKeyBinding(keyBinding);
//#else
//$$ FabricKeyBinding fabricKeyBinding = FabricKeyBinding.Builder.create(id, InputUtil.Type.KEYSYM, keyCode, CATEGORY).build();
//$$ net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry.INSTANCE.register(fabricKeyBinding);
//$$ KeyBinding keyBinding = fabricKeyBinding;
//#endif
//#else
//$$ KeyBinding keyBinding = new KeyBinding(name, keyCode, CATEGORY);
//$$ ClientRegistry.registerKeyBinding(keyBinding);
//#endif
binding = new Binding(name, keyBinding);
bindings.put(name, binding);
if (onlyInRepay) {
this.onlyInReplay.add(keyBinding);
}
} else if (!onlyInRepay) {
this.onlyInReplay.remove(binding.keyBinding);
} }
return keyBinding; return binding;
} }
public void registerRaw(int keyCode, Runnable whenPressed) { public void registerRaw(int keyCode, Function<KeyInput, Boolean> whenPressed) {
rawHandlers.put(keyCode, whenPressed); rawHandlers.put(keyCode, whenPressed);
} }
public Map<String, KeyBinding> getKeyBindings() { public Map<String, Binding> getBindings() {
return Collections.unmodifiableMap(keyBindings); return Collections.unmodifiableMap(bindings);
} }
@SubscribeEvent public Set<KeyBinding> getOnlyInReplay() {
public void onKeyInput(InputEvent.KeyInputEvent event) { return Collections.unmodifiableSet(onlyInReplay);
handleKeyBindings();
handleRaw();
} }
@SubscribeEvent { on(PreRenderCallback.EVENT, this::handleRepeatedKeyBindings); }
public void onTick(TickEvent.RenderTickEvent event) {
if (event.phase != TickEvent.Phase.START) return;
handleRepeatedKeyBindings();
}
public void handleRepeatedKeyBindings() { public void handleRepeatedKeyBindings() {
for (Map.Entry<KeyBinding, Collection<Runnable>> entry : repeatedKeyBindingHandlers.asMap().entrySet()) { for (Binding binding : bindings.values()) {
if (entry.getKey().isKeyDown()) { if (binding.keyBinding.isPressed()) {
invokeKeyBindingHandlers(entry.getKey(), entry.getValue()); invokeKeyBindingHandlers(binding, binding.repeatedHandlers);
} }
} }
} }
public void handleKeyBindings() { { on(KeyBindingEventCallback.EVENT, this::handleKeyBindings); }
for (Map.Entry<KeyBinding, Collection<Runnable>> entry : keyBindingHandlers.asMap().entrySet()) { private void handleKeyBindings() {
while (entry.getKey().isPressed()) { for (Binding binding : bindings.values()) {
invokeKeyBindingHandlers(entry.getKey(), entry.getValue()); while (binding.keyBinding.wasPressed()) {
invokeKeyBindingHandlers(binding, binding.handlers);
invokeKeyBindingHandlers(binding, binding.repeatedHandlers);
} }
} }
} }
private void invokeKeyBindingHandlers(KeyBinding keyBinding, Collection<Runnable> handlers) { private void invokeKeyBindingHandlers(Binding binding, Collection<Runnable> handlers) {
for (final Runnable runnable : handlers) { for (final Runnable runnable : handlers) {
try { try {
runnable.run(); runnable.run();
} catch (Throwable cause) { } catch (Throwable cause) {
CrashReport crashReport = CrashReport.makeCrashReport(cause, "Handling Key Binding"); CrashReport crashReport = CrashReport.create(cause, "Handling Key Binding");
CrashReportCategory category = crashReport.makeCategory("Key Binding"); CrashReportSection category = crashReport.addElement("Key Binding");
category.addCrashSection("Key Binding", keyBinding); category.add("Key Binding", () -> binding.name);
category.addDetail("Handler", runnable::toString); category.add("Handler", runnable::toString);
throw new ReportedException(crashReport); throw new CrashException(crashReport);
} }
} }
} }
public void handleRaw() { { on(KeyEventCallback.EVENT, this::handleRaw); }
int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey(); private boolean handleRaw(KeyInput keyInput, int action) {
for (final Runnable runnable : rawHandlers.get(keyCode)) { if (action != KeyEventCallback.ACTION_PRESS) return false;
for (final Function<KeyInput, Boolean> handler : rawHandlers.get(keyInput.key)) {
try { try {
runnable.run(); if (handler.apply(keyInput)) {
return true;
}
} catch (Throwable cause) { } catch (Throwable cause) {
CrashReport crashReport = CrashReport.makeCrashReport(cause, "Handling Raw Key Binding"); CrashReport crashReport = CrashReport.create(cause, "Handling Raw Key Binding");
CrashReportCategory category = crashReport.makeCategory("Key Binding"); CrashReportSection category = crashReport.addElement("Key Binding");
category.addCrashSection("Key Code", keyCode); category.add("Key Code", () -> "" + keyInput.key);
category.addDetail("Handler", runnable::toString); category.add("Handler", handler::toString);
throw new ReportedException(crashReport); throw new CrashException(crashReport);
} }
} }
return false;
}
public class Binding {
public final String name;
public final KeyBinding keyBinding;
private final List<Runnable> handlers = new ArrayList<>();
private final List<Runnable> repeatedHandlers = new ArrayList<>();
private boolean autoActivation;
private Consumer<Boolean> autoActivationUpdate;
public Binding(String name, KeyBinding keyBinding) {
this.name = name;
this.keyBinding = keyBinding;
}
public String getBoundKey() {
try {
return keyBinding.getBoundKeyLocalizedText().getString();
} catch (ArrayIndexOutOfBoundsException e) {
// Apparently windows likes to press strange keys, see https://www.replaymod.com/forum/thread/55
return "Unknown";
}
}
public boolean isBound() {
//#if MC>=11400
return !keyBinding.isUnbound();
//#else
//$$ return keyBinding.getKeyCode() != 0;
//#endif
}
public void trigger() {
KeyBindingAccessor acc = (KeyBindingAccessor) keyBinding;
acc.setPressTime(acc.getPressTime() + 1);
handleKeyBindings();
}
public void registerAutoActivationSupport(boolean active, Consumer<Boolean> update) {
this.autoActivation = active;
this.autoActivationUpdate = update;
}
public boolean supportsAutoActivation() {
return autoActivationUpdate != null;
}
public boolean isAutoActivating() {
return supportsAutoActivation() && autoActivation;
}
public void setAutoActivating(boolean active) {
if (this.autoActivation == active) {
return;
}
this.autoActivation = active;
this.autoActivationUpdate.accept(active);
}
} }
} }

70
src/main/java/com/replaymod/core/LoadingPlugin.java Executable file → Normal file
View File

@@ -1,69 +1 @@
package com.replaymod.core; // 1.12.2 and below
import net.minecraftforge.fml.relauncher.CoreModManager;
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
import org.apache.logging.log4j.LogManager;
import org.spongepowered.asm.launch.MixinBootstrap;
import org.spongepowered.asm.mixin.Mixins;
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.util.Map;
public class LoadingPlugin implements IFMLLoadingPlugin {
public LoadingPlugin() {
MixinBootstrap.init();
Mixins.addConfiguration("mixins.recording.replaymod.json");
Mixins.addConfiguration("mixins.render.replaymod.json");
Mixins.addConfiguration("mixins.replay.replaymod.json");
Mixins.addConfiguration("mixins.compat.shaders.replaymod.json");
Mixins.addConfiguration("mixins.extras.playeroverview.replaymod.json");
CodeSource codeSource = getClass().getProtectionDomain().getCodeSource();
if (codeSource != null) {
URL location = codeSource.getLocation();
try {
File file = new File(location.toURI());
if (file.isFile()) {
// This forces forge to reexamine the jar file for FML mods
// Should eventually be handled by Mixin itself, maybe?
CoreModManager.getIgnoredMods().remove(file.getName());
}
} catch (URISyntaxException e) {
e.printStackTrace();
}
} else {
LogManager.getLogger().warn("No CodeSource, if this is not a development environment we might run into problems!");
LogManager.getLogger().warn(getClass().getProtectionDomain());
}
}
@Override
public String[] getASMTransformerClass() {
return new String[]{
};
}
@Override
public String getModContainerClass() {
return null;
}
@Override
public String getSetupClass() {
return null;
}
@Override
public void injectData(Map<String, Object> data) {
}
@Override
public String getAccessTransformerClass() {
return null;
}
}

View File

@@ -0,0 +1,14 @@
//#if FABRIC>=1
package com.replaymod.core;
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
public class MixinExtrasInit implements PreLaunchEntrypoint {
@Override
public void onPreLaunch() {
//#if MC>=11604
com.llamalad7.mixinextras.MixinExtrasBootstrap.init();
//#endif
}
}
//#endif

View File

@@ -0,0 +1,10 @@
package com.replaymod.core;
public interface Module {
// FMLCommonSetupEvent for 1.13+, FMLInitializationEvent below
default void initCommon() {}
// FMLClientSetupEvent for 1.13+, FMLInitializationEvent (if client) below
default void initClient() {}
// FMLClientSetupEvent for 1.13+, FMLInitializationEvent below
default void registerKeyBindings(KeyBindingRegistry registry) {}
}

426
src/main/java/com/replaymod/core/ReplayMod.java Executable file → Normal file
View File

@@ -1,84 +1,116 @@
package com.replaymod.core; package com.replaymod.core;
import com.google.common.io.Files; import com.replaymod.compat.ReplayModCompat;
import com.google.common.util.concurrent.ListenableFutureTask; import com.replaymod.core.files.ReplayFilesService;
import com.replaymod.core.files.ReplayFoldersService;
import com.replaymod.core.gui.GuiBackgroundProcesses;
import com.replaymod.core.gui.GuiReplaySettings; import com.replaymod.core.gui.GuiReplaySettings;
import com.replaymod.core.gui.RestoreReplayGui; import com.replaymod.core.versions.MCVer;
import com.replaymod.core.handler.MainMenuHandler; import com.replaymod.core.versions.scheduler.Scheduler;
import com.replaymod.core.utils.OpenGLUtils; import com.replaymod.core.versions.scheduler.SchedulerImpl;
import com.replaymod.editor.ReplayModEditor;
import com.replaymod.extras.ReplayModExtras;
import com.replaymod.recording.ReplayModRecording;
import com.replaymod.render.ReplayModRender;
import com.replaymod.replay.ReplayModReplay;
import com.replaymod.replaystudio.lib.viaversion.api.protocol.version.ProtocolVersion;
import com.replaymod.replaystudio.studio.ReplayStudio;
import com.replaymod.replaystudio.util.I18n; import com.replaymod.replaystudio.util.I18n;
import de.johni0702.minecraft.gui.container.GuiScreen; import com.replaymod.simplepathing.ReplayModSimplePathing;
import lombok.Getter; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.Minecraft; import net.minecraft.resource.DirectoryResourcePack;
import net.minecraft.client.settings.GameSettings; import net.minecraft.text.LiteralText;
import net.minecraft.crash.CrashReport; import net.minecraft.text.Style;
import net.minecraft.crash.CrashReportCategory; import net.minecraft.text.Text;
import net.minecraft.util.ResourceLocation; import net.minecraft.text.TranslatableText;
import net.minecraft.util.text.*; import net.minecraft.util.Formatting;
import net.minecraftforge.common.MinecraftForge; import net.minecraft.util.Identifier;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.Mod.Instance;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.EventBus;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.apache.commons.io.FileUtils;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@Mod(modid = ReplayMod.MOD_ID, import static de.johni0702.minecraft.gui.versions.MCVer.identifier;
useMetadata = true,
version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*",
updateJSON = "https://raw.githubusercontent.com/ReplayMod/ReplayMod/master/versions.json",
guiFactory = "com.replaymod.core.gui.GuiFactory")
public class ReplayMod {
public static ModContainer getContainer() { //#if MC>=12006
return Loader.instance().getIndexedModList().get(MOD_ID); //$$ import net.minecraft.resource.ResourcePackInfo;
} //$$ import net.minecraft.resource.ResourcePackSource;
//$$ import net.minecraft.text.Text;
//$$ import java.util.Optional;
//#endif
@Getter(lazy = true) //#if MC>=11900
private static final String minecraftVersion = parseMinecraftVersion(); //#else
private static String parseMinecraftVersion() { import net.minecraft.client.options.Option;
CrashReport crashReport = new CrashReport("", new Throwable()); //#endif
@SuppressWarnings("unchecked")
List<CrashReportCategory.Entry> list = crashReport.getCategory().children; public class ReplayMod implements Module, Scheduler {
for (CrashReportCategory.Entry entry : list) {
if ("Minecraft Version".equals(entry.getKey())) {
return entry.getValue();
}
}
return "Unknown";
}
public static final String MOD_ID = "replaymod"; public static final String MOD_ID = "replaymod";
public static final ResourceLocation TEXTURE = new ResourceLocation("replaymod", "replay_gui.png"); public static final Identifier TEXTURE = identifier("replaymod", "replay_gui.png");
public static final int TEXTURE_SIZE = 256; public static final int TEXTURE_SIZE = 256;
public static final Identifier LOGO_FAVICON = identifier("replaymod", "favicon_logo.png");
private static final Minecraft mc = Minecraft.getMinecraft(); private static final MinecraftClient mc = MCVer.getMinecraft();
@Deprecated
public static Configuration config;
private final ReplayModBackend backend;
private final SchedulerImpl scheduler = new SchedulerImpl();
private final KeyBindingRegistry keyBindingRegistry = new KeyBindingRegistry(); private final KeyBindingRegistry keyBindingRegistry = new KeyBindingRegistry();
private final SettingsRegistry settingsRegistry = new SettingsRegistry(); private final SettingsRegistry settingsRegistry = new SettingsRegistry();
{
settingsRegistry.register(Setting.class);
}
// The instance of your mod that Forge uses. { instance = this; }
@Instance(MOD_ID)
public static ReplayMod instance; public static ReplayMod instance;
private final List<Module> modules = new ArrayList<>();
private final GuiBackgroundProcesses backgroundProcesses = new GuiBackgroundProcesses();
public final ReplayFoldersService folders = new ReplayFoldersService(settingsRegistry);
public final ReplayFilesService files = new ReplayFilesService(folders);
/**
* Whether the current MC version is supported by the embedded ReplayStudio version.
* If this is not the case (i.e. if this is variable true), any feature of the RM which depends on the ReplayStudio
* lib will be disabled.
*
* Only supported on Fabric builds, i.e. will always be false / crash the game with Forge/pre-1.14 builds.
* (specifically the code below and MCVer#getProtocolVersion make this assumption)
*/
private boolean minimalMode;
public ReplayMod(ReplayModBackend backend) {
this.backend = backend;
I18n.setI18n(net.minecraft.client.resource.language.I18n::translate);
// Check Minecraft protocol version for compatibility
if (!ProtocolVersion.isRegistered(MCVer.getProtocolVersion()) && !Boolean.parseBoolean(System.getProperty("replaymod.skipversioncheck", "false"))) {
minimalMode = true;
}
// Register all RM modules
modules.add(this);
modules.add(new ReplayModRecording(this));
ReplayModReplay replayModule = new ReplayModReplay(this);
modules.add(replayModule);
modules.add(new ReplayModRender(this));
modules.add(new ReplayModSimplePathing(this));
modules.add(new ReplayModEditor(this));
modules.add(new ReplayModExtras(this));
modules.add(new ReplayModCompat());
settingsRegistry.register();
}
public KeyBindingRegistry getKeyBindingRegistry() { public KeyBindingRegistry getKeyBindingRegistry() {
return keyBindingRegistry; return keyBindingRegistry;
} }
@@ -87,126 +119,133 @@ public class ReplayMod {
return settingsRegistry; return settingsRegistry;
} }
public File getReplayFolder() throws IOException { public static final DirectoryResourcePack jGuiResourcePack = createJGuiResourcePack();
String path = getSettingsRegistry().get(Setting.RECORDING_PATH); public static final String JGUI_RESOURCE_PACK_NAME = "replaymod_jgui";
File folder = new File(path.startsWith("./") ? getMinecraft().mcDataDir : null, path); private static DirectoryResourcePack createJGuiResourcePack() {
FileUtils.forceMkdir(folder); File folder = new File("../jGui/src/main/resources");
return folder; if (!folder.exists()) {
} folder = new File("../../../jGui/src/main/resources");
if (!folder.exists()) {
@EventHandler return null;
public void preInit(FMLPreInitializationEvent event) {
// Initialize the static OpenGL info field from the minecraft main thread
// Unfortunately lwjgl uses static methods so we have to make use of magic init calls as well
OpenGLUtils.init();
I18n.setI18n(net.minecraft.client.resources.I18n::format);
config = new Configuration(event.getSuggestedConfigurationFile());
config.load();
settingsRegistry.setConfiguration(config);
}
@EventHandler
public void init(FMLInitializationEvent event) {
getSettingsRegistry().register(Setting.class);
new MainMenuHandler().register();
MinecraftForge.EVENT_BUS.register(keyBindingRegistry);
getKeyBindingRegistry().registerKeyBinding("replaymod.input.settings", 0, () -> {
new GuiReplaySettings(null, settingsRegistry).display();
});
}
@EventHandler
public void postInit(FMLPostInitializationEvent event) throws IOException {
settingsRegistry.save(); // Save default values to disk
if(!FMLClientHandler.instance().hasOptifine())
GameSettings.Options.RENDER_DISTANCE.setValueMax(64f);
testIfMoeshAndExitMinecraft();
runLater(() -> {
// Cleanup deleted corrupted replays
try {
File[] files = getReplayFolder().listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory() && file.getName().endsWith(".mcpr.del")) {
if (file.lastModified() + 2 * 24 * 60 * 60 * 1000 < System.currentTimeMillis()) {
FileUtils.deleteDirectory(file);
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
} }
// Restore corrupted replays
try {
File[] files = getReplayFolder().listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory() && file.getName().endsWith(".mcpr.tmp")) {
File origFile = new File(file.getParentFile(), Files.getNameWithoutExtension(file.getName()));
new RestoreReplayGui(GuiScreen.wrap(mc.currentScreen), origFile).display();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
});
}
/**
* Set when the currently running code has been scheduled by runLater.
* If this is the case, subsequent calls to runLater have to be delayed until all scheduled tasks have been
* processed, otherwise a livelock may occur.
*/
private boolean inRunLater = false;
public void runLater(Runnable runnable) {
if (mc.isCallingFromMinecraftThread() && inRunLater) {
EventBus bus = MinecraftForge.EVENT_BUS;
bus.register(new Object() {
@SubscribeEvent
public void onRenderTick(TickEvent.RenderTickEvent event) {
if (event.phase == TickEvent.Phase.START) {
runLater(runnable);
bus.unregister(this);
}
}
});
return;
} }
synchronized (mc.scheduledTasks) { //#if MC>=12006
mc.scheduledTasks.add(ListenableFutureTask.create(() -> { //$$ return new DirectoryResourcePack(new ResourcePackInfo(JGUI_RESOURCE_PACK_NAME, Text.literal("jGui"), ResourcePackSource.NONE, Optional.empty()), folder.toPath()) {
inRunLater = true; //#elseif MC>=11903
//$$ return new DirectoryResourcePack(JGUI_RESOURCE_PACK_NAME, folder.toPath(), true) {
//#else
return new DirectoryResourcePack(folder) {
//#endif
@Override
//#if MC>=11400
public String getName() {
//#else
//$$ public String getPackName() {
//#endif
return JGUI_RESOURCE_PACK_NAME;
}
//#if MC>=11903
//$$ @Override
//$$ public net.minecraft.resource.InputSupplier<InputStream> openRoot(String... segments) {
//$$ if (segments.length == 1 && segments[0].equals("pack.mcmeta")) {
//$$ return () -> new ByteArrayInputStream(generatePackMeta());
//$$ }
//$$ return super.openRoot(segments);
//$$ }
//#else
@Override
protected InputStream openFile(String resourceName) throws IOException {
try { try {
runnable.run(); return super.openFile(resourceName);
} finally { } catch (IOException e) {
inRunLater = false; if ("pack.mcmeta".equals(resourceName)) {
return new ByteArrayInputStream(generatePackMeta());
}
throw e;
} }
}, null)); }
//#endif
private byte[] generatePackMeta() {
//#if MC>=11400
int version = 4;
//#else
//$$ int version = 1;
//#endif
return ("{\"pack\": {\"description\": \"dummy pack for jGui resources in dev-env\", \"pack_format\": "
+ version + "}}").getBytes(StandardCharsets.UTF_8);
}
};
}
void initModules() {
modules.forEach(Module::initCommon);
modules.forEach(Module::initClient);
modules.forEach(m -> m.registerKeyBindings(keyBindingRegistry));
}
@Override
public void registerKeyBindings(KeyBindingRegistry registry) {
registry.registerKeyBinding("replaymod.input.settings", 0, () -> {
new GuiReplaySettings(null, settingsRegistry).display();
}, false);
}
@Override
public void initClient() {
backgroundProcesses.register();
keyBindingRegistry.register();
// 1.7.10 crashes when render distance > 16
// Post 1.19 this has become non-trivial to do, install Sodium+Bobby or OptiFine if you need it
//#if MC>=10800 && MC<11900
if (!MCVer.hasOptifine()) {
Option.RENDER_DISTANCE.setMax(64f);
} }
//#endif
runPostStartup(() -> files.initialScan(this));
}
@Override
public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException {
scheduler.runSync(runnable);
}
@Override
public void runPostStartup(Runnable runnable) {
scheduler.runPostStartup(runnable);
}
@Override
public void runLaterWithoutLock(Runnable runnable) {
scheduler.runLaterWithoutLock(runnable);
}
@Override
public void runLater(Runnable runnable) {
scheduler.runLater(runnable);
}
@Override
public void runTasks() {
scheduler.runTasks();
} }
public String getVersion() { public String getVersion() {
return getContainer().getVersion(); return backend.getVersion();
} }
private void testIfMoeshAndExitMinecraft() { public String getMinecraftVersion() {
if("currentPlayer".equals("Moesh")) { return backend.getMinecraftVersion();
System.exit(-1);
}
} }
public Minecraft getMinecraft() { public boolean isModLoaded(String id) {
return backend.isModLoaded(id);
}
public MinecraftClient getMinecraft() {
return mc; return mc;
} }
@@ -219,18 +258,55 @@ public class ReplayMod {
} }
private void printToChat(boolean warning, String message, Object... args) { private void printToChat(boolean warning, String message, Object... args) {
if (!mc.isOnThread()) {
runLater(() -> printToChat(warning, message, args));
return;
}
if (getSettingsRegistry().get(Setting.NOTIFICATIONS)) { if (getSettingsRegistry().get(Setting.NOTIFICATIONS)) {
// Some nostalgia: "§8[§6Replay Mod§8]§r Your message goes here" // Some nostalgia: "§8[§6Replay Mod§8]§r Your message goes here"
Style coloredDarkGray = new Style().setColor(TextFormatting.DARK_GRAY); //#if MC>=10904
Style coloredGold = new Style().setColor(TextFormatting.GOLD); //#if MC>=11600
ITextComponent text = new TextComponentString("[").setStyle(coloredDarkGray) Style coloredDarkGray = Style.EMPTY.withColor(Formatting.DARK_GRAY);
.appendSibling(new TextComponentTranslation("replaymod.title").setStyle(coloredGold)) Style coloredGold = Style.EMPTY.withColor(Formatting.GOLD);
.appendSibling(new TextComponentString("] ")) Style alert = Style.EMPTY.withColor(warning ? Formatting.RED : Formatting.DARK_GREEN);
.appendSibling(new TextComponentTranslation(message, args).setStyle(new Style() //#else
.setColor(warning ? TextFormatting.RED : TextFormatting.DARK_GREEN))); //$$ Style coloredDarkGray = new Style().setColor(Formatting.DARK_GRAY);
//$$ Style coloredGold = new Style().setColor(Formatting.GOLD);
//$$ Style alert = new Style().setColor(warning ? Formatting.RED : Formatting.DARK_GREEN);
//#endif
Text text = new LiteralText("[").setStyle(coloredDarkGray)
.append(new TranslatableText("replaymod.title").setStyle(coloredGold))
.append(new LiteralText("] "))
.append(new TranslatableText(message, args).setStyle(alert));
//#else
//$$ ChatStyle coloredDarkGray = new ChatStyle().setColor(EnumChatFormatting.DARK_GRAY);
//$$ ChatStyle coloredGold = new ChatStyle().setColor(EnumChatFormatting.GOLD);
//$$ IChatComponent text = new ChatComponentText("[").setChatStyle(coloredDarkGray)
//$$ .appendSibling(new ChatComponentTranslation("replaymod.title").setChatStyle(coloredGold))
//$$ .appendSibling(new ChatComponentText("] "))
//$$ .appendSibling(new ChatComponentTranslation(message, args).setChatStyle(new ChatStyle()
//$$ .setColor(warning ? EnumChatFormatting.RED : EnumChatFormatting.DARK_GREEN)));
//#endif
// Send message to chat GUI // Send message to chat GUI
// The ingame GUI is initialized at startup, therefore this is possible before the client is connected // The ingame GUI is initialized at startup, therefore this is possible before the client is connected
mc.ingameGUI.getChatGUI().printChatMessage(text); mc.inGameHud.getChatHud().addMessage(text);
}
}
public GuiBackgroundProcesses getBackgroundProcesses() {
return backgroundProcesses;
}
// This method is static because it depends solely on the environment, not on the actual RM instance.
public static boolean isMinimalMode() {
return ReplayMod.instance.minimalMode;
}
public static boolean isCompatible(int fileFormatVersion, int protocolVersion) {
if (isMinimalMode()) {
return protocolVersion == MCVer.getProtocolVersion();
} else {
return new ReplayStudio().isCompatible(fileFormatVersion, protocolVersion, MCVer.getProtocolVersion());
} }
} }
} }

View File

@@ -0,0 +1,34 @@
package com.replaymod.core;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.SharedConstants;
import static com.replaymod.core.ReplayMod.MOD_ID;
public class ReplayModBackend implements ClientModInitializer {
private final ReplayMod mod = new ReplayMod(this);
@Override
public void onInitializeClient() {
mod.initModules();
}
public String getVersion() {
return FabricLoader.getInstance().getModContainer(MOD_ID)
.orElseThrow(IllegalStateException::new)
.getMetadata().getVersion().toString();
}
public String getMinecraftVersion() {
//#if MC>=12106
//$$ return SharedConstants.getGameVersion().comp_4025();
//#else
return SharedConstants.getGameVersion().getName();
//#endif
}
public boolean isModLoaded(String id) {
return FabricLoader.getInstance().isModLoaded(id.toLowerCase());
}
}

View File

@@ -0,0 +1,31 @@
//#if FABRIC>=1
package com.replaymod.core;
import org.spongepowered.asm.mixin.Mixins;
// We need to wait for MM to call us, otherwise we might initialize our mixins before it calls optifabric which would
// result in OF classes not existing while our mixins get resolved.
public class ReplayModMMLauncher implements Runnable {
private static boolean ran;
@Override
public void run() {
// If this is MM2, then we're currently getting called because of our entrypoint declaration.
// For backwards compatibility with MM1, we also declare our early_riser via custom metadata and MM2 supports
// that as well and will therefore call us twice.
if (ran) {
return;
}
ran = true;
Mixins.addConfiguration("mixins.compat.mapwriter.replaymod.json");
Mixins.addConfiguration("mixins.compat.shaders.replaymod.json");
Mixins.addConfiguration("mixins.core.replaymod.json");
Mixins.addConfiguration("mixins.extras.playeroverview.replaymod.json");
Mixins.addConfiguration("mixins.recording.replaymod.json");
Mixins.addConfiguration("mixins.render.blend.replaymod.json");
Mixins.addConfiguration("mixins.render.replaymod.json");
Mixins.addConfiguration("mixins.replay.replaymod.json");
}
}
//#endif

View File

@@ -0,0 +1,96 @@
package com.replaymod.core;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import java.io.IOException;
import java.util.List;
import java.util.Set;
//#if FABRIC
import net.fabricmc.loader.api.FabricLoader;
//#endif
//#if MC>=11400
import java.io.InputStream;
//#else
//$$ import net.minecraft.launchwrapper.Launch;
//#endif
//#if MC>=11200
import org.objectweb.asm.tree.ClassNode;
//#else
//$$ import org.spongepowered.asm.lib.tree.ClassNode;
//#endif
public class ReplayModMixinConfigPlugin implements IMixinConfigPlugin {
static boolean hasClass(String name) throws IOException {
//#if MC>=11400
InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(name.replace('.', '/') + ".class");
if (stream != null) stream.close();
return stream != null;
//#else
//$$ return Launch.classLoader.getClassBytes(name) != null;
//#endif
}
private final Logger logger = LogManager.getLogger("replaymod/mixin");
private final boolean hasOF = hasClass("optifine.OptiFineForgeTweaker") || hasClass("me.modmuss50.optifabric.mod.Optifabric");
//#if FABRIC
private final boolean hasIris = FabricLoader.getInstance().isModLoaded("iris");
//#endif
{
logger.debug("hasOF: " + hasOF);
}
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
if (hasOF) {
//#if MC>=11500
// OF renames the lambda method name and I see no way we can target it now, so we give up on that patch
if (mixinClassName.endsWith("MixinTileEntityEndPortalRenderer")) return false;
//#endif
}
if (mixinClassName.endsWith("_OF")) return hasOF;
if (mixinClassName.endsWith("_NoOF")) return !hasOF;
//#if FABRIC
if (mixinClassName.endsWith("_Iris")) return hasIris;
//#endif
return true;
}
@Override
public void onLoad(String mixinPackage) {
}
@Override
public String getRefMapperConfig() {
return null;
}
@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
}
@Override
public List<String> getMixins() {
return null;
}
@Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
@Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
public ReplayModMixinConfigPlugin() throws IOException {
}
}

View File

@@ -0,0 +1,62 @@
//#if FABRIC>=1
package com.replaymod.core;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import java.io.IOException;
import java.util.List;
import java.util.Set;
// See ReplayModMMLauncher. This is the fallback if MM is not installed.
public class ReplayModNonMMLauncher implements IMixinConfigPlugin {
private final Logger logger = LogManager.getLogger("replaymod/nonmm");
@Override
public void onLoad(String mixinPackage) {
}
@Override
public String getRefMapperConfig() {
return null;
}
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
return false;
}
@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
}
@Override
public List<String> getMixins() {
try {
if (ReplayModMixinConfigPlugin.hasClass("com.chocohead.mm.Plugin")) {
logger.debug("Detected MM, they should call us...");
} else {
logger.debug("Did not detect MM, initializing ourselves...");
new ReplayModMMLauncher().run();
}
return null;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
@Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
}
//#endif

View File

@@ -3,6 +3,7 @@ package com.replaymod.core;
public final class Setting<T> extends SettingsRegistry.SettingKeys<T> { public final class Setting<T> extends SettingsRegistry.SettingKeys<T> {
public static final Setting<Boolean> NOTIFICATIONS = make("notifications", "notifications", true); public static final Setting<Boolean> NOTIFICATIONS = make("notifications", "notifications", true);
public static final Setting<String> RECORDING_PATH = advanced("recordingPath", null, "./replay_recordings/"); public static final Setting<String> RECORDING_PATH = advanced("recordingPath", null, "./replay_recordings/");
public static final Setting<String> CACHE_PATH = advanced("cachePath", null, "./.replay_cache/");
private static <T> Setting<T> make(String key, String displayName, T defaultValue) { private static <T> Setting<T> make(String key, String displayName, T defaultValue) {
return new Setting<>("core", key, displayName, defaultValue); return new Setting<>("core", key, displayName, defaultValue);

View File

@@ -1,28 +1,17 @@
package com.replaymod.core; package com.replaymod.core;
import com.replaymod.core.events.SettingsChangedEvent; import com.replaymod.core.events.SettingsChangedCallback;
import net.minecraft.client.resources.I18n;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.config.Configuration;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class SettingsRegistry { public class SettingsRegistry {
private static final Object NULL_OBJECT = new Object(); private final Map<SettingKey<?>, Object> settings = Collections.synchronizedMap(new LinkedHashMap<>());
private Map<SettingKey<?>, Object> settings = new ConcurrentHashMap<>(); final SettingsRegistryBackend backend = new SettingsRegistryBackend(settings);
private Configuration configuration;
public void setConfiguration(Configuration configuration) { public void register() {
this.configuration = configuration; backend.register();
List<SettingKey<?>> keys = new ArrayList<>(settings.keySet());
settings.clear();
for (SettingKey key : keys) {
register(key);
}
} }
public void register(Class<?> settingsClass) { public void register(Class<?> settingsClass) {
@@ -39,23 +28,8 @@ public class SettingsRegistry {
} }
public void register(SettingKey<?> key) { public void register(SettingKey<?> key) {
Object value; settings.put(key, key.getDefault());
if (configuration != null) { backend.register(key);
if (key.getDefault() instanceof Boolean) {
value = configuration.get(key.getCategory(), key.getKey(), (Boolean) key.getDefault()).getBoolean();
} else if (key.getDefault() instanceof Integer) {
value = configuration.get(key.getCategory(), key.getKey(), (Integer) key.getDefault()).getInt();
} else if (key.getDefault() instanceof Double) {
value = configuration.get(key.getCategory(), key.getKey(), (Double) key.getDefault()).getDouble();
} else if (key.getDefault() instanceof String) {
value = configuration.get(key.getCategory(), key.getKey(), (String) key.getDefault()).getString();
} else {
throw new IllegalArgumentException("Default type " + key.getDefault().getClass() + " not supported.");
}
} else {
value = NULL_OBJECT;
}
settings.put(key, value);
} }
public Set<SettingKey<?>> getSettings() { public Set<SettingKey<?>> getSettings() {
@@ -71,23 +45,13 @@ public class SettingsRegistry {
} }
public <T> void set(SettingKey<T> key, T value) { public <T> void set(SettingKey<T> key, T value) {
if (key.getDefault() instanceof Boolean) { backend.update(key, value);
configuration.get(key.getCategory(), key.getKey(), (Boolean) key.getDefault()).set((Boolean) value);
} else if (key.getDefault() instanceof Integer) {
configuration.get(key.getCategory(), key.getKey(), (Integer) key.getDefault()).set((Integer) value);
} else if (key.getDefault() instanceof Double) {
configuration.get(key.getCategory(), key.getKey(), (Double) key.getDefault()).set((Double) value);
} else if (key.getDefault() instanceof String) {
configuration.get(key.getCategory(), key.getKey(), (String) key.getDefault()).set((String) value);
} else {
throw new IllegalArgumentException("Default type " + key.getDefault().getClass() + " not supported.");
}
settings.put(key, value); settings.put(key, value);
MinecraftForge.EVENT_BUS.post(new SettingsChangedEvent(this, key)); SettingsChangedCallback.EVENT.invoker().onSettingsChanged(this, key);
} }
public void save() { public void save() {
configuration.save(); backend.save();
} }
public interface SettingKey<T> { public interface SettingKey<T> {
@@ -126,7 +90,7 @@ public class SettingsRegistry {
@Override @Override
public String getDisplayString() { public String getDisplayString() {
return displayString == null ? null : I18n.format(displayString); return displayString;
} }
@Override @Override

View File

@@ -0,0 +1,189 @@
package com.replaymod.core;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.replaymod.core.events.SettingsChangedCallback;
import net.minecraft.client.MinecraftClient;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.List;
import java.util.Map;
import static com.replaymod.core.utils.Utils.ensureDirectoryExists;
import static com.replaymod.core.versions.MCVer.getMinecraft;
class SettingsRegistryBackend {
private static final Logger LOGGER = LogManager.getLogger();
private final Map<SettingsRegistry.SettingKey<?>, Object> settings;
private final Path configFile = getMinecraft().runDirectory.toPath().resolve("config/replaymod.json");
SettingsRegistryBackend(Map<SettingsRegistry.SettingKey<?>, Object> settings) {
this.settings = settings;
}
public void register() {
load(true);
try {
registerWatcher();
} catch (IOException e) {
LOGGER.warn("Failed to setup file watcher for {}, live-reloading is disabled. Cause: {}", configFile, e);
}
}
private void load(boolean createIfMissingOrBroken) {
String config;
if (Files.exists(configFile)) {
try {
config = new String(Files.readAllBytes(configFile), StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
return;
}
} else {
if (createIfMissingOrBroken) {
save();
}
return;
}
Gson gson = new Gson();
JsonObject root = gson.fromJson(config, JsonObject.class);
if (root == null) {
LOGGER.error("Config file {} appears corrupted: {}", configFile, config);
if (createIfMissingOrBroken) {
save();
}
return;
}
for (Map.Entry<SettingsRegistry.SettingKey<?>, Object> entry : settings.entrySet()) {
SettingsRegistry.SettingKey<?> key = entry.getKey();
JsonElement category = root.get(key.getCategory());
if (category != null && category.isJsonObject()) {
JsonElement valueElem = category.getAsJsonObject().get(key.getKey());
if (valueElem == null || !valueElem.isJsonPrimitive()) continue;
JsonPrimitive value = valueElem.getAsJsonPrimitive();
if (key.getDefault() instanceof Boolean && value.isBoolean()) {
entry.setValue(value.getAsBoolean());
}
if (key.getDefault() instanceof Integer && value.isNumber()) {
entry.setValue(value.getAsNumber().intValue());
}
if (key.getDefault() instanceof Double && value.isNumber()) {
entry.setValue(value.getAsNumber().doubleValue());
}
if (key.getDefault() instanceof String && value.isString()) {
String valueStr = value.getAsString();
if (entry instanceof SettingsRegistry.MultipleChoiceSettingKey) {
@SuppressWarnings("unchecked")
List<String> choices = ((SettingsRegistry.MultipleChoiceSettingKey<String>) entry).getChoices();
if (choices.stream().noneMatch(valueStr::equals)) {
continue;
}
}
entry.setValue(valueStr);
}
}
}
}
private void registerWatcher() throws IOException {
WatchService watchService = configFile.getFileSystem().newWatchService();
configFile.getParent().register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY);
Thread thread = new Thread(() -> {
while (true) {
WatchKey nextKey;
try {
nextKey = watchService.take();
} catch (InterruptedException e) {
return;
}
for (WatchEvent<?> event : nextKey.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
continue;
}
Path fileName = ((Path) event.context());
if (fileName.equals(configFile.getFileName())) {
MinecraftClient.getInstance().send(this::reload);
}
}
if (!nextKey.reset()) {
return;
}
}
});
thread.setName("replaymod-config-watcher");
thread.setDaemon(true);
thread.start();
}
private void reload() {
load(false);
SettingsRegistry settingsRegistry = ReplayMod.instance.getSettingsRegistry();
for (SettingsRegistry.SettingKey<?> key : settings.keySet()) {
SettingsChangedCallback.EVENT.invoker().onSettingsChanged(settingsRegistry, key);
}
}
@SuppressWarnings("unused")
public void register(SettingsRegistry.SettingKey<?> key) {
}
@SuppressWarnings("unused")
public <T> void update(SettingsRegistry.SettingKey<T> key, T value) {
}
public void save() {
JsonObject root = new JsonObject();
for (Map.Entry<SettingsRegistry.SettingKey<?>, Object> entry : settings.entrySet()) {
SettingsRegistry.SettingKey<?> key = entry.getKey();
JsonObject category = root.getAsJsonObject(key.getCategory());
if (category == null) {
category = new JsonObject();
root.add(key.getCategory(), category);
}
Object value = entry.getValue();
if (value instanceof Boolean) {
category.addProperty(key.getKey(), (Boolean) value);
}
if (value instanceof Number) {
category.addProperty(key.getKey(), (Number) value);
}
if (value instanceof String) {
category.addProperty(key.getKey(), (String) value);
if (key instanceof SettingsRegistry.MultipleChoiceSettingKey) {
@SuppressWarnings("unchecked")
List<String> choices = ((SettingsRegistry.MultipleChoiceSettingKey<String>) key).getChoices();
JsonArray array = new JsonArray();
for (String choice : choices) {
array.add(choice);
}
category.add(key.getKey() + "_valid_values", array);
}
}
}
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String config = gson.toJson(root);
try {
ensureDirectoryExists(configFile.getParent());
Files.write(configFile, config.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1 @@
// 1.7.10 and below

View File

@@ -0,0 +1 @@
// 1.7.10 and below

View File

@@ -0,0 +1,15 @@
package com.replaymod.core.events;
import de.johni0702.minecraft.gui.utils.Event;
public interface KeyBindingEventCallback {
Event<KeyBindingEventCallback> EVENT = Event.create((listeners) ->
() -> {
for (KeyBindingEventCallback listener : listeners) {
listener.onKeybindingEvent();
}
}
);
void onKeybindingEvent();
}

View File

@@ -0,0 +1,27 @@
package com.replaymod.core.events;
import de.johni0702.minecraft.gui.function.KeyInput;
import de.johni0702.minecraft.gui.utils.Event;
public interface KeyEventCallback {
Event<KeyEventCallback> EVENT = Event.create((listeners) ->
(keyInput, action) -> {
for (KeyEventCallback listener : listeners) {
if (listener.onKeyEvent(keyInput, action)) {
return true;
}
}
return false;
}
);
//#if MC>=11400
int ACTION_RELEASE = org.lwjgl.glfw.GLFW.GLFW_RELEASE;
int ACTION_PRESS = org.lwjgl.glfw.GLFW.GLFW_PRESS;
//#else
//$$ int ACTION_RELEASE = 0;
//$$ int ACTION_PRESS = 1;
//#endif
boolean onKeyEvent(KeyInput keyInput, int action);
}

View File

@@ -0,0 +1,15 @@
package com.replaymod.core.events;
import de.johni0702.minecraft.gui.utils.Event;
public interface PostRenderCallback {
Event<PostRenderCallback> EVENT = Event.create((listeners) ->
() -> {
for (PostRenderCallback listener : listeners) {
listener.postRender();
}
}
);
void postRender();
}

View File

@@ -0,0 +1,16 @@
package com.replaymod.core.events;
import de.johni0702.minecraft.gui.utils.Event;
import net.minecraft.client.util.math.MatrixStack;
public interface PostRenderWorldCallback {
Event<PostRenderWorldCallback> EVENT = Event.create((listeners) ->
(MatrixStack matrixStack) -> {
for (PostRenderWorldCallback listener : listeners) {
listener.postRenderWorld(matrixStack);
}
}
);
void postRenderWorld(MatrixStack matrixStack);
}

View File

@@ -0,0 +1,15 @@
package com.replaymod.core.events;
import de.johni0702.minecraft.gui.utils.Event;
public interface PreRenderCallback {
Event<PreRenderCallback> EVENT = Event.create((listeners) ->
() -> {
for (PreRenderCallback listener : listeners) {
listener.preRender();
}
}
);
void preRender();
}

View File

@@ -0,0 +1,18 @@
package com.replaymod.core.events;
import de.johni0702.minecraft.gui.utils.Event;
public interface PreRenderHandCallback {
Event<PreRenderHandCallback> EVENT = Event.create((listeners) ->
() -> {
for (PreRenderHandCallback listener : listeners) {
if (listener.preRenderHand()) {
return true;
}
}
return false;
}
);
boolean preRenderHand();
}

View File

@@ -0,0 +1,16 @@
package com.replaymod.core.events;
import com.replaymod.core.SettingsRegistry;
import de.johni0702.minecraft.gui.utils.Event;
public interface SettingsChangedCallback {
Event<SettingsChangedCallback> EVENT = Event.create((listeners) ->
(registry, key) -> {
for (SettingsChangedCallback listener : listeners) {
listener.onSettingsChanged(registry, key);
}
}
);
void onSettingsChanged(SettingsRegistry registry, SettingsRegistry.SettingKey<?> key);
}

View File

@@ -1,15 +0,0 @@
package com.replaymod.core.events;
import com.replaymod.core.SettingsRegistry;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.minecraftforge.fml.common.eventhandler.Event;
@RequiredArgsConstructor
public class SettingsChangedEvent extends Event {
@Getter
private final SettingsRegistry settingsRegistry;
@Getter
private final SettingsRegistry.SettingKey<?> key;
}

View File

@@ -0,0 +1,202 @@
package com.replaymod.core.files;
import com.replaymod.replaystudio.data.Marker;
import com.replaymod.replaystudio.data.ModInfo;
import com.replaymod.replaystudio.data.ReplayAssetEntry;
import com.replaymod.replaystudio.io.ReplayInputStream;
import com.replaymod.replaystudio.io.ReplayOutputStream;
import com.replaymod.replaystudio.lib.guava.base.Optional;
import com.replaymod.replaystudio.pathing.PathingRegistry;
import com.replaymod.replaystudio.pathing.path.Timeline;
import com.replaymod.replaystudio.protocol.PacketTypeRegistry;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ReplayMetaData;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;
public class DelegatingReplayFile implements ReplayFile {
private final ReplayFile delegate;
public DelegatingReplayFile(ReplayFile delegate) {
this.delegate = delegate;
}
@Override
public Optional<InputStream> get(String entry) throws IOException {
return this.delegate.get(entry);
}
@Override
public Optional<InputStream> getCache(String entry) throws IOException {
return this.delegate.getCache(entry);
}
@Override
public Map<String, InputStream> getAll(Pattern pattern) throws IOException {
return this.delegate.getAll(pattern);
}
@Override
public OutputStream write(String entry) throws IOException {
return this.delegate.write(entry);
}
@Override
public OutputStream writeCache(String entry) throws IOException {
return this.delegate.writeCache(entry);
}
@Override
public void remove(String entry) throws IOException {
this.delegate.remove(entry);
}
@Override
public void removeCache(String entry) throws IOException {
this.delegate.removeCache(entry);
}
@Override
public void save() throws IOException {
this.delegate.save();
}
@Override
public void saveTo(File target) throws IOException {
this.delegate.saveTo(target);
}
@Override
public ReplayMetaData getMetaData() throws IOException {
return this.delegate.getMetaData();
}
@Override
public void writeMetaData(PacketTypeRegistry registry, ReplayMetaData metaData) throws IOException {
this.delegate.writeMetaData(registry, metaData);
}
@Override
public ReplayInputStream getPacketData(PacketTypeRegistry registry) throws IOException {
return this.delegate.getPacketData(registry);
}
@Override
public ReplayOutputStream writePacketData() throws IOException {
return this.delegate.writePacketData();
}
@Override
public Map<Integer, String> getResourcePackIndex() throws IOException {
return this.delegate.getResourcePackIndex();
}
@Override
public void writeResourcePackIndex(Map<Integer, String> index) throws IOException {
this.delegate.writeResourcePackIndex(index);
}
@Override
public Optional<InputStream> getResourcePack(String hash) throws IOException {
return this.delegate.getResourcePack(hash);
}
@Override
public OutputStream writeResourcePack(String hash) throws IOException {
return this.delegate.writeResourcePack(hash);
}
@Override
public Map<String, Timeline> getTimelines(PathingRegistry pathingRegistry) throws IOException {
return this.delegate.getTimelines(pathingRegistry);
}
@Override
public void writeTimelines(PathingRegistry pathingRegistry, Map<String, Timeline> timelines) throws IOException {
this.delegate.writeTimelines(pathingRegistry, timelines);
}
@Override
public Optional<BufferedImage> getThumb() throws IOException {
return this.delegate.getThumb();
}
@Override
public void writeThumb(BufferedImage image) throws IOException {
this.delegate.writeThumb(image);
}
@Override
public Optional<InputStream> getThumbBytes() throws IOException {
return this.delegate.getThumbBytes();
}
@Override
public void writeThumbBytes(byte[] image) throws IOException {
this.delegate.writeThumbBytes(image);
}
@Override
public Optional<Set<UUID>> getInvisiblePlayers() throws IOException {
return this.delegate.getInvisiblePlayers();
}
@Override
public void writeInvisiblePlayers(Set<UUID> uuids) throws IOException {
this.delegate.writeInvisiblePlayers(uuids);
}
@Override
public Optional<Set<Marker>> getMarkers() throws IOException {
return this.delegate.getMarkers();
}
@Override
public void writeMarkers(Set<Marker> markers) throws IOException {
this.delegate.writeMarkers(markers);
}
@Override
public Collection<ReplayAssetEntry> getAssets() throws IOException {
return this.delegate.getAssets();
}
@Override
public Optional<InputStream> getAsset(UUID uuid) throws IOException {
return this.delegate.getAsset(uuid);
}
@Override
public OutputStream writeAsset(ReplayAssetEntry asset) throws IOException {
return this.delegate.writeAsset(asset);
}
@Override
public void removeAsset(UUID uuid) throws IOException {
this.delegate.removeAsset(uuid);
}
@Override
public Collection<ModInfo> getModInfo() throws IOException {
return this.delegate.getModInfo();
}
@Override
public void writeModInfo(Collection<ModInfo> modInfo) throws IOException {
this.delegate.writeModInfo(modInfo);
}
@Override
public void close() throws IOException {
this.delegate.close();
}
}

View File

@@ -0,0 +1,23 @@
package com.replaymod.core.files;
import com.replaymod.replaystudio.replay.ReplayFile;
import java.io.IOException;
public class ManagedReplayFile extends DelegatingReplayFile {
private Runnable onClose;
public ManagedReplayFile(ReplayFile delegate, Runnable onClose) {
super(delegate);
this.onClose = onClose;
}
@Override
public void close() throws IOException {
super.close();
onClose.run();
onClose = () -> {};
}
}

View File

@@ -0,0 +1,192 @@
package com.replaymod.core.files;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.gui.RestoreReplayGui;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import de.johni0702.minecraft.gui.container.GuiScreen;
import net.minecraft.util.Util;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class ReplayFilesService {
private final ReplayFoldersService folders;
private final Set<Path> lockedPaths = Collections.newSetFromMap(new ConcurrentHashMap<>());
public ReplayFilesService(ReplayFoldersService folders) {
this.folders = folders;
}
public ReplayFile open(Path path) throws IOException {
return open(path, path);
}
public ReplayFile open(Path input, Path output) throws IOException {
Path realInput = input != null ? input.toAbsolutePath().normalize() : null;
Path realOutput = output.toAbsolutePath().normalize();
if (realInput != null && !lockedPaths.add(realInput)) {
throw new FileLockedException(realInput);
}
if (!Objects.equals(realInput, realOutput) && !lockedPaths.add(realOutput)) {
if (realInput != null) {
lockedPaths.remove(realInput);
}
throw new FileLockedException(realOutput);
}
Runnable onClose = () -> {
if (realInput != null) {
lockedPaths.remove(realInput);
}
lockedPaths.remove(realOutput);
};
ReplayFile replayFile;
try {
replayFile = new ZipReplayFile(
new ReplayStudio(),
realInput != null ? realInput.toFile() : null,
realOutput.toFile(),
folders.getCachePathForReplay(realOutput).toFile()
);
} catch (IOException e) {
onClose.run();
throw e;
}
return new ManagedReplayFile(replayFile, onClose);
}
public void initialScan(ReplayMod core) {
// Move anything which is still in the recording folder into the regular replay folder
// so it can be opened and/or recovered
try (DirectoryStream<Path> paths = Files.newDirectoryStream(folders.getRecordingFolder())) {
for (Path path : paths) {
Path destination = folders.getReplayFolder().resolve(path.getFileName());
if (Files.exists(destination)) {
continue; // better play it save
}
Files.move(path, destination);
}
} catch (IOException e) {
e.printStackTrace();
}
// Restore corrupted replays
try (DirectoryStream<Path> paths = Files.newDirectoryStream(folders.getReplayFolder())) {
for (Path path : paths) {
String name = path.getFileName().toString();
if (name.endsWith(".mcpr.tmp") && Files.isDirectory(path)) {
Path original = path.resolveSibling(FilenameUtils.getBaseName(name));
Path noRecoverMarker = original.resolveSibling(original.getFileName() + ".no_recover");
if (Files.exists(noRecoverMarker)) {
// This file, when its markers are processed, doesn't actually result in any replays.
// So we don't really need to recover it either, let's just get rid of it.
FileUtils.deleteDirectory(path.toFile());
Files.delete(noRecoverMarker);
continue;
}
new RestoreReplayGui(core, GuiScreen.wrap(core.getMinecraft().currentScreen), original.toFile()).display();
}
}
} catch (IOException e) {
e.printStackTrace();
}
// Run general purpose, non-essential cleanup in a background thread
new Thread(this::cleanup, "replaymod-cleanup").start();
}
private void cleanup() {
final long DAYS = 24 * 60 * 60 * 1000;
// Cleanup any cache folders still remaining in the recording folder (we once used to put them there)
try {
Files.walkFileTree(folders.getReplayFolder(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
String name = dir.getFileName().toString();
if (name.endsWith(".mcpr.cache")) {
FileUtils.deleteDirectory(dir.toFile());
return FileVisitResult.SKIP_SUBTREE;
}
return super.preVisitDirectory(dir, attrs);
}
});
} catch (IOException e) {
e.printStackTrace();
}
// Cleanup raw folder content three weeks after creation (these are pretty valuable for debugging)
try (DirectoryStream<Path> paths = Files.newDirectoryStream(folders.getRawReplayFolder())) {
for (Path path : paths) {
if (Files.getLastModifiedTime(path).toMillis() + 21 * DAYS < System.currentTimeMillis()) {
Files.delete(path);
}
}
} catch (IOException e) {
e.printStackTrace();
}
// Cleanup cache folders 7 days after last modification or when its replay is gone
try (DirectoryStream<Path> paths = Files.newDirectoryStream(folders.getCacheFolder())) {
for (Path path : paths) {
if (Files.isDirectory(path)) {
Path replay = folders.getReplayPathForCache(path);
long lastModified = Files.getLastModifiedTime(path).toMillis();
if (lastModified + 7 * DAYS < System.currentTimeMillis() || !Files.exists(replay)) {
FileUtils.deleteDirectory(path.toFile());
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
// Cleanup deleted corrupted replays
try (DirectoryStream<Path> paths = Files.newDirectoryStream(folders.getReplayFolder())) {
for (Path path : paths) {
String name = path.getFileName().toString();
if (name.endsWith(".mcpr.del") && Files.isDirectory(path)) {
long lastModified = Files.getLastModifiedTime(path).toMillis();
if (lastModified + 2 * DAYS < System.currentTimeMillis()) {
FileUtils.deleteDirectory(path.toFile());
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
// Cleanup leftover no_recover files
try (DirectoryStream<Path> paths = Files.newDirectoryStream(folders.getReplayFolder())) {
for (Path path : paths) {
String name = path.getFileName().toString();
if (name.endsWith(".no_recover")) {
Files.delete(path);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static class FileLockedException extends IOException {
public FileLockedException(Path path) {
super(path.toString());
}
}
}

View File

@@ -0,0 +1,71 @@
package com.replaymod.core.files;
import com.google.common.net.PercentEscaper;
import com.replaymod.core.Setting;
import com.replaymod.core.SettingsRegistry;
import net.minecraft.client.MinecraftClient;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import static com.replaymod.core.utils.Utils.ensureDirectoryExists;
public class ReplayFoldersService {
private final Path mcDir = MinecraftClient.getInstance().runDirectory.toPath();
private final SettingsRegistry settings;
public ReplayFoldersService(SettingsRegistry settings) {
this.settings = settings;
}
public Path getReplayFolder() throws IOException {
return ensureDirectoryExists(mcDir.resolve(settings.get(Setting.RECORDING_PATH)));
}
/**
* Folder into which replay backups are saved before the MarkerProcessor is unleashed.
*/
public Path getRawReplayFolder() throws IOException {
return ensureDirectoryExists(getReplayFolder().resolve("raw"));
}
/**
* Folder into which replays are recorded.
* Distinct from the main folder, so they cannot be opened while they are still saving.
*/
public Path getRecordingFolder() throws IOException {
return ensureDirectoryExists(getReplayFolder().resolve("recording"));
}
/**
* Folder in which replay cache files are stored.
* Distinct from the recording folder cause people kept confusing them with recordings.
*/
public Path getCacheFolder() throws IOException {
Path path = ensureDirectoryExists(mcDir.resolve(settings.get(Setting.CACHE_PATH)));
try {
Files.setAttribute(path, "dos:hidden", true);
} catch (UnsupportedOperationException ignored) {
} catch (Exception e) {
e.printStackTrace();
}
return path;
}
private static final PercentEscaper CACHE_FILE_NAME_ENCODER = new PercentEscaper("-_ ", false);
public Path getCachePathForReplay(Path replay) throws IOException {
Path replayFolder = getReplayFolder();
Path cacheFolder = getCacheFolder();
Path relative = replayFolder.toAbsolutePath().relativize(replay.toAbsolutePath());
return cacheFolder.resolve(CACHE_FILE_NAME_ENCODER.escape(relative.toString()));
}
public Path getReplayPathForCache(Path cache) throws IOException {
String relative = URLDecoder.decode(cache.getFileName().toString(), "UTF-8");
Path replayFolder = getReplayFolder();
return replayFolder.resolve(relative);
}
}

View File

@@ -0,0 +1,135 @@
package com.replaymod.core.gui;
import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.container.AbstractGuiContainer;
import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.container.GuiScreen;
import de.johni0702.minecraft.gui.container.VanillaGuiScreen;
import de.johni0702.minecraft.gui.element.GuiElement;
import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.utils.EventRegistrations;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback;
import static com.replaymod.core.versions.MCVer.getMinecraft;
public class GuiBackgroundProcesses extends EventRegistrations {
private GuiPanel panel = new GuiPanel().setLayout(new VerticalLayout().setSpacing(10));
private boolean reentrant;
{ on(InitScreenCallback.EVENT, (screen, buttons) -> onGuiInit(screen)); }
private void onGuiInit(net.minecraft.client.gui.screen.Screen guiScreen) {
if (guiScreen != getMinecraft().currentScreen) return; // people tend to construct GuiScreens without opening them
VanillaGuiScreen vanillaGui;
// TODO Workaround for #473 and #501 where another mod opens a new gui in response to the MCGuiScreen.init we
// call from VanillaGuiScreen.register.
// Ideally, we don't have an hidden inner MCGuiScreen and instead have a common parent class for
// AbstractGuiScreen, AbstractGuiOverlay and VanillaGuiScreen which deals with the common things. That's
// quite a bit of changes though, so I'll keep that for 2.7 and have this workaround until then.
if (reentrant) return;
try {
reentrant = true;
vanillaGui = VanillaGuiScreen.wrap(guiScreen);
} finally {
reentrant = false;
}
vanillaGui.setLayout(new CustomLayout<GuiScreen>(vanillaGui.getLayout()) {
@Override
protected void layout(GuiScreen container, int width, int height) {
pos(panel, width - 5 - width(panel), 5);
}
}).addElements(null, panel);
}
public void addProcess(GuiElement<?> element) {
panel.addElements(new VerticalLayout.Data(1.0),
new Element(element));
}
public void removeProcess(GuiElement<?> element) {
for (GuiElement child : panel.getChildren()) {
if (((Element) child).inner == element) {
panel.removeElement(child);
return;
}
}
}
private static class Element extends AbstractGuiContainer<Element> {
private GuiElement inner;
Element(GuiElement inner) {
this.inner = inner;
addElements(null, inner);
setLayout(new CustomLayout<Element>() {
@Override
protected void layout(Element container, int width, int height) {
pos(inner, 10, 10);
size(inner, width - 20, height - 20);
}
});
}
@Override
public int getLayer() {
return 1;
}
@Override
public ReadableDimension getMinSize() {
ReadableDimension minSize = inner.getMinSize();
return new Dimension(minSize.getWidth() + 20, minSize.getHeight() + 20);
}
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
final int u0 = 0;
final int v0 = 39;
renderer.bindTexture(TEXTURE);
int w = size.getWidth();
int h = size.getHeight();
// Corners
renderer.drawTexturedRect(0, 0, u0, v0, 5, 5); // Top left
renderer.drawTexturedRect(w - 5, 0, u0 + 12, v0, 5, 5); // Top right
renderer.drawTexturedRect(0, h - 5, u0, v0 + 12, 5, 5); // Bottom left
renderer.drawTexturedRect(w - 5, h - 5, u0 + 12, v0 + 12, 5, 5); // Bottom right
// Top and bottom edge
for (int x = 5; x < w - 5; x += 5) {
int rx = Math.min(5, w - 5 - x);
renderer.drawTexturedRect(x, 0, u0 + 6, v0, rx, 5); // Top
renderer.drawTexturedRect(x, h - 5, u0 + 6, v0 + 12, rx, 5); // Bottom
}
// Left and right edge
for (int y = 5; y < h - 5; y += 5) {
int ry = Math.min(5, h - 5 - y);
renderer.drawTexturedRect(0, y, u0, v0 + 6, 5, ry); // Left
renderer.drawTexturedRect(w - 5, y, u0 + 12, v0 + 6, 5, ry); // Right
}
// Center
for (int x = 5; x < w - 5; x += 5) {
for (int y = 5; y < h - 5; y += 5) {
int rx = Math.min(5, w - 5 - x);
int ry = Math.min(5, h - 5 - y);
renderer.drawTexturedRect(x, y, u0 + 6, v0 + 6, rx, ry);
}
}
super.draw(renderer, size, renderInfo);
}
@Override
protected Element getThis() {
return this;
}
}
}

View File

@@ -1,31 +1 @@
package com.replaymod.core.gui; // 1.12.2 and below
import com.replaymod.core.ReplayMod;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.client.IModGuiFactory;
import java.util.Set;
@SuppressWarnings("unused")
public class GuiFactory implements IModGuiFactory {
@Override
public void initialize(Minecraft minecraftInstance) {
}
@Override
public boolean hasConfigGui() {
return true;
}
@Override
public GuiScreen createConfigGui(GuiScreen parentScreen) {
return new GuiReplaySettings(parentScreen, ReplayMod.instance.getSettingsRegistry()).toMinecraft();
}
@Override
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories() {
return null;
}
}

View File

@@ -0,0 +1,21 @@
package com.replaymod.core.gui;
import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.element.GuiButton;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.util.Identifier;
import static de.johni0702.minecraft.gui.versions.MCVer.identifier;
public class GuiReplayButton extends GuiButton {
public static final Identifier ICON = identifier("replaymod", "logo_button.png");
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
super.draw(renderer, size, renderInfo);
renderer.bindTexture(ICON);
renderer.drawTexturedRect(3, 3, 0, 0, size.getWidth() - 6, size.getHeight() - 6, 1, 1, 1, 1);
}
}

View File

@@ -12,18 +12,19 @@ import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout; import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.utils.Consumer; import de.johni0702.minecraft.gui.utils.Consumer;
import lombok.RequiredArgsConstructor; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import net.minecraft.client.resources.I18n; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.client.resource.language.I18n;
import java.util.List; import java.util.List;
public class GuiReplaySettings extends AbstractGuiScreen<GuiReplaySettings> { public class GuiReplaySettings extends AbstractGuiScreen<GuiReplaySettings> {
public GuiReplaySettings(final net.minecraft.client.gui.GuiScreen parent, final SettingsRegistry settingsRegistry) { public GuiReplaySettings(final net.minecraft.client.gui.screen.Screen parent, final SettingsRegistry settingsRegistry) {
final GuiButton doneButton = new GuiButton(this).setI18nLabel("gui.done").setSize(200, 20).onClick(new Runnable() { final GuiButton doneButton = new GuiButton(this).setI18nLabel("gui.done").setSize(200, 20).onClick(new Runnable() {
@Override @Override
public void run() { public void run() {
getMinecraft().displayGuiScreen(parent); getMinecraft().openScreen(parent);
} }
}); });
@@ -41,8 +42,8 @@ public class GuiReplaySettings extends AbstractGuiScreen<GuiReplaySettings> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final SettingsRegistry.SettingKey<Boolean> booleanKey = (SettingsRegistry.SettingKey<Boolean>) key; final SettingsRegistry.SettingKey<Boolean> booleanKey = (SettingsRegistry.SettingKey<Boolean>) key;
final GuiToggleButton button = new GuiToggleButton<>().setSize(150, 20) final GuiToggleButton button = new GuiToggleButton<>().setSize(150, 20)
.setLabel(key.getDisplayString()).setSelected(settingsRegistry.get(booleanKey) ? 0 : 1) .setI18nLabel(key.getDisplayString()).setSelected(settingsRegistry.get(booleanKey) ? 0 : 1)
.setValues(I18n.format("options.on"), I18n.format("options.off")); .setValues(I18n.translate("options.on"), I18n.translate("options.off"));
element = button.onClick(new Runnable() { element = button.onClick(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -60,13 +61,22 @@ public class GuiReplaySettings extends AbstractGuiScreen<GuiReplaySettings> {
for (int j = 0; j < entries.length; j++) { for (int j = 0; j < entries.length; j++) {
Object value = values.get(j); Object value = values.get(j);
entries[j] = new MultipleChoiceDropdownEntry(value, entries[j] = new MultipleChoiceDropdownEntry(value,
multipleChoiceKey.getDisplayString() + ": " + I18n.format(value.toString())); I18n.translate(multipleChoiceKey.getDisplayString()) + ": " + I18n.translate(value.toString()));
if (currentValue.equals(value)) { if (currentValue.equals(value)) {
selected = j; selected = j;
} }
} }
final GuiDropdownMenu<MultipleChoiceDropdownEntry> menu = final GuiDropdownMenu<MultipleChoiceDropdownEntry> menu = new GuiDropdownMenu<MultipleChoiceDropdownEntry>() {
new GuiDropdownMenu<MultipleChoiceDropdownEntry>().setSize(150, 20).setValues(entries); @Override
protected ReadableDimension calcMinSize() {
ReadableDimension size = super.calcMinSize();
if (size.getWidth() > 150) {
return new Dimension(150, size.getHeight());
} else {
return size;
}
}
}.setSize(150, 20).setValues(entries);
menu.setSelected(selected).onSelection(new Consumer<Integer>() { menu.setSelected(selected).onSelection(new Consumer<Integer>() {
@Override @Override
public void consume(Integer obj) { public void consume(Integer obj) {
@@ -104,11 +114,15 @@ public class GuiReplaySettings extends AbstractGuiScreen<GuiReplaySettings> {
return this; return this;
} }
@RequiredArgsConstructor
private static class MultipleChoiceDropdownEntry { private static class MultipleChoiceDropdownEntry {
private final Object value; private final Object value;
private final String text; private final String text;
public MultipleChoiceDropdownEntry(Object value, String text) {
this.value = value;
this.text = text;
}
@Override @Override
public String toString() { public String toString() {
return text; return text;

View File

@@ -0,0 +1,33 @@
//#if FABRIC>=1
package com.replaymod.core.gui;
import com.replaymod.core.ReplayMod;
import net.minecraft.client.gui.screen.Screen;
import java.util.function.Function;
//#if MC>=11700
//$$ import com.terraformersmc.modmenu.api.ConfigScreenFactory;
//$$ import com.terraformersmc.modmenu.api.ModMenuApi;
//#else
import io.github.prospector.modmenu.api.ModMenuApi;
//#endif
public class ModMenuApiImpl implements ModMenuApi {
//#if MC<11700
@Override
public String getModId() {
return ReplayMod.MOD_ID;
}
//#endif
@Override
//#if MC>=11700
//$$ public ConfigScreenFactory<?> getModConfigScreenFactory() {
//#else
public Function<Screen, ? extends Screen> getConfigScreenFactory() {
//#endif
return parent -> new GuiReplaySettings(parent, ReplayMod.instance.getSettingsRegistry()).toMinecraft();
}
}
//#endif

View File

@@ -1,27 +1,42 @@
package com.replaymod.core.gui; package com.replaymod.core.gui;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.replaymod.replaystudio.PacketData; import com.google.gson.Gson;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Utils;
import com.replaymod.core.versions.MCVer;
import com.replaymod.replaystudio.io.ReplayInputStream; import com.replaymod.replaystudio.io.ReplayInputStream;
import com.replaymod.replaystudio.io.ReplayOutputStream; import com.replaymod.replaystudio.io.ReplayOutputStream;
import com.replaymod.replaystudio.lib.viaversion.api.protocol.packet.State;
import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ReplayMetaData; import com.replaymod.replaystudio.replay.ReplayMetaData;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import de.johni0702.minecraft.gui.container.AbstractGuiScreen; import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
import de.johni0702.minecraft.gui.container.GuiPanel; import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.container.GuiScreen; import de.johni0702.minecraft.gui.container.GuiScreen;
import de.johni0702.minecraft.gui.container.VanillaGuiScreen;
import de.johni0702.minecraft.gui.element.GuiButton; import de.johni0702.minecraft.gui.element.GuiButton;
import de.johni0702.minecraft.gui.element.GuiLabel; import de.johni0702.minecraft.gui.element.GuiLabel;
import de.johni0702.minecraft.gui.element.advanced.GuiProgressBar;
import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout; import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.utils.Colors;
import net.minecraft.util.crash.CrashReport;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.util.function.Consumer;
import static com.replaymod.replaystudio.util.Utils.readInt;
import static com.replaymod.replaystudio.util.Utils.writeInt;
public class RestoreReplayGui extends AbstractGuiScreen<RestoreReplayGui> { public class RestoreReplayGui extends AbstractGuiScreen<RestoreReplayGui> {
private static Logger LOGGER = LogManager.getLogger();
public final GuiScreen parent; public final GuiScreen parent;
public final File file; public final File file;
@@ -31,8 +46,10 @@ public class RestoreReplayGui extends AbstractGuiScreen<RestoreReplayGui> {
textPanel, buttonPanel).setLayout(new VerticalLayout().setSpacing(20)); textPanel, buttonPanel).setLayout(new VerticalLayout().setSpacing(20));
public final GuiButton yesButton = new GuiButton(buttonPanel).setSize(150, 20).setI18nLabel("gui.yes"); public final GuiButton yesButton = new GuiButton(buttonPanel).setSize(150, 20).setI18nLabel("gui.yes");
public final GuiButton noButton = new GuiButton(buttonPanel).setSize(150, 20).setI18nLabel("gui.no"); public final GuiButton noButton = new GuiButton(buttonPanel).setSize(150, 20).setI18nLabel("gui.no");
private final ReplayMod core;
public RestoreReplayGui(GuiScreen parent, File file) { public RestoreReplayGui(ReplayMod core, GuiScreen parent, File file) {
this.core = core;
this.parent = parent; this.parent = parent;
this.file = file; this.file = file;
@@ -40,34 +57,16 @@ public class RestoreReplayGui extends AbstractGuiScreen<RestoreReplayGui> {
new GuiLabel().setI18nText("replaymod.gui.restorereplay1"), new GuiLabel().setI18nText("replaymod.gui.restorereplay1"),
new GuiLabel().setI18nText("replaymod.gui.restorereplay2", Files.getNameWithoutExtension(file.getName())), new GuiLabel().setI18nText("replaymod.gui.restorereplay2", Files.getNameWithoutExtension(file.getName())),
new GuiLabel().setI18nText("replaymod.gui.restorereplay3")); new GuiLabel().setI18nText("replaymod.gui.restorereplay3"));
LOGGER.info("Found partially saved replay, offering recovery: " + file);
yesButton.onClick(() -> { yesButton.onClick(() -> {
try { LOGGER.info("Attempting recovery: " + file);
ReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), null, file); recoverInBackground();
ReplayMetaData metaData = replayFile.getMetaData();
if (metaData != null && metaData.getDuration() == 0) {
// Try to restore replay duration
// We need to re-write the packet data in case there are any incomplete packets dangling at the end
try (ReplayInputStream in = replayFile.getPacketData();
ReplayOutputStream out = replayFile.writePacketData()) {
PacketData last = null;
while ((last = in.readPacket()) != null) {
metaData.setDuration((int) last.getTime());
out.write(last);
}
} catch (Throwable t) {
t.printStackTrace();
}
// Write back the actual duration
replayFile.writeMetaData(metaData);
}
replayFile.save();
replayFile.close();
} catch (IOException e) {
e.printStackTrace();
}
parent.display(); parent.display();
}); });
noButton.onClick(() -> { noButton.onClick(() -> {
LOGGER.info("Recovery rejected, marking for deletion: " + file);
try { try {
File tmp = new File(file.getParentFile(), file.getName() + ".tmp"); File tmp = new File(file.getParentFile(), file.getName() + ".tmp");
File deleted = new File(file.getParentFile(), file.getName() + ".del"); File deleted = new File(file.getParentFile(), file.getName() + ".del");
@@ -93,4 +92,72 @@ public class RestoreReplayGui extends AbstractGuiScreen<RestoreReplayGui> {
protected RestoreReplayGui getThis() { protected RestoreReplayGui getThis() {
return this; return this;
} }
private void recoverInBackground() {
GuiLabel label = new GuiLabel().setI18nText("replaymod.gui.replaysaving.title").setColor(Colors.BLACK);
GuiProgressBar progressBar = new GuiProgressBar().setHeight(14);
GuiPanel savingProcess = new GuiPanel()
.setLayout(new VerticalLayout())
.addElements(new VerticalLayout.Data(0.5), label, progressBar);
new Thread(() -> {
core.runLater(() -> core.getBackgroundProcesses().addProcess(savingProcess));
try {
tryRecover(progressBar::setProgress);
} catch (IOException e) {
LOGGER.error("Recovering replay file:", e);
CrashReport crashReport = CrashReport.create(e, "Recovering replay file");
core.runLater(() -> Utils.error(LOGGER, VanillaGuiScreen.wrap(getMinecraft().currentScreen), crashReport, () -> {}));
} finally {
core.runLater(() -> core.getBackgroundProcesses().removeProcess(savingProcess));
}
}).start();
}
private void tryRecover(Consumer<Float> progress) throws IOException {
ReplayFile replayFile = ReplayMod.instance.files.open(file.toPath());
// Commit all not-yet-committed files into the main zip file.
// If we don't do this, then re-writing packet data below can actually overwrite uncommitted packet data!
replayFile.save();
progress.accept(0.4f);
ReplayMetaData metaData = replayFile.getMetaData();
if (metaData != null && metaData.getDuration() == 0) {
// Try to restore replay duration
// We need to re-write the packet data in case there are any incomplete packets dangling at the end
try (ReplayInputStream in = replayFile.getPacketData(MCVer.getPacketTypeRegistry(State.LOGIN));
ReplayOutputStream out = replayFile.writePacketData()) {
while (true) {
// To prevent failing at un-parsable packets and to support recovery in minimal mode,
// we do not use the ReplayIn/OutputStream methods but instead parse the packets ourselves.
int time = readInt(in);
int length = readInt(in);
if (time == -1 || length == -1) {
break;
}
byte[] buf = new byte[length];
IOUtils.readFully(in, buf);
// Fully read, update replay duration
metaData.setDuration(time);
// Write packet back into recovered replay
writeInt(out, time);
writeInt(out, length);
out.write(buf);
}
} catch (Throwable t) {
t.printStackTrace();
}
// Write back the actual duration
try (OutputStream out = replayFile.write("metaData.json")) {
metaData.setGenerator(metaData.getGenerator() + "(+ ReplayMod Replay Recovery)");
String json = (new Gson()).toJson(metaData);
out.write(json.getBytes());
}
}
progress.accept(0.6f);
replayFile.save();
progress.accept(0.9f);
replayFile.close();
progress.accept(1f);
}
} }

View File

@@ -1,31 +0,0 @@
package com.replaymod.core.handler;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiMainMenu;
import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
/**
* Moves certain buttons on the main menu upwards so we can inject our own.
*/
public class MainMenuHandler {
public void register() {
MinecraftForge.EVENT_BUS.register(this);
}
@SubscribeEvent
public void onInit(GuiScreenEvent.InitGuiEvent.Post event) {
if (event.getGui() instanceof GuiMainMenu) {
for (GuiButton button : event.getButtonList()) {
// Buttons that aren't in a rectangle directly above our space don't need moving
if (button.x + button.width < event.getGui().width / 2 - 100
|| button.x > event.getGui().width / 2 + 100
|| button.y > event.getGui().height / 4 + 10 + 4 * 24) continue;
// Move button up to make space for two rows of buttons
// and then move back down by 10 to compensate for the space to the exit button that was already there
button.y -= 2 * 24 - 10;
}
}
}
}

View File

@@ -0,0 +1,13 @@
//#if MC>=11400
package com.replaymod.core.mixin;
import net.minecraft.client.gui.widget.AbstractButtonWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(AbstractButtonWidget.class)
public interface AbstractButtonWidgetAccessor {
@Accessor
int getHeight();
}
//#endif

View File

@@ -0,0 +1 @@
// 26.1+

View File

@@ -0,0 +1,34 @@
package com.replaymod.core.mixin;
import net.minecraft.client.gui.screen.Screen;
import org.spongepowered.asm.mixin.Mixin;
//#if MC>=11700
//$$ import net.minecraft.client.gui.Drawable;
//$$ import net.minecraft.client.gui.Element;
//$$ import net.minecraft.client.gui.Selectable;
//#else
//#endif
//#if MC>=11400
import net.minecraft.client.gui.widget.AbstractButtonWidget;
import org.spongepowered.asm.mixin.gen.Invoker;
//#else
//$$ import net.minecraft.client.gui.GuiButton;
//$$ import org.spongepowered.asm.mixin.gen.Accessor;
//$$ import java.util.List;
//#endif
@Mixin(Screen.class)
public interface GuiScreenAccessor {
//#if MC>=11700
//$$ @Invoker("addDrawableChild")
//$$ <T extends Element & Drawable & Selectable> T invokeAddButton(T drawableElement);
//#elseif MC>=11400
@Invoker
<T extends AbstractButtonWidget> T invokeAddButton(T button);
//#else
//$$ @Accessor("buttonList")
//$$ List<GuiButton> getButtons();
//#endif
}

View File

@@ -0,0 +1,13 @@
package com.replaymod.core.mixin;
import net.minecraft.client.options.KeyBinding;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(KeyBinding.class)
public interface KeyBindingAccessor {
@Accessor("timesPressed")
int getPressTime();
@Accessor("timesPressed")
void setPressTime(int value);
}

View File

@@ -0,0 +1,80 @@
package com.replaymod.core.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.network.ClientConnection;
import net.minecraft.util.crash.CrashReport;
import net.minecraft.client.render.RenderTickCounter;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
//#if MC>=11800
//$$ import java.util.function.Supplier;
//#endif
//#if MC>=11400
import java.util.concurrent.CompletableFuture;
//#endif
//#if MC<11400
//$$ import java.util.concurrent.FutureTask;
//#endif
//#if MC<11400
//$$ import net.minecraft.client.resources.IResourcePack;
//$$ import java.util.List;
//$$ import java.util.Queue;
//#endif
@Mixin(MinecraftClient.class)
public interface MinecraftAccessor {
//#if MC>=12100
//$$ @Accessor("renderTickCounter")
//$$ RenderTickCounter.Dynamic getTimer();
//$$ @Accessor("renderTickCounter")
//$$ @Mutable
//$$ void setTimer(RenderTickCounter.Dynamic value);
//#else
@Accessor("renderTickCounter")
RenderTickCounter getTimer();
@Accessor("renderTickCounter")
//#if MC>=11200
@Mutable
//#endif
void setTimer(RenderTickCounter value);
//#endif
//#if MC>=11400
@Accessor
CompletableFuture<Void> getResourceReloadFuture();
@Accessor
void setResourceReloadFuture(CompletableFuture<Void> value);
//#endif
//#if MC>=11400
//#else
//$$ @Accessor
//$$ Queue<FutureTask<?>> getScheduledTasks();
//#endif
//#if MC >= 26.1
//$$ // Now in BlockableEventLoopAccessor
//#else
@Accessor("crashReport")
//#if MC>=11800
//$$ Supplier<CrashReport> getCrashReporter();
//#else
CrashReport getCrashReporter();
//#endif
//#endif
//#if MC<11400
//$$ @Accessor
//$$ List<IResourcePack> getDefaultResourcePacks();
//#endif
//#if MC>=11400
@Accessor
void setConnection(ClientConnection connection);
//#endif
}

View File

@@ -0,0 +1,33 @@
package com.replaymod.core.mixin;
import com.replaymod.core.events.KeyBindingEventCallback;
import com.replaymod.core.events.KeyEventCallback;
import de.johni0702.minecraft.gui.function.KeyInput;
import net.minecraft.client.Keyboard;
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(Keyboard.class)
public class MixinKeyboardListener {
private static final String ON_KEY_PRESSED = "Lnet/minecraft/client/options/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V";
@Inject(method = "onKey", at = @At(value = "INVOKE", target = ON_KEY_PRESSED), cancellable = true)
//#if MC>=12109
//$$ private void beforeKeyBindingTick(long window, int action, net.minecraft.client.input.KeyInput mcKeyInput, CallbackInfo ci) {
//$$ KeyInput keyInput = new KeyInput(mcKeyInput);
//#else
private void beforeKeyBindingTick(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo ci) {
KeyInput keyInput = new KeyInput(key, scanCode, modifiers);
//#endif
if (KeyEventCallback.EVENT.invoker().onKeyEvent(keyInput, action)) {
ci.cancel();
}
}
@Inject(method = "onKey", at = @At(value = "INVOKE", target = ON_KEY_PRESSED, shift = At.Shift.AFTER))
private void afterKeyBindingTick(CallbackInfo ci) {
KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent();
}
}

View File

@@ -0,0 +1,143 @@
package com.replaymod.core.mixin;
import com.replaymod.core.versions.MCVer;
import net.minecraft.client.MinecraftClient;
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.CallbackInfo;
//#if MC>=12109
//$$ import net.minecraft.network.PacketApplyBatcher;
//$$ import org.spongepowered.asm.mixin.Final;
//#endif
//#if MC>=11400
import com.replaymod.core.events.PostRenderCallback;
import com.replaymod.core.events.PreRenderCallback;
//#else
//$$ import org.spongepowered.asm.mixin.injection.Redirect;
//$$ import com.replaymod.replay.InputReplayTimer;
//$$ import org.lwjgl.input.Mouse;
//#endif
import java.io.IOException;
//#if MC>=11400
import net.minecraft.util.thread.ReentrantThreadExecutor;
//#endif
@Mixin(MinecraftClient.class)
public abstract class MixinMinecraft
//#if MC>=11400
extends ReentrantThreadExecutor<Runnable>
//#endif
implements MCVer.MinecraftMethodAccessor {
//#if MC>=11400
@Shadow protected abstract void handleInputEvents();
@Override
public void replayModProcessKeyBinds() {
handleInputEvents();
}
//#if MC>=11400
//#if MC>=12109
//$$ @Shadow @Final private PacketApplyBatcher packetApplyBatcher;
//#endif
@Override
public void replayModExecuteTaskQueue() {
//#if MC>=12109
//$$ this.packetApplyBatcher.apply();
//#endif
runTasks();
}
//#endif
//#if MC >= 26.1
//$$ private static final String GAME_RENDERER_RENDER = "Lnet/minecraft/client/Minecraft;renderFrame(Z)V";
//#elseif MC>=12100
//$$ private static final String GAME_RENDERER_RENDER = "Lnet/minecraft/client/render/GameRenderer;render(Lnet/minecraft/client/render/RenderTickCounter;Z)V";
//#else
private static final String GAME_RENDERER_RENDER = "Lnet/minecraft/client/render/GameRenderer;render(FJZ)V";
//#endif
@Inject(method = "render",
at = @At(value = "INVOKE",
target = GAME_RENDERER_RENDER))
private void preRender(boolean unused, CallbackInfo ci) {
PreRenderCallback.EVENT.invoker().preRender();
}
@Inject(method = "render",
at = @At(value = "INVOKE",
target = GAME_RENDERER_RENDER,
shift = At.Shift.AFTER))
private void postRender(boolean unused, CallbackInfo ci) {
PostRenderCallback.EVENT.invoker().postRender();
}
//#else
//$$ @Shadow long systemTime;
//#if MC>=10904
//$$ @Shadow protected abstract void runTickKeyboard() throws IOException;
//$$ @Shadow protected abstract void runTickMouse() throws IOException;
//$$
//$$ @Override
//$$ public void replayModRunTickKeyboard() {
//$$ try {
//$$ runTickKeyboard();
//$$ } catch (IOException e) {
//$$ e.printStackTrace();
//$$ }
//$$ }
//$$
//$$ @Override
//$$ public void replayModRunTickMouse() {
//$$ try {
//$$ runTickMouse();
//$$ // Update last tick time (MC ignores inputs when there hasn't been a tick in 200ms)
//$$ systemTime = Minecraft.getSystemTime();
//$$ } catch (IOException e) {
//$$ e.printStackTrace();
//$$ }
//$$ }
//#else
//$$ private boolean earlyReturn;
//$$
//$$ @Override
//$$ public void replayModSetEarlyReturnFromRunTick(boolean earlyReturn) {
//$$ this.earlyReturn = earlyReturn;
//$$ }
//$$
//$$ @Inject(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;sendClickBlockToController(Z)V"), cancellable = true)
//$$ private void doEarlyReturnFromRunTick(CallbackInfo ci) {
//$$ if (earlyReturn) {
//$$ ci.cancel();
//$$
//$$ // Update last tick time (MC ignores inputs when there hasn't been a tick in 200ms)
//$$ systemTime = Minecraft.getSystemTime();
//$$ }
//$$ }
//#endif
//$$ @Redirect(
//#if MC>=10904
//$$ method = "runTickMouse",
//#else
//$$ method = "runTick",
//#endif
//$$ at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getEventDWheel()I", remap = false)
//$$ )
//$$ private int scroll() {
//$$ int wheel = Mouse.getEventDWheel();
//$$ InputReplayTimer.handleScroll(wheel);
//$$ return wheel;
//$$ }
//#endif
//#if MC >= 26.1
//$$ MixinMinecraft() { super(null, false); }
//#elseif MC>=11400
MixinMinecraft() { super(null); }
//#endif
}

View File

@@ -0,0 +1,20 @@
//#if MC>=11400
package com.replaymod.core.mixin;
import com.replaymod.core.events.KeyBindingEventCallback;
import com.replaymod.core.events.KeyEventCallback;
import net.minecraft.client.Keyboard;
import net.minecraft.client.Mouse;
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(Mouse.class)
public class MixinMouse {
@Inject(method = "onMouseButton", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/options/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V", shift = At.Shift.AFTER))
private void afterKeyBindingTick(CallbackInfo ci) {
KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent();
}
}
//#endif

View File

@@ -0,0 +1,78 @@
package com.replaymod.core.mixin;
import com.replaymod.core.ReplayMod;
import com.replaymod.replay.ReplayModReplay;
import net.minecraft.client.options.KeyBinding;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* We have bunch of keybindings which only have an effect while in a replay but heavily conflict with vanilla ones
* otherwise. To work around this, we prevent our keybindings (or conflicting ones) from making it into the keysByCode
* map, depending on the current context.
*/
@Mixin(KeyBinding.class)
public class Mixin_ContextualKeyBindings {
//#if MC>=11200
@Shadow @Final private static Map<String, KeyBinding> keysById;
@Unique private static Collection<KeyBinding> keyBindings() { return Mixin_ContextualKeyBindings.keysById.values(); }
//#else
//$$ @Shadow @Final private static List<KeyBinding> KEYBIND_ARRAY;
//$$ @Unique private static Collection<KeyBinding> keyBindings() { return Mixin_ContextualKeyBindings.KEYBIND_ARRAY; }
//#endif
@Unique private static final List<KeyBinding> temporarilyRemoved = new ArrayList<>();
@Inject(method = "updateKeysByCode", at = @At("HEAD"))
private static void preContextualKeyBindings(CallbackInfo ci) {
ReplayMod mod = ReplayMod.instance;
if (mod == null) {
return;
}
Set<KeyBinding> onlyInReplay = mod.getKeyBindingRegistry().getOnlyInReplay();
if (ReplayModReplay.instance.getReplayHandler() != null) {
// In replay, remove any conflicting key bindings, so that ours are guaranteed in
keyBindings().removeIf(keyBinding -> {
for (KeyBinding exclusiveBinding : onlyInReplay) {
if (keyBinding.equals(exclusiveBinding) && keyBinding != exclusiveBinding) {
temporarilyRemoved.add(keyBinding);
return true;
}
}
return false;
});
} else {
// Not in a replay, remove all replay-exclusive keybindings
keyBindings().removeIf(keyBinding -> {
if (onlyInReplay.contains(keyBinding)) {
temporarilyRemoved.add(keyBinding);
return true;
}
return false;
});
}
}
@Inject(method = "updateKeysByCode", at = @At("RETURN"))
private static void postContextualKeyBindings(CallbackInfo ci) {
for (KeyBinding keyBinding : temporarilyRemoved) {
//#if MC>=11200
Mixin_ContextualKeyBindings.keysById.put(keyBinding.getTranslationKey(), keyBinding);
//#else
//$$ keyBindings().add(keyBinding);
//#endif
}
temporarilyRemoved.clear();
}
}

View File

@@ -0,0 +1,52 @@
//#if FABRIC>=1
package com.replaymod.core.mixin;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.versions.LangResourcePack;
import net.minecraft.resource.ResourcePack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import java.util.function.BiConsumer;
import java.util.stream.Collector;
//#if MC>=11600
@Mixin(net.minecraft.resource.ResourcePackManager.class)
//#else
//$$ @Mixin(net.minecraft.client.MinecraftClient.class)
//#endif
public class Mixin_InjectDynamicResourcePacks {
@ModifyArg(
//#if MC>=11600
method = "createResourcePacks",
//#elseif MC>=11500
//$$ method = { "<init>", "reloadResources" },
//#else
//$$ method = { "init", "reloadResources" },
//#endif
at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;collect(Ljava/util/stream/Collector;)Ljava/lang/Object;")
)
private Collector<ResourcePack, ?, ?> injectReplayModPacks(Collector<ResourcePack, ?, ?> collector) {
collector = append(collector, new LangResourcePack());
if (ReplayMod.jGuiResourcePack != null) {
collector = append(collector, ReplayMod.jGuiResourcePack);
}
return collector;
}
private static <T, A, R> Collector<T, A, R> append(Collector<T, A, R> collector, T value) {
BiConsumer<A, T> accumulator = collector.accumulator();
return Collector.of(
collector.supplier(),
accumulator,
collector.combiner(),
result -> {
accumulator.accept(result, value);
return collector.finisher().apply(result);
}
);
}
}
//#endif

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