Initial work

This commit is contained in:
shedaniel
2020-11-01 19:59:17 +08:00
commit 5a39747a65
44 changed files with 2562 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public class Architectury {
private static final String MOD_LOADER;
public static String getModLoader() {
return MOD_LOADER;
}
static {
String loader;
try {
Class.forName("net.fabricmc.loader.FabricLoader");
loader = "fabric";
} catch (ClassNotFoundException e) {
loader = "forge";
}
MOD_LOADER = loader;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury;
import org.apache.commons.lang3.reflect.FieldUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public final class ArchitecturyPopulator {
private ArchitecturyPopulator() {}
public static void populate(Object o) {
try {
if (o instanceof Class) {
Class<?> aClass = (Class<?>) o;
for (Field field : aClass.getDeclaredFields()) {
if (!field.isAnnotationPresent(Populatable.class)) continue;
if (Modifier.isStatic(field.getModifiers())) {
FieldUtils.removeFinalModifier(field);
field.setAccessible(true);
String type = field.getType().toString().replace("$", "");
Class<?> newClass = Class.forName(type.substring(0, type.lastIndexOf('.')) + "." + Architectury.getModLoader() + "." + type.substring(type.lastIndexOf('.') + 1));
field.set(null, newClass.getConstructor().newInstance());
}
}
} else {
for (Field field : o.getClass().getDeclaredFields()) {
if (!field.isAnnotationPresent(Populatable.class)) continue;
if (!Modifier.isStatic(field.getModifiers())) {
FieldUtils.removeFinalModifier(field);
field.setAccessible(true);
String type = field.getType().toString().replace("$", "");
Class<?> newClass = Class.forName(type.substring(0, type.lastIndexOf('.')) + "." + Architectury.getModLoader() + "." + type.substring(type.lastIndexOf('.') + 1));
field.set(o, newClass.getConstructor().newInstance());
}
}
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Populatable {
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury.event;
public interface Event<T> {
T invoker();
void register(T listener);
void unregister(T listener);
boolean isRegistered(T listener);
void clearListeners();
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury.event;
import com.google.common.reflect.AbstractInvocationHandler;
import me.shedaniel.architectury.ArchitecturyPopulator;
import me.shedaniel.architectury.Populatable;
import me.shedaniel.architectury.platform.Platform;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.jodah.typetools.TypeResolver;
import net.minecraft.world.InteractionResult;
import org.apache.commons.lang3.ArrayUtils;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Objects;
import java.util.function.Function;
public final class EventFactory {
private EventFactory() {}
@Populatable
private static final Impl IMPL = null;
public static <T> Event<T> create(Function<T[], T> function) {
Class<?>[] arguments = TypeResolver.resolveRawArguments(Function.class, function.getClass());
return new EventImpl<>(arguments[1], function);
}
@SuppressWarnings("UnstableApiUsage")
public static <T> Event<T> createLoop(Class<T> clazz) {
return create(ts -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
@Override
protected Object handleInvocation(Object proxy, Method method, Object[] args) {
return null;
}
}));
}
@SuppressWarnings("UnstableApiUsage")
public static <T> Event<T> createInteractionResult(Class<T> clazz) {
return create(ts -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
@Override
protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
T[] listeners = (T[]) args;
for (T listener : listeners) {
InteractionResult result = (InteractionResult) method.invoke(listener, args);
if (result != InteractionResult.PASS) {
return result;
}
}
return InteractionResult.PASS;
}
}));
}
private static class EventImpl<T> implements Event<T> {
private final Function<T[], T> function;
private T invoker = null;
private T[] listeners;
private Class<?> clazz;
public EventImpl(Class<?> clazz, Function<T[], T> function) {
this.clazz = Objects.requireNonNull(clazz);
this.function = function;
this.listeners = emptyArray();
update();
}
private T[] emptyArray() {
try {
return (T[]) Array.newInstance(clazz, 0);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public T invoker() {
return invoker;
}
@Override
public void register(T listener) {
listeners = ArrayUtils.add(listeners, listener);
update();
}
@Override
public void unregister(T listener) {
listeners = ArrayUtils.removeElement(listeners, listener);
update();
}
@Override
public boolean isRegistered(T listener) {
return ArrayUtils.contains(listeners, listener);
}
@Override
public void clearListeners() {
listeners = emptyArray();
update();
}
public void update() {
if (listeners.length == 1) {
invoker = listeners[0];
} else {
invoker = function.apply(listeners);
}
}
}
public interface Impl {
@Environment(EnvType.CLIENT)
void registerClient();
void registerCommon();
@Environment(EnvType.SERVER)
void registerServer();
}
static {
ArchitecturyPopulator.populate(EventFactory.class);
if (Platform.getEnv() == EnvType.CLIENT)
IMPL.registerClient();
IMPL.registerCommon();
if (Platform.getEnv() == EnvType.SERVER)
IMPL.registerServer();
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury.event.events;
import com.mojang.blaze3d.vertex.PoseStack;
import me.shedaniel.architectury.event.Event;
import me.shedaniel.architectury.event.EventFactory;
public interface GuiEvent {
Event<RenderHud> RENDER_HUD = EventFactory.createLoop(RenderHud.class);
interface RenderHud {
void renderHud(PoseStack matrices, float tickDelta);
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury.event.events;
import me.shedaniel.architectury.event.Event;
import me.shedaniel.architectury.event.EventFactory;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.server.MinecraftServer;
public interface LifecycleEvent {
@Environment(EnvType.CLIENT)
Event<ClientState> CLIENT_STARTED = EventFactory.createLoop(ClientState.class);
@Environment(EnvType.CLIENT)
Event<ClientState> CLIENT_STOPPING = EventFactory.createLoop(ClientState.class);
Event<ServerState> SERVER_STARTING = EventFactory.createLoop(ServerState.class);
Event<ServerState> SERVER_STARTED = EventFactory.createLoop(ServerState.class);
Event<ServerState> SERVER_STOPPING = EventFactory.createLoop(ServerState.class);
Event<ServerState> SERVER_STOPPED = EventFactory.createLoop(ServerState.class);
interface InstanceState<T> {
void stateChanged(T instance);
}
@Environment(EnvType.CLIENT)
interface ClientState extends InstanceState<Minecraft> {}
interface ServerState extends InstanceState<MinecraftServer> {}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury.event.events;
import me.shedaniel.architectury.event.Event;
import me.shedaniel.architectury.event.EventFactory;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
public interface TickEvent<T> {
@Environment(EnvType.CLIENT)
Event<Client> CLIENT_PRE = EventFactory.createLoop(Client.class);
@Environment(EnvType.CLIENT)
Event<Client> CLIENT_POST = EventFactory.createLoop(Client.class);
Event<Server> SERVER_PRE = EventFactory.createLoop(Server.class);
Event<Server> SERVER_POST = EventFactory.createLoop(Server.class);
@Environment(EnvType.CLIENT)
Event<ClientWorld> CLIENT_WORLD_PRE = EventFactory.createLoop(ClientWorld.class);
@Environment(EnvType.CLIENT)
Event<ClientWorld> CLIENT_WORLD_POST = EventFactory.createLoop(ClientWorld.class);
Event<ServerWorld> SERVER_WORLD_PRE = EventFactory.createLoop(ServerWorld.class);
Event<ServerWorld> SERVER_WORLD_POST = EventFactory.createLoop(ServerWorld.class);
void tick(T instance);
@Environment(EnvType.CLIENT)
interface Client extends TickEvent<Minecraft> {}
interface Server extends TickEvent<MinecraftServer> {}
interface WorldTick<T extends Level> extends TickEvent<T> {}
@Environment(EnvType.CLIENT)
interface ClientWorld extends WorldTick<ClientLevel> {}
interface ServerWorld extends WorldTick<ServerLevel> {}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury.event.events;
import me.shedaniel.architectury.event.Event;
import me.shedaniel.architectury.event.EventFactory;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import java.util.List;
@Environment(EnvType.CLIENT)
public interface TooltipEvent {
Event<Item> ITEM = EventFactory.createLoop(Item.class);
@Environment(EnvType.CLIENT)
interface Item {
void append(ItemStack stack, List<Component> lines, TooltipFlag flag);
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury.networking;
import me.shedaniel.architectury.ArchitecturyPopulator;
import me.shedaniel.architectury.Populatable;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
public final class NetworkManager {
@Populatable
private static final Impl IMPL = null;
public static void registerReceiver(Side side, ResourceLocation id, NetworkReceiver receiver) {
IMPL.registerReceiver(side, id, receiver);
}
public static Packet<?> toPacket(Side side, ResourceLocation id, FriendlyByteBuf buf) {
return IMPL.toPacket(side, id, buf);
}
public static void sendToPlayer(ServerPlayer player, ResourceLocation id, FriendlyByteBuf buf) {
player.connection.send(toPacket(serverToClient(), id, buf));
}
public static void sendToPlayers(Iterable<ServerPlayer> players, ResourceLocation id, FriendlyByteBuf buf) {
Packet<?> packet = toPacket(serverToClient(), id, buf);
for (ServerPlayer player : players) {
player.connection.send(packet);
}
}
@Environment(EnvType.CLIENT)
public static void sendToServer(ResourceLocation id, FriendlyByteBuf buf) {
Minecraft.getInstance().getConnection().send(toPacket(clientToServer(), id, buf));
}
@Environment(EnvType.CLIENT)
public static boolean canServerReceive(ResourceLocation id) {
return IMPL.canServerReceive(id);
}
public static boolean canPlayerReceive(ServerPlayer player, ResourceLocation id) {
return IMPL.canPlayerReceive(player, id);
}
public interface Impl {
void registerReceiver(Side side, ResourceLocation id, NetworkReceiver receiver);
Packet<?> toPacket(Side side, ResourceLocation id, FriendlyByteBuf buf);
@Environment(EnvType.CLIENT)
boolean canServerReceive(ResourceLocation id);
boolean canPlayerReceive(ServerPlayer player, ResourceLocation id);
}
@FunctionalInterface
public interface NetworkReceiver {
void receive(FriendlyByteBuf buf, PacketContext context);
}
public interface PacketContext {
Player getPlayer();
void queue(Runnable runnable);
EnvType getEnv();
}
public static Side s2c() {
return Side.S2C;
}
public static Side c2s() {
return Side.C2S;
}
public static Side serverToClient() {
return Side.S2C;
}
public static Side clientToServer() {
return Side.C2S;
}
public enum Side {
S2C,
C2S
}
static {
ArchitecturyPopulator.populate(NetworkManager.class);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury.platform;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.screens.Screen;
import org.jetbrains.annotations.NotNull;
public interface Mod {
@NotNull
String getModId();
@NotNull
String getVersion();
@NotNull
String getName();
@NotNull
String getDescription();
@Environment(EnvType.CLIENT)
void registerConfigurationScreen(ConfigurationScreenProvider provider);
@Environment(EnvType.CLIENT)
@FunctionalInterface
interface ConfigurationScreenProvider {
Screen provide(Screen parent);
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury.platform;
import me.shedaniel.architectury.Architectury;
import me.shedaniel.architectury.ArchitecturyPopulator;
import me.shedaniel.architectury.Populatable;
import net.fabricmc.api.EnvType;
import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
import java.util.Collection;
public final class Platform {
private Platform() {}
@Populatable
private static final Impl IMPL = null;
/**
* @return the current mod loader, either "fabric" or "forge"
*/
@NotNull
public static String getModLoader() {
return Architectury.getModLoader();
}
@NotNull
public static Path getGameFolder() {
return IMPL.getGameFolder();
}
@NotNull
public static Path getConfigFolder() {
return IMPL.getConfigFolder();
}
@NotNull
public static EnvType getEnv() {
return IMPL.getEnv();
}
public static boolean isModLoaded(String id) {
return IMPL.isModLoaded(id);
}
@NotNull
public static Mod getMod(String id) {
return IMPL.getMod(id);
}
@NotNull
public static Collection<Mod> getMods() {
return IMPL.getMods();
}
public interface Impl {
Path getGameFolder();
Path getConfigFolder();
Path getModsFolder();
EnvType getEnv();
boolean isModLoaded(String id);
Mod getMod(String id);
Collection<Mod> getMods();
}
static {
ArchitecturyPopulator.populate(Platform.class);
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury.registry;
import me.shedaniel.architectury.ArchitecturyPopulator;
import me.shedaniel.architectury.Populatable;
import net.minecraft.resources.ResourceKey;
import java.util.HashMap;
import java.util.Map;
public final class Registries {
@Populatable
private static final Impl IMPL = null;
private static final Map<String, Registries> REGISTRIES = new HashMap<>();
private final RegistryProvider provider;
public static Registries get(String modId) {
return REGISTRIES.computeIfAbsent(modId, Registries::new);
}
private Registries(String modId) {
this.provider = IMPL.get(modId);
}
public <T> Registry<T> get(ResourceKey<net.minecraft.core.Registry<T>> key) {
return this.provider.get(key);
}
@Deprecated
public <T> Registry<T> get(net.minecraft.core.Registry<T> registry) {
return this.provider.get(registry);
}
public interface Impl {
RegistryProvider get(String modId);
}
public interface RegistryProvider {
<T> Registry<T> get(ResourceKey<net.minecraft.core.Registry<T>> key);
@Deprecated
<T> Registry<T> get(net.minecraft.core.Registry<T> registry);
}
static {
ArchitecturyPopulator.populate(Registries.class);
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2020 shedaniel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.shedaniel.architectury.registry;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier;
public interface Registry<T> {
Supplier<T> delegate(ResourceLocation id);
Supplier<T> register(ResourceLocation id, Supplier<T> supplier);
@Nullable
ResourceLocation getId(T obj);
@Nullable
T get(ResourceLocation id);
}

View File

@@ -0,0 +1,31 @@
package me.shedaniel.architectury.utils;
import me.shedaniel.architectury.ArchitecturyPopulator;
import me.shedaniel.architectury.Populatable;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.server.MinecraftServer;
public final class GameInstance {
@Populatable
private static final Impl IMPL = null;
@Environment(EnvType.CLIENT)
public static Minecraft getClient() {
return Minecraft.getInstance();
}
@Environment(EnvType.SERVER)
public static MinecraftServer getServer() {
return IMPL.getServer();
}
public interface Impl {
MinecraftServer getServer();
}
static {
ArchitecturyPopulator.populate(GameInstance.class);
}
}

View File

@@ -0,0 +1,6 @@
{
"_comment": "This file is here to make fabric loader load this on the Knot classloader.",
"schemaVersion": 1,
"id": "architectury-common",
"version": "0.0.1"
}