├── .gitignore
├── LICENSE
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ └── gradle-wrapper.properties
├── icon.png
├── settings.gradle
└── src
└── main
├── java
└── com
│ └── moepus
│ └── flerovium
│ ├── Config.java
│ ├── ConfigParser.java
│ ├── Flerovium.java
│ ├── MixinPlugin.java
│ ├── functions
│ ├── Chunk
│ │ ├── FastSimpleFrustum.java
│ │ └── Occlusion.java
│ ├── DummyModel.java
│ ├── FastEntityRenderer.java
│ ├── FastSimpleBakedModelRenderer.java
│ ├── IntFlatMap.java
│ ├── MathUtil.java
│ └── MatrixStuff.java
│ └── mixins
│ ├── Chunk
│ ├── FrustumMixin.java
│ └── OcclusionCullerMixin.java
│ ├── Entity
│ ├── ClientLevelMixin.java
│ └── ModelPartMixin.java
│ ├── Item
│ ├── ItemEntityRenderMixin.java
│ ├── ItemRendererMixin.java
│ ├── ItemTransformMixin.java
│ └── SimpleBakedModelMixin.java
│ └── Particle
│ ├── ParticleEngineMixin.java
│ ├── ParticleMixin.java
│ └── SingleQuadParticleMixin.java
└── resources
├── META-INF
├── accesstransformer.cfg
└── mods.toml
├── flerovium.mixins.json
└── pack.mcmeta
/.gitignore:
--------------------------------------------------------------------------------
1 | # eclipse
2 | bin
3 | *.launch
4 | .settings
5 | .metadata
6 | .classpath
7 | .project
8 |
9 | # idea
10 | out
11 | *.ipr
12 | *.iws
13 | *.iml
14 | .idea
15 |
16 | # gradle
17 | build
18 | .gradle
19 |
20 | # other
21 | eclipse
22 | run
23 | runs
24 |
25 | # Files from Forge MDK
26 | forge*changelog.txt
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | // These repositories are only for Gradle plugins, put any other repositories in the repository block further below
4 | maven { url = 'https://repo.spongepowered.org/repository/maven-public/' }
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT'
9 | }
10 | }
11 |
12 | plugins {
13 | id 'eclipse'
14 | id 'idea'
15 | id 'net.minecraftforge.gradle' version '[6.0,6.2)'
16 | }
17 |
18 | apply plugin: 'org.spongepowered.mixin'
19 |
20 | group = mod_group_id
21 | version = mod_version
22 |
23 | base {
24 | archivesName = mod_id + "-forge-" + minecraft_version
25 | }
26 |
27 | java {
28 | toolchain.languageVersion = JavaLanguageVersion.of(17)
29 | }
30 |
31 | minecraft {
32 | // The mappings can be changed at any time and must be in the following format.
33 | // Channel: Version:
34 | // official MCVersion Official field/method names from Mojang mapping files
35 | // parchment YYYY.MM.DD-MCVersion Open community-sourced parameter names and javadocs layered on top of official
36 | //
37 | // You must be aware of the Mojang license when using the 'official' or 'parchment' mappings.
38 | // See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md
39 | //
40 | // Parchment is an unofficial project maintained by ParchmentMC, separate from MinecraftForge
41 | // Additional setup is needed to use their mappings: https://parchmentmc.org/docs/getting-started
42 | //
43 | // Use non-default mappings at your own risk. They may not always work.
44 | // Simply re-run your setup task after changing the mappings to update your workspace.
45 | mappings channel: mapping_channel, version: mapping_version
46 |
47 | // When true, this property will have all Eclipse/IntelliJ IDEA run configurations run the "prepareX" task for the given run configuration before launching the game.
48 | // enableEclipsePrepareRuns = true
49 | // enableIdeaPrepareRuns = true
50 |
51 | // This property allows configuring Gradle's ProcessResources task(s) to run on IDE output locations before launching the game.
52 | // It is REQUIRED to be set to true for this template to function.
53 | // See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html
54 | copyIdeResources = true
55 |
56 | // When true, this property will add the folder name of all declared run configurations to generated IDE run configurations.
57 | // The folder name can be set on a run configuration using the "folderName" property.
58 | // By default, the folder name of a run configuration is the name of the Gradle project containing it.
59 | // generateRunFolders = true
60 |
61 | // This property enables access transformers for use in development.
62 | // They will be applied to the Minecraft artifact.
63 | // The access transformer file can be anywhere in the project.
64 | // However, it must be at "META-INF/accesstransformer.cfg" in the final mod jar to be loaded by Forge.
65 | // This default location is a best practice to automatically put the file in the right place in the final jar.
66 | // See https://docs.minecraftforge.net/en/latest/advanced/accesstransformers/ for more information.
67 | accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
68 |
69 | // Default run configurations.
70 | // These can be tweaked, removed, or duplicated as needed.
71 | runs {
72 | // applies to all the run configs below
73 | configureEach {
74 | workingDirectory project.file('run')
75 |
76 | // Recommended logging data for a userdev environment
77 | // The markers can be added/remove as needed separated by commas.
78 | // "SCAN": For mods scan.
79 | // "REGISTRIES": For firing of registry events.
80 | // "REGISTRYDUMP": For getting the contents of all registries.
81 | property 'forge.logging.markers', 'REGISTRIES'
82 | property 'mixin.env.remapRefMap', 'true'
83 | property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
84 |
85 | // Recommended logging level for the console
86 | // You can set various levels here.
87 | // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
88 | property 'forge.logging.console.level', 'debug'
89 |
90 | mods {
91 | "${mod_id}" {
92 | source sourceSets.main
93 | }
94 | }
95 | }
96 |
97 | client {
98 | // Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
99 | property 'forge.enabledGameTestNamespaces', mod_id
100 | property 'mixin.env.remapRefMap', 'true'
101 | property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
102 | }
103 |
104 | server {
105 | property 'forge.enabledGameTestNamespaces', mod_id
106 | args '--nogui'
107 | }
108 |
109 | // This run config launches GameTestServer and runs all registered gametests, then exits.
110 | // By default, the server will crash when no gametests are provided.
111 | // The gametest system is also enabled by default for other run configs under the /test command.
112 | gameTestServer {
113 | property 'forge.enabledGameTestNamespaces', mod_id
114 | }
115 |
116 | data {
117 | // example of overriding the workingDirectory set in configureEach above
118 | workingDirectory project.file('run-data')
119 |
120 | // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
121 | args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
122 | }
123 | }
124 | }
125 |
126 | mixin {
127 | add sourceSets.main, "${mod_id}.refmap.json"
128 |
129 | config "${mod_id}.mixins.json"
130 |
131 | debug.verbose = true
132 | debug.export = true
133 | }
134 |
135 | // Include resources generated by data generators.
136 | sourceSets.main.resources { srcDir 'src/generated/resources' }
137 |
138 | repositories {
139 | // Put repositories for dependencies here
140 | // ForgeGradle automatically adds the Forge maven and Maven Central for you
141 |
142 | // If you have mod jar dependencies in ./libs, you can declare them as a repository like so.
143 | // See https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver
144 | // flatDir {
145 | // dir 'libs'
146 | // }
147 | maven {
148 | url = "https://maven.blamejared.com"
149 | }
150 | maven {
151 | url = 'https://www.cursemaven.com'
152 | content {
153 | includeGroup "curse.maven"
154 | }
155 | }
156 | maven {
157 | name = 'tterrag maven'
158 | url = 'https://maven.tterrag.com/'
159 | }
160 | }
161 |
162 | dependencies {
163 | minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
164 |
165 | annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
166 | compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:0.4.1"))
167 | implementation(jarJar("io.github.llamalad7:mixinextras-forge:0.4.1")) {
168 | jarJar.ranged(it, "[0.4.1,)")
169 | }
170 | implementation fg.deobf("org.embeddedt:embeddium-${minecraft_version}:0.3.31-beta.53+mc${minecraft_version}")
171 | runtimeOnly fg.deobf("curse.maven:oculus-581495:6020952")
172 | // runtimeOnly fg.deobf("curse.maven:moonlight-499980:5938277")
173 | // runtimeOnly fg.deobf("curse.maven:supplementaries-412082:5928556")
174 | // runtimeOnly fg.deobf("curse.maven:ftbteams-404468:5267190")
175 | // runtimeOnly fg.deobf("curse.maven:ftblib-404465:5925398")
176 | // runtimeOnly fg.deobf("curse.maven:ftbquests-289412:5816794")
177 | // runtimeOnly fg.deobf("curse.maven:architectury-419699:5137938")
178 | // runtimeOnly fg.deobf("curse.maven:simplyswords-659887:5639538")
179 | // runtimeOnly fg.deobf("curse.maven:clothconfig-348521:5729105")
180 | // runtimeOnly fg.deobf("curse.maven:create-328085:5838779")
181 | // runtimeOnly fg.deobf("curse.maven:mek-268560:5919382")
182 | // runtimeOnly fg.deobf("curse.maven:functional-storage-556861:5650296")
183 | // runtimeOnly fg.deobf("curse.maven:titanium-287342:5468426")
184 | }
185 |
186 | // This block of code expands all declared replace properties in the specified resource targets.
187 | // A missing property will result in an error. Properties are expanded using ${} Groovy notation.
188 | // When "copyIdeResources" is enabled, this will also run before the game launches in IDE environments.
189 | // See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html
190 | tasks.named('processResources', ProcessResources).configure {
191 | var replaceProperties = [
192 | minecraft_version: minecraft_version, minecraft_version_range: minecraft_version_range,
193 | forge_version: forge_version, forge_version_range: forge_version_range,
194 | loader_version_range: loader_version_range,
195 | mod_id: mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version,
196 | mod_authors: mod_authors, mod_description: mod_description,
197 | ]
198 |
199 | inputs.properties replaceProperties
200 |
201 | filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) {
202 | expand replaceProperties + [project: project]
203 | }}
204 |
205 | // Example for how to get properties into the manifest for reading at runtime.
206 | tasks.named('jar', Jar).configure {
207 | manifest {
208 | attributes([
209 | "Specification-Title": mod_id,
210 | "Specification-Vendor": mod_authors,
211 | "Specification-Version": "1", // We are version 1 of ourselves
212 | "Implementation-Title": project.name,
213 | "Implementation-Version": project.jar.archiveVersion,
214 | "Implementation-Vendor": mod_authors,
215 | "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
216 | ])
217 | }
218 |
219 | // This is the preferred method to reobfuscate your jar file
220 | finalizedBy 'reobfJar'
221 | }
222 |
223 | tasks.withType(JavaCompile).configureEach {
224 | options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
225 | }
226 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx3G
2 | org.gradle.daemon=false
3 |
4 |
5 | # The Minecraft version must agree with the Forge version to get a valid artifact
6 | minecraft_version=1.20.1
7 | # The Minecraft version range can use any release version of Minecraft as bounds.
8 | # Snapshots, pre-releases, and release candidates are not guaranteed to sort properly
9 | # as they do not follow standard versioning conventions.
10 | minecraft_version_range=[1.20.1,1.21)
11 | # The Forge version must agree with the Minecraft version to get a valid artifact
12 | forge_version=47.3.7
13 | # The Forge version range can use any version of Forge as bounds or match the loader version range
14 | forge_version_range=[47,)
15 | # The loader version range can only use the major version of Forge/FML as bounds
16 | loader_version_range=[47,)
17 |
18 | # The mapping channel to use for mappings.
19 | # The default set of supported mapping channels are ["official", "snapshot", "snapshot_nodoc", "stable", "stable_nodoc"].
20 | # Additional mapping channels can be registered through the "channelProviders" extension in a Gradle plugin.
21 | #
22 | # | Channel | Version | |
23 | # |-----------|----------------------|--------------------------------------------------------------------------------|
24 | # | official | MCVersion | Official field/method names from Mojang mapping files |
25 | # | parchment | YYYY.MM.DD-MCVersion | Open community-sourced parameter names and javadocs layered on top of official |
26 | #
27 | # You must be aware of the Mojang license when using the 'official' or 'parchment' mappings.
28 | # See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md
29 | #
30 | # Parchment is an unofficial project maintained by ParchmentMC, separate from Minecraft Forge.
31 | # Additional setup is needed to use their mappings, see https://parchmentmc.org/docs/getting-started
32 | mapping_channel=official
33 | # The mapping version to query from the mapping channel.
34 | # This must match the format required by the mapping channel.
35 | mapping_version=1.20.1
36 |
37 |
38 | # The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63}
39 | # Must match the String constant located in the main mod class annotated with @Mod.
40 | mod_id=flerovium
41 | # The human-readable display name for the mod.
42 | mod_name=Flerovium
43 | # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
44 | mod_license=LGPL3.0
45 | # The mod version. See https://semver.org/
46 | mod_version=1.2.14
47 | # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
48 | # This should match the base package used for the mod sources.
49 | # See https://maven.apache.org/guides/mini/guide-naming-conventions.html
50 | mod_group_id=com.moepus
51 | # The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
52 | mod_authors=
53 | # The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
54 | mod_description=
55 |
56 | create_minecraft_version = 1.20.1
57 | flywheel_minecraft_version = 1.20.1
58 | create_version = 0.5.1.j-55
59 | flywheel_version = 0.6.11-13
60 | registrate_version = MC1.20-1.3.3
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
2 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoePus/Flerovium/45e2ee56e6541c218b2ee7ed0c3c26091dc754b0/icon.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | maven {
5 | name = 'MinecraftForge'
6 | url = 'https://maven.minecraftforge.net/'
7 | }
8 | }
9 | }
10 |
11 | plugins {
12 | id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
13 | }
14 |
15 | rootProject.name = 'Flerovium'
16 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/Config.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium;
2 |
3 | public class Config {
4 | public boolean entityBackFaceCulling = true;
5 | public boolean itemBackFaceCulling = true;
6 | }
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/ConfigParser.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import com.google.gson.JsonIOException;
6 | import com.google.gson.JsonSyntaxException;
7 | import net.minecraftforge.fml.loading.FMLPaths;
8 |
9 | import java.io.File;
10 | import java.io.FileReader;
11 | import java.io.FileWriter;
12 | import java.io.IOException;
13 | import java.nio.file.Paths;
14 | import java.util.function.Supplier;
15 |
16 | public class ConfigParser {
17 | private static Config config;
18 | static Supplier config_path = ()->String.valueOf(Paths.get(String.valueOf(FMLPaths.CONFIGDIR.get()),
19 | "flerovium.json"));
20 |
21 | public static void loadConfig() {
22 | Gson gson = new Gson();
23 | File configFile = new File(config_path.get());
24 |
25 | if (!configFile.exists()) {
26 | config = new Config();
27 | saveConfig();
28 | } else {
29 | // Load the existing config
30 | try (FileReader reader = new FileReader(configFile)) {
31 | config = gson.fromJson(reader, Config.class);
32 | saveConfig();
33 | } catch (JsonIOException | JsonSyntaxException | IOException e) {
34 | e.printStackTrace();
35 | }
36 | }
37 | }
38 |
39 | public static void saveConfig() {
40 | Gson gson = new GsonBuilder().setPrettyPrinting().create();
41 | try (FileWriter writer = new FileWriter(config_path.get())) {
42 | gson.toJson(config, writer);
43 | } catch (IOException e) {
44 | Flerovium.LOGGER.error(e.getMessage());;
45 | }
46 | }
47 |
48 | public static Config getConfig() {
49 | if (config == null) {
50 | loadConfig();
51 | }
52 | return config;
53 | }
54 | }
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/Flerovium.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium;
2 |
3 | import com.mojang.logging.LogUtils;
4 | import net.minecraftforge.api.distmarker.Dist;
5 | import net.minecraftforge.common.MinecraftForge;
6 | import net.minecraftforge.eventbus.api.IEventBus;
7 | import net.minecraftforge.eventbus.api.SubscribeEvent;
8 | import net.minecraftforge.fml.common.Mod;
9 | import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
10 | import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
11 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
12 | import org.slf4j.Logger;
13 |
14 | // The value here should match an entry in the META-INF/mods.toml file
15 | @Mod(Flerovium.MODID)
16 | public class Flerovium {
17 | // Define mod id in a common place for everything to reference
18 | public static final String MODID = "flerovium";
19 | // Directly reference a slf4j logger
20 | public static final Logger LOGGER = LogUtils.getLogger();
21 | // Create a Deferred Register to hold Blocks which will all be registered under the "flerovium" namespace
22 | public static final Config config = ConfigParser.getConfig();
23 |
24 | public Flerovium() {
25 | IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
26 |
27 | // Register the commonSetup method for modloading
28 | modEventBus.addListener(this::commonSetup);
29 |
30 | // Register ourselves for server and other game events we are interested in
31 | MinecraftForge.EVENT_BUS.register(this);
32 | }
33 |
34 | private void commonSetup(final FMLCommonSetupEvent event) {
35 | }
36 |
37 | // You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent
38 | @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
39 | public static class ClientModEvents {
40 |
41 | @SubscribeEvent
42 | public static void onClientSetup(FMLClientSetupEvent event)
43 | {
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/MixinPlugin.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium;
2 |
3 | import net.minecraftforge.api.distmarker.Dist;
4 | import net.minecraftforge.fml.loading.FMLLoader;
5 | import net.minecraftforge.fml.loading.LoadingModList;
6 | import org.objectweb.asm.tree.ClassNode;
7 | import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
8 | import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
9 |
10 | import java.util.List;
11 | import java.util.Set;
12 |
13 | public class MixinPlugin implements IMixinConfigPlugin {
14 | @Override
15 | public void onLoad(String mixinPackage) {
16 | }
17 |
18 | @Override
19 | public String getRefMapperConfig() {
20 | return null;
21 | }
22 |
23 | private static boolean isModLoaded(String modId) {
24 | return LoadingModList.get().getModFileById(modId) != null;
25 | }
26 |
27 | @Override
28 | public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
29 | return switch (mixinClassName) {
30 | case "com.moepus.flerovium.mixins.Entity.ModelPartMixin" -> !isModLoaded("bendylib") && !isModLoaded("physicsmod");
31 | case "com.moepus.flerovium.mixins.Chunk.FrustumMixin" -> !isModLoaded("acedium") && !isModLoaded("nvidium");
32 | default -> true;
33 | };
34 | }
35 |
36 | @Override
37 | public void acceptTargets(Set myTargets, Set otherTargets) {
38 |
39 | }
40 |
41 | @Override
42 | public List getMixins() {
43 | return null;
44 | }
45 |
46 | @Override
47 | public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
48 | }
49 |
50 | @Override
51 | public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
52 |
53 | }
54 | }
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/functions/Chunk/FastSimpleFrustum.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.functions.Chunk;
2 |
3 | import me.jellysquid.mods.sodium.client.render.viewport.frustum.Frustum;
4 | import org.joml.FrustumIntersection;
5 | import org.joml.Vector4f;
6 |
7 | import java.lang.reflect.Field;
8 |
9 | public class FastSimpleFrustum implements Frustum {
10 | // The bounding box of a chunk section must be large enough to contain all possible geometry within it. Block models
11 | // can extend outside a block volume by +/- 1.0 blocks on all axis. Additionally, we make use of a small epsilon
12 | // to deal with floating point imprecision during a frustum check (see GH#2132).
13 | public static final float CHUNK_SECTION_RADIUS = 8.0f /* chunk bounds */;
14 | public static final float CHUNK_SECTION_SIZE = CHUNK_SECTION_RADIUS + 1.0f /* maximum model extent */ + 0.125f /* epsilon */;
15 |
16 | // all the w components are double negated
17 | private float nxX, nxY, nxZ, negNxW;
18 | private float pxX, pxY, pxZ, negPxW;
19 | private float nyX, nyY, nyZ, negNyW;
20 | private float pyX, pyY, pyZ, negPyW;
21 | private float nzX, nzY, nzZ, negNzW;
22 |
23 | public FastSimpleFrustum(FrustumIntersection frustumIntersection) {
24 | Vector4f[] planes = getFrustumPlanes(frustumIntersection);
25 |
26 | nxX = planes[0].x;
27 | nxY = planes[0].y;
28 | nxZ = planes[0].z;
29 | pxX = planes[1].x;
30 | pxY = planes[1].y;
31 | pxZ = planes[1].z;
32 | nyX = planes[2].x;
33 | nyY = planes[2].y;
34 | nyZ = planes[2].z;
35 | pyX = planes[3].x;
36 | pyY = planes[3].y;
37 | pyZ = planes[3].z;
38 | nzX = planes[4].x;
39 | nzY = planes[4].y;
40 | nzZ = planes[4].z;
41 |
42 | final float size = CHUNK_SECTION_SIZE;
43 | negNxW = 2 * (-(planes[0].w + nxX * (nxX < 0 ? -size : size) +
44 | nxY * (nxY < 0 ? -size : size) +
45 | nxZ * (nxZ < 0 ? -size : size)));
46 | negPxW = 2 * (-(planes[1].w + pxX * (pxX < 0 ? -size : size) +
47 | pxY * (pxY < 0 ? -size : size) +
48 | pxZ * (pxZ < 0 ? -size : size)));
49 | negNyW = 2 * (-(planes[2].w + nyX * (nyX < 0 ? -size : size) +
50 | nyY * (nyY < 0 ? -size : size) +
51 | nyZ * (nyZ < 0 ? -size : size)));
52 | negPyW = 2 * (-(planes[3].w + pyX * (pyX < 0 ? -size : size) +
53 | pyY * (pyY < 0 ? -size : size) +
54 | pyZ * (pyZ < 0 ? -size : size)));
55 | negNzW = 2 * (-(planes[4].w + nzX * (nzX < 0 ? -size : size) +
56 | nzY * (nzY < 0 ? -size : size) +
57 | nzZ * (nzZ < 0 ? -size : size)));
58 | }
59 |
60 | private static Vector4f[] getFrustumPlanes(Object frustumIntersection) {
61 | Vector4f[] planes;
62 | try {
63 | Field planesField = FrustumIntersection.class.getDeclaredField("planes");
64 | planesField.setAccessible(true);
65 | planes = (Vector4f[]) planesField.get(frustumIntersection);
66 | } catch (NoSuchFieldException | IllegalAccessException e) {
67 | throw new RuntimeException("Failed to access planes field in FrustumIntersection", e);
68 | }
69 | return planes;
70 | }
71 |
72 | public boolean testCubeQuick(float wx, float wy, float wz) {
73 | // Skip far plane checks because it has been ensured by searchDistance and isWithinRenderDistance check in OcclusionCuller
74 | return nxX * wx + nxY * wy + nxZ * wz >= negNxW &&
75 | pxX * wx + pxY * wy + pxZ * wz >= negPxW &&
76 | nyX * wx + nyY * wy + nyZ * wz >= negNyW &&
77 | pyX * wx + pyY * wy + pyZ * wz >= negPyW &&
78 | nzX * wx + nzY * wy + nzZ * wz >= negNzW;
79 | }
80 |
81 | @Override
82 | public boolean testAab(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
83 | return testCubeQuick(minX + maxX, minY + maxY, minZ + maxZ);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/functions/Chunk/Occlusion.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.functions.Chunk;
2 |
3 | import me.jellysquid.mods.sodium.client.render.chunk.occlusion.GraphDirection;
4 | import org.spongepowered.asm.mixin.Unique;
5 |
6 | public class Occlusion {
7 | public static long ThroughUpDown = between(GraphDirection.UP, GraphDirection.DOWN);
8 |
9 | public static long ThroughNorthSouth = between(GraphDirection.NORTH, GraphDirection.SOUTH);
10 |
11 | public static long ThroughEastWest = between(GraphDirection.EAST, GraphDirection.WEST);
12 |
13 | public static int bit(int from, int to) {
14 | return (from * 8) + to;
15 | }
16 |
17 | public static long dir(int from, int to) {
18 | return (1L << bit(from, to));
19 | }
20 |
21 | public static long between(int from, int to) {
22 | return dir(from, to) | dir(to, from);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/functions/DummyModel.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.functions;
2 |
3 |
4 | import net.minecraft.client.renderer.block.model.BakedQuad;
5 | import net.minecraft.client.renderer.block.model.ItemOverrides;
6 | import net.minecraft.client.renderer.texture.TextureAtlasSprite;
7 | import net.minecraft.client.resources.model.BakedModel;
8 | import net.minecraft.core.Direction;
9 | import net.minecraft.util.RandomSource;
10 | import net.minecraft.world.level.block.state.BlockState;
11 | import org.jetbrains.annotations.Nullable;
12 |
13 | import java.util.List;
14 |
15 | public class DummyModel implements BakedModel {
16 | static final List EMPTY_QUADS = List.of();
17 |
18 | @Override
19 | public List getQuads(@Nullable BlockState blockState, @Nullable Direction direction, RandomSource randomSource) {
20 | return EMPTY_QUADS;
21 | }
22 |
23 | @Override
24 | public boolean useAmbientOcclusion() {
25 | return false;
26 | }
27 |
28 | @Override
29 | public boolean isGui3d() {
30 | return false;
31 | }
32 |
33 | @Override
34 | public boolean usesBlockLight() {
35 | return false;
36 | }
37 |
38 | @Override
39 | public boolean isCustomRenderer() {
40 | return false;
41 | }
42 |
43 | @Override
44 | public TextureAtlasSprite getParticleIcon() {
45 | return null;
46 | }
47 |
48 | @Override
49 | public ItemOverrides getOverrides() {
50 | return null;
51 | }
52 | }
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/functions/FastEntityRenderer.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.functions;
2 |
3 | import com.moepus.flerovium.Flerovium;
4 | import com.mojang.blaze3d.systems.RenderSystem;
5 | import com.mojang.blaze3d.vertex.PoseStack;
6 | import me.jellysquid.mods.sodium.client.render.immediate.model.ModelCuboid;
7 | import me.jellysquid.mods.sodium.client.render.immediate.model.ModelPartData;
8 | import net.caffeinemc.mods.sodium.api.math.MatrixHelper;
9 | import net.caffeinemc.mods.sodium.api.vertex.attributes.common.NormalAttribute;
10 | import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter;
11 | import net.caffeinemc.mods.sodium.api.vertex.format.common.ModelVertex;
12 | import net.minecraft.client.model.geom.ModelPart;
13 | import org.apache.commons.lang3.ArrayUtils;
14 | import org.embeddedt.embeddium.render.matrix_stack.CachingPoseStack;
15 | import org.joml.*;
16 | import org.lwjgl.system.MemoryStack;
17 | import org.lwjgl.system.MemoryUtil;
18 |
19 | import static com.moepus.flerovium.functions.MathUtil.*;
20 |
21 | public class FastEntityRenderer {
22 |
23 | private static final int NUM_CUBE_VERTICES = 8;
24 | private static final int NUM_CUBE_FACES = 6;
25 | private static final int NUM_FACE_VERTICES = 4;
26 |
27 | private static final byte
28 | FACE_NEG_Y = 0, // DOWN
29 | FACE_POS_Y = 1, // UP
30 | FACE_NEG_Z = 2, // NORTH
31 | FACE_POS_Z = 3, // SOUTH
32 | FACE_NEG_X = 4, // WEST
33 | FACE_POS_X = 5; // EAST
34 |
35 | private static final byte
36 | VERTEX_X1_Y1_Z1 = 0,
37 | VERTEX_X2_Y1_Z1 = 1,
38 | VERTEX_X2_Y2_Z1 = 2,
39 | VERTEX_X1_Y2_Z1 = 3,
40 | VERTEX_X1_Y1_Z2 = 4,
41 | VERTEX_X2_Y1_Z2 = 5,
42 | VERTEX_X2_Y2_Z2 = 6,
43 | VERTEX_X1_Y2_Z2 = 7;
44 |
45 |
46 | private static final long SCRATCH_BUFFER = MemoryUtil.nmemAlignedAlloc(64, NUM_CUBE_FACES * NUM_FACE_VERTICES * ModelVertex.STRIDE);
47 | private static final MemoryStack STACK = MemoryStack.create();
48 |
49 | static class Vertex {
50 | public long xy;
51 | public long zw;
52 |
53 | public void set(float x, float y, float z, int color) {
54 | this.xy = compose(Float.floatToRawIntBits(x), Float.floatToRawIntBits(y));
55 | this.zw = compose(Float.floatToRawIntBits(z), color);
56 | }
57 | }
58 |
59 | private static final Vertex[] CUBE_CORNERS = new Vertex[NUM_CUBE_VERTICES];
60 | private static final byte[][] CUBE_VERTICES = new byte[][]{
61 | {VERTEX_X2_Y1_Z2, VERTEX_X1_Y1_Z2, VERTEX_X1_Y1_Z1, VERTEX_X2_Y1_Z1},
62 | {VERTEX_X2_Y2_Z1, VERTEX_X1_Y2_Z1, VERTEX_X1_Y2_Z2, VERTEX_X2_Y2_Z2},
63 | {VERTEX_X2_Y1_Z1, VERTEX_X1_Y1_Z1, VERTEX_X1_Y2_Z1, VERTEX_X2_Y2_Z1},
64 | {VERTEX_X1_Y1_Z2, VERTEX_X2_Y1_Z2, VERTEX_X2_Y2_Z2, VERTEX_X1_Y2_Z2},
65 | {VERTEX_X1_Y1_Z1, VERTEX_X1_Y1_Z2, VERTEX_X1_Y2_Z2, VERTEX_X1_Y2_Z1},
66 | {VERTEX_X2_Y1_Z2, VERTEX_X2_Y1_Z1, VERTEX_X2_Y2_Z1, VERTEX_X2_Y2_Z2},
67 | };
68 |
69 | private static final Vertex[][] VERTEX_POSITIONS = new Vertex[NUM_CUBE_FACES][NUM_FACE_VERTICES];
70 | private static final long[][] VERTEX_TEXTURES = new long[NUM_CUBE_FACES][NUM_FACE_VERTICES];
71 |
72 | private static final int[] CUBE_NORMALS = new int[NUM_CUBE_FACES];
73 |
74 | private static int FACE;
75 |
76 | static {
77 | for (int cornerIndex = 0; cornerIndex < NUM_CUBE_VERTICES; cornerIndex++) {
78 | CUBE_CORNERS[cornerIndex] = new Vertex();
79 | }
80 |
81 | for (int quadIndex = 0; quadIndex < NUM_CUBE_FACES; quadIndex++) {
82 | for (int vertexIndex = 0; vertexIndex < NUM_FACE_VERTICES; vertexIndex++) {
83 | VERTEX_POSITIONS[quadIndex][vertexIndex] = CUBE_CORNERS[CUBE_VERTICES[quadIndex][vertexIndex]];
84 | }
85 | }
86 | }
87 |
88 | public static void render(PoseStack matrixStack, VertexBufferWriter writer, ModelPart part, int light, int overlay, int color) {
89 | ModelPartData accessor = ModelPartData.from(part);
90 |
91 | if (!accessor.isVisible()) {
92 | return;
93 | }
94 |
95 | var cuboids = accessor.getCuboids();
96 | var children = accessor.getChildren();
97 |
98 | if (ArrayUtils.isEmpty(cuboids) && ArrayUtils.isEmpty(children)) {
99 | return;
100 | }
101 |
102 | ((CachingPoseStack) matrixStack).embeddium$setCachingEnabled(true);
103 |
104 | matrixStack.pushPose();
105 |
106 | part.translateAndRotate(matrixStack);
107 |
108 | if (!accessor.isHidden()) {
109 | renderCuboids(matrixStack.last(), writer, cuboids, light, overlay, color);
110 | }
111 |
112 | renderChildren(matrixStack, writer, light, overlay, color, children);
113 |
114 | matrixStack.popPose();
115 |
116 | ((CachingPoseStack) matrixStack).embeddium$setCachingEnabled(false);
117 | }
118 |
119 | private static void renderCuboids(PoseStack.Pose matrices, VertexBufferWriter writer, ModelCuboid[] cuboids, int light, int overlay, int color) {
120 | prepareNormals(matrices);
121 |
122 | for (ModelCuboid cuboid : cuboids) {
123 | prepareVertices(matrices, cuboid, color);
124 |
125 | var vertexCount = emitQuads(cuboid, overlay, light);
126 |
127 | try (MemoryStack stack = MemoryStack.stackPush()) {
128 | writer.push(stack, SCRATCH_BUFFER, vertexCount, ModelVertex.FORMAT);
129 | }
130 | }
131 | }
132 |
133 | private static void renderChildren(PoseStack matrices, VertexBufferWriter writer, int light, int overlay, int color, ModelPart[] children) {
134 | for (ModelPart part : children) {
135 | render(matrices, writer, part, light, overlay, color);
136 | }
137 | }
138 |
139 | public static void renderCuboidFast(PoseStack.Pose matrices, VertexBufferWriter writer, ModelCuboid cuboid, int light, int overlay, int color) {
140 | prepareVertices(matrices, cuboid, color);
141 |
142 | var vertexCount = emitQuads(cuboid, overlay, light);
143 |
144 | STACK.push();
145 | writer.push(STACK, SCRATCH_BUFFER, vertexCount, ModelVertex.FORMAT);
146 | STACK.pop();
147 | }
148 |
149 | private static int emitQuads(ModelCuboid cuboid, int overlay, int light) {
150 | final long packedOverlayLight = compose(overlay, light);
151 | var vertexCount = 0;
152 | long ptr = SCRATCH_BUFFER;
153 |
154 | if (!cuboid.mirror) {
155 | for (int quadIndex = 0; quadIndex < NUM_CUBE_FACES; quadIndex++) {
156 | if (!cuboid.shouldDrawFace(quadIndex) || (FACE & (1 << quadIndex)) == 0) {
157 | continue;
158 | }
159 | int normal = CUBE_NORMALS[quadIndex];
160 |
161 | emitVertex(ptr, VERTEX_POSITIONS[quadIndex][0], VERTEX_TEXTURES[quadIndex][0], packedOverlayLight, normal);
162 | ptr += ModelVertex.STRIDE;
163 |
164 | emitVertex(ptr, VERTEX_POSITIONS[quadIndex][1], VERTEX_TEXTURES[quadIndex][1], packedOverlayLight, normal);
165 | ptr += ModelVertex.STRIDE;
166 |
167 | emitVertex(ptr, VERTEX_POSITIONS[quadIndex][2], VERTEX_TEXTURES[quadIndex][2], packedOverlayLight, normal);
168 | ptr += ModelVertex.STRIDE;
169 |
170 | emitVertex(ptr, VERTEX_POSITIONS[quadIndex][3], VERTEX_TEXTURES[quadIndex][3], packedOverlayLight, normal);
171 | ptr += ModelVertex.STRIDE;
172 |
173 | vertexCount += 4;
174 | }
175 | } else {
176 | for (int quadIndex = 0; quadIndex < NUM_CUBE_FACES; quadIndex++) {
177 | if (!cuboid.shouldDrawFace(quadIndex) || (FACE & (1 << quadIndex)) == 0) {
178 | continue;
179 | }
180 | int normal = CUBE_NORMALS[quadIndex];
181 |
182 | emitVertex(ptr, VERTEX_POSITIONS[quadIndex][3], VERTEX_TEXTURES[quadIndex][3], packedOverlayLight, normal);
183 | ptr += ModelVertex.STRIDE;
184 |
185 | emitVertex(ptr, VERTEX_POSITIONS[quadIndex][2], VERTEX_TEXTURES[quadIndex][2], packedOverlayLight, normal);
186 | ptr += ModelVertex.STRIDE;
187 |
188 | emitVertex(ptr, VERTEX_POSITIONS[quadIndex][1], VERTEX_TEXTURES[quadIndex][1], packedOverlayLight, normal);
189 | ptr += ModelVertex.STRIDE;
190 |
191 | emitVertex(ptr, VERTEX_POSITIONS[quadIndex][0], VERTEX_TEXTURES[quadIndex][0], packedOverlayLight, normal);
192 | ptr += ModelVertex.STRIDE;
193 |
194 | vertexCount += 4;
195 | }
196 | }
197 |
198 | return vertexCount;
199 | }
200 |
201 | private static void emitVertex(long ptr, Vertex vertex, long uv, long packedOverlayLight, int normal) {
202 | MemoryUtil.memPutLong(ptr + 0L, vertex.xy);
203 | MemoryUtil.memPutLong(ptr + 8L, vertex.zw); // overlaps with color attribute
204 | MemoryUtil.memPutLong(ptr + 16L, uv);
205 | MemoryUtil.memPutLong(ptr + 24L, packedOverlayLight);
206 | NormalAttribute.set(ptr + 32L, normal);
207 | }
208 |
209 | private static void prepareVertices(PoseStack.Pose matrices, ModelCuboid cuboid, int color) {
210 | Matrix4f pose = matrices.pose();
211 |
212 | /**
213 | * Build a Cube from a Vertex and 3 Vectors
214 | *
215 | * Using one vertex (P1) and three vectors (X, Y, Z):
216 | *
217 | * P8 +----------------+ P7
218 | * /| /|
219 | * / | / |
220 | * P4 +----------------+ P3|
221 | * | | | |
222 | * | | | |
223 | * | P5 +-----------|--+ P6
224 | * | / | /
225 | * |/ |/
226 | * P1 +----------------+ P2
227 | *
228 | * Vertices:
229 | * P2 = P1 + X
230 | * P3 = P2 + Y
231 | * P4 = P1 + Y
232 | * P5 = P1 + Z
233 | * P6 = P2 + Z
234 | * P7 = P6 + Y
235 | * P8 = P5 + Y
236 | */
237 | float p1x = MatrixHelper.transformPositionX(pose, cuboid.x1, cuboid.y1, cuboid.z1);
238 | float p1y = MatrixHelper.transformPositionY(pose, cuboid.x1, cuboid.y1, cuboid.z1);
239 | float p1z = MatrixHelper.transformPositionZ(pose, cuboid.x1, cuboid.y1, cuboid.z1);
240 | CUBE_CORNERS[VERTEX_X1_Y1_Z1].set(p1x, p1y, p1z, color);
241 |
242 | float lx = cuboid.x2 - cuboid.x1, ly = cuboid.y2 - cuboid.y1, lz = cuboid.z2 - cuboid.z1;
243 | float vxx = pose.m00() * lx, vxy = pose.m01() * lx, vxz = pose.m02() * lx;
244 | float vyx = pose.m10() * ly, vyy = pose.m11() * ly, vyz = pose.m12() * ly;
245 | float vzx = pose.m20() * lz, vzy = pose.m21() * lz, vzz = pose.m22() * lz;
246 |
247 | float p2x = p1x + vxx;
248 | float p2y = p1y + vxy;
249 | float p2z = p1z + vxz;
250 | CUBE_CORNERS[VERTEX_X2_Y1_Z1].set(p2x, p2y, p2z, color);
251 |
252 | float p3x = p2x + vyx;
253 | float p3y = p2y + vyy;
254 | float p3z = p2z + vyz;
255 | CUBE_CORNERS[VERTEX_X2_Y2_Z1].set(p3x, p3y, p3z, color);
256 |
257 | float p4x = p1x + vyx;
258 | float p4y = p1y + vyy;
259 | float p4z = p1z + vyz;
260 | CUBE_CORNERS[VERTEX_X1_Y2_Z1].set(p4x, p4y, p4z, color);
261 |
262 | float p5x = p1x + vzx;
263 | float p5y = p1y + vzy;
264 | float p5z = p1z + vzz;
265 | CUBE_CORNERS[VERTEX_X1_Y1_Z2].set(p5x, p5y, p5z, color);
266 |
267 | float p6x = p2x + vzx;
268 | float p6y = p2y + vzy;
269 | float p6z = p2z + vzz;
270 | CUBE_CORNERS[VERTEX_X2_Y1_Z2].set(p6x, p6y, p6z, color);
271 |
272 | float p7x = p3x + vzx;
273 | float p7y = p3y + vzy;
274 | float p7z = p3z + vzz;
275 | CUBE_CORNERS[VERTEX_X2_Y2_Z2].set(p7x, p7y, p7z, color);
276 |
277 | float p8x = p4x + vzx;
278 | float p8y = p4y + vzy;
279 | float p8z = p4z + vzz;
280 | CUBE_CORNERS[VERTEX_X1_Y2_Z2].set(p8x, p8y, p8z, color);
281 |
282 | buildVertexTexCoord(VERTEX_TEXTURES[FACE_NEG_Y], cuboid.u1, cuboid.v0, cuboid.u2, cuboid.v1);
283 | buildVertexTexCoord(VERTEX_TEXTURES[FACE_POS_Y], cuboid.u2, cuboid.v1, cuboid.u3, cuboid.v0);
284 | buildVertexTexCoord(VERTEX_TEXTURES[FACE_NEG_Z], cuboid.u1, cuboid.v1, cuboid.u2, cuboid.v2);
285 | buildVertexTexCoord(VERTEX_TEXTURES[FACE_POS_Z], cuboid.u4, cuboid.v1, cuboid.u5, cuboid.v2);
286 | buildVertexTexCoord(VERTEX_TEXTURES[FACE_NEG_X], cuboid.u0, cuboid.v1, cuboid.u1, cuboid.v2);
287 | buildVertexTexCoord(VERTEX_TEXTURES[FACE_POS_X], cuboid.u2, cuboid.v1, cuboid.u4, cuboid.v2);
288 |
289 | FACE = ~0;
290 | if (!Flerovium.config.entityBackFaceCulling)
291 | return;
292 |
293 | if (matrices.pose().m32() <= -16.0F && RenderSystem.modelViewMatrix.m32() == 0 && ly != 0) {
294 | Matrix3f normal = matrices.normal();
295 |
296 | float posX = p1x + p8x;
297 | float posY = p1y + p8y;
298 | float posZ = p1z + p8z;
299 | if (posX * normal.m00 + posY * normal.m01 + posZ * normal.m02 < 0)
300 | FACE &= ~(1 << (lx > 0 ? FACE_NEG_X : FACE_POS_X));
301 |
302 | posX = p2x + p7x;
303 | posY = p2y + p7y;
304 | posZ = p2z + p7z;
305 | if (posX * normal.m00 + posY * normal.m01 + posZ * normal.m02 > 0)
306 | FACE &= ~(1 << (lx < 0 ? FACE_NEG_X : FACE_POS_X));
307 |
308 | posX = p1x + p3x;
309 | posY = p1y + p3y;
310 | posZ = p1z + p3z;
311 | if (posX * normal.m20 + posY * normal.m21 + posZ * normal.m22 < 0) FACE &= ~(1 << FACE_NEG_Z);
312 |
313 | posX = p5x + p7x;
314 | posY = p5y + p7y;
315 | posZ = p5z + p7z;
316 | if (posX * normal.m20 + posY * normal.m21 + posZ * normal.m22 > 0) FACE &= ~(1 << FACE_POS_Z);
317 |
318 | posX = p1x + p6x;
319 | posY = p1y + p6y;
320 | posZ = p1z + p6z;
321 | if (posX * normal.m10 + posY * normal.m11 + posZ * normal.m12 < 0) FACE &= ~(1 << FACE_NEG_Y);
322 |
323 | posX = p4x + p7x;
324 | posY = p4y + p7y;
325 | posZ = p4z + p7z;
326 | if (posX * normal.m10 + posY * normal.m11 + posZ * normal.m12 > 0) FACE &= ~(1 << FACE_POS_Y);
327 | }
328 | }
329 |
330 | public static void prepareNormals(PoseStack.Pose matrices) {
331 | Matrix3f normal = matrices.normal();
332 | CUBE_NORMALS[FACE_NEG_Y] = normal2IntClamp(-normal.m10, -normal.m11, -normal.m12);
333 | CUBE_NORMALS[FACE_POS_Y] = normal2IntClamp(normal.m10, normal.m11, normal.m12);
334 | CUBE_NORMALS[FACE_NEG_Z] = normal2IntClamp(-normal.m20, -normal.m21, -normal.m22);
335 | CUBE_NORMALS[FACE_POS_Z] = normal2IntClamp(normal.m20, normal.m21, normal.m22);
336 | CUBE_NORMALS[FACE_NEG_X] = normal2IntClamp(-normal.m00, -normal.m01, -normal.m02);
337 | CUBE_NORMALS[FACE_POS_X] = normal2IntClamp(normal.m00, normal.m01, normal.m02);
338 | }
339 |
340 | private static void buildVertexTexCoord(long[] uvs, float u1, float v1, float u2, float v2) {
341 | uvs[0] = compose(Float.floatToRawIntBits(u2), Float.floatToRawIntBits(v1));
342 | uvs[1] = compose(Float.floatToRawIntBits(u1), Float.floatToRawIntBits(v1));
343 | uvs[2] = compose(Float.floatToRawIntBits(u1), Float.floatToRawIntBits(v2));
344 | uvs[3] = compose(Float.floatToRawIntBits(u2), Float.floatToRawIntBits(v2));
345 | }
346 | }
347 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/functions/FastSimpleBakedModelRenderer.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.functions;
2 |
3 | import com.mojang.blaze3d.vertex.PoseStack;
4 | import me.jellysquid.mods.sodium.client.model.color.interop.ItemColorsExtended;
5 | import me.jellysquid.mods.sodium.client.model.quad.BakedQuadView;
6 | import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing;
7 | import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil;
8 | import net.caffeinemc.mods.sodium.api.math.MatrixHelper;
9 | import net.caffeinemc.mods.sodium.api.util.ColorARGB;
10 | import net.caffeinemc.mods.sodium.api.util.NormI8;
11 | import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter;
12 | import net.caffeinemc.mods.sodium.api.vertex.format.common.ModelVertex;
13 | import net.minecraft.client.color.item.ItemColor;
14 | import net.minecraft.client.color.item.ItemColors;
15 | import net.minecraft.client.renderer.block.model.BakedQuad;
16 | import net.minecraft.client.resources.model.SimpleBakedModel;
17 | import net.minecraft.core.Direction;
18 | import net.minecraft.world.item.ItemStack;
19 | import org.joml.Math;
20 | import org.joml.Matrix3f;
21 | import org.joml.Matrix4f;
22 | import org.joml.Vector3f;
23 | import org.lwjgl.system.MemoryStack;
24 | import org.lwjgl.system.MemoryUtil;
25 |
26 | import java.util.List;
27 |
28 | import static com.moepus.flerovium.functions.MathUtil.*;
29 |
30 | public class FastSimpleBakedModelRenderer {
31 | private static final MemoryStack STACK = MemoryStack.create();
32 | private static final int VERTEX_COUNT = 4;
33 | private static final int BUFFER_VERTEX_COUNT = 48;
34 | private static final int STRIDE = 8;
35 | private static final long SCRATCH_BUFFER = MemoryUtil.nmemAlignedAlloc(64, BUFFER_VERTEX_COUNT * ModelVertex.STRIDE);
36 | private static long BUFFER_PTR = SCRATCH_BUFFER;
37 | private static int BUFFED_VERTEX = 0;
38 | private static int LAST_TINT_INDEX = -1;
39 | private static int LAST_TINT = -1;
40 |
41 | public static int multiplyIntBytes(int a, int b) {
42 | int first = ((a & 0xff) * (b & 0xff) + 127) / 255;
43 | int second = (((a >>> 8) & 0xff) * ((b >>> 8) & 0xff) + 127) / 255;
44 | int third = (((a >>> 16) & 0xff) * ((b >>> 16) & 0xff) + 127) / 255;
45 | return first | second << 8 | third << 16 | (b & 0xff000000);
46 | }
47 |
48 | private static void flush(VertexBufferWriter writer) {
49 | if (BUFFED_VERTEX == 0) return;
50 | STACK.push();
51 | writer.push(STACK, SCRATCH_BUFFER, BUFFED_VERTEX, ModelVertex.FORMAT);
52 | STACK.pop();
53 | BUFFER_PTR = SCRATCH_BUFFER;
54 | BUFFED_VERTEX = 0;
55 | }
56 |
57 | private static boolean isBufferMax() {
58 | return BUFFED_VERTEX >= BUFFER_VERTEX_COUNT;
59 | }
60 |
61 | // Check for functional storage, they are doing rotation by mul the pose only but not normal.
62 | // Sign for X axis should be the same.
63 | private static boolean checkNormalRotateEqual(PoseStack.Pose pose) {
64 | return ((Float.floatToRawIntBits(pose.pose().m00()) ^ Float.floatToRawIntBits(pose.normal().m00())) >> 31) +
65 | ((Float.floatToRawIntBits(pose.pose().m10()) ^ Float.floatToRawIntBits(pose.normal().m10())) >> 31) +
66 | ((Float.floatToRawIntBits(pose.pose().m20()) ^ Float.floatToRawIntBits(pose.normal().m20())) >> 31)
67 | == 0;
68 | }
69 |
70 | private static void putBulkData(VertexBufferWriter writer, PoseStack.Pose pose, BakedQuad bakedQuad,
71 | int light, int overlay, int color, int faces) {
72 | int[] vertices = bakedQuad.getVertices();
73 | if (vertices.length != VERTEX_COUNT * STRIDE) return;
74 | Matrix4f pose_matrix = pose.pose();
75 | int baked_normal = vertices[7];
76 | float unpackedX = NormI8.unpackX(baked_normal);
77 | float unpackedY = NormI8.unpackY(baked_normal);
78 | float unpackedZ = NormI8.unpackZ(baked_normal);
79 | float nx = MatrixHelper.transformNormalX(pose.normal(), unpackedX, unpackedY, unpackedZ);
80 | float ny = MatrixHelper.transformNormalY(pose.normal(), unpackedX, unpackedY, unpackedZ);
81 | float nz = MatrixHelper.transformNormalZ(pose.normal(), unpackedX, unpackedY, unpackedZ);
82 |
83 | float x = Float.intBitsToFloat(vertices[0]), y = Float.intBitsToFloat(vertices[1]), z = Float.intBitsToFloat(vertices[2]);
84 | float pos0_x = MatrixHelper.transformPositionX(pose_matrix, x, y, z);
85 | float pos0_y = MatrixHelper.transformPositionY(pose_matrix, x, y, z);
86 | float pos0_z = MatrixHelper.transformPositionZ(pose_matrix, x, y, z);
87 | x = Float.intBitsToFloat(vertices[STRIDE * 2]);
88 | y = Float.intBitsToFloat(vertices[STRIDE * 2 + 1]);
89 | z = Float.intBitsToFloat(vertices[STRIDE * 2 + 2]);
90 |
91 | float pos2_x = MatrixHelper.transformPositionX(pose_matrix, x, y, z);
92 | float pos2_y = MatrixHelper.transformPositionY(pose_matrix, x, y, z);
93 | float pos2_z = MatrixHelper.transformPositionZ(pose_matrix, x, y, z);
94 |
95 | if ((faces & 0b1000000) != 0) { // Backface culling
96 | if (checkNormalRotateEqual(pose))
97 | if ((pos0_x + pos2_x) * nx + (pos0_y + pos2_y) * ny + (pos0_z + pos2_z) * nz > 0)
98 | if (((BakedQuadView) bakedQuad).getNormalFace() != ModelQuadFacing.UNASSIGNED)
99 | return;
100 | }
101 | int n = packSafe(nx, ny, nz);
102 |
103 | x = Float.intBitsToFloat(vertices[STRIDE]);
104 | y = Float.intBitsToFloat(vertices[STRIDE + 1]);
105 | z = Float.intBitsToFloat(vertices[STRIDE + 2]);
106 | float pos1_x = MatrixHelper.transformPositionX(pose_matrix, x, y, z);
107 | float pos1_y = MatrixHelper.transformPositionY(pose_matrix, x, y, z);
108 | float pos1_z = MatrixHelper.transformPositionZ(pose_matrix, x, y, z);
109 |
110 | x = Float.intBitsToFloat(vertices[STRIDE * 3]);
111 | y = Float.intBitsToFloat(vertices[STRIDE * 3 + 1]);
112 | z = Float.intBitsToFloat(vertices[STRIDE * 3 + 2]);
113 | float pos3_x = MatrixHelper.transformPositionX(pose_matrix, x, y, z);
114 | float pos3_y = MatrixHelper.transformPositionY(pose_matrix, x, y, z);
115 | float pos3_z = MatrixHelper.transformPositionZ(pose_matrix, x, y, z);
116 |
117 | final int c = color != -1 ? multiplyIntBytes(color, vertices[3]):vertices[3];
118 | final int baked = vertices[6];
119 | final int l = Math.max(((baked & 0xffff) << 16) | (baked >> 16), light);
120 | ModelVertex.write(BUFFER_PTR, pos0_x, pos0_y, pos0_z, c, Float.intBitsToFloat(vertices[4]),
121 | Float.intBitsToFloat(vertices[5]), overlay, l, n);
122 | BUFFER_PTR += ModelVertex.STRIDE;
123 | ModelVertex.write(BUFFER_PTR, pos1_x, pos1_y, pos1_z, c, Float.intBitsToFloat(vertices[STRIDE + 4]),
124 | Float.intBitsToFloat(vertices[STRIDE + 5]), overlay, l, n);
125 | BUFFER_PTR += ModelVertex.STRIDE;
126 | ModelVertex.write(BUFFER_PTR, pos2_x, pos2_y, pos2_z, c, Float.intBitsToFloat(vertices[STRIDE * 2 + 4]),
127 | Float.intBitsToFloat(vertices[STRIDE * 2 + 5]), overlay, l, n);
128 | BUFFER_PTR += ModelVertex.STRIDE;
129 | ModelVertex.write(BUFFER_PTR, pos3_x, pos3_y, pos3_z, c, Float.intBitsToFloat(vertices[STRIDE * 3 + 4]),
130 | Float.intBitsToFloat(vertices[STRIDE * 3 + 5]), overlay, l, n);
131 | BUFFER_PTR += ModelVertex.STRIDE;
132 |
133 | BUFFED_VERTEX += VERTEX_COUNT;
134 | if (isBufferMax()) flush(writer);
135 | }
136 |
137 | public static int GetItemTint(int tintIndex, ItemStack itemStack, ItemColor colorProvider) {
138 | if (tintIndex == LAST_TINT_INDEX) return LAST_TINT;
139 | int tint = colorProvider.getColor(itemStack, tintIndex);
140 | LAST_TINT = ColorARGB.toABGR(tint, 255);
141 | LAST_TINT_INDEX = tintIndex;
142 | return LAST_TINT;
143 | }
144 |
145 | private static void renderQuadList(PoseStack.Pose pose, VertexBufferWriter writer, int faces, List bakedQuads,
146 | int light, int overlay, ItemStack itemStack, ItemColor colorProvider) {
147 | for (BakedQuad bakedQuad : bakedQuads) {
148 | if ((faces & (1 << bakedQuad.getDirection().ordinal())) == 0) continue;
149 | int color = colorProvider != null && bakedQuad.getTintIndex() != -1 ? GetItemTint(bakedQuad.getTintIndex(), itemStack, colorProvider):-1;
150 | putBulkData(writer, pose, bakedQuad, light, overlay, color, faces);
151 | }
152 | if (pose.pose().m32() > -8.0F) { // Do animation for item in GUI or nearby in world
153 | for (BakedQuad bakedQuad : bakedQuads) {
154 | SpriteUtil.markSpriteActive(bakedQuad.getSprite());
155 | }
156 | }
157 | }
158 |
159 | public static void render(SimpleBakedModel model, int faces, ItemStack itemStack, int packedLight, int packedOverlay,
160 | PoseStack poseStack, VertexBufferWriter writer, ItemColors itemColors) {
161 | PoseStack.Pose pose = poseStack.last();
162 | ItemColor colorProvider = !itemStack.isEmpty() ? ((ItemColorsExtended) itemColors).sodium$getColorProvider(itemStack):null;
163 |
164 | LAST_TINT_INDEX = LAST_TINT = -1;
165 | for (Direction direction : Direction.values()) {
166 | renderQuadList(pose, writer, faces, model.getQuads(null, direction, null), packedLight, packedOverlay, itemStack, colorProvider);
167 | }
168 | renderQuadList(pose, writer, faces, model.getQuads(null, null, null), packedLight, packedOverlay, itemStack, colorProvider);
169 |
170 | flush(writer);
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/functions/IntFlatMap.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.functions;
2 |
3 | import java.util.Arrays;
4 |
5 | public class IntFlatMap {
6 | private int[] keys;
7 | private V[] values;
8 | private int size = 0;
9 |
10 | @SuppressWarnings("unchecked")
11 | public IntFlatMap(int capacity) {
12 | this.keys = new int[capacity];
13 | this.values = (V[]) new Object[capacity];
14 | }
15 |
16 | public int size() {
17 | return size;
18 | }
19 |
20 | public boolean isEmpty() {
21 | return size == 0;
22 | }
23 |
24 | public V get(int key) {
25 | int index = findIndex(key);
26 | return index >= 0 ? values[index] : null;
27 | }
28 |
29 | public void put(int key, V value) {
30 | if (size >= keys.length) {
31 | throw new ArrayIndexOutOfBoundsException();
32 | }
33 | keys[size] = key;
34 | values[size] = value;
35 | size++;
36 | }
37 |
38 | public V remove(int key) {
39 | int index = findIndex(key);
40 | if (index < 0) {
41 | return null;
42 | }
43 | V oldValue = values[index];
44 | shift(index);
45 | return oldValue;
46 | }
47 |
48 | private int findIndex(int key) {
49 | return Arrays.binarySearch(keys, key);
50 | }
51 |
52 | private void shift(int index) {
53 | System.arraycopy(keys, index + 1, keys, index, size - index - 1);
54 | System.arraycopy(values, index + 1, values, index, size - index - 1);
55 | values[size - 1] = null;
56 | size--;
57 | }
58 |
59 | public void resize(int newCapacity) {
60 | keys = Arrays.copyOf(keys, newCapacity);
61 | values = Arrays.copyOf(values, newCapacity);
62 | }
63 |
64 | public void sort() {
65 | if (size != keys.length) {
66 | resize(size);
67 | }
68 | quickSort(0, size - 1);
69 | }
70 |
71 | private void quickSort(int low, int high) {
72 | if (low < high) {
73 | int pi = partition(low, high);
74 | quickSort(low, pi - 1);
75 | quickSort(pi + 1, high);
76 | }
77 | }
78 |
79 | private int partition(int low, int high) {
80 | int pivot = keys[high];
81 | int i = (low - 1);
82 | for (int j = low; j < high; j++) {
83 | if (keys[j] < pivot) {
84 | i++;
85 | swap(i, j);
86 | }
87 | }
88 | swap(i + 1, high);
89 | return i + 1;
90 | }
91 |
92 | private void swap(int i, int j) {
93 | int tempintey = keys[i];
94 | keys[i] = keys[j];
95 | keys[j] = tempintey;
96 |
97 | V tempValue = values[i];
98 | values[i] = values[j];
99 | values[j] = tempValue;
100 | }
101 |
102 | public void clear() {
103 | Arrays.fill(keys, 0, size, 0);
104 | Arrays.fill(values, 0, size, null);
105 | size = 0;
106 | }
107 | }
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/functions/MathUtil.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.functions;
2 |
3 | import net.minecraft.util.Mth;
4 | import org.joml.Math;
5 |
6 | public class MathUtil {
7 |
8 | static final public float[] PACK_FACTOR = {127.0f, -127.0f};
9 | public static int packSafe(float x, float y, float z, float factor) {
10 | float scalar = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
11 |
12 | x *= scalar;
13 | y *= scalar;
14 | z *= scalar;
15 |
16 | int normX = (int) (x * factor) & 255;
17 | int normY = (int) (y * factor) & 255;
18 | int normZ = (int) (z * factor) & 255;
19 |
20 | return (normZ << 16) | (normY << 8) | normX;
21 | }
22 |
23 | public static int packSafe(float x, float y, float z) {
24 | float scalar = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
25 |
26 | x *= scalar;
27 | y *= scalar;
28 | z *= scalar;
29 |
30 | int normX = (int) (x * 127.0f) & 255;
31 | int normY = (int) (y * 127.0f) & 255;
32 | int normZ = (int) (z * 127.0f) & 255;
33 |
34 | return (normZ << 16) | (normY << 8) | normX;
35 | }
36 |
37 | public static int packUnsafe(float x, float y, float z, float factor) {
38 | int normX = (int) (x * factor) & 255;
39 | int normY = (int) (y * factor) & 255;
40 | int normZ = (int) (z * factor) & 255;
41 |
42 | return (normZ << 16) | (normY << 8) | normX;
43 | }
44 | public static int packUnsafe(float x, float y, float z) {
45 | int normX = (int) (x * 127.0f) & 255;
46 | int normY = (int) (y * 127.0f) & 255;
47 | int normZ = (int) (z * 127.0f) & 255;
48 |
49 | return (normZ << 16) | (normY << 8) | normX;
50 | }
51 |
52 | public static int normal2Int(float x, float y, float z) {
53 | float scalar = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
54 | return packUnsafe(x * scalar, y * scalar, z * scalar);
55 | }
56 |
57 | public static int normal2IntClamp(float x, float y, float z) {
58 | return packUnsafe(Mth.clamp(x, -1.0F, 1.0F), Mth.clamp(y, -1.0F, 1.0F), Mth.clamp(z, -1.0F, 1.0F));
59 | }
60 |
61 | public static boolean cullBackFace(byte viewX, byte viewY, byte viewZ, int normal) {
62 | byte normalX = (byte) normal;
63 | byte normalY = (byte) (normal >> 8);
64 | byte normalZ = (byte) (normal >> 16);
65 | return (int) viewX * (int) normalX + (int) viewY * (int) normalY + (int) viewZ * (int) normalZ > 768;
66 | }
67 |
68 | public static long compose(int lo, int hi) {
69 | return ((long) hi << 32) | (lo & 0xFFFFFFFFL);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/functions/MatrixStuff.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.functions;
2 |
3 | import org.joml.Math;
4 | import org.joml.Matrix3f;
5 | import org.joml.Matrix4f;
6 |
7 | public class MatrixStuff {
8 | public static void rotateXY(Matrix4f dest, float sinX, float cosX, float sinY, float cosY) {
9 | final float lm00 = dest.m00(), lm01 = dest.m01(), lm02 = dest.m02(), lm03 = dest.m03(),
10 | lm10 = dest.m10(), lm11 = dest.m11(), lm12 = dest.m12(), lm13 = dest.m13(),
11 | lm20 = dest.m20(), lm21 = dest.m21(), lm22 = dest.m22(), lm23 = dest.m23();
12 |
13 | final float m_sinX = -sinX;
14 | final float m_sinY = -sinY;
15 |
16 | final float xm20 = Math.fma(lm10, m_sinX, lm20 * cosX);
17 | final float xm21 = Math.fma(lm11, m_sinX, lm21 * cosX);
18 | final float xm22 = Math.fma(lm12, m_sinX, lm22 * cosX);
19 | final float xm23 = Math.fma(lm13, m_sinX, lm23 * cosX);
20 | final float xm10 = Math.fma(lm10, cosX, lm20 * sinX);
21 | final float xm11 = Math.fma(lm11, cosX, lm21 * sinX);
22 | final float xm12 = Math.fma(lm12, cosX, lm22 * sinX);
23 | final float xm13 = Math.fma(lm13, cosX, lm23 * sinX);
24 | final float nm00 = Math.fma(lm00, cosY, xm20 * m_sinY);
25 | final float nm01 = Math.fma(lm01, cosY, xm21 * m_sinY);
26 | final float nm02 = Math.fma(lm02, cosY, xm22 * m_sinY);
27 | final float nm03 = Math.fma(lm03, cosY, xm23 * m_sinY);
28 | final float ym20 = Math.fma(lm00, sinY, xm20 * cosY);
29 | final float ym21 = Math.fma(lm01, sinY, xm21 * cosY);
30 | final float ym22 = Math.fma(lm02, sinY, xm22 * cosY);
31 | final float ym23 = Math.fma(lm03, sinY, xm23 * cosY);
32 | dest.set(nm00, nm01, nm02, nm03,
33 | xm10, xm11, xm12, xm13,
34 | ym20, ym21, ym22, ym23,
35 | dest.m30(), dest.m31(), dest.m32(), dest.m33());
36 | }
37 |
38 | public static void rotateXY(Matrix3f dest, float sinX, float cosX, float sinY, float cosY) {
39 | final float m_sinX = -sinX;
40 | final float m_sinY = -sinY;
41 |
42 | final float nm10 = Math.fma(dest.m10, cosX, dest.m20 * sinX);
43 | final float nm11 = Math.fma(dest.m11, cosX, dest.m21 * sinX);
44 | final float nm12 = Math.fma(dest.m12, cosX, dest.m22 * sinX);
45 | final float nm20 = Math.fma(dest.m10, m_sinX, dest.m20 * cosX);
46 | final float nm21 = Math.fma(dest.m11, m_sinX, dest.m21 * cosX);
47 | final float nm22 = Math.fma(dest.m12, m_sinX, dest.m22 * cosX);
48 | final float nm00 = Math.fma(dest.m00, cosY, nm20 * m_sinY);
49 | final float nm01 = Math.fma(dest.m01, cosY, nm21 * m_sinY);
50 | final float nm02 = Math.fma(dest.m02, cosY, nm22 * m_sinY);
51 | dest.m20 = Math.fma(dest.m00, sinY, nm20 * cosY);
52 | dest.m21 = Math.fma(dest.m01, sinY, nm21 * cosY);
53 | dest.m22 = Math.fma(dest.m02, sinY, nm22 * cosY);
54 | dest.m00 = nm00;
55 | dest.m01 = nm01;
56 | dest.m02 = nm02;
57 | dest.m10 = nm10;
58 | dest.m11 = nm11;
59 | dest.m12 = nm12;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/mixins/Chunk/FrustumMixin.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.mixins.Chunk;
2 |
3 | import com.moepus.flerovium.functions.Chunk.FastSimpleFrustum;
4 | import me.jellysquid.mods.sodium.client.render.viewport.Viewport;
5 | import me.jellysquid.mods.sodium.client.render.viewport.ViewportProvider;
6 | import net.minecraft.client.renderer.culling.Frustum;
7 | import org.joml.FrustumIntersection;
8 | import org.joml.Vector3d;
9 | import org.spongepowered.asm.mixin.Final;
10 | import org.spongepowered.asm.mixin.Mixin;
11 | import org.spongepowered.asm.mixin.Shadow;
12 |
13 | @Mixin(Frustum.class)
14 | public class FrustumMixin implements ViewportProvider {
15 | @Shadow
16 | public double camX;
17 |
18 | @Shadow
19 | public double camY;
20 |
21 | @Shadow
22 | public double camZ;
23 |
24 | @Shadow
25 | @Final
26 | public FrustumIntersection intersection;
27 |
28 | @Override
29 | public Viewport sodium$createViewport() {
30 | return new Viewport(new FastSimpleFrustum(this.intersection), new Vector3d(this.camX, this.camY, this.camZ));
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/mixins/Chunk/OcclusionCullerMixin.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.mixins.Chunk;
2 |
3 | import com.moepus.flerovium.functions.Chunk.Occlusion;
4 | import me.jellysquid.mods.sodium.client.render.chunk.RenderSection;
5 | import me.jellysquid.mods.sodium.client.render.chunk.occlusion.GraphDirectionSet;
6 | import me.jellysquid.mods.sodium.client.render.chunk.occlusion.OcclusionCuller;
7 | import me.jellysquid.mods.sodium.client.render.chunk.occlusion.VisibilityEncoding;
8 | import me.jellysquid.mods.sodium.client.render.viewport.Viewport;
9 | import me.jellysquid.mods.sodium.client.util.collections.ReadQueue;
10 | import me.jellysquid.mods.sodium.client.util.collections.WriteQueue;
11 | import net.minecraft.core.SectionPos;
12 | import org.spongepowered.asm.mixin.*;
13 |
14 | @Mixin(value = OcclusionCuller.class, remap = false)
15 | public abstract class OcclusionCullerMixin {
16 | @Shadow
17 | private static boolean isSectionVisible(RenderSection section, Viewport viewport, float searchDistance) {
18 | return false;
19 | }
20 |
21 | @Shadow
22 | private static int getOutwardDirections(SectionPos origin, RenderSection section) {
23 | return 0;
24 | }
25 |
26 | @Shadow
27 | private static void visitNeighbors(final WriteQueue queue, RenderSection section, int outgoing, int frame) {
28 | }
29 |
30 | /**
31 | * @author MoePus
32 | * @reason Cull More Chunks
33 | */
34 | @Overwrite
35 | private static void processQueue(OcclusionCuller.Visitor visitor,
36 | Viewport viewport,
37 | float searchDistance,
38 | boolean useOcclusionCulling,
39 | int frame,
40 | ReadQueue readQueue,
41 | WriteQueue writeQueue) {
42 | RenderSection section;
43 |
44 | while ((section = readQueue.dequeue()) != null) {
45 | if (!isSectionVisible(section, viewport, searchDistance)) {
46 | continue;
47 | }
48 | visitor.visit(section, true);
49 |
50 | int connections;
51 | {
52 | if (useOcclusionCulling) {
53 | long visibilityData = flerovium$processVisibilityByAngleOcculusion(viewport, section, section.getVisibilityData());
54 |
55 | // When using occlusion culling, we can only traverse into neighbors for which there is a path of
56 | // visibility through this chunk. This is determined by taking all the incoming paths to this chunk and
57 | // creating a union of the outgoing paths from those.
58 | connections = VisibilityEncoding.getConnections(visibilityData, section.getIncomingDirections());
59 | } else {
60 | // Not using any occlusion culling, so traversing in any direction is legal.
61 | connections = GraphDirectionSet.ALL;
62 | }
63 |
64 | // We can only traverse *outwards* from the center of the graph search, so mask off any invalid
65 | // directions.
66 | connections &= getOutwardDirections(viewport.getChunkCoord(), section);
67 | }
68 |
69 | visitNeighbors(writeQueue, section, connections, frame);
70 | }
71 | }
72 |
73 | // Picked from https://github.com/CaffeineMC/sodium/pull/2811
74 | @Unique
75 | private static long flerovium$processVisibilityByAngleOcculusion(Viewport viewport, RenderSection section, long visibilityData) {
76 | double dx = Math.abs(viewport.getTransform().x - section.getCenterX());
77 | double dy = Math.abs(viewport.getTransform().y - section.getCenterY());
78 | double dz = Math.abs(viewport.getTransform().z - section.getCenterZ());
79 |
80 | long mask = 0L;
81 |
82 | if (dx < dy || dx < dz) {
83 | mask |= Occlusion.ThroughEastWest;
84 | }
85 | if (dy < dx || dy < dz) {
86 | mask |= Occlusion.ThroughUpDown;
87 | }
88 | if (dz < dx || dz < dy) {
89 | mask |= Occlusion.ThroughNorthSouth;
90 | }
91 |
92 | return visibilityData & ~mask;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/mixins/Entity/ClientLevelMixin.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.mixins.Entity;
2 |
3 | import com.google.common.collect.ImmutableList;
4 | import net.minecraft.client.multiplayer.ClientLevel;
5 | import net.minecraft.client.player.LocalPlayer;
6 | import net.minecraft.world.entity.Entity;
7 | import net.minecraft.world.entity.EntitySelector;
8 | import net.minecraft.world.level.CommonLevelAccessor;
9 | import net.minecraft.world.phys.AABB;
10 | import net.minecraft.world.phys.shapes.Shapes;
11 | import net.minecraft.world.phys.shapes.VoxelShape;
12 | import org.jetbrains.annotations.NotNull;
13 | import org.spongepowered.asm.mixin.Mixin;
14 | import org.spongepowered.asm.mixin.Unique;
15 |
16 | import javax.annotation.Nullable;
17 | import java.util.List;
18 | import java.util.function.Predicate;
19 |
20 | @Mixin(ClientLevel.class)
21 | public abstract class ClientLevelMixin implements CommonLevelAccessor {
22 | @Unique
23 | List flerovium$getPlayerCollisions(Entity entity, AABB aabb) {
24 | if (aabb.getSize() < 1.0E-7D) {
25 | return List.of();
26 | }
27 | List list = this.getEntities(entity, aabb.inflate(1.0E-7D), EntitySelector.NO_SPECTATORS.and(entity::canCollideWith));
28 | if (list.isEmpty()) {
29 | return List.of();
30 | }
31 | ImmutableList.Builder builder = ImmutableList.builderWithExpectedSize(list.size());
32 |
33 | for (Entity e : list) {
34 | builder.add(Shapes.create(e.getBoundingBox()));
35 | }
36 |
37 | return builder.build();
38 | }
39 |
40 | @Override
41 | public @NotNull List getEntityCollisions(@Nullable Entity entity, AABB aabb) {
42 | if (entity instanceof LocalPlayer) {
43 | return flerovium$getPlayerCollisions(entity, aabb);
44 | }
45 | return List.of();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/mixins/Entity/ModelPartMixin.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.mixins.Entity;
2 |
3 | import com.moepus.flerovium.functions.FastEntityRenderer;
4 | import me.jellysquid.mods.sodium.client.render.vertex.VertexConsumerUtils;
5 | import net.caffeinemc.mods.sodium.api.util.ColorABGR;
6 | import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter;
7 | import net.minecraft.client.model.geom.ModelPart;
8 | import org.spongepowered.asm.mixin.*;
9 | import org.spongepowered.asm.mixin.injection.At;
10 | import org.spongepowered.asm.mixin.injection.Inject;
11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
12 | import com.mojang.blaze3d.vertex.PoseStack;
13 | import com.mojang.blaze3d.vertex.VertexConsumer;
14 |
15 | @Mixin(value = ModelPart.class, priority = 900)
16 | public class ModelPartMixin {
17 | @Inject(method = "render(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;IIFFFF)V", at = @At("HEAD"), cancellable = true)
18 | private void onRender(PoseStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha, CallbackInfo ci) {
19 | if ((Object) this.getClass() != ModelPart.class) {
20 | return;
21 | }
22 |
23 | VertexBufferWriter writer = VertexConsumerUtils.convertOrLog(vertices);
24 |
25 | if (writer == null) {
26 | return;
27 | }
28 |
29 | ci.cancel();
30 |
31 | FastEntityRenderer.render(matrices, writer, (ModelPart) (Object) this, light, overlay, ColorABGR.pack(red, green, blue, alpha));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/mixins/Item/ItemEntityRenderMixin.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.mixins.Item;
2 |
3 | import com.mojang.blaze3d.vertex.PoseStack;
4 | import net.minecraft.client.Minecraft;
5 | import net.minecraft.client.player.LocalPlayer;
6 | import net.minecraft.client.renderer.MultiBufferSource;
7 | import net.minecraft.client.renderer.entity.EntityRenderer;
8 | import net.minecraft.client.renderer.entity.EntityRendererProvider;
9 | import net.minecraft.client.renderer.entity.ItemEntityRenderer;
10 | import net.minecraft.world.entity.Entity;
11 | import net.minecraft.world.entity.item.ItemEntity;
12 | import net.minecraft.world.item.ItemStack;
13 | import net.minecraft.world.phys.Vec3;
14 | import net.minecraftforge.client.event.RenderNameTagEvent;
15 | import net.minecraftforge.common.MinecraftForge;
16 | import org.spongepowered.asm.mixin.Mixin;
17 | import org.spongepowered.asm.mixin.injection.At;
18 | import org.spongepowered.asm.mixin.injection.Redirect;
19 |
20 | @Mixin(ItemEntityRenderer.class)
21 | public abstract class ItemEntityRenderMixin extends EntityRenderer {
22 | protected ItemEntityRenderMixin(EntityRendererProvider.Context p_174008_) {
23 | super(p_174008_);
24 | }
25 |
26 | @Redirect(
27 | method = {"render(Lnet/minecraft/world/entity/item/ItemEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V"},
28 | at = @At(
29 | value = "INVOKE",
30 | target = "Lnet/minecraft/client/renderer/entity/ItemEntityRenderer;getRenderAmount(Lnet/minecraft/world/item/ItemStack;)I"
31 | )
32 | )
33 | private int redirectGetRenderAmount(ItemEntityRenderer instance, ItemStack itemstack, ItemEntity itemEntity) {
34 | int count = itemstack.getCount();
35 | LocalPlayer player = Minecraft.getInstance().player;
36 | Vec3 eye = new Vec3(player.getX(), player.getY(), player.getZ());
37 | int maxRender = (int) Math.ceil(360.0F / eye.distanceToSqr(itemEntity.getX(), itemEntity.getY(), itemEntity.getZ()));
38 | return Math.min(Math.min(count, (count - 1) / 16 + 2), Math.min(maxRender, 5));
39 | }
40 |
41 | @Redirect(
42 | method = "render(Lnet/minecraft/world/entity/item/ItemEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V",
43 | at = @At(
44 | value = "INVOKE",
45 | target = "Lnet/minecraft/client/renderer/entity/EntityRenderer;render(Lnet/minecraft/world/entity/Entity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V"
46 | )
47 | )
48 | private void skipSuperRender(EntityRenderer instance, Entity entity, float p_115037_, float p_115038_, PoseStack p_115039_, MultiBufferSource p_115040_, int p_115041_) {
49 | RenderNameTagEvent renderNameTagEvent = new RenderNameTagEvent(entity, entity.getDisplayName(), this, p_115039_, p_115040_, p_115041_, p_115038_);
50 | MinecraftForge.EVENT_BUS.post(renderNameTagEvent);
51 | // skip render
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/mixins/Item/ItemRendererMixin.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.mixins.Item;
2 |
3 | import com.moepus.flerovium.Flerovium;
4 | import com.moepus.flerovium.functions.DummyModel;
5 | import com.moepus.flerovium.functions.FastSimpleBakedModelRenderer;
6 | import com.mojang.blaze3d.systems.RenderSystem;
7 | import com.mojang.blaze3d.vertex.PoseStack;
8 | import com.mojang.blaze3d.vertex.VertexConsumer;
9 | import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter;
10 | import net.minecraft.client.color.item.ItemColors;
11 | import net.minecraft.client.renderer.block.model.ItemTransform;
12 | import net.minecraft.client.renderer.block.model.ItemTransforms;
13 | import net.minecraft.client.renderer.entity.ItemRenderer;
14 | import net.minecraft.client.resources.model.BakedModel;
15 | import net.minecraft.client.resources.model.SimpleBakedModel;
16 | import net.minecraft.core.Direction;
17 | import net.minecraft.world.item.ItemDisplayContext;
18 | import net.minecraft.world.item.ItemStack;
19 | import org.spongepowered.asm.mixin.Final;
20 | import org.spongepowered.asm.mixin.Mixin;
21 | import org.spongepowered.asm.mixin.Shadow;
22 | import org.spongepowered.asm.mixin.Unique;
23 | import org.spongepowered.asm.mixin.injection.At;
24 | import org.spongepowered.asm.mixin.injection.Inject;
25 | import org.spongepowered.asm.mixin.injection.ModifyArg;
26 | import com.llamalad7.mixinextras.sugar.Local;
27 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
28 |
29 | @Mixin(value = ItemRenderer.class, priority = 100)
30 | public abstract class ItemRendererMixin {
31 | @Final
32 | @Shadow
33 | private ItemColors itemColors;
34 |
35 | @Unique
36 | private static final DummyModel flerovium$dummy = new DummyModel();
37 |
38 | @Inject(method = "renderModelLists(Lnet/minecraft/client/resources/model/BakedModel;Lnet/minecraft/world/item/ItemStack;IILcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;)V", at = @At("HEAD"), cancellable = true)
39 | public void renderModelLists(BakedModel model, ItemStack itemStack, int packedLight, int packedOverlay, PoseStack poseStack, VertexConsumer vertexConsumer, CallbackInfo ci) {
40 | if (model == flerovium$dummy) ci.cancel();
41 | }
42 |
43 | @ModifyArg(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/ItemRenderer;renderModelLists(Lnet/minecraft/client/resources/model/BakedModel;Lnet/minecraft/world/item/ItemStack;IILcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;)V"))
44 | public BakedModel onRrenderModelLists(BakedModel model, ItemStack stack, int light, int overlay, PoseStack poseStack, VertexConsumer vertexConsumer, @Local(ordinal = 0) BakedModel originalModel, @Local ItemDisplayContext itemDisplayContext) {
45 | if (originalModel.getClass() != SimpleBakedModel.class)
46 | return model;
47 | if (model.getClass() != SimpleBakedModel.class)
48 | return model;
49 |
50 | VertexBufferWriter writer = VertexBufferWriter.tryOf(vertexConsumer);
51 | if (writer == null) return model;
52 |
53 | int faces = flerovium$decideCull(((SimpleBakedModel) originalModel).getTransforms(), itemDisplayContext, poseStack.last());
54 | FastSimpleBakedModelRenderer.render((SimpleBakedModel) model, faces, stack, light, overlay, poseStack, writer, itemColors);
55 |
56 | return flerovium$dummy;
57 | }
58 |
59 | @Unique
60 | private int flerovium$decideCull(ItemTransforms transforms, ItemDisplayContext itemDisplayContext, PoseStack.Pose pose) {
61 | final int extraCull = 0b1000000;
62 | if (RenderSystem.modelViewMatrix.m32() != 0) { // In GUI
63 | if (itemDisplayContext != ItemDisplayContext.GUI) {
64 | return 0b111111;
65 | }
66 | if (transforms.gui == ItemTransform.NO_TRANSFORM) { // Item
67 | if (pose.pose().m20() == 0 && pose.pose().m21() == 0) { // Not per-transformed
68 | return 1 << Direction.SOUTH.ordinal();
69 | }
70 | } else if (transforms.gui.rotation.equals(30.0F, 225.0F, 0.0F)) { // Block
71 | return (1 << Direction.UP.ordinal()) | (1 << Direction.NORTH.ordinal()) |
72 | (1 << Direction.EAST.ordinal());
73 | } else if (transforms.gui.rotation.equals(30.0F, 135.0F, 0.0F)) { // Block
74 | return (1 << Direction.UP.ordinal()) | (1 << Direction.NORTH.ordinal()) |
75 | (1 << Direction.WEST.ordinal());
76 | }
77 | return 0b111111;
78 | }
79 | // In World
80 | int faces = 0b111111;
81 | if (transforms.gui == ItemTransform.NO_TRANSFORM && pose.pose().m32() < -10.0F) { // Item Far away
82 | faces &= ((1 << Direction.NORTH.ordinal()) | (1 << Direction.SOUTH.ordinal()));
83 | }
84 | if (Flerovium.config.itemBackFaceCulling && pose.pose().m32() < -3.0F) {
85 | faces |= extraCull;
86 | }
87 | return faces;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/mixins/Item/ItemTransformMixin.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.mixins.Item;
2 |
3 | import com.mojang.blaze3d.vertex.PoseStack;
4 | import net.minecraft.client.renderer.block.model.ItemTransform;
5 | import org.joml.Vector3f;
6 | import org.joml.Math;
7 | import org.spongepowered.asm.mixin.Final;
8 | import org.spongepowered.asm.mixin.Mixin;
9 | import org.spongepowered.asm.mixin.Shadow;
10 | import org.spongepowered.asm.mixin.Unique;
11 | import org.spongepowered.asm.mixin.injection.At;
12 | import org.spongepowered.asm.mixin.injection.Inject;
13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
14 |
15 | import static net.minecraftforge.common.util.TransformationHelper.quatFromXYZ;
16 | import com.moepus.flerovium.functions.MatrixStuff;
17 |
18 | @Mixin(ItemTransform.class)
19 | public abstract class ItemTransformMixin {
20 | @Final
21 | @Shadow
22 | public Vector3f rotation;
23 | @Final
24 | @Shadow
25 | public Vector3f translation;
26 | @Final
27 | @Shadow
28 | public Vector3f scale;
29 | @Final
30 | @Shadow(remap = false)
31 | public Vector3f rightRotation;
32 |
33 | @Unique
34 | boolean flerovium$noRot = false;
35 | @Unique
36 | boolean flerovium$noTrans = false;
37 | @Unique
38 | boolean flerovium$scaleSameAndPositive = false;
39 | @Unique
40 | boolean flerovium$noRightRot = false;
41 | @Unique
42 | float flerovium$sinX = 0f;
43 | @Unique
44 | float flerovium$cosX = 0f;
45 | @Unique
46 | float flerovium$sinY = 0f;
47 | @Unique
48 | float flerovium$cosY = 0f;
49 |
50 | @Inject(method = "(Lorg/joml/Vector3f;Lorg/joml/Vector3f;Lorg/joml/Vector3f;Lorg/joml/Vector3f;)V", at = @At("TAIL"), remap = false)
51 | public void init(Vector3f p_254427_, Vector3f p_254496_, Vector3f p_254022_, Vector3f rightRotation, CallbackInfo ci) {
52 | if (rotation.equals(0, 0, 0)) {
53 | flerovium$noRot = true;
54 | } else if (rotation.z == 0) {
55 | float radX = Math.toRadians(rotation.x);
56 | float radY = Math.toRadians(rotation.y);
57 | flerovium$sinX = Math.sin(radX);
58 | flerovium$sinY = Math.sin(radY);
59 | flerovium$cosX = Math.cosFromSin(flerovium$sinX, radX);
60 | flerovium$cosY = Math.cosFromSin(flerovium$sinY, radY);
61 | }
62 | if (translation.equals(0, 0, 0)) {
63 | flerovium$noTrans = true;
64 | }
65 | if (scale.x() == scale.y() && scale.y() == scale.z() && scale.x() > 0) {
66 | flerovium$scaleSameAndPositive = true;
67 | } else if (scale.z() == 0) {
68 | scale.z = 1E-5F; // Work Around for some MCR mods
69 | }
70 | if (rightRotation.equals(0, 0, 0)) {
71 | flerovium$noRightRot = true;
72 | }
73 | }
74 |
75 | @Inject(method = "apply(ZLcom/mojang/blaze3d/vertex/PoseStack;)V", at = @At("HEAD"), cancellable = true)
76 | public void apply(boolean doFlip, PoseStack pose, CallbackInfo ci) {
77 | if ((Object) this != ItemTransform.NO_TRANSFORM) {
78 | final float flip = doFlip ? -1 : 1;
79 | if (!flerovium$noTrans) {
80 | pose.translate(flip * translation.x(), translation.y(), translation.z());
81 | }
82 | if (!flerovium$noRot) {
83 | if (rotation.z() == 0) {
84 | PoseStack.Pose last = pose.last();
85 | float flipY = flip * flerovium$sinY;
86 | MatrixStuff.rotateXY(last.pose(), flerovium$sinX, flerovium$cosX, flipY, flerovium$cosY);
87 | MatrixStuff.rotateXY(last.normal(), flerovium$sinX, flerovium$cosX, flipY, flerovium$cosY);
88 | } else {
89 | pose.mulPose(quatFromXYZ(rotation.x(), rotation.y() * flip, rotation.z() * flip, true));
90 | }
91 | }
92 | if (flerovium$scaleSameAndPositive) {
93 | pose.last().pose().scale(scale.x(), scale.x(), scale.x());
94 | } else {
95 | pose.scale(scale.x(), scale.y(), scale.z());
96 | }
97 | if (!flerovium$noRightRot) {
98 | pose.mulPose(quatFromXYZ(rightRotation.x(), rightRotation.y() * flip, rightRotation.z() * flip, true));
99 | }
100 | }
101 | ci.cancel();
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/mixins/Item/SimpleBakedModelMixin.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.mixins.Item;
2 |
3 | import net.minecraft.client.renderer.RenderType;
4 | import net.minecraft.client.resources.model.SimpleBakedModel;
5 | import net.minecraft.world.item.ItemStack;
6 | import net.minecraftforge.client.extensions.IForgeBakedModel;
7 | import org.jetbrains.annotations.NotNull;
8 | import org.spongepowered.asm.mixin.*;
9 |
10 | import java.util.List;
11 |
12 | @Mixin(SimpleBakedModel.class)
13 | public abstract class SimpleBakedModelMixin implements IForgeBakedModel {
14 | @Shadow(remap = false)
15 | @Final
16 | @Mutable
17 | protected List itemRenderTypes;
18 | @Shadow(remap = false)
19 | @Final
20 | @Mutable
21 | protected List fabulousItemRenderTypes;
22 | /**
23 | * @author MoePus
24 | * @reason Cache Render Types
25 | */
26 | @Overwrite(remap = false)
27 | public @NotNull List getRenderTypes(@NotNull ItemStack itemStack, boolean fabulous) {
28 | if (!fabulous) {
29 | if (itemRenderTypes == null) {
30 | itemRenderTypes = IForgeBakedModel.super.getRenderTypes(itemStack, fabulous);
31 | }
32 | return itemRenderTypes;
33 | }
34 | if (fabulousItemRenderTypes == null) {
35 | fabulousItemRenderTypes = IForgeBakedModel.super.getRenderTypes(itemStack, fabulous);
36 | }
37 | return fabulousItemRenderTypes;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/mixins/Particle/ParticleEngineMixin.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.mixins.Particle;
2 |
3 | import com.llamalad7.mixinextras.sugar.Local;
4 | import net.minecraft.client.particle.Particle;
5 | import net.minecraft.client.particle.ParticleEngine;
6 | import net.minecraft.client.renderer.culling.Frustum;
7 | import net.minecraft.world.phys.AABB;
8 | import org.spongepowered.asm.mixin.Mixin;
9 | import org.spongepowered.asm.mixin.injection.At;
10 | import org.spongepowered.asm.mixin.injection.Redirect;
11 |
12 | @Mixin(value = ParticleEngine.class, priority = 500)
13 | public abstract class ParticleEngineMixin {
14 | @Redirect(method = "render(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;Lnet/minecraft/client/renderer/LightTexture;Lnet/minecraft/client/Camera;FLnet/minecraft/client/renderer/culling/Frustum;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/culling/Frustum;isVisible(Lnet/minecraft/world/phys/AABB;)Z"))
15 | boolean FastFrustumCheck(Frustum instance, AABB aabb, @Local Particle particle) {
16 | if (aabb.minX == Double.NEGATIVE_INFINITY) return true;
17 |
18 | float x = (float) (particle.x - instance.camX);
19 | float y = (float) (particle.y - instance.camY);
20 | float z = (float) (particle.z - instance.camZ);
21 |
22 | float width = particle.bbWidth;
23 | float height = particle.bbHeight;
24 | return instance.intersection.testSphere(x, y, z, Math.max(width, height) * 0.5F);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/mixins/Particle/ParticleMixin.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.mixins.Particle;
2 | import net.minecraft.client.particle.Particle;
3 | import net.minecraft.util.RandomSource;
4 | import org.spongepowered.asm.mixin.Mixin;
5 | import org.spongepowered.asm.mixin.injection.At;
6 | import org.spongepowered.asm.mixin.injection.Redirect;
7 |
8 | @Mixin(Particle.class)
9 | public abstract class ParticleMixin {
10 | @Redirect(method = "(Lnet/minecraft/client/multiplayer/ClientLevel;DDD)V", at = @At(value = "INVOKE", target ="Lnet/minecraft/util/RandomSource;create()Lnet/minecraft/util/RandomSource;"))
11 | private RandomSource onInit() {
12 | return RandomSource.createNewThreadLocalInstance();
13 | }
14 | }
--------------------------------------------------------------------------------
/src/main/java/com/moepus/flerovium/mixins/Particle/SingleQuadParticleMixin.java:
--------------------------------------------------------------------------------
1 | package com.moepus.flerovium.mixins.Particle;
2 |
3 | import com.mojang.blaze3d.vertex.VertexConsumer;
4 | import net.caffeinemc.mods.sodium.api.util.ColorABGR;
5 | import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter;
6 | import net.caffeinemc.mods.sodium.api.vertex.format.common.ParticleVertex;
7 | import net.minecraft.client.Camera;
8 | import net.minecraft.client.multiplayer.ClientLevel;
9 | import net.minecraft.client.particle.Particle;
10 | import net.minecraft.client.particle.SingleQuadParticle;
11 | import net.minecraft.util.Mth;
12 | import net.minecraft.world.phys.Vec3;
13 | import org.joml.Math;
14 | import org.spongepowered.asm.mixin.Mixin;
15 | import org.spongepowered.asm.mixin.Shadow;
16 | import org.spongepowered.asm.mixin.Unique;
17 | import org.spongepowered.asm.mixin.injection.At;
18 | import org.spongepowered.asm.mixin.injection.Inject;
19 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
20 | import org.lwjgl.system.MemoryStack;
21 |
22 |
23 | @Mixin(value = SingleQuadParticle.class, priority = 100)
24 | public abstract class SingleQuadParticleMixin extends Particle {
25 | @Shadow
26 | public abstract float getQuadSize(float pt);
27 |
28 | @Shadow
29 | protected abstract float getU0();
30 |
31 | @Shadow
32 | protected abstract float getU1();
33 |
34 | @Shadow
35 | protected abstract float getV0();
36 |
37 | @Shadow
38 | protected abstract float getV1();
39 |
40 | protected SingleQuadParticleMixin(ClientLevel p_107234_, double p_107235_, double p_107236_, double p_107237_) {
41 | super(p_107234_, p_107235_, p_107236_, p_107237_);
42 | }
43 |
44 | @Unique
45 | int flerovium$lastTick = 0;
46 |
47 | @Unique
48 | int flerovium$cachedLight = 0;
49 |
50 | @Unique
51 | private int flerovium$getLightColorCached(float pt, Camera camera) {
52 | if (camera.getEntity() == null)
53 | return getLightColor(pt);
54 | int tickCount = camera.getEntity().tickCount;
55 | if (tickCount == 0)
56 | return getLightColor(pt);
57 | if (tickCount == flerovium$lastTick) {
58 | return flerovium$cachedLight;
59 | }
60 | flerovium$lastTick = tickCount;
61 | flerovium$cachedLight = getLightColor(pt);
62 | return flerovium$cachedLight;
63 | }
64 |
65 | @Inject(method = "render", at = @At("HEAD"), cancellable = true)
66 | public void renderFast(VertexConsumer vertexConsumer, Camera camera, float pt, CallbackInfo ci) {
67 | VertexBufferWriter writer = VertexBufferWriter.tryOf(vertexConsumer);
68 | if (writer == null)
69 | return;
70 | ci.cancel();
71 |
72 | Vec3 camPos = camera.getPosition();
73 | float x = (float) (Mth.lerp(pt, this.xo, this.x) - camPos.x());
74 | float y = (float) (Mth.lerp(pt, this.yo, this.y) - camPos.y());
75 | float z = (float) (Mth.lerp(pt, this.zo, this.z) - camPos.z());
76 |
77 | float minU = this.getU0();
78 | float maxU = this.getU1();
79 | float minV = this.getV0();
80 | float maxV = this.getV1();
81 | int light = flerovium$getLightColorCached(pt, camera);
82 | float size = this.getQuadSize(pt);
83 | int color = ColorABGR.pack(this.rCol, this.gCol, this.bCol, this.alpha);
84 |
85 | float lx = camera.getLeftVector().x, ly = camera.getLeftVector().y, lz = camera.getLeftVector().z;
86 | float ux = camera.getUpVector().x, uy = camera.getUpVector().y, uz = camera.getUpVector().z;
87 | if (roll != 0) {
88 | // Manually rotate the left and up vectors by the roll angle
89 | float nroll = Mth.lerp(pt, this.oRoll, this.roll);
90 | float sinRoll = Math.sin(nroll);
91 | float cosRoll = Math.cosFromSin(sinRoll, nroll);
92 |
93 | float rv1x = Math.fma(cosRoll, lx, sinRoll * ux),
94 | rv1y = Math.fma(cosRoll, ly, sinRoll * uy),
95 | rv1z = Math.fma(cosRoll, lz, sinRoll * uz);
96 | float rv2x = Math.fma(-sinRoll, lx, cosRoll * ux),
97 | rv2y = Math.fma(-sinRoll, ly, cosRoll * uy),
98 | rv2z = Math.fma(-sinRoll, lz, cosRoll * uz);
99 | lx = rv1x;
100 | ly = rv1y;
101 | lz = rv1z;
102 | ux = rv2x;
103 | uy = rv2y;
104 | uz = rv2z;
105 | }
106 |
107 | /**
108 | * Constructs a sprite's four vertices using the camera's leftVector and upVector.
109 | *
110 | * +---------------------+
111 | * | |
112 | * (-left, +up) | +up | (+left, +up)
113 | * | |
114 | * Vertex 2| ^ | Vertex 3
115 | * | | |
116 | * | <------+------> |
117 | * | left |
118 | * | |
119 | * (-left, -up) | -up | (+left, -up)
120 | * | |
121 | * Vertex 1| | Vertex 4
122 | * +---------------------+
123 | *
124 | * The sprite lies in a plane defined by the camera's orientation. Using the
125 | * size of the sprite (S), leftVector (L), and upVector (U), we calculate:
126 | *
127 | * Vertex 1: (L + U) * -S
128 | * Vertex 2: (-L + U) * S
129 | * Vertex 3: (L + U) * S
130 | * Vertex 4: (-L + U) * -S
131 | *
132 | * Each vertex is then transformed to the world position of the sprite
133 | * by adding the sprite's position (P).
134 | *
135 | * This approach avoids expensive quaternion operations and directly
136 | * leverages the camera's orientation to efficiently calculate vertices.
137 | */
138 | try (MemoryStack stack = MemoryStack.stackPush()) {
139 | long buffer = stack.nmalloc(4 * ParticleVertex.STRIDE);
140 | long ptr = buffer;
141 |
142 | ParticleVertex.put(ptr, Math.fma(lx + ux, -size, x), Math.fma(ly + uy, -size, y), Math.fma(lz + uz, -size, z), maxU, maxV, color, light);
143 | ptr += ParticleVertex.STRIDE;
144 |
145 | ParticleVertex.put(ptr, Math.fma(-lx + ux, size, x), Math.fma(-ly + uy, size, y), Math.fma(-lz + uz, size, z), maxU, minV, color, light);
146 | ptr += ParticleVertex.STRIDE;
147 |
148 | ParticleVertex.put(ptr, Math.fma(lx + ux, size, x), Math.fma(ly + uy, size, y), Math.fma(lz + uz, size, z), minU, minV, color, light);
149 | ptr += ParticleVertex.STRIDE;
150 |
151 | ParticleVertex.put(ptr, Math.fma(-lx + ux, -size, x), Math.fma(-ly + uy, -size, y), Math.fma(-lz + uz, -size, z), minU, maxV, color, light);
152 |
153 | writer.push(stack, buffer, 4, ParticleVertex.FORMAT);
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/accesstransformer.cfg:
--------------------------------------------------------------------------------
1 | public net.minecraft.client.renderer.culling.Frustum f_112996_ # camX
2 | public net.minecraft.client.renderer.culling.Frustum f_112997_ # camY
3 | public net.minecraft.client.renderer.culling.Frustum f_112998_ # camZ
4 | public net.minecraft.client.renderer.culling.Frustum f_252531_ # intersection
5 | public net.minecraft.client.particle.Particle f_107212_ # x
6 | public net.minecraft.client.particle.Particle f_107213_ # y
7 | public net.minecraft.client.particle.Particle f_107214_ # z
8 | public net.minecraft.client.particle.Particle f_107221_ # bbWidth
9 | public net.minecraft.client.particle.Particle f_107222_ # bbHeight
10 | public com.mojang.blaze3d.systems.RenderSystem modelViewMatrix # modelViewMatrix
--------------------------------------------------------------------------------
/src/main/resources/META-INF/mods.toml:
--------------------------------------------------------------------------------
1 | # This is an example mods.toml file. It contains the data relating to the loading mods.
2 | # There are several mandatory fields (#mandatory), and many more that are optional (#optional).
3 | # The overall format is standard TOML format, v0.5.0.
4 | # Note that there are a couple of TOML lists in this file.
5 | # Find more information on toml format here: https://github.com/toml-lang/toml
6 | # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
7 | modLoader="javafml" #mandatory
8 | # A version range to match for said mod loader - for regular FML @Mod it will be the forge version
9 | loaderVersion="${loader_version_range}" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions.
10 | # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties.
11 | # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here.
12 | license="${mod_license}"
13 | # A URL to refer people to when problems occur with this mod
14 | #issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional
15 | # A list of mods - how many allowed here is determined by the individual mod loader
16 | [[mods]] #mandatory
17 | # The modid of the mod
18 | modId="${mod_id}" #mandatory
19 | # The version number of the mod
20 | version="${mod_version}" #mandatory
21 | # A display name for the mod
22 | displayName="${mod_name}" #mandatory
23 | # A URL to query for updates for this mod. See the JSON update specification https://docs.minecraftforge.net/en/latest/misc/updatechecker/
24 | #updateJSONURL="https://change.me.example.invalid/updates.json" #optional
25 | # A URL for the "homepage" for this mod, displayed in the mod UI
26 | #displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional
27 | # A file name (in the root of the mod JAR) containing a logo for display
28 | #logoFile="flerovium.png" #optional
29 | # A text field displayed in the mod UI
30 | #credits="Thanks for this example mod goes to Java" #optional
31 | # A text field displayed in the mod UI
32 | authors="${mod_authors}" #optional
33 | # Display Test controls the display for your mod in the server connection screen
34 | # MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod.
35 | # IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod.
36 | # IGNORE_ALL_VERSION means that your mod will not cause a red X if it's present on the client or the server. This is a special case and should only be used if your mod has no server component.
37 | # NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value.
38 | # IMPORTANT NOTE: this is NOT an instruction as to which environments (CLIENT or DEDICATED SERVER) your mod loads on. Your mod should load (and maybe do nothing!) whereever it finds itself.
39 | #displayTest="MATCH_VERSION" # MATCH_VERSION is the default if nothing is specified (#optional)
40 |
41 | # The description text for the mod (multi line!) (#mandatory)
42 | description='''${mod_description}'''
43 | # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional.
44 | [[dependencies.${mod_id}]] #optional
45 | # the modid of the dependency
46 | modId="forge" #mandatory
47 | # Does this dependency have to exist - if not, ordering below must be specified
48 | mandatory=true #mandatory
49 | # The version range of the dependency
50 | versionRange="${forge_version_range}" #mandatory
51 | # An ordering relationship for the dependency - BEFORE or AFTER required if the dependency is not mandatory
52 | # BEFORE - This mod is loaded BEFORE the dependency
53 | # AFTER - This mod is loaded AFTER the dependency
54 | ordering="NONE"
55 | # Side this dependency is applied on - BOTH, CLIENT, or SERVER
56 | side="CLIENT"# Here's another dependency
57 | [[dependencies.${mod_id}]]
58 | modId="minecraft"
59 | mandatory=true
60 | # This version range declares a minimum of the current minecraft version up to but not including the next major version
61 | versionRange="${minecraft_version_range}"
62 | ordering="NONE"
63 | side="CLIENT"
64 | [[dependencies.${mod_id}]]
65 | modId="embeddium"
66 | mandatory=true
67 | versionRange="[0.3.25,)"
68 | ordering="NONE"
69 | side="CLIENT"
--------------------------------------------------------------------------------
/src/main/resources/flerovium.mixins.json:
--------------------------------------------------------------------------------
1 | {
2 | "required": true,
3 | "minVersion": "0.8",
4 | "package": "com.moepus.flerovium.mixins",
5 | "compatibilityLevel": "JAVA_17",
6 | "refmap": "flerovium.refmap.json",
7 | "plugin": "com.moepus.flerovium.MixinPlugin",
8 | "mixins": [
9 | "Chunk.OcclusionCullerMixin"
10 | ],
11 | "client": [
12 | "Chunk.FrustumMixin",
13 | "Entity.ClientLevelMixin",
14 | "Entity.ModelPartMixin",
15 | "Item.ItemEntityRenderMixin",
16 | "Item.ItemRendererMixin",
17 | "Item.ItemTransformMixin",
18 | "Item.SimpleBakedModelMixin",
19 | "Particle.ParticleEngineMixin",
20 | "Particle.ParticleMixin",
21 | "Particle.SingleQuadParticleMixin"
22 | ],
23 | "injectors": {
24 | "defaultRequire": 1
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/resources/pack.mcmeta:
--------------------------------------------------------------------------------
1 | {
2 | "pack": {
3 | "description": "flerovium resources",
4 | "pack_format": 15,
5 | "forge:server_data_pack_format": 12
6 | }
7 | }
8 |
--------------------------------------------------------------------------------