/
ZenClassRegistrationManager.java
152 lines (112 loc) · 6.38 KB
/
ZenClassRegistrationManager.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package com.blamejared.crafttweaker.impl.plugin.crafttweaker;
import com.blamejared.crafttweaker.api.annotation.Preprocessor;
import com.blamejared.crafttweaker.api.natives.NativeTypeInfo;
import com.blamejared.crafttweaker.api.plugin.IJavaNativeIntegrationRegistrationHandler;
import com.blamejared.crafttweaker.api.util.InstantiationUtil;
import com.blamejared.crafttweaker.api.zencode.IPreprocessor;
import com.blamejared.crafttweaker.api.zencode.ZenTypeInfo;
import com.blamejared.crafttweaker_annotations.annotations.NativeMethod;
import com.blamejared.crafttweaker_annotations.annotations.NativeTypeRegistration;
import com.blamejared.crafttweaker_annotations.annotations.TypedExpansion;
import org.openzen.zencode.java.ZenCodeType;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
final class ZenClassRegistrationManager {
@FunctionalInterface
private interface LateCallback {
void callback(final Class<?> clazz, final String loader, final IJavaNativeIntegrationRegistrationHandler handler);
}
private record LateRegistrationCandidate(Class<?> clazz, String loader, LateCallback callback) {}
private final AnnotationsToApiConverters converters;
private final Map<Class<?>, NativeTypeInfo> foundNatives;
private final Queue<LateRegistrationCandidate> lateRegistrations;
ZenClassRegistrationManager() {
this.converters = new AnnotationsToApiConverters();
this.foundNatives = new HashMap<>();
this.lateRegistrations = new ArrayDeque<>();
}
void attemptRegistration(final String loader, final Class<?> clazz, final IJavaNativeIntegrationRegistrationHandler handler) {
this.attemptNativeRegistration(clazz, loader, handler);
this.attemptZenRegistration(clazz, loader, handler);
this.attemptPreprocessorRegistration(clazz, loader, handler);
}
void attemptDeferredRegistration(final IJavaNativeIntegrationRegistrationHandler handler) {
this.lateRegistrations.forEach(it -> it.callback().callback(it.clazz(), it.loader(), handler));
this.lateRegistrations.clear();
}
private void attemptNativeRegistration(final Class<?> clazz, final String loader, final IJavaNativeIntegrationRegistrationHandler handler) {
final NativeTypeRegistration ntr = clazz.getDeclaredAnnotation(NativeTypeRegistration.class);
if(ntr == null) {
return;
}
final NativeMethod[] methods = clazz.getDeclaredAnnotationsByType(NativeMethod.class);
final NativeTypeInfo nativeTypeInfo = this.converters.toNativeTypeInfo(ntr, methods);
this.foundNatives.put(nativeTypeInfo.targetedType(), nativeTypeInfo);
handler.registerNativeType(loader, clazz, nativeTypeInfo);
}
private void attemptZenRegistration(final Class<?> clazz, final String loader, final IJavaNativeIntegrationRegistrationHandler handler) {
this.attemptZenClassRegistration(clazz, loader, handler);
this.attemptZenExpandRegistration(clazz, loader, handler);
this.orFuture(clazz, loader, handler, this::attemptTypedExpandRegistration);
}
private void attemptZenClassRegistration(final Class<?> clazz, final String loader, final IJavaNativeIntegrationRegistrationHandler handler) {
final ZenCodeType.Name name = clazz.getDeclaredAnnotation(ZenCodeType.Name.class);
if(name == null) {
return;
}
final ZenTypeInfo typeInfo = this.converters.toZenTypeInfo(name);
handler.registerZenClass(loader, clazz, typeInfo);
handler.registerGlobalsIn(loader, clazz, typeInfo);
}
private void attemptZenExpandRegistration(final Class<?> clazz, final String loader, final IJavaNativeIntegrationRegistrationHandler handler) {
final ZenCodeType.Expansion expansion = clazz.getDeclaredAnnotation(ZenCodeType.Expansion.class);
if(expansion == null) {
return;
}
handler.registerZenClass(loader, clazz, this.converters.toZenTypeInfo(expansion));
}
private void attemptTypedExpandRegistration(final Class<?> clazz, final String loader, final IJavaNativeIntegrationRegistrationHandler handler) {
final TypedExpansion expansion = clazz.getDeclaredAnnotation(TypedExpansion.class);
if(expansion == null) {
return;
}
final Class<?> target = expansion.value();
final String targetName = this.figureOutTypedExpansionName(target);
if(targetName == null) {
throw new IllegalStateException("Unable to register typed expansion for unknown type " + clazz.getName());
}
handler.registerZenClass(loader, clazz, new ZenTypeInfo(targetName, ZenTypeInfo.TypeKind.EXPANSION));
}
private void attemptPreprocessorRegistration(final Class<?> clazz, final String loader, final IJavaNativeIntegrationRegistrationHandler handler) {
final Preprocessor preprocessor = clazz.getDeclaredAnnotation(Preprocessor.class);
if(preprocessor == null) {
return;
}
handler.registerPreprocessor((IPreprocessor) InstantiationUtil.getOrCreateInstance(clazz));
}
private void orFuture(final Class<?> clazz, final String loader, final IJavaNativeIntegrationRegistrationHandler handler, final LateCallback callback) {
try {
callback.callback(clazz, loader, handler);
} catch(final Exception e) {
// Let's try again later: maybe some information is not yet available
this.lateRegistrations.add(new LateRegistrationCandidate(clazz, loader, callback));
}
}
private String figureOutTypedExpansionName(final Class<?> target) {
final NativeTypeRegistration registration = target.getDeclaredAnnotation(NativeTypeRegistration.class);
if(registration != null) {
return registration.zenCodeName();
}
final ZenCodeType.Name name = target.getDeclaredAnnotation(ZenCodeType.Name.class);
if(name != null) {
return name.value();
}
final NativeTypeInfo knownNative = this.foundNatives.get(target);
if(knownNative != null) {
return knownNative.name();
}
return null;
}
}