Skip to content

Commit 16f4df2

Browse files
committed
chore: bring over/create synched manager
1 parent 218de8a commit 16f4df2

34 files changed

+2033
-1
lines changed

src/main/java/dev/amble/lib/api/KitEvents.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,33 @@
33
import net.fabricmc.fabric.api.event.Event;
44
import net.fabricmc.fabric.api.event.EventFactory;
55

6+
import net.minecraft.server.network.ServerPlayerEntity;
7+
import net.minecraft.world.chunk.WorldChunk;
8+
69
public class KitEvents {
710
public static final Event<PreDatapackLoad> PRE_DATAPACK_LOAD = EventFactory.createArrayBacked(PreDatapackLoad.class, callbacks -> () -> {
811
for (PreDatapackLoad callback : callbacks) {
912
callback.load();
1013
}
1114
});
1215

16+
public static final Event<SyncRoot> SYNC_ROOT = EventFactory.createArrayBacked(SyncRoot.class,
17+
callbacks -> (player, chunk) -> {
18+
for (SyncRoot callback : callbacks) {
19+
callback.sync(player, chunk);
20+
}
21+
});
22+
1323
/**
1424
* Called when just before datapacks are loaded
1525
*/
1626
@FunctionalInterface
1727
public interface PreDatapackLoad {
1828
void load();
1929
}
30+
31+
@FunctionalInterface
32+
public interface SyncRoot {
33+
void sync(ServerPlayerEntity player, WorldChunk chunk);
34+
}
2035
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package dev.amble.lib.api.sync;
2+
3+
public interface Disposable {
4+
5+
default void age() {
6+
}
7+
8+
void dispose();
9+
10+
default boolean isAged() {
11+
return false;
12+
}
13+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package dev.amble.lib.api.sync;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Target(ElementType.FIELD)
9+
@Retention(RetentionPolicy.RUNTIME)
10+
public @interface Exclude {
11+
Strategy strategy() default Strategy.ALL;
12+
13+
enum Strategy {
14+
ALL, NETWORK, FILE
15+
}
16+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package dev.amble.lib.api.sync;
2+
3+
public abstract class Initializable<T extends Initializable.Context> {
4+
5+
public static <T extends Initializable.Context> void init(Initializable<T> component, T context) {
6+
component.init(context);
7+
}
8+
9+
protected void init(T context) {
10+
this.onEarlyInit(context);
11+
12+
if (context.deserialized()) {
13+
this.onLoaded();
14+
} else {
15+
this.onCreate();
16+
}
17+
18+
this.onInit(context);
19+
}
20+
21+
/**
22+
* Called first in the initialization sequence.
23+
*/
24+
protected void onEarlyInit(T ctx) {
25+
}
26+
27+
/**
28+
* Called after a {@link #onLoaded()} or {@link #onCreate()} is called.
29+
*/
30+
protected void onInit(T ctx) {
31+
}
32+
33+
/**
34+
* Called when the component is created. Server-side only.
35+
*/
36+
public void onCreate() {
37+
}
38+
39+
/**
40+
* Called when the component is loaded from a file or received on the client.
41+
*/
42+
public void onLoaded() {
43+
}
44+
45+
public interface Context {
46+
boolean created();
47+
48+
boolean deserialized();
49+
}
50+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package dev.amble.lib.api.sync;
2+
3+
import java.util.UUID;
4+
5+
import net.fabricmc.api.EnvType;
6+
import net.fabricmc.api.Environment;
7+
8+
import net.minecraft.client.MinecraftClient;
9+
import net.minecraft.server.MinecraftServer;
10+
11+
import dev.amble.lib.AmbleKit;
12+
import dev.amble.lib.api.sync.handler.ComponentManager;
13+
import dev.amble.lib.api.sync.handler.SyncComponent;
14+
import dev.amble.lib.api.sync.handler.TickingComponent;
15+
import dev.amble.lib.api.sync.manager.SyncManager;
16+
17+
public abstract class RootComponent extends Initializable<SyncComponent.InitContext> implements Disposable, TickingComponent {
18+
private UUID uuid;
19+
protected ComponentManager manager;
20+
21+
protected RootComponent(UUID uuid) {
22+
this.uuid = uuid;
23+
this.manager = new ComponentManager(getSyncManager().getManagerId(), getSyncManager().getRegistry());
24+
}
25+
26+
@Override
27+
protected void onInit(SyncComponent.InitContext ctx) {
28+
super.onInit(ctx);
29+
30+
SyncComponent.init(manager, this, ctx);
31+
32+
SyncComponent.postInit(manager, ctx);
33+
}
34+
35+
public UUID getUuid() {
36+
return uuid;
37+
}
38+
39+
@Override
40+
public String toString() {
41+
return uuid.toString();
42+
}
43+
44+
@Override
45+
public int hashCode() {
46+
return uuid.hashCode();
47+
}
48+
49+
public <T extends SyncComponent> T handler(SyncComponent.IdLike type) {
50+
if (this.manager == null) {
51+
AmbleKit.LOGGER.error("Asked for a handler too early on {}", this);
52+
return null;
53+
}
54+
55+
return this.manager.get(type);
56+
}
57+
58+
public ComponentManager getHandlers() {
59+
return manager;
60+
}
61+
public abstract SyncManager<?, ?> getSyncManager();
62+
63+
@Override
64+
public void tick(MinecraftServer server) {
65+
this.getHandlers().tick(server);
66+
}
67+
68+
@Environment(EnvType.CLIENT)
69+
@Override
70+
public void tick(MinecraftClient client) {
71+
this.getHandlers().tick(client) ;
72+
}
73+
}
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
package dev.amble.lib.api.sync.handler;
2+
3+
import java.lang.reflect.Array;
4+
import java.util.Map;
5+
import java.util.function.Consumer;
6+
7+
import com.google.gson.*;
8+
import net.fabricmc.api.EnvType;
9+
import net.fabricmc.api.Environment;
10+
import org.jetbrains.annotations.ApiStatus;
11+
12+
import net.minecraft.client.MinecraftClient;
13+
import net.minecraft.server.MinecraftServer;
14+
15+
import dev.amble.lib.AmbleKit;
16+
import dev.amble.lib.api.sync.Exclude;
17+
import dev.amble.lib.api.sync.RootComponent;
18+
import dev.amble.lib.data.enummap.EnumMap;
19+
20+
public class ComponentManager extends SyncComponent implements TickingComponent {
21+
@Exclude
22+
private final EnumMap<SyncComponent.IdLike, SyncComponent> handlers;
23+
protected final ComponentRegistry registry;
24+
25+
public ComponentManager(SyncComponent.IdLike id, ComponentRegistry registry) {
26+
super(id);
27+
28+
this.registry = registry;
29+
handlers = new EnumMap<>(registry::lookup,
30+
size -> (SyncComponent[]) Array.newInstance(SyncComponent.class, size));
31+
}
32+
33+
@Override
34+
public void onCreate() {
35+
this.registry.fill(this::createHandler);
36+
}
37+
38+
@Override
39+
protected void onInit(InitContext ctx) {
40+
this.forEach(component -> SyncComponent.init(component, this.parent, ctx));
41+
}
42+
43+
44+
@Override
45+
public void postInit(InitContext ctx) {
46+
this.forEach(component -> component.postInit(ctx));
47+
}
48+
49+
private void forEach(Consumer<SyncComponent> consumer) {
50+
for (SyncComponent component : this.handlers.getValues()) {
51+
if (component == null)
52+
continue;
53+
54+
consumer.accept(component);
55+
}
56+
}
57+
58+
private void createHandler(SyncComponent component) {
59+
this.handlers.put(component.getId(), component);
60+
}
61+
62+
/**
63+
* Called on the END of a servers tick
64+
*
65+
* @param server
66+
* the current server
67+
*/
68+
public void tick(MinecraftServer server) {
69+
this.forEach(component -> {
70+
if (!(component instanceof TickingComponent tickable))
71+
return;
72+
73+
try {
74+
tickable.tick(server);
75+
} catch (Exception e) {
76+
AmbleKit.LOGGER.error("Ticking failed for {} | {}", component.getId().name(), component.parent().getUuid().toString(), e);
77+
}
78+
});
79+
}
80+
81+
@Environment(EnvType.CLIENT)
82+
@Override
83+
public void tick(MinecraftClient client) {
84+
this.forEach(component -> {
85+
if (!(component instanceof TickingComponent tickable))
86+
return;
87+
88+
try {
89+
tickable.tick(client);
90+
} catch (Exception e) {
91+
AmbleKit.LOGGER.error("Ticking failed for {} | {}", component.getId().name(), component.parent().getUuid().toString(), e);
92+
}
93+
});
94+
}
95+
96+
/**
97+
* @deprecated Use {@link RootComponent#handler(IdLike)}
98+
*/
99+
@Deprecated
100+
@ApiStatus.Internal
101+
@SuppressWarnings("unchecked")
102+
public <C extends SyncComponent> C get(IdLike id) {
103+
return (C) this.handlers.get(id);
104+
}
105+
106+
@Override
107+
public void dispose() {
108+
super.dispose();
109+
110+
this.forEach(SyncComponent::dispose);
111+
this.handlers.clear();
112+
}
113+
114+
@ApiStatus.Internal
115+
public void set(SyncComponent t) {
116+
this.handlers.put(t.getId(), t);
117+
}
118+
119+
public Object serializer() {
120+
return new Serializer(this.registry, this.getId());
121+
}
122+
public static Object serializer(ComponentRegistry r, IdLike id) {
123+
return new Serializer(r, id);
124+
}
125+
126+
static class Serializer implements JsonSerializer<ComponentManager>, JsonDeserializer<ComponentManager> {
127+
private final IdLike id;
128+
private final ComponentRegistry registry;
129+
130+
public Serializer(ComponentRegistry registry, IdLike id) {
131+
this.id = id;
132+
this.registry = registry;
133+
}
134+
135+
@Override
136+
public ComponentManager deserialize(JsonElement json, java.lang.reflect.Type type,
137+
JsonDeserializationContext context) throws JsonParseException {
138+
ComponentManager manager = new ComponentManager(id, registry);
139+
Map<String, JsonElement> map = json.getAsJsonObject().asMap();
140+
141+
ComponentRegistry registry = manager.registry;
142+
143+
for (Map.Entry<String, JsonElement> entry : map.entrySet()) {
144+
String key = entry.getKey();
145+
JsonElement element = entry.getValue();
146+
147+
IdLike id = registry.get(key);
148+
149+
if (id == null) {
150+
AmbleKit.LOGGER.error("Can't find a component id with name '{}'!", key);
151+
continue;
152+
}
153+
154+
manager.set(context.deserialize(element, id.clazz()));
155+
}
156+
157+
for (int i = 0; i < manager.handlers.size(); i++) {
158+
if (manager.handlers.get(i) != null)
159+
continue;
160+
161+
IdLike id = registry.get(i);
162+
AmbleKit.LOGGER.debug("Appending new component {}", id);
163+
164+
manager.set(id.create());
165+
}
166+
167+
return manager;
168+
}
169+
170+
@Override
171+
public JsonElement serialize(ComponentManager manager, java.lang.reflect.Type type,
172+
JsonSerializationContext context) {
173+
JsonObject result = new JsonObject();
174+
175+
manager.forEach(component -> {
176+
IdLike idLike = component.getId();
177+
178+
if (idLike == null) {
179+
AmbleKit.LOGGER.error("Id was null for {}", component.getClass());
180+
return;
181+
}
182+
183+
result.add(idLike.name(), context.serialize(component));
184+
});
185+
186+
return result;
187+
}
188+
}
189+
}

0 commit comments

Comments
 (0)