diff --git a/assets/js/neoforge.js b/assets/js/neoforge.js index 5bfd91f..2dbf911 100644 --- a/assets/js/neoforge.js +++ b/assets/js/neoforge.js @@ -3,23 +3,39 @@ const FORGE_GAV = 'net/neoforged/neoforge' const LEGACY_GAV = 'net/neoforged/forge' const LATEST_ENDPOINT = 'https://maven.neoforged.net/api/maven/latest/version/releases/' const DOWNLOAD_URL = 'https://maven.neoforged.net/releases' -//https://maven.neoforged.net/api/maven/latest/version/releases/net%2Fneoforged%2Fneoforge?filter=20.2 +// For the latest version: https://maven.neoforged.net/api/maven/latest/version/releases/net/neoforged/neoforge +// For legacy version(s): https://maven.neoforged.net/api/maven/latest/version/releases/net/neoforged/forge +// To filter a specific MC version: https://maven.neoforged.net/api/maven/latest/version/releases/net/neoforged/neoforge?filter=20.4 async function loadLatestVersions(minecraftVersions) { for (const mcVersion of minecraftVersions) { - let gav; - let fn; - let mcvers; - if (mcVersion.startsWith("1.20.1")) { - gav = LEGACY_GAV; - fn = "forge"; - mcvers = "1.20.1" - } else { - gav = FORGE_GAV; - fn = "neoforge"; - mcvers = `1.${mcVersion}` - } - let currentMcVersionUrl = new URL(LATEST_ENDPOINT + encodeURIComponent(gav) + '?filter=' + encodeURIComponent(mcVersion)); + let gav; + let fn; + let mcvers; + let dropDown_VAL; + let badges_beta; + let badges_new; + if (mcVersion.startsWith("1.20.1")) { + gav = LEGACY_GAV; + fn = "forge"; + mcvers = "1.20.1"; + badges_new = ""; + badges_beta = ""; + dropDown_VAL = ""; + } else { + gav = FORGE_GAV; + fn = "neoforge"; + badges_beta = ""; + badges_new = `NEW`; + dropDown_VAL = ` open="open"`; + } + + let currentMcVersionUrl; let versionJson; + if (mcvers == "1.20.1") { + currentMcVersionUrl = new URL(LATEST_ENDPOINT + encodeURIComponent(gav) + '?filter=' + encodeURIComponent(mcVersion)); + } else { + currentMcVersionUrl = new URL(LATEST_ENDPOINT + encodeURIComponent(gav)); + } try { const response = await fetch(currentMcVersionUrl); @@ -34,17 +50,27 @@ async function loadLatestVersions(minecraftVersions) { if (versionJson) { const {version} = versionJson; + if (mcVersion == "latest") { + mcvers = "1." + Array.from(version)[0] + Array.from(version)[1] + Array.from(version)[2] + Array.from(version)[3]; + } + if (version.includes("beta")) { + badges_beta = `BETA`; + } + const vs = `#filelist${mcVersion}`.split('.').join(""); const installerUrl = `${DOWNLOAD_URL}/${gav}/${encodeURIComponent(version)}/${fn}-${encodeURIComponent(version)}-installer.jar`; const changelogUrl = `${DOWNLOAD_URL}/${gav}/${encodeURIComponent(version)}/${fn}-${encodeURIComponent(version)}-changelog.txt`; + document.querySelector(vs).innerHTML = ` -
NeoForge ${version} for Minecraft ${mcvers}
+ + ${badges_beta} ${badges_new} NeoForge ${version} for Minecraft ${mcvers}
- Latest NeoForge Installer${fn}-${version}-installer.jar + Latest NeoForge Installer${fn}-${version}-installer.jar - Latest Changelog${version} + Latest Changelog${version}
+ `; } } diff --git a/content/_index.md b/content/_index.md index 8cec828..314e153 100644 --- a/content/_index.md +++ b/content/_index.md @@ -12,11 +12,9 @@ description: | # NeoForge installer files You can find a direct link to our latest installer files below. -{{}} - +{{< files "latest" >}} {{< files "1.20.1" >}} - -Note: the file is still called forge in 1.20.1 to maintain compatibility with launchers. +{{< versions >}} # Using NeoForge for mod development diff --git a/content/news/20.4networking-rework.md b/content/news/20.4networking-rework.md index 1ae2f73..7ba0882 100644 --- a/content/news/20.4networking-rework.md +++ b/content/news/20.4networking-rework.md @@ -34,19 +34,19 @@ public static void register(final RegisterPacketHandlerEvent event) { .optional(); } ``` -{{< notice note >}} +{{< box note >}} The registrar is a semi-immutable object; calling `versioned(String version)` or `optional()` on an instance of the registrar will cause a new instance with the desired configuration to be created. -{{< /notice >}} +{{< /box >}} -{{< notice warning >}} +{{< box warning >}} The registrar loses its validity the moment the scope of the event has been left. Registering payload handlers outside the event handling scope will result in those payloads not being known to the system and not being sent over the connection. Additionally, the attempt to register them outside the event scope will trigger an exception. -{{< /notice >}} +{{< /box >}} The registrar offers six different endpoints, three pairs of two, to register new payloads. A pair exists for the play phase, one pair for the special configuration sub-phase, and one pair of methods for both. -{{< notice info >}} +{{< box info >}} It is impossible to register custom payloads that should be sent during the login phase of the connection. And the new code offers, as such, no infrastructure to achieve this. -{{< /notice >}} +{{< /box >}} Within each pair of registration methods for a phase, two variants (as such, six methods) are available. One that registers the same handler for both sides of the connection and one that takes a consumer, allowing for the configuration of single-sided or differentially handled payloads. @@ -70,42 +70,42 @@ The value of the discriminator during writing is retrieved from the `CustomPacke The value against which the id, read from the connection, is compared to find a reader, is the one that is given to the registrar as the first argument. It is as such of the upmost importance that both the registrar and the `id()` method of the payload instance receive the same resource location. -{{< notice tip >}} +{{< box tip >}} We recommend that you store your ID in a `public static final ResourceLocation ID = new ResourceLocation("mod_id", "payload_id")` field, and reference that in both places. -{{< /notice >}} +{{< /box >}} -{{< notice warning >}} +{{< box warning >}} Given that the id is used as a discriminator, it is important that you use a unique value, especially for the path of each payload type. If you try to register the same id twice, the registrar will throw an exception. If you try to register an id with a namespace other than the one the registrar is for, the registrar will throw an exception. You are free to request registrars for other namespaces than your own. -{{< /notice >}} +{{< /box >}} ### Payload reading Payload reading happens via the vanilla method, implementing the `FriendlyByteBuf.Reader` functional interface. During the registration of the payload type, as can be seen above, you need to pass an implementation of this interface so that a new instance of the payload can be created by the system when a custom payload packet with it as payload arrives at the receiving end. -{{< notice tip >}} +{{< box tip >}} As we recommend that your payload implementations are `record`s in Java, instead of classes, we also recommend that you create a custom constructor with the record, to read the records fields from the buffer. This constructor can then be passed as a method reference for the reader implementation. So if `SimplePayload(String something) {}` is your normal record, then adding `SimplePayload(FriendlyByteBuf buf) { this(buf.readUtf()); }` as a constructor to the `SimplePayload` record will allow you to pass it as a method reference `SimplePayload::new` to the registrar when it asks for an implementation of `FriendlyByteBuf.Reader` -{{< /notice >}} +{{< /box >}} -{{< notice warning >}} +{{< box warning >}} There is no guarantee regarding which thread the reading or writing callback is invoked upon. It is as such important to note that the method can be called on many threads in parallel if the same packet is processed by many connections simultaneously. -{{< /notice >}} +{{< /box >}} ### Payload writing The `CustomPacketPayload` interface contains a method: `write(FriendlyByteBuf)` method. This method is invoked when it is time to write your payload to the network connection. There is no guarantee regarding what thread invokes the writer. -{{< notice warning >}} +{{< box warning >}} As with payload reading there is no guarantee regarding which thread the writing callback is invoked upon. It is as such important to note that the method can be called on many threads in parallel if the same packet is sent on many connections simultaneously. -{{< /notice >}} +{{< /box >}} -{{< notice warning >}} +{{< box warning >}} Payloads are only read and written if sent over a connection. This means that the host of a single-player world (even if exposed to LAN) has packets and, as such, payloads transferred in memory. This means that for those payloads, no write method is invoked, and no reader is called. Only the handler is invoked! -{{< /notice >}} +{{< /box >}} ### Payload handling Once a payload has been written, transmitted and read, the payload handler is invoked. This handler is again looked up using the id of the payload, and then invoked with the context of the receiving end. Each handler takes two arguments the: payload instance, and the context. -{{< notice warning >}} +{{< box warning >}} Payloads are processed on the network thread, and can as such happen in parallel with other payloads of the same type being handled. If you need to ensure that the payload is processed on the main thread, serially, see the `ISynchronizedWorkHandler` available in the context under the `workHandler()` method. -{{< /notice >}} +{{< /box >}} #### The context The context contains information, callbacks and entry points, to access the surrounding network system, the main thread, as well as handling processing other packets, or completing configuration tasks. @@ -116,9 +116,9 @@ The reply handler can be used to quickly send a payload back to the sender. It i ##### PacketHandler In case you implement a packet splitting mechanism, whether that splits on full vanilla packets, or custom packet payloads, the `IPacketHandler` interface gives you access to the start of the processing pipeline, allowing you to process other payloads immediately. -{{< notice note >}} +{{< box note >}} This does not transmit payloads, it purely allows for the receiving end to process additional packets or payloads constructed in memory during the processing of your payload. -{{< /notice >}} +{{< /box >}} The packet handler also gives you access to a `disconnect(Component)` method, allowing you to terminate the connection, and showing the given component as reason to the user. @@ -169,16 +169,16 @@ Vanilla now provides a centralized way to perform tasks and jobs that need to be Under normal circumstances these tasks are implementations of the `ConfigurationTask` interface, with a single method: `start(Consumer>)`. However, this is subpar in our situation. Modders should never really have to touch raw Packets to perform their duties, only payloads. And as such it was decided to have modders implement the `ICustomConfigurationTask` interface from NeoForge. This provides a wrapper around the `ConfigurationTask` signature and allows sending payloads instead of packets, by implementing `run(Consumer)` instead. The given consumer will then automatically convert the payload to a packet and send it to the client that is being configured. -{{< notice note >}} +{{< box note >}} In practice, an instance of `ICustomConfigurationTask` is also an instance of `ConfigurationTask` as one extends the other. But to provide the ability for it to be a functional interface, the `start` method is implemented by default. You should not override it. -{{< /notice >}} +{{< /box >}} ### OnGameConfigurationEvent This event is fired to collect all tasks that should be run, and allows for the registration of `ICustomConfigurationTask` instances to the listener. It is not possible to register the vanilla `ConfigurationTask` instances. -{{< notice tip >}} +{{< box tip >}} This event is fired on the mod bus, to preserve dependency order. Given that configuration tasks can only be running in order of registration, you can safely assume that configuration tasks of your dependencies have been running before yours. -{{< /notice >}} +{{< /box >}} ### NeoForge packet changes: Moved configuration sync, registry sync, and tier registry sync to configuration phase tasks. @@ -186,9 +186,9 @@ Moved configuration sync, registry sync, and tier registry sync to configuration ## Bundle packet processing In 1.19.4 Mojang introduced the bundling system for packets, which is a core component that allows packets to be processed together. We anticipate that modders may want to use this system, so we adapted it to accept custom payloads. You will find a `sendBundled(CustomPacketPayload... payloads)` method on the `ServerGamePacketListener`. -{{< notice warning >}} +{{< box warning >}} Packet bundling is only supported during the play phase of the network protocol. It cannot be used during the configuration phase of the protocol. -{{< /notice >}} +{{< /box >}} ## Opening menus with custom data In the past, NeoForge supported opening UIs from the server side with additional data, via `NetworkHooks.openScreen(...)`. This system has been moved and is now part of the server `ServerPlayer` extension. You can call the method `openMenu` with the same parameters. diff --git a/layouts/shortcodes/box.html b/layouts/shortcodes/box.html new file mode 100644 index 0000000..5e0ea5f --- /dev/null +++ b/layouts/shortcodes/box.html @@ -0,0 +1,17 @@ + + +{{/* Available notice types: warning, info, note, tip */}} +{{- $noticeType := .Get 0 | default "note" -}} +{{/* Workaround markdownify inconsistency for single/multiple paragraphs */}} +{{- $raw := (markdownify .Inner | chomp) -}} +{{- $block := findRE "(?is)^<(?:address|article|aside|blockquote|canvas|dd|div|dl|dt|fieldset|figcaption|figure|footer|form|h(?:1|2|3|4|5|6)|header|hgroup|hr|li|main|nav|noscript|ol|output|p|pre|section|table|tfoot|ul|video)\\b" $raw 1 -}} +{{/* Count how many times we've called this shortcode and load the css if it's the first time */}} +{{- if not ($.Page.Scratch.Get "noticecount") -}} + +
+{{- end -}} +{{- $.Page.Scratch.Add "noticecount" 1 -}} +
+

{{- i18n $noticeType -}}

+{{- if or $block (not $raw) }}{{ $raw }}{{ else }}

{{ $raw }}

{{ end -}} +
diff --git a/layouts/shortcodes/files.html b/layouts/shortcodes/files.html index 0960a69..f9ee53e 100644 --- a/layouts/shortcodes/files.html +++ b/layouts/shortcodes/files.html @@ -4,17 +4,21 @@ {{ .Page.Scratch.Set "nfJS" "hi" }} {{ end }} -
-
NeoForge (loading version...)
- + diff --git a/layouts/shortcodes/projects.html b/layouts/shortcodes/projects.html deleted file mode 100644 index 3c539e9..0000000 --- a/layouts/shortcodes/projects.html +++ /dev/null @@ -1,7 +0,0 @@ - \ No newline at end of file diff --git a/layouts/shortcodes/versions.html b/layouts/shortcodes/versions.html new file mode 100644 index 0000000..c9253e7 --- /dev/null +++ b/layouts/shortcodes/versions.html @@ -0,0 +1,9 @@ + diff --git a/themes/hugo-notice b/themes/hugo-notice index 2d7d746..afb7a84 160000 --- a/themes/hugo-notice +++ b/themes/hugo-notice @@ -1 +1 @@ -Subproject commit 2d7d7460bc60a6801e648f1cf95b53dd6741a665 +Subproject commit afb7a842241c1cd8a7d54a2e2fe90a09e8ebc8b3 diff --git a/themes/mainroad/assets/css/style.css b/themes/mainroad/assets/css/style.css index 8c85f76..b4b7634 100644 --- a/themes/mainroad/assets/css/style.css +++ b/themes/mainroad/assets/css/style.css @@ -144,12 +144,6 @@ textarea { border-radius: 0.2rem; } -/* Animation */ -.menu__item, -.btn { - transition: background-color .25s ease-out; -} - /* Typography */ h1, h2, @@ -349,7 +343,6 @@ select { .warning { padding: 20px 10px; - text-align: center; } .warning__icon { @@ -778,6 +771,7 @@ figure.meta__icon { float: left; padding: 3px; margin: 0 25px 0 0; + border-radius: 0.2rem; } .authorbox__header { @@ -995,6 +989,7 @@ textarea { display: block; padding: 5%; margin: 0 auto; + border-radius: 0.2rem; } .widget-search__form .widget-search__submit { @@ -1009,7 +1004,7 @@ textarea { margin: 0 auto; font-size: 11px; cursor: pointer; - border-radius: 0; + border-radius: 0.2rem; outline-offset: -2px; transition: none; -webkit-appearance: none; @@ -1053,10 +1048,42 @@ textarea { display: inline-block; } +/* Installer Dropdowns */ +details { + border: .15rem solid transparent; + border-radius: 0.2rem; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +details:hover { + border: .15rem solid; + border-radius: 0.2rem; +} + +summary { + cursor: grabbing; +} + +details[open] summary { + cursor: grab; +} + +summary:hover { + filter: brightness(.85); +} + +/* Installer */ .fileinfo { text-align: center; margin: 0 0 20px; margin: 0 0 1.25rem; + margin-bottom: 5px; + border-radius: 0.2rem; } .fileinfo .fileinfo__header { @@ -1083,12 +1110,13 @@ textarea { padding: 10px; padding: .625rem; align-items: center; - display: flex; + display: flex; flex-direction: row; align-items: stretch; justify-content: center; flex: 1 1 0px; text-decoration: none; + border-radius: 0.2rem; } .fileinfo__icon { @@ -1106,6 +1134,16 @@ textarea { visibility: hidden; } +/* Installer Badges */ +.badges_beta { + padding: 0 5px; +} + +.badges_new { + padding: 0 5px; +} + +/* News Section */ .news { margin-top: 1rem; } @@ -1115,6 +1153,10 @@ textarea { margin-top: 1rem; } +.avatar { + border-radius: 0.2rem; +} + /* Footer */ .footer { font-size: 12px; @@ -1254,6 +1296,7 @@ textarea { display: inline-block; float: none; margin: 0 0 20px; + border-radius: 0.2rem; } .pager { @@ -1305,6 +1348,8 @@ textarea { [data-theme="light"] { --color-highlight: #d7742f; --color-background: #d5e0df; + --color-badges-beta: #d7742f; + --color-badges-new: #e57; --color-download: #e68c37; --color-download-highlight: #e5b04c; --color-box: #bdc7c7; @@ -1315,7 +1360,7 @@ textarea { --color-code: #b12a48; --color-code-background: #bdc7c7; --color-code-notice: #e57; - --color-code-notice-background: #2e3135; + --color-code-notice-background: #bdc7c7; --color-code-block-background: #2e3135; --color-footer-text: #aab0b3; --color-footer-link-text: #bdc7c7; @@ -1328,6 +1373,8 @@ textarea { [data-theme="dark"] { --color-highlight: #d7742f; + --color-badges-beta: #d7742f; + --color-badges-new: #e57; --color-background: #222427; --color-download: #d7742f; --color-download-highlight: #e68c37; diff --git a/themes/mainroad/layouts/partials/colors.css b/themes/mainroad/layouts/partials/colors.css index c1bc612..30eacbd 100644 --- a/themes/mainroad/layouts/partials/colors.css +++ b/themes/mainroad/layouts/partials/colors.css @@ -57,7 +57,7 @@ figcaption { pre, code { background-color: var(--color-code-background); - border-radius: 0.2em; + border-radius: 4px; } div.notice code { @@ -67,6 +67,7 @@ div.notice code { code { color: var(--color-code); + border: 1px solid var(--color-border); } pre { @@ -90,10 +91,6 @@ abbr[title] { border-bottom: 1px dotted var(--color-text); } -.warning { - border: 1px solid var(--color-border); -} - .warning__icon { fill: var(--color-border); } @@ -361,6 +358,12 @@ textarea { background: var(--color-highlight); } +/* Installer Dropdowns */ +details:hover { + border-color: var(--color-border); +} + +/* Installer */ .fileinfo { background-color: var(--color-box); } @@ -375,6 +378,16 @@ textarea { color: var(--color-text); } +/* Installer Badges */ +.badges_beta { + background-color: var(--color-badges-beta); +} + +.badges_new { + background-color: var(--color-badges-new); +} + +/* News Section */ .news { border-top: 3px solid var(--color-border); } diff --git a/themes/mainroad/layouts/partials/svg/mastodon.svg b/themes/mainroad/layouts/partials/svg/mastodon.svg index 5f0704f..aa26239 100644 --- a/themes/mainroad/layouts/partials/svg/mastodon.svg +++ b/themes/mainroad/layouts/partials/svg/mastodon.svg @@ -1,10 +1 @@ - - - - - - - - - - +