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

16
.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
build/
*.ipr
run/
*.iws
out/
*.iml
.gradle/
output/
bin/
libs/
.classpath
.project
.settings/org.eclipse.core.resources.prefs
.idea/
classes/

13
HEADER Normal file
View File

@@ -0,0 +1,13 @@
Copyright ${year} ${name}
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.

170
LICENSE.md Normal file
View File

@@ -0,0 +1,170 @@
Apache License
==============
_Version 2.0, January 2004_
_&lt;<http://www.apache.org/licenses/>&gt;_
### Terms and Conditions for use, reproduction, and distribution
#### 1. Definitions
“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
“Licensor” shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means **(i)** the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
outstanding shares, or **(iii)** beneficial ownership of such entity.
“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.
“Source” form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
“Work” shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
“Contribution” shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
“submitted” means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as “Not a Contribution.”
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
#### 2. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
#### 3. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
#### 4. Redistribution
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
this License; and
* **(b)** You must cause any modified files to carry prominent notices stating that You
changed the files; and
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
#### 5. Submission of Contributions
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
#### 6. Trademarks
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
#### 7. Disclaimer of Warranty
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
#### 8. Limitation of Liability
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
#### 9. Accepting Warranty or Additional Liability
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
_END OF TERMS AND CONDITIONS_

36
build.gradle Normal file
View File

@@ -0,0 +1,36 @@
plugins {
id "architect-plugin" version "1.0.10"
id "org.cadixdev.licenser" version "0.5.0"
}
architect {
minecraft = rootProject.minecraft_version
}
allprojects {
apply plugin: "java"
apply plugin: "architect-plugin"
apply plugin: "org.cadixdev.licenser"
archivesBaseName = rootProject.archives_base_name
version = rootProject.mod_version
group = rootProject.maven_group
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
license {
header = rootProject.file("HEADER")
ext {
name = "shedaniel"
year = 2020
}
ignoreFailures = true
}
}
task licenseFormatAll
subprojects { p -> licenseFormatAll.dependsOn("${p.path}:licenseFormat") }

16
common/build.gradle Normal file
View File

@@ -0,0 +1,16 @@
plugins {
id "fabric-loom"
}
dependencies {
minecraft "com.mojang:minecraft:${rootProject.architect.minecraft}"
mappings minecraft.officialMojangMappings()
// We depend on fabric loader here to use the fabric @Environment annotations
// Do NOT use other classes from fabric loader
modCompile "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
implementation "net.jodah:typetools:0.6.2"
}
architect {
common()
}

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"
}

33
fabric/build.gradle Normal file
View File

@@ -0,0 +1,33 @@
plugins {
id "fabric-loom"
id "com.github.johnrengelman.shadow" version "5.0.0"
}
configurations {
shadow
}
dependencies {
minecraft("com.mojang:minecraft:${rootProject.architect.minecraft}")
mappings(minecraft.officialMojangMappings())
modCompile("net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}")
modCompile("net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}")
modCompileOnly("io.github.prospector:modmenu:${rootProject.mod_menu_version}")
compile(project(":common")) {
transitive = false
}
shadow(project(":common")) {
transitive = false
}
}
shadowJar {
configurations = [project.configurations.shadow]
classifier "shadow"
}
remapJar {
dependsOn(shadowJar)
input.set(shadowJar.archivePath)
}

View File

@@ -0,0 +1,43 @@
/*
* 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.compat.fabric;
import com.google.common.collect.Maps;
import io.github.prospector.modmenu.api.ConfigScreenFactory;
import io.github.prospector.modmenu.api.ModMenuApi;
import me.shedaniel.architectury.platform.fabric.PlatformImpl;
import me.shedaniel.architectury.platform.Mod;
import java.util.Map;
public class ModMenuCompatibility implements ModMenuApi {
private static final Map<String, ConfigScreenFactory<?>> FACTORIES = Maps.newHashMap();
@Override
public Map<String, ConfigScreenFactory<?>> getProvidedConfigScreenFactories() {
validateMap();
return FACTORIES;
}
private void validateMap() {
for (Map.Entry<String, Mod.ConfigurationScreenProvider> entry : PlatformImpl.CONFIG_SCREENS.entrySet()) {
if (!FACTORIES.containsKey(entry.getKey())) {
FACTORIES.put(entry.getKey(), entry.getValue()::provide);
}
}
}
}

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.event.fabric;
import me.shedaniel.architectury.event.EventFactory;
import me.shedaniel.architectury.event.events.GuiEvent;
import me.shedaniel.architectury.event.events.LifecycleEvent;
import me.shedaniel.architectury.event.events.TickEvent;
import me.shedaniel.architectury.event.events.TooltipEvent;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
public class EventFactoryImpl implements EventFactory.Impl {
@Override
public void registerClient() {
ClientLifecycleEvents.CLIENT_STARTED.register(LifecycleEvent.CLIENT_STARTED.invoker()::stateChanged);
ClientLifecycleEvents.CLIENT_STOPPING.register(LifecycleEvent.CLIENT_STOPPING.invoker()::stateChanged);
ClientTickEvents.START_CLIENT_TICK.register(TickEvent.CLIENT_PRE.invoker()::tick);
ClientTickEvents.END_CLIENT_TICK.register(TickEvent.CLIENT_POST.invoker()::tick);
ClientTickEvents.START_WORLD_TICK.register(TickEvent.CLIENT_WORLD_PRE.invoker()::tick);
ClientTickEvents.END_WORLD_TICK.register(TickEvent.CLIENT_WORLD_POST.invoker()::tick);
ItemTooltipCallback.EVENT.register((itemStack, tooltipFlag, list) -> TooltipEvent.ITEM.invoker().append(itemStack, list, tooltipFlag));
HudRenderCallback.EVENT.register(GuiEvent.RENDER_HUD.invoker()::renderHud);
}
@Override
public void registerCommon() {
ServerLifecycleEvents.SERVER_STARTING.register(LifecycleEvent.SERVER_STARTING.invoker()::stateChanged);
ServerLifecycleEvents.SERVER_STARTED.register(LifecycleEvent.SERVER_STARTED.invoker()::stateChanged);
ServerLifecycleEvents.SERVER_STOPPING.register(LifecycleEvent.SERVER_STOPPING.invoker()::stateChanged);
ServerLifecycleEvents.SERVER_STOPPED.register(LifecycleEvent.SERVER_STOPPED.invoker()::stateChanged);
ServerTickEvents.START_SERVER_TICK.register(TickEvent.SERVER_PRE.invoker()::tick);
ServerTickEvents.END_SERVER_TICK.register(TickEvent.SERVER_POST.invoker()::tick);
ServerTickEvents.START_WORLD_TICK.register(TickEvent.SERVER_WORLD_PRE.invoker()::tick);
ServerTickEvents.END_WORLD_TICK.register(TickEvent.SERVER_WORLD_POST.invoker()::tick);
}
@Override
public void registerServer() {
}
}

View File

@@ -0,0 +1,83 @@
package me.shedaniel.architectury.networking.fabric;
import me.shedaniel.architectury.networking.NetworkManager;
import me.shedaniel.architectury.networking.NetworkManager.NetworkReceiver;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
import net.fabricmc.fabric.api.network.PacketContext;
import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
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 class NetworkManagerImpl implements NetworkManager.Impl {
@Override
public void registerReceiver(NetworkManager.Side side, ResourceLocation id, NetworkReceiver receiver) {
if (side == NetworkManager.Side.C2S) {
registerC2SReceiver(id, receiver);
} else if (side == NetworkManager.Side.S2C) {
registerS2CReceiver(id, receiver);
}
}
private void registerC2SReceiver(ResourceLocation id, NetworkReceiver receiver) {
ServerSidePacketRegistry.INSTANCE.register(id, (packetContext, buf) -> receiver.receive(buf, to(packetContext)));
}
@Environment(EnvType.CLIENT)
private void registerS2CReceiver(ResourceLocation id, NetworkReceiver receiver) {
ClientSidePacketRegistry.INSTANCE.register(id, (packetContext, buf) -> receiver.receive(buf, to(packetContext)));
}
private NetworkManager.PacketContext to(PacketContext context) {
return new NetworkManager.PacketContext() {
@Override
public Player getPlayer() {
return context.getPlayer();
}
@Override
public void queue(Runnable runnable) {
context.getTaskQueue().execute(runnable);
}
@Override
public EnvType getEnv() {
return context.getPacketEnvironment();
}
};
}
@Override
public Packet<?> toPacket(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf) {
if (side == NetworkManager.Side.C2S) {
return toC2SPacket(id, buf);
} else if (side == NetworkManager.Side.S2C) {
return toS2CPacket(id, buf);
}
throw new IllegalArgumentException("Invalid side: " + side);
}
@Override
public boolean canServerReceive(ResourceLocation id) {
return ClientSidePacketRegistry.INSTANCE.canServerReceive(id);
}
@Override
public boolean canPlayerReceive(ServerPlayer player, ResourceLocation id) {
return ServerSidePacketRegistry.INSTANCE.canPlayerReceive(player, id);
}
@Environment(EnvType.CLIENT)
private Packet<?> toC2SPacket(ResourceLocation id, FriendlyByteBuf buf) {
return ClientSidePacketRegistry.INSTANCE.toPacket(id, buf);
}
private Packet<?> toS2CPacket(ResourceLocation id, FriendlyByteBuf buf) {
return ServerSidePacketRegistry.INSTANCE.toPacket(id, buf);
}
}

View File

@@ -0,0 +1,108 @@
/*
* 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.fabric;
import me.shedaniel.architectury.platform.Mod;
import me.shedaniel.architectury.platform.Platform;
import net.fabricmc.api.EnvType;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.metadata.ModMetadata;
import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class PlatformImpl implements Platform.Impl {
public static final Map<String, Mod.ConfigurationScreenProvider> CONFIG_SCREENS = new HashMap<>();
private final Map<String, Mod> mods = new HashMap<>();
@Override
public Path getGameFolder() {
return FabricLoader.getInstance().getGameDir();
}
@Override
public Path getConfigFolder() {
return FabricLoader.getInstance().getConfigDir();
}
@Override
public Path getModsFolder() {
return getGameFolder().resolve("mods");
}
@Override
public EnvType getEnv() {
return FabricLoader.getInstance().getEnvironmentType();
}
@Override
public boolean isModLoaded(String id) {
return FabricLoader.getInstance().isModLoaded(id);
}
@Override
public Mod getMod(String id) {
return this.mods.computeIfAbsent(id, ModImpl::new);
}
@Override
public Collection<Mod> getMods() {
for (ModContainer mod : FabricLoader.getInstance().getAllMods()) {
getMod(mod.getMetadata().getId());
}
return this.mods.values();
}
private static class ModImpl implements Mod {
private final ModMetadata metadata;
public ModImpl(String id) {
this.metadata = FabricLoader.getInstance().getModContainer(id).get().getMetadata();
}
@Override
public @NotNull String getModId() {
return metadata.getId();
}
@Override
public @NotNull String getVersion() {
return metadata.getVersion().getFriendlyString();
}
@Override
public @NotNull String getName() {
return metadata.getName();
}
@Override
public @NotNull String getDescription() {
return metadata.getDescription();
}
@Override
public void registerConfigurationScreen(ConfigurationScreenProvider provider) {
if (CONFIG_SCREENS.containsKey(getModId()))
throw new IllegalStateException("Can not register configuration screen for mod '" + getModId() + "' because it was already registered!");
CONFIG_SCREENS.put(getModId(), provider);
}
}
}

View File

@@ -0,0 +1,77 @@
/*
* 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.fabric;
import me.shedaniel.architectury.registry.Registries;
import me.shedaniel.architectury.registry.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.LazyLoadedValue;
import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier;
public class RegistriesImpl implements Registries.Impl {
@Override
public Registries.RegistryProvider get(String modId) {
return RegistryProviderImpl.INSTANCE;
}
public enum RegistryProviderImpl implements Registries.RegistryProvider {
INSTANCE;
@Override
public <T> Registry<T> get(ResourceKey<net.minecraft.core.Registry<T>> key) {
return new RegistryImpl<>((net.minecraft.core.Registry<T>) net.minecraft.core.Registry.REGISTRY.get(key.location()));
}
@Override
public <T> Registry<T> get(net.minecraft.core.Registry<T> registry) {
return new RegistryImpl<>(registry);
}
}
public static class RegistryImpl<T> implements Registry<T> {
private net.minecraft.core.Registry<T> delegate;
public RegistryImpl(net.minecraft.core.Registry<T> delegate) {
this.delegate = delegate;
}
@Override
public Supplier<T> delegate(ResourceLocation id) {
LazyLoadedValue<T> value = new LazyLoadedValue<>(() -> get(id));
return value::get;
}
@Override
public Supplier<T> register(ResourceLocation id, Supplier<T> supplier) {
net.minecraft.core.Registry.register(delegate, id, supplier.get());
return delegate(id);
}
@Override
public @Nullable ResourceLocation getId(T obj) {
return delegate.getKey(obj);
}
@Override
public @Nullable T get(ResourceLocation id) {
return delegate.get(id);
}
}
}

View File

@@ -0,0 +1,33 @@
package me.shedaniel.architectury.utils.fabric;
import me.shedaniel.architectury.event.events.LifecycleEvent;
import me.shedaniel.architectury.platform.Platform;
import me.shedaniel.architectury.utils.GameInstance;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.server.MinecraftServer;
public class GameInstanceImpl implements GameInstance.Impl {
private static MinecraftServer server = null;
@Override
public MinecraftServer getServer() {
MinecraftServer server = null;
if (GameInstanceImpl.server != null) server = GameInstanceImpl.server;
if (Platform.getEnv() == EnvType.CLIENT) {
server = getServerFromClient();
}
return server;
}
public static void init() {
LifecycleEvent.SERVER_STARTING.register(server -> GameInstanceImpl.server = server);
LifecycleEvent.SERVER_STOPPED.register(server -> GameInstanceImpl.server = null);
}
@Environment(EnvType.CLIENT)
private static MinecraftServer getServerFromClient() {
return Minecraft.getInstance().getSingleplayerServer();
}
}

View File

@@ -0,0 +1,26 @@
{
"schemaVersion": 1,
"id": "architectury",
"version": "${version}",
"name": "Architectury",
"description": "This is an example description! Tell everyone what your mod is about!",
"authors": [
"shedaniel"
],
"license": "MIT",
"environment": "*",
"mixins": [
"architectury.mixins.json"
],
"entrypoints": {
"main": [
"me.shedaniel.architectury.utils.fabric.GameInstanceImpl::init"
],
"modmenu": [
"me.shedaniel.architectury.compat.fabric.ModMenuCompatibility"
]
},
"depends": {
"minecraft": ">=1.16.2"
}
}

71
forge/build.gradle Normal file
View File

@@ -0,0 +1,71 @@
buildscript {
repositories {
maven { url "https://files.minecraftforge.net/maven" }
jcenter()
mavenCentral()
}
dependencies {
classpath(group: "net.minecraftforge.gradle", name: "ForgeGradle", version: "3.+", changing: true)
}
}
plugins {
id "com.github.johnrengelman.shadow" version "5.0.0"
id "eclipse"
}
apply plugin: "net.minecraftforge.gradle"
minecraft {
mappings(channel: "official", version: rootProject.architect.minecraft)
accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
runs {
client {
workingDirectory project.file("run")
mods {
examplemod {
source sourceSets.main
}
}
}
server {
workingDirectory project.file("run")
mods {
examplemod {
source sourceSets.main
}
}
}
}
}
repositories {
jcenter()
maven { url "https://files.minecraftforge.net/maven" }
}
configurations {
shadow
}
dependencies {
minecraft("net.minecraftforge:forge:${rootProject.architect.minecraft}-${rootProject.forge_version}")
compile(project(path: ":common", configuration: "mcpGenerateMod")) {
transitive = false
}
shadow(project(path: ":common", configuration: "mcp")) {
transitive = false
}
}
shadowJar {
exclude "fabric.mod.json"
configurations = [project.configurations.shadow]
classifier null
}
reobf {
shadowJar {}
}

View File

@@ -0,0 +1,124 @@
/*
* 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.forge;
import me.shedaniel.architectury.event.EventFactory;
import me.shedaniel.architectury.event.events.GuiEvent;
import me.shedaniel.architectury.event.events.LifecycleEvent;
import me.shedaniel.architectury.event.events.TickEvent;
import me.shedaniel.architectury.event.events.TooltipEvent;
import net.minecraft.client.Minecraft;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.TickEvent.ClientTickEvent;
import net.minecraftforge.event.TickEvent.Phase;
import net.minecraftforge.event.TickEvent.ServerTickEvent;
import net.minecraftforge.event.TickEvent.WorldTickEvent;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
public class EventFactoryImpl implements EventFactory.Impl {
@Override
public void registerClient() {
MinecraftForge.EVENT_BUS.register(Client.class);
}
@Override
public void registerCommon() {
MinecraftForge.EVENT_BUS.register(Common.class);
}
@Override
public void registerServer() {
MinecraftForge.EVENT_BUS.register(Server.class);
}
@OnlyIn(Dist.CLIENT)
public static class Client {
@SubscribeEvent
public static void event(ItemTooltipEvent event) {
TooltipEvent.ITEM.invoker().append(event.getItemStack(), event.getToolTip(), event.getFlags());
}
@SubscribeEvent
public static void event(ClientTickEvent event) {
if (event.phase == Phase.START)
TickEvent.CLIENT_PRE.invoker().tick(Minecraft.getInstance());
else if (event.phase == Phase.END)
TickEvent.CLIENT_POST.invoker().tick(Minecraft.getInstance());
}
@SubscribeEvent
public static void event(RenderGameOverlayEvent.Post event) {
GuiEvent.RENDER_HUD.invoker().renderHud(event.getMatrixStack(), event.getPartialTicks());
}
}
public static class Common {
@SubscribeEvent
public static void event(ServerTickEvent event) {
if (event.phase == Phase.START)
TickEvent.SERVER_PRE.invoker().tick(ServerLifecycleHooks.getCurrentServer());
else if (event.phase == Phase.END)
TickEvent.SERVER_POST.invoker().tick(ServerLifecycleHooks.getCurrentServer());
}
@SubscribeEvent
public static void event(WorldTickEvent event) {
if (event.side == LogicalSide.SERVER) {
if (event.phase == Phase.START)
TickEvent.SERVER_WORLD_PRE.invoker().tick((ServerWorld) event.world);
else if (event.phase == Phase.END)
TickEvent.SERVER_WORLD_POST.invoker().tick((ServerWorld) event.world);
}
}
@SubscribeEvent
public static void event(FMLServerStartingEvent event) {
LifecycleEvent.SERVER_STARTING.invoker().stateChanged(event.getServer());
}
@SubscribeEvent
public static void event(FMLServerStartedEvent event) {
LifecycleEvent.SERVER_STARTED.invoker().stateChanged(event.getServer());
}
@SubscribeEvent
public static void event(FMLServerStoppingEvent event) {
LifecycleEvent.SERVER_STOPPING.invoker().stateChanged(event.getServer());
}
@SubscribeEvent
public static void event(FMLServerStoppedEvent event) {
LifecycleEvent.SERVER_STOPPED.invoker().stateChanged(event.getServer());
}
}
@OnlyIn(Dist.DEDICATED_SERVER)
public static class Server {
}
}

View File

@@ -0,0 +1,39 @@
package me.shedaniel.architectury.networking.forge;
import me.shedaniel.architectury.networking.NetworkManager;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.ClientPlayerNetworkEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.network.NetworkEvent;
import java.util.Set;
import java.util.function.Consumer;
import static me.shedaniel.architectury.networking.forge.NetworkManagerImpl.C2S;
import static me.shedaniel.architectury.networking.forge.NetworkManagerImpl.SYNC_IDS;
@OnlyIn(Dist.CLIENT)
public class ClientNetworkingManager {
public static Consumer<NetworkManagerImpl> initClient() {
NetworkManagerImpl.CHANNEL.addListener(NetworkManagerImpl.createPacketHandler(NetworkEvent.ServerCustomPayloadEvent.class, NetworkManagerImpl.S2C));
MinecraftForge.EVENT_BUS.<ClientPlayerNetworkEvent.LoggedOutEvent>addListener(event -> NetworkManagerImpl.serverReceivables.clear());
return impl -> impl.registerS2CReceiver(SYNC_IDS, (buffer, context) -> {
Set<ResourceLocation> receivables = NetworkManagerImpl.serverReceivables;
int size = buffer.readInt();
receivables.clear();
for (int i = 0; i < size; i++) {
receivables.add(buffer.readResourceLocation());
}
NetworkManager.sendToServer(SYNC_IDS, NetworkManagerImpl.sendSyncPacket(C2S));
});
}
public static PlayerEntity getClientPlayer() {
return Minecraft.getInstance().player;
}
}

View File

@@ -0,0 +1,137 @@
package me.shedaniel.architectury.networking.forge;
import com.google.common.collect.*;
import io.netty.buffer.Unpooled;
import me.shedaniel.architectury.networking.NetworkManager;
import me.shedaniel.architectury.networking.NetworkManager.NetworkReceiver;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.network.IPacket;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.network.NetworkDirection;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraftforge.fml.network.NetworkRegistry;
import net.minecraftforge.fml.network.event.EventNetworkChannel;
import org.apache.commons.lang3.tuple.Pair;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
public class NetworkManagerImpl implements NetworkManager.Impl {
@Override
public void registerReceiver(NetworkManager.Side side, ResourceLocation id, NetworkReceiver receiver) {
if (side == NetworkManager.Side.C2S) {
registerC2SReceiver(id, receiver);
} else if (side == NetworkManager.Side.S2C) {
registerS2CReceiver(id, receiver);
}
}
@Override
public IPacket<?> toPacket(NetworkManager.Side side, ResourceLocation id, PacketBuffer buffer) {
PacketBuffer packetBuffer = new PacketBuffer(Unpooled.buffer());
packetBuffer.writeResourceLocation(id);
packetBuffer.writeBytes(buffer);
return (side == NetworkManager.Side.C2S ? NetworkDirection.PLAY_TO_SERVER : NetworkDirection.PLAY_TO_CLIENT).buildPacket(Pair.of(packetBuffer, 0), CHANNEL_ID).getThis();
}
private static final ResourceLocation CHANNEL_ID = new ResourceLocation("architectury:network");
static final ResourceLocation SYNC_IDS = new ResourceLocation("architectury:sync_ids");
static final EventNetworkChannel CHANNEL = NetworkRegistry.newEventChannel(CHANNEL_ID, () -> "1", version -> true, version -> true);
static final Map<ResourceLocation, NetworkReceiver> S2C = Maps.newHashMap();
static final Map<ResourceLocation, NetworkReceiver> C2S = Maps.newHashMap();
static final Set<ResourceLocation> serverReceivables = Sets.newHashSet();
private static final Multimap<PlayerEntity, ResourceLocation> clientReceivables = Multimaps.newMultimap(Maps.newHashMap(), Sets::newHashSet);
public NetworkManagerImpl() {
CHANNEL.addListener(createPacketHandler(NetworkEvent.ClientCustomPayloadEvent.class, C2S));
DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> ClientNetworkingManager::initClient).accept(this);
MinecraftForge.EVENT_BUS.<PlayerEvent.PlayerLoggedInEvent>addListener(event -> NetworkManager.sendToPlayer((ServerPlayerEntity) event.getPlayer(), SYNC_IDS, sendSyncPacket(C2S)));
MinecraftForge.EVENT_BUS.<PlayerEvent.PlayerLoggedOutEvent>addListener(event -> clientReceivables.removeAll(event.getPlayer()));
registerC2SReceiver(SYNC_IDS, (buffer, context) -> {
Set<ResourceLocation> receivables = (Set<ResourceLocation>) clientReceivables.get(context.getPlayer());
int size = buffer.readInt();
receivables.clear();
for (int i = 0; i < size; i++) {
receivables.add(buffer.readResourceLocation());
}
});
}
static <T extends NetworkEvent> Consumer<T> createPacketHandler(Class<T> clazz, Map<ResourceLocation, NetworkReceiver> map) {
return event -> {
if (event.getClass() != clazz) return;
NetworkEvent.Context context = event.getSource().get();
if (context.getPacketHandled()) return;
PacketBuffer buffer = new PacketBuffer(event.getPayload().copy());
ResourceLocation type = buffer.readResourceLocation();
NetworkReceiver receiver = map.get(type);
if (receiver != null) {
receiver.receive(buffer, new NetworkManager.PacketContext() {
@Override
public PlayerEntity getPlayer() {
return getEnv() == Dist.CLIENT ? getClientPlayer() : context.getSender();
}
@Override
public void queue(Runnable runnable) {
context.enqueueWork(runnable);
}
@Override
public Dist getEnv() {
return context.getDirection().getReceptionSide() == LogicalSide.CLIENT ? Dist.CLIENT : Dist.DEDICATED_SERVER;
}
private PlayerEntity getClientPlayer() {
return DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> ClientNetworkingManager::getClientPlayer);
}
});
}
context.setPacketHandled(true);
};
}
@OnlyIn(Dist.CLIENT)
public void registerS2CReceiver(ResourceLocation id, NetworkReceiver receiver) {
S2C.put(id, receiver);
}
public void registerC2SReceiver(ResourceLocation id, NetworkReceiver receiver) {
C2S.put(id, receiver);
}
@Override
public boolean canServerReceive(ResourceLocation id) {
return serverReceivables.contains(id);
}
@Override
public boolean canPlayerReceive(ServerPlayerEntity player, ResourceLocation id) {
return clientReceivables.get(player).contains(id);
}
static PacketBuffer sendSyncPacket(Map<ResourceLocation, NetworkReceiver> map) {
List<ResourceLocation> availableIds = Lists.newArrayList(map.keySet());
PacketBuffer packetBuffer = new PacketBuffer(Unpooled.buffer());
packetBuffer.writeInt(availableIds.size());
for (ResourceLocation availableId : availableIds) {
packetBuffer.writeResourceLocation(availableId);
}
return packetBuffer;
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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.forge;
import net.minecraftforge.eventbus.api.IEventBus;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public final class EventBuses {
private EventBuses() {}
private static final Map<String, IEventBus> EVENT_BUS_MAP = new HashMap<>();
public static void registerModEventBus(String modId, IEventBus bus) {
IEventBus previous = EVENT_BUS_MAP.put(modId, bus);
if (previous != null) {
EVENT_BUS_MAP.put(modId, previous);
throw new IllegalStateException("Can't register event bus for mod '" + modId + "' because it was previously registered!");
}
}
public static Optional<IEventBus> getModEventBus(String modId) {
return Optional.ofNullable(EVENT_BUS_MAP.get(modId));
}
}

View File

@@ -0,0 +1,114 @@
/*
* 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.forge;
import me.shedaniel.architectury.platform.Mod;
import me.shedaniel.architectury.platform.Platform;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.ExtensionPoint;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.loading.FMLEnvironment;
import net.minecraftforge.fml.loading.FMLPaths;
import net.minecraftforge.forgespi.language.IModInfo;
import javax.annotation.Nonnull;
import java.nio.file.Path;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class PlatformImpl implements Platform.Impl {
private final Map<String, Mod> mods = new HashMap<>();
@Override
public Path getGameFolder() {
return FMLPaths.GAMEDIR.get();
}
@Override
public Path getConfigFolder() {
return FMLPaths.CONFIGDIR.get();
}
@Override
public Path getModsFolder() {
return FMLPaths.MODSDIR.get();
}
@Override
public Dist getEnv() {
return FMLEnvironment.dist;
}
@Override
public boolean isModLoaded(String id) {
return ModList.get().isLoaded(id);
}
@Override
public Mod getMod(String id) {
return this.mods.computeIfAbsent(id, ModImpl::new);
}
@Override
public Collection<Mod> getMods() {
for (IModInfo mod : ModList.get().getMods()) {
getMod(mod.getModId());
}
return this.mods.values();
}
private static class ModImpl implements Mod {
private final ModContainer container;
private final IModInfo metadata;
public ModImpl(String id) {
this.container = ModList.get().getModContainerById(id).get();
this.metadata = container.getModInfo();
}
@Override
@Nonnull
public String getModId() {
return metadata.getModId();
}
@Override
@Nonnull
public String getVersion() {
return metadata.getVersion().toString();
}
@Override
@Nonnull
public String getName() {
return metadata.getDisplayName();
}
@Override
@Nonnull
public String getDescription() {
return metadata.getDescription();
}
@Override
public void registerConfigurationScreen(ConfigurationScreenProvider configurationScreenProvider) {
container.registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY, () -> (minecraft, screen) -> configurationScreenProvider.provide(screen));
}
}
}

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.registry.forge;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import me.shedaniel.architectury.platform.forge.EventBuses;
import me.shedaniel.architectury.registry.Registries;
import me.shedaniel.architectury.registry.Registry;
import net.minecraft.util.LazyValue;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.IForgeRegistryEntry;
import net.minecraftforge.registries.RegistryManager;
import javax.annotation.Nullable;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.function.Supplier;
public class RegistriesImpl implements Registries.Impl {
@Override
public Registries.RegistryProvider get(String modId) {
return new RegistryProviderImpl(modId);
}
public static class RegistryProviderImpl implements Registries.RegistryProvider {
private final String modId;
private final IEventBus eventBus;
private final Table<Type, RegistryObject<?>, Supplier<? extends IForgeRegistryEntry<?>>> registry = HashBasedTable.create();
public RegistryProviderImpl(String modId) {
this.modId = modId;
this.eventBus = EventBuses.getModEventBus(modId).orElseThrow(() -> new IllegalStateException("Can't get event bus for mod '" + modId + "' because it was not registered!"));
this.eventBus.register(new EventListener());
}
@Override
public <T> Registry<T> get(RegistryKey<net.minecraft.util.registry.Registry<T>> registryKey) {
return new ForgeBackedRegistryImpl<>(registry, (IForgeRegistry) RegistryManager.ACTIVE.getRegistry(registryKey.location()));
}
@Override
public <T> Registry<T> get(net.minecraft.util.registry.Registry<T> registry) {
return new VanillaBackedRegistryImpl<>(registry);
}
public class EventListener {
@SubscribeEvent
public void handleEvent(RegistryEvent.Register event) {
IForgeRegistry registry = event.getRegistry();
for (Map.Entry<Type, Map<RegistryObject<?>, Supplier<? extends IForgeRegistryEntry<?>>>> row : RegistryProviderImpl.this.registry.rowMap().entrySet()) {
if (row.getKey() == event.getGenericType()) {
for (Map.Entry<RegistryObject<?>, Supplier<? extends IForgeRegistryEntry<?>>> entry : row.getValue().entrySet()) {
registry.register(entry.getValue().get());
entry.getKey().updateReference(registry);
}
}
}
}
}
}
public static class VanillaBackedRegistryImpl<T> implements Registry<T> {
private net.minecraft.util.registry.Registry<T> delegate;
public VanillaBackedRegistryImpl(net.minecraft.util.registry.Registry<T> delegate) {
this.delegate = delegate;
}
@Override
public Supplier<T> delegate(ResourceLocation id) {
LazyValue<T> value = new LazyValue<>(() -> get(id));
return value::get;
}
@Override
public Supplier<T> register(ResourceLocation id, Supplier<T> supplier) {
net.minecraft.util.registry.Registry.register(delegate, id, supplier.get());
return delegate(id);
}
@Override
@Nullable
public ResourceLocation getId(T obj) {
return delegate.getKey(obj);
}
@Override
@Nullable
public T get(ResourceLocation id) {
return delegate.get(id);
}
}
public static class ForgeBackedRegistryImpl<T extends IForgeRegistryEntry<T>> implements Registry<T> {
private IForgeRegistry<T> delegate;
private Table<Type, RegistryObject<?>, Supplier<? extends IForgeRegistryEntry<?>>> registry;
public ForgeBackedRegistryImpl(Table<Type, RegistryObject<?>, Supplier<? extends IForgeRegistryEntry<?>>> registry, IForgeRegistry<T> delegate) {
this.registry = registry;
this.delegate = delegate;
}
@Override
public Supplier<T> delegate(ResourceLocation id) {
LazyValue<T> value = new LazyValue<>(() -> get(id));
return value::get;
}
@Override
public Supplier<T> register(ResourceLocation id, Supplier<T> supplier) {
RegistryObject registryObject = RegistryObject.of(id, delegate);
registry.put(delegate.getRegistrySuperType(), registryObject, () -> supplier.get().setRegistryName(id));
return registryObject;
}
@Override
@Nullable
public ResourceLocation getId(T obj) {
return delegate.getKey(obj);
}
@Override
@Nullable
public T get(ResourceLocation id) {
return delegate.getValue(id);
}
}
}

View File

@@ -0,0 +1,12 @@
package me.shedaniel.architectury.utils.forge;
import me.shedaniel.architectury.utils.GameInstance;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
public class GameInstanceImpl implements GameInstance.Impl {
@Override
public MinecraftServer getServer() {
return ServerLifecycleHooks.getCurrentServer();
}
}

11
gradle.properties Normal file
View File

@@ -0,0 +1,11 @@
minecraft_version=1.16.3
archives_base_name=architectury
mod_version=1.0.0
maven_group=me.shedaniel
fabric_loader_version=0.10.5+build.213
fabric_api_version=0.24.3+build.414-1.16
mod_menu_version=1.14.6+
forge_version=34.1.34

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

185
gradlew vendored Executable file
View File

@@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# 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
#
# https://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.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

0
logs/latest.log Normal file
View File

14
settings.gradle Normal file
View File

@@ -0,0 +1,14 @@
pluginManagement {
repositories {
jcenter()
maven { url "https://maven.fabricmc.net/" }
maven { url "https://dl.bintray.com/shedaniel/cloth" }
gradlePluginPortal()
}
}
include("common")
include("fabric")
include("forge")
rootProject.name = "architectury"