Skip to content

Commit f6322f7

Browse files
committed
2 parents 8b6238c + a8ff3d1 commit f6322f7

4 files changed

Lines changed: 203 additions & 1 deletion

File tree

src/main/java/com/cake/azimuth/AzimuthEvents.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,52 @@
66
import net.minecraft.world.level.block.entity.BlockEntity;
77
import net.neoforged.bus.api.SubscribeEvent;
88
import net.neoforged.fml.common.EventBusSubscriber;
9+
import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;
910
import net.neoforged.neoforge.event.level.BlockEvent;
1011

1112
@EventBusSubscriber
1213
public class AzimuthEvents {
1314

1415
@SubscribeEvent
1516
public static void onPlayerWillDestroy(final BlockEvent.BreakEvent destroyEvent) {
16-
//Check if there is an asbee block entity there. Call onBlockBroken on each.
1717
final BlockPos pos = destroyEvent.getPos();
1818
final BlockEntity blockEntity = destroyEvent.getLevel().getBlockEntity(pos);
1919
if (blockEntity instanceof final AzimuthSmartBlockEntityExtension asbee) {
2020
for (final SuperBlockEntityBehaviour behaviour : asbee.azimuth$getSuperBehaviours()) {
2121
behaviour.onBlockBroken(destroyEvent);
22+
if (destroyEvent.isCanceled()) {
23+
break;
24+
}
2225
}
2326
}
2427
}
2528

29+
@SubscribeEvent
30+
public static void onItemUseOnBlock(final PlayerInteractEvent.RightClickBlock event) {
31+
final BlockPos pos = event.getPos();
32+
final BlockEntity blockEntity = event.getLevel().getBlockEntity(pos);
33+
if (blockEntity instanceof final AzimuthSmartBlockEntityExtension asbee) {
34+
for (final SuperBlockEntityBehaviour behaviour : asbee.azimuth$getSuperBehaviours()) {
35+
behaviour.onItemUse(event);
36+
if (event.isCanceled()) {
37+
break;
38+
}
39+
}
40+
}
41+
}
42+
43+
@SubscribeEvent
44+
public static void onBlockPlaced(final BlockEvent.EntityPlaceEvent event) {
45+
final BlockPos pos = event.getPos();
46+
final BlockEntity blockEntity = event.getLevel().getBlockEntity(pos);
47+
if (blockEntity instanceof final AzimuthSmartBlockEntityExtension asbee) {
48+
for (final SuperBlockEntityBehaviour behaviour : asbee.azimuth$getSuperBehaviours()) {
49+
behaviour.onBlockPlaced(event);
50+
if (event.isCanceled()) {
51+
break;
52+
}
53+
}
54+
}
55+
}
2656

2757
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.cake.azimuth.mixin;
2+
3+
import com.cake.azimuth.registration.CreateBlockEdits;
4+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
5+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
6+
import com.simibubi.create.AllBlocks;
7+
import com.simibubi.create.foundation.data.CreateRegistrate;
8+
import com.tterrag.registrate.builders.BlockBuilder;
9+
import com.tterrag.registrate.util.nullness.NonNullFunction;
10+
import org.spongepowered.asm.mixin.Mixin;
11+
import org.spongepowered.asm.mixin.injection.At;
12+
import org.spongepowered.asm.mixin.injection.Inject;
13+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
14+
15+
import java.util.function.Consumer;
16+
17+
@Mixin(AllBlocks.class)
18+
public class AllBlocksMixin {
19+
20+
@Inject(method = "<clinit>", at = @At("HEAD"))
21+
private static void azimuth$bootstrapBlockEdits(final CallbackInfo ci) {
22+
CreateBlockEdits.bootstrapRegistrators();
23+
}
24+
25+
@WrapOperation(method = "<clinit>", at = @At(value = "INVOKE", target = "Lcom/simibubi/create/foundation/data/CreateRegistrate;block(Ljava/lang/String;Lcom/tterrag/registrate/util/nullness/NonNullFunction;)Lcom/tterrag/registrate/builders/BlockBuilder;"))
26+
private static BlockBuilder azimuth$applyBlockEdits(final CreateRegistrate instance, final String s, final NonNullFunction nonNullFunction, final Operation<BlockBuilder> original) {
27+
final BlockBuilder builder = original.call(instance, s, nonNullFunction);
28+
29+
final Consumer<BlockBuilder<?, CreateRegistrate>> transform = CreateBlockEdits.getEditForId(s);
30+
if (transform != null) {
31+
transform.accept(builder);
32+
}
33+
34+
return builder;
35+
}
36+
37+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package com.cake.azimuth.registration;
2+
3+
import com.simibubi.create.foundation.data.CreateRegistrate;
4+
import com.tterrag.registrate.builders.BlockBuilder;
5+
import net.neoforged.fml.ModList;
6+
import net.neoforged.neoforgespi.language.ModFileScanData;
7+
8+
import java.lang.annotation.ElementType;
9+
import java.lang.annotation.Retention;
10+
import java.lang.annotation.RetentionPolicy;
11+
import java.lang.annotation.Target;
12+
import java.lang.reflect.Method;
13+
import java.lang.reflect.Modifier;
14+
import java.util.Arrays;
15+
import java.util.Comparator;
16+
import java.util.LinkedHashMap;
17+
import java.util.List;
18+
import java.util.Map;
19+
import java.util.Objects;
20+
import java.util.function.Consumer;
21+
22+
/**
23+
* Registry for block edits to be applied to Create blocks during registration.
24+
* Registrators are discovered and invoked via NeoForge scan data during Create's AllBlocks static initialization.
25+
*/
26+
public class CreateBlockEdits {
27+
28+
private static final Map<String, Consumer<BlockBuilder<?, CreateRegistrate>>> EDITS_BY_ID = new LinkedHashMap<>();
29+
private static RegistrationWindow registrationWindow = RegistrationWindow.NOT_STARTED;
30+
31+
public static synchronized void bootstrapRegistrators() {
32+
if (registrationWindow != RegistrationWindow.NOT_STARTED) {
33+
return;
34+
}
35+
36+
final ModList modList = ModList.get();
37+
if (modList == null) {
38+
throw new IllegalStateException("Cannot discover @CreateBlockEdits.Registrator methods before NeoForge ModList is available.");
39+
}
40+
41+
registrationWindow = RegistrationWindow.OPEN;
42+
try {
43+
discoverRegistrators(modList).forEach(CreateBlockEdits::invokeRegistrator);
44+
} finally {
45+
registrationWindow = RegistrationWindow.CLOSED;
46+
}
47+
}
48+
49+
public static synchronized void forBlock(final String id, final Consumer<BlockBuilder<?, CreateRegistrate>> edit) {
50+
if (registrationWindow != RegistrationWindow.OPEN) {
51+
throw new IllegalStateException("CreateBlockEdits.forBlock(...) can only be called from a @CreateBlockEdits.Registrator method while Create's AllBlocks are bootstrapping; current registration window is " + registrationWindow + ".");
52+
}
53+
54+
Objects.requireNonNull(id, "id");
55+
Objects.requireNonNull(edit, "edit");
56+
EDITS_BY_ID.merge(id, edit, (existing, additional) -> builder -> {
57+
existing.accept(builder);
58+
additional.accept(builder);
59+
});
60+
}
61+
62+
public static Consumer<BlockBuilder<?, CreateRegistrate>> getEditForId(final String id) {
63+
if (registrationWindow != RegistrationWindow.CLOSED) {
64+
throw new IllegalStateException("CreateBlockEdits.getEditForId(...) was called before registrators were fully discovered; current registration window is " + registrationWindow + ".");
65+
}
66+
67+
return EDITS_BY_ID.get(id);
68+
}
69+
70+
private static List<ModFileScanData.AnnotationData> discoverRegistrators(final ModList modList) {
71+
return modList.getAllScanData().stream()
72+
.flatMap(scanData -> scanData.getAnnotatedBy(Registrator.class, ElementType.METHOD))
73+
.sorted(Comparator.comparing((ModFileScanData.AnnotationData data) -> data.clazz().getClassName())
74+
.thenComparing(ModFileScanData.AnnotationData::memberName))
75+
.toList();
76+
}
77+
78+
private static void invokeRegistrator(final ModFileScanData.AnnotationData annotationData) {
79+
final Method registratorMethod = resolveRegistratorMethod(annotationData);
80+
try {
81+
registratorMethod.invoke(null);
82+
} catch (final ReflectiveOperationException e) {
83+
throw new IllegalStateException("Failed to invoke @CreateBlockEdits.Registrator method " + describe(annotationData) + ".", e);
84+
}
85+
}
86+
87+
private static Method resolveRegistratorMethod(final ModFileScanData.AnnotationData annotationData) {
88+
final Class<?> owner;
89+
try {
90+
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
91+
owner = Class.forName(annotationData.clazz().getClassName(), false, contextClassLoader != null ? contextClassLoader : CreateBlockEdits.class.getClassLoader());
92+
} catch (final ClassNotFoundException e) {
93+
throw new IllegalStateException("Failed to load @CreateBlockEdits.Registrator owner " + describe(annotationData) + ".", e);
94+
}
95+
96+
final List<Method> registrators = Arrays.stream(owner.getDeclaredMethods())
97+
.filter(method -> method.getName().equals(annotationData.memberName()))
98+
.filter(method -> method.isAnnotationPresent(Registrator.class))
99+
.toList();
100+
if (registrators.size() != 1) {
101+
throw new IllegalStateException("Expected exactly one annotated @CreateBlockEdits.Registrator method for " + describe(annotationData) + ", but found " + registrators.size() + ".");
102+
}
103+
104+
final Method registratorMethod = registrators.get(0);
105+
if (!Modifier.isPublic(registratorMethod.getModifiers())
106+
|| !Modifier.isStatic(registratorMethod.getModifiers())
107+
|| registratorMethod.getParameterCount() != 0
108+
|| registratorMethod.getReturnType() != Void.TYPE
109+
|| !registratorMethod.getName().equals("register")) {
110+
throw new IllegalStateException("Invalid @CreateBlockEdits.Registrator method " + registratorMethod.toGenericString() + "; expected public static void register() with no arguments.");
111+
}
112+
113+
return registratorMethod;
114+
}
115+
116+
private static String describe(final ModFileScanData.AnnotationData annotationData) {
117+
return annotationData.clazz().getClassName() + "#" + annotationData.memberName();
118+
}
119+
120+
/**
121+
* Marks a public static void register() method with no arguments to be invoked while Create's AllBlocks are bootstrapping.
122+
*/
123+
@Retention(RetentionPolicy.RUNTIME)
124+
@Target(ElementType.METHOD)
125+
public @interface Registrator {
126+
}
127+
128+
private enum RegistrationWindow {
129+
NOT_STARTED,
130+
OPEN,
131+
CLOSED
132+
}
133+
134+
}

src/main/resources/azimuth.mixins.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"package": "com.cake.azimuth.mixin",
44
"compatibilityLevel": "JAVA_21",
55
"mixins": [
6+
"AllBlocksMixin",
67
"CachedRenderBBBlockEntityMixin",
78
"CreateAdvancementIdMixin",
89
"ItemRequirementMixin",

0 commit comments

Comments
 (0)