1.4 start, virtual threads support
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
group=net.gensokyoreimagined.nitori
|
group=net.gensokyoreimagined.nitori
|
||||||
version=1.3-SNAPSHOT
|
version=1.4-SNAPSHOT
|
||||||
description=Converting patches into mixins, for the Ignite Framework
|
description=Converting patches into mixins, for the Ignite Framework
|
||||||
|
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package net.gensokyoreimagined.nitori.mixin.alloc;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
|
||||||
|
@Mixin(ResourceLocation.class)
|
||||||
|
public class MixinIdentifier {
|
||||||
|
|
||||||
|
@Shadow @Final
|
||||||
|
private String namespace;
|
||||||
|
|
||||||
|
@Shadow @Final
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private String nitori$cachedString = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ishland
|
||||||
|
* @reason cache toString
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public String toString() {
|
||||||
|
if (this.nitori$cachedString != null) return this.nitori$cachedString;
|
||||||
|
final String s = this.namespace + ":" + this.path;
|
||||||
|
this.nitori$cachedString = s;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
package net.gensokyoreimagined.nitori.mixin;
|
package net.gensokyoreimagined.nitori.mixin.entity.micro_opts;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// Gale - virtual thread support
|
||||||
|
|
||||||
|
package net.gensokyoreimagined.nitori.mixin.virtual_thread;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of {@link VirtualThreadService} that can create virtual threads directly.
|
||||||
|
*
|
||||||
|
* @author Martijn Muijsers
|
||||||
|
*/
|
||||||
|
final class DirectVirtualThreadService extends VirtualThreadService {
|
||||||
|
|
||||||
|
private DirectVirtualThreadService() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ThreadFactory createFactory() {
|
||||||
|
// Disabled until Minecraft requires servers to have a Java version that can read class files compiled with functionality from Java 19+ on preview / Java 21+ on stable
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
// return Thread.ofVirtual().factory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Thread start(@NotNull Runnable task) {
|
||||||
|
// Disabled until Minecraft requires servers to have a Java version that can read class files compiled with functionality from Java 19+ on preview / Java 21+ on stable
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
// Objects.requireNonNull(task, "The task to start a virtual thread cannot be null");
|
||||||
|
// return Thread.ofVirtual().start(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A functional {@link DirectVirtualThreadService}.
|
||||||
|
* @throws Throwable If creating virtual threads directly is not supported by the current runtime.
|
||||||
|
* This could be any {@link Throwable}, including an {@link Exception} or an {@link Error}.
|
||||||
|
*/
|
||||||
|
static @NotNull DirectVirtualThreadService create() throws Throwable {
|
||||||
|
// Disabled until Minecraft requires servers to have a Java version that can read class files compiled with functionality from Java 19+ on preview / Java 21+ on stable
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
// var service = new DirectVirtualThreadService();
|
||||||
|
// // Run some tests to verify
|
||||||
|
// service.runTest();
|
||||||
|
// // If we end up here, it works
|
||||||
|
// return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
// Gale - virtual thread support
|
||||||
|
|
||||||
|
package net.gensokyoreimagined.nitori.mixin.virtual_thread;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of {@link VirtualThreadService} that can create virtual threads using Java reflection.
|
||||||
|
*
|
||||||
|
* @author Martijn Muijsers
|
||||||
|
*/
|
||||||
|
final class ReflectionVirtualThreadService extends VirtualThreadService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link Thread}<code>#ofVirtual()</code> method.
|
||||||
|
*/
|
||||||
|
private final @NotNull Method Thread_ofVirtual_method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link Thread}<code>.Builder#factory()</code> method.
|
||||||
|
*/
|
||||||
|
private final @NotNull Method Thread_Builder_factory_method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link Thread}<code>.Builder#start(Runnable)</code> method.
|
||||||
|
*/
|
||||||
|
private final @NotNull Method Thread_Builder_start_method;
|
||||||
|
|
||||||
|
private ReflectionVirtualThreadService() throws Throwable {
|
||||||
|
this.Thread_ofVirtual_method = Objects.requireNonNull(Thread.class.getMethod("ofVirtual"));
|
||||||
|
// The Thread.Builder class
|
||||||
|
var Thread_Builder_class = Objects.requireNonNull(Class.forName("java.lang.Thread$Builder"));
|
||||||
|
this.Thread_Builder_factory_method = Objects.requireNonNull(Thread_Builder_class.getMethod("factory"));
|
||||||
|
this.Thread_Builder_start_method = Objects.requireNonNull(Thread_Builder_class.getMethod("start", Runnable.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ThreadFactory createFactory() {
|
||||||
|
try {
|
||||||
|
return (ThreadFactory) this.Thread_Builder_factory_method.invoke(this.Thread_ofVirtual_method.invoke(null));
|
||||||
|
} catch (Exception e) {
|
||||||
|
// This should not be possible because it was tested in create()
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Thread start(@NotNull Runnable task) {
|
||||||
|
Objects.requireNonNull(task, "The task to start a virtual thread cannot be null");
|
||||||
|
try {
|
||||||
|
return (Thread) this.Thread_Builder_start_method.invoke(this.Thread_ofVirtual_method.invoke(null), task);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// This should not be possible because it was tested in create()
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A functional {@link ReflectionVirtualThreadService}.
|
||||||
|
* @throws Throwable If creating virtual threads via reflection is not supported by the current runtime.
|
||||||
|
* This could be any {@link Throwable}, including an {@link Exception} or an {@link Error}.
|
||||||
|
*/
|
||||||
|
static @NotNull ReflectionVirtualThreadService create() throws Throwable {
|
||||||
|
// This will already throw something if the reflection fails
|
||||||
|
var service = new ReflectionVirtualThreadService();
|
||||||
|
// Run some tests to verify
|
||||||
|
service.runTest();
|
||||||
|
// If we end up here, it works
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
// Gale - virtual thread support
|
||||||
|
|
||||||
|
package net.gensokyoreimagined.nitori.mixin.virtual_thread;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract service to create virtual threads.
|
||||||
|
*
|
||||||
|
* @author Martijn Muijsers
|
||||||
|
*/
|
||||||
|
public sealed abstract class VirtualThreadService permits ReflectionVirtualThreadService, DirectVirtualThreadService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A {@link ThreadFactory} that produces virtual threads.
|
||||||
|
*/
|
||||||
|
public abstract @NotNull ThreadFactory createFactory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param task The runnable for the thread to execute.
|
||||||
|
* @return A virtual thread that has been started with the given task.
|
||||||
|
*/
|
||||||
|
public abstract @NotNull Thread start(Runnable task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a test on the {@link #createFactory} and {@link #start} methods,
|
||||||
|
* which certainly throws some {@link Throwable} if something goes wrong.
|
||||||
|
*/
|
||||||
|
protected void runTest() throws Throwable {
|
||||||
|
// This will definitely throw something if it doesn't work
|
||||||
|
try {
|
||||||
|
this.start(() -> {}).join();
|
||||||
|
} catch (InterruptedException ignored) {} // Except InterruptedException, we don't care about that one
|
||||||
|
try {
|
||||||
|
var thread = this.createFactory().newThread(() -> {});
|
||||||
|
thread.start();
|
||||||
|
thread.join();
|
||||||
|
} catch (InterruptedException ignored) {} // Except InterruptedException, we don't care about that one
|
||||||
|
// If we end up here, it works
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean initialized = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link VirtualThreadService} for the current runtime,
|
||||||
|
* or null if virtual threads are not supported, or if not {@link #initialized} yet.
|
||||||
|
*/
|
||||||
|
private static @Nullable VirtualThreadService implementation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Whether virtual threads are supported on the current runtime.
|
||||||
|
*/
|
||||||
|
public static boolean isSupported() {
|
||||||
|
return get() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The {@link VirtualThreadService} for the current runtime,
|
||||||
|
* or null if virtual threads are not {@linkplain #isSupported() supported}.
|
||||||
|
*
|
||||||
|
* This method is thread-safe only after the first time it has been fully run.
|
||||||
|
*/
|
||||||
|
public static @Nullable VirtualThreadService get() {
|
||||||
|
if (!initialized) {
|
||||||
|
initialized = true;
|
||||||
|
try {
|
||||||
|
implementation = DirectVirtualThreadService.create();
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
try {
|
||||||
|
implementation = ReflectionVirtualThreadService.create();
|
||||||
|
} catch (Throwable ignored2) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return implementation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum major version of Java that is known to support using virtual threads
|
||||||
|
* (although possibly behind a feature preview flag).
|
||||||
|
*/
|
||||||
|
public static final int minimumJavaMajorVersionWithFeaturePreview = 19;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum major version of Java that is known to support using virtual threads
|
||||||
|
* even without any feature preview flags.
|
||||||
|
*/
|
||||||
|
public static final int minimumJavaMajorVersionWithoutFeaturePreview = 21;
|
||||||
|
|
||||||
|
public static int getJavaMajorVersion() {
|
||||||
|
var version = System.getProperty("java.version");
|
||||||
|
if (version.startsWith("1.")) {
|
||||||
|
return version.charAt(2) - '0';
|
||||||
|
}
|
||||||
|
int dotIndex = version.indexOf(".");
|
||||||
|
return Integer.parseInt(dotIndex == -1 ? version : version.substring(0, dotIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"id": "Nitori",
|
"id": "Nitori",
|
||||||
"version": "1.3-SNAPSHOT",
|
"version": "1.4-SNAPSHOT",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"mixins.core.json"
|
"mixins.core.json"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"MixinGameRules",
|
"MixinGameRules",
|
||||||
"MixinIteratorSafeOrderedReferenceSet",
|
"MixinIteratorSafeOrderedReferenceSet",
|
||||||
"MixinLevelStorageAccess",
|
"MixinLevelStorageAccess",
|
||||||
"MixinMob",
|
"entity.micro_opts.MixinMob",
|
||||||
"MixinNoiseBasedChunkGenerator",
|
"MixinNoiseBasedChunkGenerator",
|
||||||
"MixinPlayer",
|
"MixinPlayer",
|
||||||
"MixinPlayerList",
|
"MixinPlayerList",
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
"alloc.composter.ComposterMixin$ComposterBlockDummyInventoryMixin",
|
"alloc.composter.ComposterMixin$ComposterBlockDummyInventoryMixin",
|
||||||
"alloc.composter.ComposterMixin$ComposterBlockFullComposterInventoryMixin",
|
"alloc.composter.ComposterMixin$ComposterBlockFullComposterInventoryMixin",
|
||||||
"alloc.biome_temprature_leak.Biome_threadLocalMixin",
|
"alloc.biome_temprature_leak.Biome_threadLocalMixin",
|
||||||
|
"alloc.MixinIdentifier",
|
||||||
"cached_hashcode.BlockNeighborGroupMixin",
|
"cached_hashcode.BlockNeighborGroupMixin",
|
||||||
"collections.attributes.AttributeContainerMixin",
|
"collections.attributes.AttributeContainerMixin",
|
||||||
"collections.block_entity_tickers.WorldChunkMixin",
|
"collections.block_entity_tickers.WorldChunkMixin",
|
||||||
|
|||||||
Reference in New Issue
Block a user