├── .github
├── FUNDING.yml
└── workflows
│ ├── gradle.yml
│ └── publish.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── idea
└── inspections.xml
├── settings.gradle
└── src
├── .gitignore
└── main
├── java
├── com
│ └── google
│ │ └── common
│ │ └── collect
│ │ ├── HydrogenEntrySet.java
│ │ ├── HydrogenEntrySetIterator.java
│ │ ├── HydrogenImmutableMapEntry.java
│ │ └── HydrogenImmutableReferenceHashMap.java
└── me
│ └── jellysquid
│ └── mods
│ └── hydrogen
│ ├── client
│ ├── HydrogenClient.java
│ ├── model
│ │ └── HydrogenModelIdentifier.java
│ └── resource
│ │ ├── ModelCacheReloadListener.java
│ │ └── ModelCaches.java
│ ├── common
│ ├── HydrogenMod.java
│ ├── HydrogenPreLaunch.java
│ ├── cache
│ │ └── StatePropertyTableCache.java
│ ├── collections
│ │ ├── CollectionHelper.java
│ │ ├── FastImmutableTable.java
│ │ ├── FastImmutableTableCache.java
│ │ ├── FixedArrayList.java
│ │ └── ImmutablePairArrayList.java
│ ├── dedup
│ │ ├── DeduplicationCache.java
│ │ └── IdentifierCaches.java
│ ├── jvm
│ │ ├── ClassConstructors.java
│ │ └── ClassDefineTool.java
│ ├── state
│ │ ├── StatePropertyPredicateHelper.java
│ │ ├── all
│ │ │ ├── AllMatchOneBoolean.java
│ │ │ └── AllMatchOneObject.java
│ │ ├── any
│ │ │ └── AllMatchAnyObject.java
│ │ └── single
│ │ │ ├── SingleMatchAny.java
│ │ │ └── SingleMatchOne.java
│ └── util
│ │ ├── AllPredicate.java
│ │ └── AnyPredicate.java
│ └── mixin
│ ├── chunk
│ ├── MixinChunkSerializer.java
│ └── MixinWorldChunk.java
│ ├── client
│ └── model
│ │ ├── MixinBakedQuad.java
│ │ ├── MixinBasicBakedModel.java
│ │ ├── MixinModelIdentifier.java
│ │ ├── MixinModelLoader.java
│ │ ├── MixinMultipartBakedModel.java
│ │ ├── MixinWeightedBakedModel.java
│ │ └── json
│ │ ├── MixinAndMultipartModelSelector.java
│ │ ├── MixinOrMultipartModelSelector.java
│ │ └── MixinSimpleMultipartModelSelector.java
│ ├── nbt
│ └── MixinNbtCompound.java
│ ├── state
│ └── MixinState.java
│ └── util
│ └── MixinIdentifier.java
└── resources
├── assets
└── hydrogen
│ └── icon.png
├── fabric.mod.json
└── hydrogen.mixins.json
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: jellysquid3
4 | patreon: jellysquid
5 |
--------------------------------------------------------------------------------
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | name: Java CI with Gradle
2 |
3 | on: [ push, pull_request ]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Set up JDK 16
12 | uses: actions/setup-java@v1
13 | with:
14 | java-version: 16
15 | - name: Grant execute permission for gradlew
16 | run: chmod +x gradlew
17 | - name: Build with Gradle
18 | run: ./gradlew build
19 | - name: Upload build artifacts
20 | uses: actions/upload-artifact@v1
21 | with:
22 | name: build-artifacts
23 | path: build/libs
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish Release v2
2 |
3 | on:
4 | release:
5 | types:
6 | - published
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout sources
13 | uses: actions/checkout@v2
14 | - name: Set up JDK 16
15 | uses: actions/setup-java@v1
16 | with:
17 | java-version: 16
18 | - name: Grant execute permission for gradlew
19 | run: chmod +x gradlew
20 | - name: Upload assets to CurseForge
21 | run: ./gradlew build
22 | env:
23 | BUILD_RELEASE: ${{ github.event.prerelease == false }}
24 | - name: Upload assets to GitHub
25 | uses: AButler/upload-release-assets@v2.0
26 | with:
27 | files: 'build/libs/*;LICENSE'
28 | repo-token: ${{ secrets.GITHUB_TOKEN }}
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | .idea
3 | run
4 | build
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Issues
2 |
3 | When opening issues, please be sure to include the following information as applicable.
4 |
5 | - The exact version of the mod you are running, such as `0.1.0-fabric`, and the version of Fabric/Forge you are using.
6 | - If your issue is a crash, attach the latest client or server log and the complete crash report as a file. You can
7 | attach these as a file (preferred) or host them on a service such as [GitHub Gist](https://gist.github.com/) or [Hastebin](https://hastebin.com/).
8 | - If your issue is a bug or otherwise unexpected behavior, explain what you expected to happen.
9 | - If your issue only occurs with other mods installed, be sure to specify the names and versions of those mods.
10 |
11 | ## Pull Requests
12 |
13 | It's super awesome to hear you're wishing to contribute to the project! Before you open a pull request, you'll need to
14 | give a quick read to the following guidelines.
15 |
16 | ### Contributor License Agreement (CLA)
17 |
18 | By submitting changes to this repository, you are hereby agreeing that:
19 |
20 | - Your contributions will be licensed irrecoverably under the [GNU LGPLv3](https://www.gnu.org/licenses/lgpl-3.0.html).
21 | - Your contributions are of your own work and free of legal restrictions (such as patents and copyrights) or other
22 | issues which would pose issues for inclusion or distribution under the above license.
23 |
24 | If you do not agree to these terms, please do not submit contributions to this repository. If you have any questions
25 | about these terms, feel free to get in contact with me through the [public Discord server](https://jellysquid.me/discord) or
26 | through opening an issue.
27 |
28 | ### Code Style
29 |
30 | When contributing source code changes to the project, ensure that you make consistent use of the code style guidelines
31 | used throughout the codebase (which follow pretty closely after the standard Java code style guidelines). These guidelines
32 | have also been packaged as EditorConfig and IDEA inspection profiles which can be found in the repository root and `idea`
33 | directory respectively.
34 |
35 | - Use 4 spaces for indentation, not tabs. Avoid lines which exceed 120 characters.
36 | - Use `this` to qualify member and field access.
37 | - Always use braces when writing if-statements and loops.
38 | - Annotate overriding methods with `@Override` so that breaking changes when updating will create hard compile errors.
39 | - Comment code which needs to mimic vanilla behavior with `[VanillaCopy]` so it can be inspected when updating.
40 |
41 | ### Making a Pull Request
42 |
43 | Your pull request should include a brief description of the changes it makes and link to any open issues which it
44 | resolves. You should also ensure that your code is well documented where non-trivial and that it follows the
45 | outlined code style guidelines above.
46 |
47 | If you're adding new Mixin patches to the project, please ensure that you have created appropriate entries to disable
48 | them in the config file. Mixins should always be self-contained and grouped into "patch sets" which are easy to isolate.
49 |
50 | Additionally, if you're making changes for the sake of improving performance in either the vanilla game or the project
51 | itself, try to provide a detailed test-case and benchmark for them. It's understandable that micro-benchmarking is
52 | difficult in the context of Minecraft, but even naive figures taken from a profiler, timings graph, or a simple counter
53 | will be greatly appreciated and help track incremental improvements.
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
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.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Status
2 | ##### January 23rd, 2022
3 |
4 | **This repository has been archived** as we do not have the time or resources needed to maintain the project. No further updates will be published, and
5 | we won't be providing help for using it.
6 |
7 | If you are looking for a replacement, consider taking a look at [FerriteCore](https://www.curseforge.com/minecraft/mc-mods/ferritecore-fabric), as it
8 | generally offers more significant improvements to memory usage in modded scenarios and is currently available for the latest version of Minecraft.
9 |
10 | ---
11 |
12 | 
13 |
14 | # Hydrogen (for Fabric)
15 | 
16 | 
17 | 
18 |
19 | Hydrogen is a free and open-source mod designed to reduce the game's memory requirements by implementing more
20 | memory-efficient data structures and logic. It's primarily designed for more heavily modded scenarios, but can
21 | offer (small) improvements even in lightly modded or vanilla scenarios.
22 |
23 | The mod works on both the **client and server**, and **doesn't require the mod to be installed
24 | on both sides**. However, the benefits of running Hydrogen on the server are pretty small as of the moment.
25 |
26 | #### Why are these patches not in [Lithium](https://github.com/jellysquid3/lithium-fabric)?
27 |
28 | Hydrogen relies on rather egregious hacks in order to load some code into the game, primarily because the Guava
29 | library developers really do not want people re-implementing their interfaces. These hacks are "safe" in the sense
30 | that the game will simply fail to start if a problem occurs, but are really rather not suitable for the standards
31 | which Lithium intends to promote. In other words, this mod could be looked at as "things too dirty to put in Lithium."
32 |
33 | ### Installation instructions
34 |
35 | Hydrogen relies on the [Fabric Loader](https://fabricmc.net/use). Users should select Fabric for either the Minecraft launcher (client) or
36 | the dedicated server (server) depending on their needs.
37 | Once you have installed Fabric, place the Hydrogen .jar in the `mods` folder generated by Fabric.
38 |
39 | ### Community
40 |
41 | If you'd like to get help with the mod, check out the latest developments, or be notified when there's a new release,
42 | the Discord community might be for you! You can join the official server for my mods by clicking
43 | [here](https://jellysquid.me/discord).
44 |
45 | ### Building from source
46 |
47 | If you're hacking on the code or would like to compile a custom build of Hydrogen from the latest sources, you'll want
48 | to start here.
49 |
50 | #### Prerequisites
51 |
52 | You will need to install JDK 8 in order to build Hydrogen. You can either install this through a package manager such as
53 | [Chocolatey](https://chocolatey.org/) on Windows or [SDKMAN!](https://sdkman.io/) on other platforms. If you'd prefer to
54 | not use a package manager, you can always grab the installers or packages directly from
55 | [AdoptOpenJDK](https://adoptopenjdk.net/).
56 |
57 | On Windows, the Oracle JDK/JRE builds should be avoided where possible due to their poor quality. Always prefer using
58 | the open-source builds from AdoptOpenJDK when possible.
59 |
60 | #### Compiling
61 |
62 | Navigate to the directory you've cloned this repository and launch a build with Gradle using `gradlew build` (Windows)
63 | or `./gradlew build` (macOS/Linux). If you are not using the Gradle wrapper, simply replace `gradlew` with `gradle`
64 | or the path to it.
65 |
66 | The initial setup may take a few minutes. After Gradle has finished building everything, you can find the resulting
67 | artifacts in `build/libs`.
68 |
69 | ### License
70 |
71 | Hydrogen is licensed under GNU LGPLv3, a free and open-source license. For more information, please see the
72 | [license file](https://github.com/jellysquid3/hydrogen-fabric/blob/1.16.x/dev/LICENSE.txt).
73 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'fabric-loom' version '0.8-SNAPSHOT'
3 | }
4 |
5 | archivesBaseName = "${project.archives_base_name}-mc${project.minecraft_version}"
6 | group = project.maven_group
7 | version = project.mod_version
8 |
9 | def build_release = System.getenv("BUILD_RELEASE") == "true"
10 | def build_id = System.getenv("BUILD_ID")
11 |
12 | if (!build_release) {
13 | version += "-SNAPSHOT"
14 | }
15 |
16 | if (build_id != null) {
17 | version += "+build.${build_id}"
18 | }
19 |
20 | minecraft {
21 | refmapName = "mixins.hydrogen.refmap.json"
22 | }
23 |
24 | dependencies {
25 | //to change the versions see the gradle.properties file
26 | minecraft "com.mojang:minecraft:${project.minecraft_version}"
27 | mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
28 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
29 |
30 | include(modImplementation(fabricApi.module("fabric-resource-loader-v0", project.fabric_api_version)))
31 | }
32 |
33 | repositories {
34 | maven { url = "https://jitpack.io" }
35 | }
36 |
37 | if (project.use_third_party_mods) {
38 | repositories {
39 | maven { url = "https://maven.gegy.dev" }
40 | }
41 |
42 | dependencies {
43 | // DataBreaker applies a number of patches to eliminate the loading of data fixers
44 | // This greatly reduces the amount of time needed to start the game, but is generally unsafe in production
45 | modRuntime ("supercoder79:databreaker:${project.databreaker_version}") {
46 | transitive = false
47 | }
48 | }
49 | }
50 |
51 | processResources {
52 | inputs.property "version", project.version
53 |
54 | filesMatching("fabric.mod.json") {
55 | expand "version": project.version
56 | }
57 | }
58 |
59 | // ensure that the encoding is set to UTF-8, no matter what the system default is
60 | // this fixes some edge cases with special characters not displaying correctly
61 | // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
62 | tasks.withType(JavaCompile) {
63 | options.encoding = "UTF-8"
64 | }
65 |
66 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
67 | // if it is present.
68 | // If you remove this task, sources will not be generated.
69 | task sourcesJar(type: Jar, dependsOn: classes) {
70 | classifier = "sources"
71 | from sourceSets.main.allSource
72 | from "LICENSE"
73 | }
74 |
75 | jar {
76 | from "LICENSE.txt"
77 | }
78 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Done to increase the memory available to gradle.
2 | org.gradle.jvmargs=-Xmx1G
3 |
4 | # Fabric Properties
5 | # check these on https://modmuss50.me/fabric.html
6 | minecraft_version=1.17.1
7 | yarn_mappings=1.17.1+build.1
8 | loader_version=0.11.6
9 | fabric_api_version=0.36.1+1.17
10 |
11 | # Mod Properties
12 | mod_version=0.3
13 | maven_group=me.jellysquid.mods
14 | archives_base_name=hydrogen-fabric
15 |
16 | # If true, third-party mods will be loaded during runtime in the developer run configurations
17 | use_third_party_mods = true
18 | databreaker_version = 0.2.7
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaffeineMC/hydrogen-fabric/95da36046c2f55617a76ebb8ea1e1f2a330330e5/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 | # Determine the Java command to use to start the JVM.
86 | if [ -n "$JAVA_HOME" ] ; then
87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
88 | # IBM's JDK on AIX uses strange locations for the executables
89 | JAVACMD="$JAVA_HOME/jre/sh/java"
90 | else
91 | JAVACMD="$JAVA_HOME/bin/java"
92 | fi
93 | if [ ! -x "$JAVACMD" ] ; then
94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
95 |
96 | Please set the JAVA_HOME variable in your environment to match the
97 | location of your Java installation."
98 | fi
99 | else
100 | JAVACMD="java"
101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
102 |
103 | Please set the JAVA_HOME variable in your environment to match the
104 | location of your Java installation."
105 | fi
106 |
107 | # Increase the maximum file descriptors if we can.
108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
109 | MAX_FD_LIMIT=`ulimit -H -n`
110 | if [ $? -eq 0 ] ; then
111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
112 | MAX_FD="$MAX_FD_LIMIT"
113 | fi
114 | ulimit -n $MAX_FD
115 | if [ $? -ne 0 ] ; then
116 | warn "Could not set maximum file descriptor limit: $MAX_FD"
117 | fi
118 | else
119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
120 | fi
121 | fi
122 |
123 | # For Darwin, add options to specify how the application appears in the dock
124 | if $darwin; then
125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
126 | fi
127 |
128 | # For Cygwin or MSYS, switch paths to Windows format before running java
129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
132 | JAVACMD=`cygpath --unix "$JAVACMD"`
133 |
134 | # We build the pattern for arguments to be converted via cygpath
135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
136 | SEP=""
137 | for dir in $ROOTDIRSRAW ; do
138 | ROOTDIRS="$ROOTDIRS$SEP$dir"
139 | SEP="|"
140 | done
141 | OURCYGPATTERN="(^($ROOTDIRS))"
142 | # Add a user-defined pattern to the cygpath arguments
143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
145 | fi
146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
147 | i=0
148 | for arg in "$@" ; do
149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
151 |
152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
154 | else
155 | eval `echo args$i`="\"$arg\""
156 | fi
157 | i=`expr $i + 1`
158 | done
159 | case $i in
160 | 0) set -- ;;
161 | 1) set -- "$args0" ;;
162 | 2) set -- "$args0" "$args1" ;;
163 | 3) set -- "$args0" "$args1" "$args2" ;;
164 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
165 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
166 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
167 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
168 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
169 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
170 | esac
171 | fi
172 |
173 | # Escape application args
174 | save () {
175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
176 | echo " "
177 | }
178 | APP_ARGS=`save "$@"`
179 |
180 | # Collect all arguments for the java command, following the shell quoting and substitution rules
181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
182 |
183 | exec "$JAVACMD" "$@"
184 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
34 |
35 | @rem Find java.exe
36 | if defined JAVA_HOME goto findJavaFromJavaHome
37 |
38 | set JAVA_EXE=java.exe
39 | %JAVA_EXE% -version >NUL 2>&1
40 | if "%ERRORLEVEL%" == "0" goto init
41 |
42 | echo.
43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
44 | echo.
45 | echo Please set the JAVA_HOME variable in your environment to match the
46 | echo location of your Java installation.
47 |
48 | goto fail
49 |
50 | :findJavaFromJavaHome
51 | set JAVA_HOME=%JAVA_HOME:"=%
52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
53 |
54 | if exist "%JAVA_EXE%" goto init
55 |
56 | echo.
57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
58 | echo.
59 | echo Please set the JAVA_HOME variable in your environment to match the
60 | echo location of your Java installation.
61 |
62 | goto fail
63 |
64 | :init
65 | @rem Get command-line arguments, handling Windows variants
66 |
67 | if not "%OS%" == "Windows_NT" goto win9xME_args
68 |
69 | :win9xME_args
70 | @rem Slurp the command line arguments.
71 | set CMD_LINE_ARGS=
72 | set _SKIP=2
73 |
74 | :win9xME_args_slurp
75 | if "x%~1" == "x" goto execute
76 |
77 | set CMD_LINE_ARGS=%*
78 |
79 | :execute
80 | @rem Setup the command line
81 |
82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
83 |
84 | @rem Execute Gradle
85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
86 |
87 | :end
88 | @rem End local scope for the variables with windows NT shell
89 | if "%ERRORLEVEL%"=="0" goto mainEnd
90 |
91 | :fail
92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
93 | rem the _cmd.exe /c_ return code!
94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
95 | exit /b 1
96 |
97 | :mainEnd
98 | if "%OS%"=="Windows_NT" endlocal
99 |
100 | :omega
101 |
--------------------------------------------------------------------------------
/idea/inspections.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | jcenter()
4 | maven {
5 | name = 'Fabric'
6 | url = 'https://maven.fabricmc.net/'
7 | }
8 | gradlePluginPortal()
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/.gitignore:
--------------------------------------------------------------------------------
1 | jmh
--------------------------------------------------------------------------------
/src/main/java/com/google/common/collect/HydrogenEntrySet.java:
--------------------------------------------------------------------------------
1 | package com.google.common.collect;
2 |
3 | import java.util.Map;
4 |
5 | class HydrogenEntrySet extends ImmutableSet> {
6 | private final K[] key;
7 | private final V[] value;
8 |
9 | private final int size;
10 |
11 | HydrogenEntrySet(K[] key, V[] value, int size) {
12 | this.key = key;
13 | this.value = value;
14 | this.size = size;
15 | }
16 |
17 | @Override
18 | public UnmodifiableIterator> iterator() {
19 | return new HydrogenEntrySetIterator<>(this.key, this.value, this.size);
20 | }
21 |
22 | @Override
23 | public boolean contains(Object object) {
24 | return false;
25 | }
26 |
27 | @Override
28 | boolean isPartialView() {
29 | return false;
30 | }
31 |
32 | @Override
33 | public int size() {
34 | return this.size;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/google/common/collect/HydrogenEntrySetIterator.java:
--------------------------------------------------------------------------------
1 | package com.google.common.collect;
2 |
3 | import java.util.Map;
4 |
5 | class HydrogenEntrySetIterator extends UnmodifiableIterator> {
6 | private final K[] key;
7 | private final V[] value;
8 |
9 | private int remaining;
10 | private int idx;
11 |
12 | public HydrogenEntrySetIterator(K[] key, V[] value, int remaining) {
13 | this.remaining = remaining;
14 | this.key = key;
15 | this.value = value;
16 | }
17 |
18 | @Override
19 | public boolean hasNext() {
20 | return this.remaining > 0;
21 | }
22 |
23 | @Override
24 | public Map.Entry next() {
25 | this.skipEmpty();
26 |
27 | Map.Entry entry = new HydrogenImmutableMapEntry<>(this.key[this.idx],
28 | this.value[this.idx]);
29 |
30 | this.remaining--;
31 | this.idx++;
32 |
33 | return entry;
34 | }
35 |
36 | private void skipEmpty() {
37 | while (this.key[this.idx] == null) {
38 | this.idx++;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/google/common/collect/HydrogenImmutableMapEntry.java:
--------------------------------------------------------------------------------
1 | package com.google.common.collect;
2 |
3 | import java.util.Map;
4 |
5 | public class HydrogenImmutableMapEntry implements Map.Entry {
6 | private final K key;
7 | private final V value;
8 |
9 | public HydrogenImmutableMapEntry(K key, V value) {
10 | this.key = key;
11 | this.value = value;
12 | }
13 |
14 | @Override
15 | public K getKey() {
16 | return this.key;
17 | }
18 |
19 | @Override
20 | public V getValue() {
21 | return this.value;
22 | }
23 |
24 | @Override
25 | public V setValue(V value) {
26 | throw new UnsupportedOperationException();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/google/common/collect/HydrogenImmutableReferenceHashMap.java:
--------------------------------------------------------------------------------
1 | package com.google.common.collect;
2 |
3 | import it.unimi.dsi.fastutil.Hash;
4 | import it.unimi.dsi.fastutil.HashCommon;
5 |
6 | import java.util.Map;
7 |
8 | import static it.unimi.dsi.fastutil.HashCommon.arraySize;
9 |
10 | @SuppressWarnings("unused")
11 | public class HydrogenImmutableReferenceHashMap extends ImmutableMap {
12 | protected transient K[] key;
13 | protected transient V[] value;
14 | protected transient int mask;
15 | protected transient int size;
16 |
17 | public HydrogenImmutableReferenceHashMap() {
18 |
19 | }
20 |
21 | public HydrogenImmutableReferenceHashMap(Map map) {
22 | this(map.size(), Hash.DEFAULT_LOAD_FACTOR);
23 |
24 | for (Map.Entry entry : map.entrySet()) {
25 | this.putInternal(entry.getKey(), entry.getValue());
26 | }
27 | }
28 |
29 | @SuppressWarnings("unchecked")
30 | private HydrogenImmutableReferenceHashMap(final int size, final float loadFactor) {
31 | if (loadFactor <= 0 || loadFactor > 1) {
32 | throw new IllegalArgumentException("Load factor must be greater than 0 and smaller than or equal to 1");
33 | }
34 |
35 | if (size < 0) {
36 | throw new IllegalArgumentException("The expected number of elements must be nonnegative");
37 | }
38 |
39 | int n = arraySize(size, loadFactor);
40 |
41 | this.key = (K[]) new Object[n];
42 | this.value = (V[]) new Object[n];
43 | this.mask = n - 1;
44 | this.size = size;
45 | }
46 |
47 | @Override
48 | public int size() {
49 | return this.size;
50 | }
51 |
52 | @Override
53 | public V get(final Object k) {
54 | int pos = HashCommon.mix(System.identityHashCode(k)) & this.mask;
55 | K curr = this.key[pos];
56 |
57 | // The starting point.
58 | if (curr == null) {
59 | return null;
60 | } else if (k == curr) {
61 | return this.value[pos];
62 | }
63 |
64 | // There's always an unused entry.
65 | while (true) {
66 | pos = pos + 1 & this.mask;
67 | curr = this.key[pos];
68 |
69 | if (curr == null) {
70 | return null;
71 | } else if (k == curr) {
72 | return this.value[pos];
73 | }
74 | }
75 | }
76 |
77 | private void putInternal(final K k, final V v) {
78 | final int pos = this.find(k);
79 |
80 | if (pos < 0) {
81 | int n = -pos - 1;
82 |
83 | this.key[n] = k;
84 | this.value[n] = v;
85 | } else {
86 | this.value[pos] = v;
87 | }
88 | }
89 |
90 | private int find(final K k) {
91 | int pos = HashCommon.mix(System.identityHashCode(k)) & this.mask;
92 | K curr = this.key[pos];
93 |
94 | // The starting point.
95 | if (curr == null) {
96 | return -(pos + 1);
97 | } else if (k == curr) {
98 | return pos;
99 | }
100 |
101 | // There's always an unused entry.
102 | while (true) {
103 | pos = pos + 1 & this.mask;
104 | curr = this.key[pos];
105 |
106 | if (curr == null) {
107 | return -(pos + 1);
108 | } else if (k == curr) {
109 | return pos;
110 | }
111 | }
112 | }
113 |
114 | @Override
115 | ImmutableSet> createEntrySet() {
116 | return new HydrogenEntrySet<>(this.key, this.value, this.size);
117 | }
118 |
119 | @Override
120 | boolean isPartialView() {
121 | return false;
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/client/HydrogenClient.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.client;
2 |
3 | import me.jellysquid.mods.hydrogen.client.resource.ModelCacheReloadListener;
4 | import net.fabricmc.api.ClientModInitializer;
5 | import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
6 | import net.minecraft.resource.ResourceType;
7 |
8 | public class HydrogenClient implements ClientModInitializer {
9 | @Override
10 | public void onInitializeClient() {
11 | ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES)
12 | .registerReloadListener(new ModelCacheReloadListener());
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/client/model/HydrogenModelIdentifier.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.client.model;
2 |
3 | public interface HydrogenModelIdentifier {
4 | String[] getProperties();
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/client/resource/ModelCacheReloadListener.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.client.resource;
2 |
3 | import com.google.common.collect.Lists;
4 | import me.jellysquid.mods.hydrogen.common.dedup.IdentifierCaches;
5 | import net.fabricmc.fabric.api.resource.ResourceReloadListenerKeys;
6 | import net.fabricmc.fabric.api.resource.SimpleResourceReloadListener;
7 | import net.minecraft.resource.ResourceManager;
8 | import net.minecraft.util.Identifier;
9 | import net.minecraft.util.profiler.Profiler;
10 |
11 | import java.util.Collection;
12 | import java.util.concurrent.CompletableFuture;
13 | import java.util.concurrent.Executor;
14 |
15 | public class ModelCacheReloadListener implements SimpleResourceReloadListener {
16 | @Override
17 | public CompletableFuture load(ResourceManager manager, Profiler profiler, Executor executor) {
18 | ModelCaches.cleanCaches();
19 |
20 | return CompletableFuture.completedFuture(null);
21 | }
22 |
23 | @Override
24 | public CompletableFuture apply(Void data, ResourceManager manager, Profiler profiler, Executor executor) {
25 | ModelCaches.printDebug();
26 | IdentifierCaches.printDebug();
27 |
28 | return CompletableFuture.completedFuture(null);
29 | }
30 |
31 | @Override
32 | public Identifier getFabricId() {
33 | return new Identifier("hydrogen", "model_cache_stats");
34 | }
35 |
36 | @Override
37 | public Collection getFabricDependencies() {
38 | return Lists.newArrayList(ResourceReloadListenerKeys.MODELS);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/client/resource/ModelCaches.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.client.resource;
2 |
3 | import it.unimi.dsi.fastutil.ints.IntArrays;
4 | import it.unimi.dsi.fastutil.objects.ObjectArrays;
5 | import me.jellysquid.mods.hydrogen.common.HydrogenMod;
6 | import me.jellysquid.mods.hydrogen.common.dedup.DeduplicationCache;
7 |
8 | public class ModelCaches {
9 | public static final DeduplicationCache QUADS = new DeduplicationCache<>(IntArrays.HASH_STRATEGY);
10 | public static final DeduplicationCache PROPERTIES = new DeduplicationCache<>();
11 |
12 | public static void printDebug() {
13 | HydrogenMod.LOGGER.info("[[[ Model de-duplication statistics ]]]");
14 | HydrogenMod.LOGGER.info("Baked quad cache: {}", QUADS);
15 | HydrogenMod.LOGGER.info("Properties cache: {}", PROPERTIES);
16 | }
17 |
18 | public static void cleanCaches() {
19 | QUADS.clearCache();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/HydrogenMod.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common;
2 |
3 | import org.apache.logging.log4j.LogManager;
4 | import org.apache.logging.log4j.Logger;
5 |
6 | public class HydrogenMod {
7 | public static final Logger LOGGER = LogManager.getLogger("Hydrogen");
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/HydrogenPreLaunch.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common;
2 |
3 | import me.jellysquid.mods.hydrogen.common.jvm.ClassConstructors;
4 | import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
5 |
6 | public class HydrogenPreLaunch implements PreLaunchEntrypoint {
7 | @Override
8 | public void onPreLaunch() {
9 | ClassConstructors.init();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/cache/StatePropertyTableCache.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.cache;
2 |
3 | import me.jellysquid.mods.hydrogen.common.collections.FastImmutableTableCache;
4 | import net.minecraft.block.Block;
5 | import net.minecraft.block.BlockState;
6 | import net.minecraft.fluid.Fluid;
7 | import net.minecraft.fluid.FluidState;
8 | import net.minecraft.state.property.Property;
9 |
10 | /**
11 | * Many of the column and row key arrays in block state tables will be duplicated, leading to an unnecessary waste of
12 | * memory. Since we have very limited options for trying to construct more optimized table types without throwing
13 | * maintainability or mod compatibility out the window, this class acts as a dirty way to find and de-duplicate arrays
14 | * after we construct our table types.
15 | *
16 | * While this global cache does not provide the ability to remove or clear entries from it, the reality is that it
17 | * shouldn't matter because block state tables are only initialized once and remain loaded for the entire lifetime of
18 | * the game. Even in the event of classloader pre-boot shenanigans, we still shouldn't leak memory as our cache will be
19 | * dropped along with the rest of the loaded classes when the class loader is reaped.
20 | */
21 | public class StatePropertyTableCache {
22 | public static final FastImmutableTableCache, Comparable>, BlockState> BLOCK_STATE_TABLE =
23 | new FastImmutableTableCache<>();
24 |
25 | public static final FastImmutableTableCache, Comparable>, FluidState> FLUID_STATE_TABLE =
26 | new FastImmutableTableCache<>();
27 |
28 | @SuppressWarnings("unchecked")
29 | public static FastImmutableTableCache, Comparable>, S> getTableCache(O owner) {
30 | if (owner instanceof Block) {
31 | return (FastImmutableTableCache, Comparable>, S>) BLOCK_STATE_TABLE;
32 | } else if (owner instanceof Fluid) {
33 | return (FastImmutableTableCache, Comparable>, S>) FLUID_STATE_TABLE;
34 | } else {
35 | throw new IllegalArgumentException("");
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/collections/CollectionHelper.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.collections;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.stream.Collector;
6 | import java.util.stream.Collectors;
7 |
8 | public class CollectionHelper {
9 | public static List fixed(List src) {
10 | return new FixedArrayList<>(src);
11 | }
12 |
13 | public static Collector> toSizedList(int size) {
14 | return Collectors.toCollection(() -> new ArrayList<>(size));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/collections/FastImmutableTable.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.collections;
2 |
3 | import com.google.common.collect.Table;
4 | import it.unimi.dsi.fastutil.Hash;
5 | import it.unimi.dsi.fastutil.HashCommon;
6 | import org.apache.commons.lang3.ArrayUtils;
7 |
8 | import java.util.Collection;
9 | import java.util.Map;
10 | import java.util.Set;
11 |
12 | import static it.unimi.dsi.fastutil.HashCommon.arraySize;
13 |
14 | public class FastImmutableTable implements Table {
15 | private R[] rowKeys;
16 | private int[] rowIndices;
17 | private final int rowMask;
18 | private final int rowCount;
19 |
20 | private C[] colKeys;
21 | private int[] colIndices;
22 | private final int colMask;
23 | private final int colCount;
24 |
25 | private V[] values;
26 | private final int size;
27 |
28 | @SuppressWarnings("unchecked")
29 | public FastImmutableTable(Table table, FastImmutableTableCache cache) {
30 | if (cache == null) {
31 | throw new IllegalArgumentException("Cache must not be null");
32 | }
33 |
34 | float loadFactor = Hash.DEFAULT_LOAD_FACTOR;
35 |
36 | Set rowKeySet = table.rowKeySet();
37 | Set colKeySet = table.columnKeySet();
38 |
39 | this.rowCount = rowKeySet.size();
40 | this.colCount = colKeySet.size();
41 |
42 | int rowN = arraySize(this.rowCount, loadFactor);
43 | int colN = arraySize(this.colCount, loadFactor);
44 |
45 | this.rowMask = rowN - 1;
46 | this.rowKeys = (R[]) new Object[rowN];
47 | this.rowIndices = new int[rowN];
48 |
49 | this.colMask = colN - 1;
50 | this.colKeys = (C[]) new Object[colN];
51 | this.colIndices = new int[colN];
52 |
53 | this.createIndex(this.colKeys, this.colIndices, this.colMask, colKeySet);
54 | this.createIndex(this.rowKeys, this.rowIndices, this.rowMask, rowKeySet);
55 |
56 | this.values = (V[]) new Object[this.rowCount * this.colCount];
57 |
58 | for (Cell cell : table.cellSet()) {
59 | int colIdx = this.getIndex(this.colKeys, this.colIndices, this.colMask, cell.getColumnKey());
60 | int rowIdx = this.getIndex(this.rowKeys, this.rowIndices, this.rowMask, cell.getRowKey());
61 |
62 | if (colIdx < 0 || rowIdx < 0) {
63 | throw new IllegalStateException("Missing index for " + cell);
64 | }
65 |
66 | this.values[this.colCount * rowIdx + colIdx] = cell.getValue();
67 | }
68 |
69 | this.size = table.size();
70 |
71 | this.rowKeys = cache.dedupRows(this.rowKeys);
72 | this.rowIndices = cache.dedupIndices(this.rowIndices);
73 |
74 | this.colIndices = cache.dedupIndices(this.colIndices);
75 | this.colKeys = cache.dedupColumns(this.colKeys);
76 |
77 | this.values = cache.dedupValues(this.values);
78 | }
79 |
80 | private void createIndex(T[] keys, int[] indices, int mask, Collection iterable) {
81 | int index = 0;
82 |
83 | for (T obj : iterable) {
84 | int i = this.find(keys, mask, obj);
85 |
86 | if (i < 0) {
87 | int pos = -i - 1;
88 |
89 | keys[pos] = obj;
90 | indices[pos] = index++;
91 | }
92 | }
93 | }
94 |
95 | private int getIndex(T[] keys, int[] indices, int mask, T key) {
96 | int pos = this.find(keys, mask, key);
97 |
98 | if (pos < 0) {
99 | return -1;
100 | }
101 |
102 | return indices[pos];
103 | }
104 |
105 | @Override
106 | public boolean contains(Object rowKey, Object columnKey) {
107 | return this.get(rowKey, columnKey) != null;
108 | }
109 |
110 | @Override
111 | public boolean containsRow(Object rowKey) {
112 | return this.find(this.rowKeys, this.rowMask, rowKey) >= 0;
113 | }
114 |
115 | @Override
116 | public boolean containsColumn(Object columnKey) {
117 | return this.find(this.colKeys, this.colMask, columnKey) >= 0;
118 | }
119 |
120 | @Override
121 | public boolean containsValue(Object value) {
122 | return ArrayUtils.contains(this.values, value);
123 | }
124 |
125 | @Override
126 | public V get(Object rowKey, Object columnKey) {
127 | final int row = this.getIndex(this.rowKeys, this.rowIndices, this.rowMask, rowKey);
128 | final int col = this.getIndex(this.colKeys, this.colIndices, this.colMask, columnKey);
129 |
130 | if (row < 0 || col < 0) {
131 | return null;
132 | }
133 |
134 | return this.values[this.colCount * row + col];
135 | }
136 |
137 | @Override
138 | public boolean isEmpty() {
139 | return this.size() == 0;
140 | }
141 |
142 | @Override
143 | public int size() {
144 | return this.size;
145 | }
146 |
147 | @Override
148 | public void clear() {
149 | throw new UnsupportedOperationException();
150 | }
151 |
152 | @Override
153 | public V put(R rowKey, C columnKey, V val) {
154 | throw new UnsupportedOperationException();
155 | }
156 |
157 | private int find(T[] key, int mask, T value) {
158 | T curr;
159 | int pos;
160 | // The starting point.
161 | if ((curr = key[pos = HashCommon.mix(value.hashCode()) & mask]) == null) {
162 | return -(pos + 1);
163 | }
164 | if (value.equals(curr)) {
165 | return pos;
166 | }
167 | // There's always an unused entry.
168 | while (true) {
169 | if ((curr = key[pos = pos + 1 & mask]) == null) {
170 | return -(pos + 1);
171 | }
172 | if (value.equals(curr)) {
173 | return pos;
174 | }
175 | }
176 | }
177 |
178 | @Override
179 | public void putAll(Table extends R, ? extends C, ? extends V> table) {
180 | throw new UnsupportedOperationException();
181 | }
182 |
183 | @Override
184 | public V remove(Object rowKey, Object columnKey) {
185 | throw new UnsupportedOperationException();
186 | }
187 |
188 | @Override
189 | public Map row(R rowKey) {
190 | throw new UnsupportedOperationException();
191 | }
192 |
193 | @Override
194 | public Map column(C columnKey) {
195 | throw new UnsupportedOperationException();
196 | }
197 |
198 | @Override
199 | public Set> cellSet() {
200 | throw new UnsupportedOperationException();
201 | }
202 |
203 | @Override
204 | public Set rowKeySet() {
205 | throw new UnsupportedOperationException();
206 | }
207 |
208 | @Override
209 | public Set columnKeySet() {
210 | throw new UnsupportedOperationException();
211 | }
212 |
213 | @Override
214 | public Collection values() {
215 | throw new UnsupportedOperationException();
216 | }
217 |
218 | @Override
219 | public Map> rowMap() {
220 | throw new UnsupportedOperationException();
221 | }
222 |
223 | @Override
224 | public Map> columnMap() {
225 | throw new UnsupportedOperationException();
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/collections/FastImmutableTableCache.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.collections;
2 |
3 | import it.unimi.dsi.fastutil.Hash;
4 | import it.unimi.dsi.fastutil.ints.IntArrays;
5 | import it.unimi.dsi.fastutil.objects.ObjectArrays;
6 | import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
7 |
8 | /**
9 | * @param The type used by the
10 | * @param
11 | * @param
12 | */
13 | public class FastImmutableTableCache {
14 | private final ObjectOpenCustomHashSet rows;
15 | private final ObjectOpenCustomHashSet columns;
16 | private final ObjectOpenCustomHashSet values;
17 |
18 | private final ObjectOpenCustomHashSet indices;
19 |
20 | @SuppressWarnings("unchecked")
21 | public FastImmutableTableCache() {
22 | this.rows = new ObjectOpenCustomHashSet<>((Hash.Strategy) ObjectArrays.HASH_STRATEGY);
23 | this.columns = new ObjectOpenCustomHashSet<>((Hash.Strategy) ObjectArrays.HASH_STRATEGY);
24 | this.values = new ObjectOpenCustomHashSet<>((Hash.Strategy) ObjectArrays.HASH_STRATEGY);
25 |
26 | this.indices = new ObjectOpenCustomHashSet<>(IntArrays.HASH_STRATEGY);
27 | }
28 |
29 | public synchronized V[] dedupValues(V[] values) {
30 | return this.values.addOrGet(values);
31 | }
32 |
33 | public synchronized R[] dedupRows(R[] rows) {
34 | return this.rows.addOrGet(rows);
35 | }
36 |
37 | public synchronized C[] dedupColumns(C[] columns) {
38 | return this.columns.addOrGet(columns);
39 | }
40 |
41 | public synchronized int[] dedupIndices(int[] ints) {
42 | return this.indices.addOrGet(ints);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/collections/FixedArrayList.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.collections;
2 |
3 | import com.google.common.collect.Iterators;
4 | import org.apache.commons.lang3.ArrayUtils;
5 |
6 | import java.util.*;
7 |
8 | public class FixedArrayList implements List {
9 | private final T[] array;
10 |
11 | @SuppressWarnings("unchecked")
12 | public FixedArrayList(List list) {
13 | this(list.toArray((T[]) new Object[0]));
14 | }
15 |
16 | public FixedArrayList(T[] array) {
17 | this.array = array;
18 | }
19 |
20 | @Override
21 | public int size() {
22 | return this.array.length;
23 | }
24 |
25 | @Override
26 | public boolean isEmpty() {
27 | return this.array.length == 0;
28 | }
29 |
30 | @Override
31 | public boolean contains(Object o) {
32 | return ArrayUtils.contains(this.array, o);
33 | }
34 |
35 | @Override
36 | public Iterator iterator() {
37 | return Iterators.forArray(this.array);
38 | }
39 |
40 | @Override
41 | public Object[] toArray() {
42 | return this.array.clone();
43 | }
44 |
45 | @SuppressWarnings("unchecked")
46 | @Override
47 | public T1[] toArray(T1[] dst) {
48 | T[] src = this.array;
49 |
50 | if (dst.length < src.length) {
51 | return (T1[]) Arrays.copyOf(src, src.length, dst.getClass());
52 | }
53 |
54 | System.arraycopy(src, 0, dst, 0, src.length);
55 |
56 | if (dst.length > src.length) {
57 | dst[src.length] = null;
58 | }
59 |
60 | return dst;
61 | }
62 |
63 | @Override
64 | public boolean add(T t) {
65 | throw new UnsupportedOperationException();
66 | }
67 |
68 | @Override
69 | public boolean remove(Object o) {
70 | throw new UnsupportedOperationException();
71 | }
72 |
73 | @Override
74 | public boolean containsAll(Collection> c) {
75 | for (Object o : c) {
76 | if (!ArrayUtils.contains(this.array, o)) {
77 | return false;
78 | }
79 | }
80 |
81 | return true;
82 | }
83 |
84 | @Override
85 | public boolean addAll(Collection extends T> c) {
86 | throw new UnsupportedOperationException();
87 | }
88 |
89 | @Override
90 | public boolean addAll(int index, Collection extends T> c) {
91 | throw new UnsupportedOperationException();
92 | }
93 |
94 | @Override
95 | public boolean removeAll(Collection> c) {
96 | throw new UnsupportedOperationException();
97 | }
98 |
99 | @Override
100 | public boolean retainAll(Collection> c) {
101 | throw new UnsupportedOperationException();
102 | }
103 |
104 | @Override
105 | public void clear() {
106 | throw new UnsupportedOperationException();
107 | }
108 |
109 | @Override
110 | public T get(int index) {
111 | return this.array[index];
112 | }
113 |
114 | @Override
115 | public T set(int index, T element) {
116 | throw new UnsupportedOperationException();
117 | }
118 |
119 | @Override
120 | public void add(int index, T element) {
121 | throw new UnsupportedOperationException();
122 | }
123 |
124 | @Override
125 | public T remove(int index) {
126 | throw new UnsupportedOperationException();
127 | }
128 |
129 | @Override
130 | public int indexOf(Object o) {
131 | return ArrayUtils.indexOf(this.array, o);
132 | }
133 |
134 | @Override
135 | public int lastIndexOf(Object o) {
136 | return ArrayUtils.lastIndexOf(this.array, o);
137 | }
138 |
139 | @Override
140 | public ListIterator listIterator() {
141 | throw new UnsupportedOperationException();
142 | }
143 |
144 | @Override
145 | public ListIterator listIterator(int index) {
146 | throw new UnsupportedOperationException();
147 | }
148 |
149 | @Override
150 | public List subList(int fromIndex, int toIndex) {
151 | throw new UnsupportedOperationException();
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/collections/ImmutablePairArrayList.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.collections;
2 |
3 | import com.google.common.collect.AbstractIterator;
4 | import org.apache.commons.lang3.tuple.Pair;
5 |
6 | import java.util.Collection;
7 | import java.util.Iterator;
8 | import java.util.List;
9 | import java.util.ListIterator;
10 |
11 | public class ImmutablePairArrayList implements List> {
12 | private final V1[] v1;
13 | private final V2[] v2;
14 | private final int size;
15 |
16 | private final MutablePair pair = new MutablePair<>();
17 |
18 | @SuppressWarnings("unchecked")
19 | public ImmutablePairArrayList(List> src) {
20 | this.size = src.size();
21 |
22 | this.v1 = (V1[]) new Object[this.size];
23 | this.v2 = (V2[]) new Object[this.size];
24 |
25 | for (int i = 0; i < this.size; i++) {
26 | Pair pair = src.get(i);
27 |
28 | this.v1[i] = pair.getKey();
29 | this.v2[i] = pair.getValue();
30 | }
31 | }
32 |
33 | @Override
34 | public int size() {
35 | return this.size;
36 | }
37 |
38 | @Override
39 | public boolean isEmpty() {
40 | return this.size() == 0;
41 | }
42 |
43 | @Override
44 | public boolean contains(Object o) {
45 | if (!(o instanceof Pair)) {
46 | return false;
47 | }
48 |
49 | Pair, ?> pair = (Pair, ?>) o;
50 |
51 | for (int i = 0; i < this.size; i++) {
52 | if (this.v1[i] == pair.getLeft() && this.v2[i] == pair.getRight()) {
53 | return true;
54 | }
55 | }
56 |
57 | return false;
58 | }
59 |
60 | @Override
61 | public Iterator> iterator() {
62 | return new AbstractIterator>() {
63 | private final V1[] v1 = ImmutablePairArrayList.this.v1;
64 | private final V2[] v2 = ImmutablePairArrayList.this.v2;
65 | private final int limit = ImmutablePairArrayList.this.size;
66 |
67 | private final MutablePair tmp = new MutablePair<>();
68 |
69 | private int index = 0;
70 |
71 | @Override
72 | protected Pair computeNext() {
73 | if (this.index >= this.limit) {
74 | return this.endOfData();
75 | }
76 |
77 | this.tmp.left = this.v1[this.index];
78 | this.tmp.right = this.v2[this.index];
79 |
80 | this.index++;
81 |
82 | return this.tmp;
83 | }
84 | };
85 | }
86 |
87 | @Override
88 | public Object[] toArray() {
89 | throw new UnsupportedOperationException();
90 | }
91 |
92 | @Override
93 | public T[] toArray(T[] a) {
94 | throw new UnsupportedOperationException();
95 | }
96 |
97 | @Override
98 | public boolean add(Pair v1V2Pair) {
99 | throw new UnsupportedOperationException();
100 | }
101 |
102 | @Override
103 | public boolean remove(Object o) {
104 | throw new UnsupportedOperationException();
105 | }
106 |
107 | @Override
108 | public boolean containsAll(Collection> collection) {
109 | for (Object obj : collection) {
110 | if (!this.contains(obj)) {
111 | return false;
112 | }
113 | }
114 |
115 | return true;
116 | }
117 |
118 | @Override
119 | public boolean addAll(Collection extends Pair> c) {
120 | throw new UnsupportedOperationException();
121 | }
122 |
123 | @Override
124 | public boolean addAll(int index, Collection extends Pair> c) {
125 | throw new UnsupportedOperationException();
126 | }
127 |
128 | @Override
129 | public boolean removeAll(Collection> c) {
130 | throw new UnsupportedOperationException();
131 | }
132 |
133 | @Override
134 | public boolean retainAll(Collection> c) {
135 | throw new UnsupportedOperationException();
136 | }
137 |
138 | @Override
139 | public void clear() {
140 | throw new UnsupportedOperationException();
141 | }
142 |
143 | @Override
144 | public Pair get(int index) {
145 | this.pair.left = this.v1[index];
146 | this.pair.right = this.v2[index];
147 |
148 | return this.pair;
149 | }
150 |
151 | @Override
152 | public Pair set(int index, Pair element) {
153 | throw new UnsupportedOperationException();
154 | }
155 |
156 | @Override
157 | public void add(int index, Pair element) {
158 | throw new UnsupportedOperationException();
159 | }
160 |
161 | @Override
162 | public Pair remove(int index) {
163 | throw new UnsupportedOperationException();
164 | }
165 |
166 | @Override
167 | public int indexOf(Object o) {
168 | throw new UnsupportedOperationException();
169 | }
170 |
171 | @Override
172 | public int lastIndexOf(Object o) {
173 | throw new UnsupportedOperationException();
174 | }
175 |
176 | @Override
177 | public ListIterator> listIterator() {
178 | throw new UnsupportedOperationException();
179 | }
180 |
181 | @Override
182 | public ListIterator> listIterator(int index) {
183 | throw new UnsupportedOperationException();
184 | }
185 |
186 | @Override
187 | public List> subList(int fromIndex, int toIndex) {
188 | throw new UnsupportedOperationException();
189 | }
190 |
191 | private static class MutablePair extends Pair {
192 | private V1 left;
193 | private V2 right;
194 |
195 | @Override
196 | public V1 getLeft() {
197 | return this.left;
198 | }
199 |
200 | @Override
201 | public V2 getRight() {
202 | return this.right;
203 | }
204 |
205 | @Override
206 | public V2 setValue(V2 value) {
207 | throw new UnsupportedOperationException();
208 | }
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/dedup/DeduplicationCache.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.dedup;
2 |
3 | import it.unimi.dsi.fastutil.Hash;
4 | import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
5 |
6 | import java.util.Objects;
7 |
8 | public class DeduplicationCache {
9 | private final ObjectOpenCustomHashSet pool;
10 |
11 | private int attemptedInsertions = 0;
12 | private int deduplicated = 0;
13 |
14 | public DeduplicationCache(Hash.Strategy strategy) {
15 | this.pool = new ObjectOpenCustomHashSet<>(strategy);
16 | }
17 |
18 | public DeduplicationCache() {
19 | this.pool = new ObjectOpenCustomHashSet<>(new Hash.Strategy() {
20 | @Override
21 | public int hashCode(T o) {
22 | return Objects.hashCode(o);
23 | }
24 |
25 | @Override
26 | public boolean equals(T a, T b) {
27 | return Objects.equals(a, b);
28 | }
29 | });
30 | }
31 |
32 | public synchronized T deduplicate(T item) {
33 | this.attemptedInsertions++;
34 |
35 | T result = this.pool.addOrGet(item);
36 |
37 | if (result != item) {
38 | this.deduplicated++;
39 | }
40 |
41 | return result;
42 | }
43 |
44 | public synchronized void clearCache() {
45 | this.attemptedInsertions = 0;
46 | this.deduplicated = 0;
47 |
48 | this.pool.clear();
49 | }
50 |
51 | @Override
52 | public synchronized String toString() {
53 | return String.format("DeduplicationCache ( %d/%d de-duplicated, %d pooled )",
54 | this.deduplicated, this.attemptedInsertions, this.pool.size());
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/dedup/IdentifierCaches.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.dedup;
2 |
3 | import me.jellysquid.mods.hydrogen.common.HydrogenMod;
4 |
5 | public class IdentifierCaches {
6 | public static final DeduplicationCache NAMESPACES = new DeduplicationCache<>();
7 | public static final DeduplicationCache PATH = new DeduplicationCache<>();
8 |
9 | public static void printDebug() {
10 | HydrogenMod.LOGGER.info("[[[ Identifier de-duplication statistics ]]]");
11 | HydrogenMod.LOGGER.info("Namespace cache: {}", NAMESPACES);
12 | HydrogenMod.LOGGER.info("Path cache: {}", PATH);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/jvm/ClassConstructors.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.jvm;
2 |
3 | import com.google.common.collect.ImmutableMap;
4 |
5 | import java.lang.invoke.MethodHandle;
6 | import java.lang.invoke.MethodHandles;
7 | import java.lang.invoke.MethodType;
8 | import java.lang.reflect.Constructor;
9 | import java.util.Map;
10 |
11 | @SuppressWarnings("unchecked")
12 | public class ClassConstructors {
13 | private static MethodHandle FAST_IMMUTABLE_REFERENCE_HASH_MAP_CONSTRUCTOR;
14 |
15 | public static void init() {
16 | initGuavaExtensions();
17 | }
18 |
19 | private static void initGuavaExtensions() {
20 | // define classes in their reverse link order to prevent duplicate definition issues
21 | ClassDefineTool.defineClass(ImmutableMap.class, "com.google.common.collect.HydrogenImmutableMapEntry");
22 | ClassDefineTool.defineClass(ImmutableMap.class, "com.google.common.collect.HydrogenEntrySetIterator");
23 | ClassDefineTool.defineClass(ImmutableMap.class, "com.google.common.collect.HydrogenEntrySet");
24 |
25 | Class> immutableRefHashMapClass = ClassDefineTool.defineClass(ImmutableMap.class, "com.google.common.collect.HydrogenImmutableReferenceHashMap");
26 |
27 | try {
28 | FAST_IMMUTABLE_REFERENCE_HASH_MAP_CONSTRUCTOR = MethodHandles.lookup()
29 | .findConstructor(immutableRefHashMapClass, MethodType.methodType(Void.TYPE, Map.class))
30 | // compiler can only generate a desc returning ImmutableMap below
31 | .asType(MethodType.methodType(ImmutableMap.class, Map.class));
32 | } catch (ReflectiveOperationException e) {
33 | throw new RuntimeException("Failed to find constructor", e);
34 | }
35 | }
36 |
37 | public static ImmutableMap createFastImmutableMap(Map orig) {
38 | try {
39 | return (ImmutableMap) FAST_IMMUTABLE_REFERENCE_HASH_MAP_CONSTRUCTOR.invokeExact((Map) orig);
40 | } catch (Throwable e) {
41 | throw new RuntimeException("Could not instantiate collection", e);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/jvm/ClassDefineTool.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.jvm;
2 |
3 | import org.apache.commons.io.IOUtils;
4 | import org.apache.logging.log4j.LogManager;
5 | import org.apache.logging.log4j.Logger;
6 |
7 | import java.io.IOException;
8 | import java.lang.invoke.MethodHandles;
9 | import java.net.URL;
10 |
11 | public class ClassDefineTool {
12 | private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
13 |
14 | private static final Logger LOGGER = LogManager.getLogger("Hydrogen");
15 |
16 | public static Class> defineClass(Class> context, String name) {
17 | String path = "/" + name.replace('.', '/') + ".class";
18 | URL url = ClassDefineTool.class.getResource(path);
19 |
20 | if (url == null) {
21 | throw new RuntimeException("Couldn't find resource: " + path);
22 | }
23 |
24 | LOGGER.info("Injecting class '{}' (url: {})", name, url);
25 |
26 | byte[] code;
27 |
28 | try {
29 | code = IOUtils.toByteArray(url);
30 | } catch (IOException e) {
31 | throw new RuntimeException("Could not read class bytes from resources: " + path, e);
32 | }
33 |
34 | try {
35 | // The context class need to be in a module that exports and opens to ClassDefineTool
36 | // Example: guava's automatic module exports and opens to everything
37 | MethodHandles.Lookup privateLookup = MethodHandles.privateLookupIn(context, LOOKUP);
38 | return privateLookup.defineClass(code);
39 | } catch (Throwable throwable) {
40 | throw new RuntimeException("Failed to define class", throwable);
41 | }
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/state/StatePropertyPredicateHelper.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.state;
2 |
3 | import me.jellysquid.mods.hydrogen.common.state.all.AllMatchOneBoolean;
4 | import me.jellysquid.mods.hydrogen.common.state.all.AllMatchOneObject;
5 | import me.jellysquid.mods.hydrogen.common.state.any.AllMatchAnyObject;
6 | import me.jellysquid.mods.hydrogen.common.state.single.SingleMatchAny;
7 | import me.jellysquid.mods.hydrogen.common.state.single.SingleMatchOne;
8 | import me.jellysquid.mods.hydrogen.common.util.AllPredicate;
9 | import me.jellysquid.mods.hydrogen.common.util.AnyPredicate;
10 | import net.minecraft.block.BlockState;
11 |
12 | import java.util.List;
13 | import java.util.function.Predicate;
14 |
15 | public class StatePropertyPredicateHelper {
16 | @SuppressWarnings("unchecked")
17 | public static Predicate allMatch(List> predicates) {
18 | if (SingleMatchOne.areOfType(predicates)) {
19 | if (SingleMatchOne.valuesMatchType(predicates, Boolean.class)) {
20 | return new AllMatchOneBoolean(predicates);
21 | }
22 |
23 | return new AllMatchOneObject(predicates);
24 | } else if (SingleMatchAny.areOfType(predicates)) {
25 | return new AllMatchAnyObject(predicates);
26 | }
27 |
28 | return new AllPredicate<>(predicates.toArray(new Predicate[0]));
29 | }
30 |
31 | @SuppressWarnings("unchecked")
32 | public static Predicate anyMatch(List> predicates) {
33 | return new AnyPredicate<>(predicates.toArray(new Predicate[0]));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/state/all/AllMatchOneBoolean.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.state.all;
2 |
3 | import me.jellysquid.mods.hydrogen.common.state.single.SingleMatchOne;
4 | import net.minecraft.block.BlockState;
5 | import net.minecraft.state.property.Property;
6 |
7 | import java.util.List;
8 | import java.util.function.Predicate;
9 |
10 | public class AllMatchOneBoolean implements Predicate {
11 | private final Property>[] properties;
12 | private final boolean[] values;
13 |
14 | public AllMatchOneBoolean(List> list) {
15 | int size = list.size();
16 |
17 | this.properties = new Property[size];
18 | this.values = new boolean[size];
19 |
20 | for (int i = 0; i < size; i++) {
21 | SingleMatchOne predicate = (SingleMatchOne) list.get(i);
22 |
23 | this.properties[i] = predicate.property;
24 | this.values[i] = (boolean) predicate.value;
25 | }
26 | }
27 |
28 | public static boolean canReplace(List> list) {
29 | return list.stream()
30 | .allMatch(p -> {
31 | return p instanceof SingleMatchOne && ((SingleMatchOne) p).value instanceof Boolean;
32 | });
33 | }
34 |
35 | @Override
36 | public boolean test(BlockState blockState) {
37 | for (int i = 0; i < this.properties.length; i++) {
38 | Boolean value = (Boolean) blockState.get(this.properties[i]);
39 |
40 | if (value != this.values[i]) {
41 | return false;
42 | }
43 | }
44 |
45 | return true;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/state/all/AllMatchOneObject.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.state.all;
2 |
3 | import me.jellysquid.mods.hydrogen.common.state.single.SingleMatchOne;
4 | import net.minecraft.block.BlockState;
5 | import net.minecraft.state.property.Property;
6 |
7 | import java.util.List;
8 | import java.util.function.Predicate;
9 |
10 | public class AllMatchOneObject implements Predicate {
11 | private final Property>[] properties;
12 | private final Object[] values;
13 |
14 | public AllMatchOneObject(List> list) {
15 | int size = list.size();
16 |
17 | this.properties = new Property[size];
18 | this.values = new Object[size];
19 |
20 | for (int i = 0; i < size; i++) {
21 | SingleMatchOne predicate = (SingleMatchOne) list.get(i);
22 |
23 | this.properties[i] = predicate.property;
24 | this.values[i] = predicate.value;
25 | }
26 | }
27 |
28 | @Override
29 | public boolean test(BlockState blockState) {
30 | for (int i = 0; i < this.properties.length; i++) {
31 | if (blockState.get(this.properties[i]) != this.values[i]) {
32 | return false;
33 | }
34 | }
35 |
36 | return true;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/state/any/AllMatchAnyObject.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.state.any;
2 |
3 | import me.jellysquid.mods.hydrogen.common.state.single.SingleMatchAny;
4 | import net.minecraft.block.BlockState;
5 | import net.minecraft.state.property.Property;
6 | import org.apache.commons.lang3.ArrayUtils;
7 |
8 | import java.util.List;
9 | import java.util.function.Predicate;
10 |
11 | public class AllMatchAnyObject implements Predicate {
12 | private final Property>[] properties;
13 | private final Object[][] values;
14 |
15 | public AllMatchAnyObject(List> list) {
16 | int size = list.size();
17 |
18 | this.properties = new Property[size];
19 | this.values = new Object[size][];
20 |
21 | for (int i = 0; i < size; i++) {
22 | SingleMatchAny predicate = (SingleMatchAny) list.get(i);
23 |
24 | this.properties[i] = predicate.property;
25 | this.values[i] = predicate.values;
26 | }
27 | }
28 |
29 | @Override
30 | public boolean test(BlockState blockState) {
31 | for (int i = 0; i < this.properties.length; i++) {
32 | if (!ArrayUtils.contains(this.values[i], blockState.get(this.properties[i]))) {
33 | return false;
34 | }
35 | }
36 |
37 | return true;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/me/jellysquid/mods/hydrogen/common/state/single/SingleMatchAny.java:
--------------------------------------------------------------------------------
1 | package me.jellysquid.mods.hydrogen.common.state.single;
2 |
3 | import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
4 | import net.minecraft.block.BlockState;
5 | import net.minecraft.state.property.Property;
6 | import org.apache.commons.lang3.ArrayUtils;
7 |
8 | import java.util.Arrays;
9 | import java.util.List;
10 | import java.util.Objects;
11 | import java.util.function.Predicate;
12 |
13 | public class SingleMatchAny implements Predicate {
14 | public static final ObjectOpenHashSet PREDICATES = new ObjectOpenHashSet<>();
15 |
16 | public final Property> property;
17 | public final Object[] values;
18 |
19 | private SingleMatchAny(Property> property, List