Skip to content

Commit

Permalink
Ensure material and modifier tags sync over the network
Browse files Browse the repository at this point in the history
  • Loading branch information
KnightMiner committed Oct 9, 2022
1 parent 44027b6 commit 1aaf7aa
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public MaterialRegistry() {
* @param packet Materials packet
*/
public static void updateMaterialsFromServer(UpdateMaterialsPacket packet) {
INSTANCE.materialManager.updateMaterialsFromServer(packet.getMaterials(), packet.getRedirects());
INSTANCE.materialManager.updateMaterialsFromServer(packet.getMaterials(), packet.getRedirects(), packet.getTags());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import slimeknights.tconstruct.library.json.JsonRedirect;
import slimeknights.tconstruct.library.materials.json.MaterialJson;
import slimeknights.tconstruct.library.modifiers.Modifier;
import slimeknights.tconstruct.library.utils.JsonUtils;
import slimeknights.tconstruct.library.utils.GenericTagUtil;
import slimeknights.tconstruct.library.utils.Util;

import javax.annotation.Nullable;
Expand All @@ -38,7 +38,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.Objects.requireNonNullElse;
Expand Down Expand Up @@ -167,17 +166,12 @@ private void onMaterialUpdate() {

/**
* Updates the material list from the server.list. Should only be called client side
* @param materialList Server material list
* @param redirects Map of material redirects
*/
public void updateMaterialsFromServer(Collection<IMaterial> materialList, Map<MaterialId,MaterialId> redirects) {
this.materials = materialList.stream()
.filter(Objects::nonNull)
.collect(Collectors.toMap(
IMaterial::getIdentifier,
Function.identity())
);
public void updateMaterialsFromServer(Map<MaterialId,IMaterial> materials, Map<MaterialId,MaterialId> redirects, Map<ResourceLocation,Tag<IMaterial>> tags) {
this.materials = materials;
this.redirects = redirects;
this.tags = tags;
this.reverseTags = GenericTagUtil.reverseTags(REGISTRY_KEY, IMaterial::getIdentifier, tags);
onMaterialUpdate();
}

Expand Down Expand Up @@ -214,7 +208,7 @@ protected void apply(Map<ResourceLocation, JsonElement> splashList, ResourceMana
// load modifier tags
TagLoader<IMaterial> tagLoader = new TagLoader<>(id -> getMaterial(new MaterialId(id)), TAG_FOLDER);
this.tags = tagLoader.loadAndBuild(resourceManagerIn);
this.reverseTags = JsonUtils.reverseTags(REGISTRY_KEY, IMaterial::getIdentifier, tags);
this.reverseTags = GenericTagUtil.reverseTags(REGISTRY_KEY, IMaterial::getIdentifier, tags);
log.info("Loaded {} material tags for {} materials in {} ms", tags.size(), reverseTags.size(), (System.nanoTime() - timeStep) / 1000000f);
}

Expand All @@ -223,7 +217,7 @@ protected void apply(Map<ResourceLocation, JsonElement> splashList, ResourceMana
* @return Packet object
*/
public UpdateMaterialsPacket getUpdatePacket() {
return new UpdateMaterialsPacket(materials.values(), redirects);
return new UpdateMaterialsPacket(materials, redirects, tags);
}

@Nullable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,40 @@
package slimeknights.tconstruct.library.materials.definition;

import com.google.common.collect.ImmutableMap;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.Tag;
import net.minecraftforge.network.NetworkEvent.Context;
import slimeknights.mantle.network.packet.IThreadsafePacket;
import slimeknights.tconstruct.library.materials.MaterialRegistry;
import slimeknights.tconstruct.library.utils.GenericTagUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Getter
@AllArgsConstructor
public class UpdateMaterialsPacket implements IThreadsafePacket {
private final Collection<IMaterial> materials;
private final Map<MaterialId,IMaterial> materials;
private final Map<MaterialId,MaterialId> redirects;
private final Map<ResourceLocation,Tag<IMaterial>> tags;

public UpdateMaterialsPacket(FriendlyByteBuf buffer) {
int materialCount = buffer.readInt();
this.materials = new ArrayList<>(materialCount);
ImmutableMap.Builder<MaterialId,IMaterial> materials = ImmutableMap.builder();

for (int i = 0; i < materialCount; i++) {
MaterialId id = new MaterialId(buffer.readResourceLocation());
int tier = buffer.readVarInt();
int sortOrder = buffer.readVarInt();
boolean craftable = buffer.readBoolean();
boolean hidden = buffer.readBoolean();
this.materials.add(new Material(id, tier, sortOrder, craftable, hidden));
materials.put(id, new Material(id, tier, sortOrder, craftable, hidden));
}
this.materials = materials.build();
// process redirects
int redirectCount = buffer.readVarInt();
if (redirectCount == 0) {
Expand All @@ -41,12 +45,13 @@ public UpdateMaterialsPacket(FriendlyByteBuf buffer) {
this.redirects.put(new MaterialId(buffer.readUtf()), new MaterialId(buffer.readUtf()));
}
}
this.tags = GenericTagUtil.decodeTags(buffer, id -> this.materials.get(new MaterialId(id)));
}

@Override
public void encode(FriendlyByteBuf buffer) {
buffer.writeInt(this.materials.size());
this.materials.forEach(material -> {
this.materials.values().forEach(material -> {
buffer.writeResourceLocation(material.getIdentifier());
buffer.writeVarInt(material.getTier());
buffer.writeVarInt(material.getSortOrder());
Expand All @@ -58,6 +63,7 @@ public void encode(FriendlyByteBuf buffer) {
buffer.writeUtf(key.toString());
buffer.writeUtf(value.toString());
});
GenericTagUtil.encodeTags(buffer, IMaterial::getIdentifier, this.tags);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import slimeknights.mantle.util.JsonHelper;
import slimeknights.tconstruct.TConstruct;
import slimeknights.tconstruct.library.json.JsonRedirect;
import slimeknights.tconstruct.library.utils.GenericTagUtil;
import slimeknights.tconstruct.library.utils.JsonUtils;

import javax.annotation.Nullable;
Expand Down Expand Up @@ -111,7 +112,7 @@ private ModifierManager() {
public void init() {
FMLJavaModLoadingContext.get().getModEventBus().addListener(EventPriority.NORMAL, false, FMLCommonSetupEvent.class, e -> e.enqueueWork(this::fireRegistryEvent));
MinecraftForge.EVENT_BUS.addListener(EventPriority.NORMAL, false, AddReloadListenerEvent.class, this::addDataPackListeners);
MinecraftForge.EVENT_BUS.addListener(EventPriority.NORMAL, false, OnDatapackSyncEvent.class, e -> JsonUtils.syncPackets(e, new UpdateModifiersPacket(this.dynamicModifiers)));
MinecraftForge.EVENT_BUS.addListener(EventPriority.NORMAL, false, OnDatapackSyncEvent.class, e -> JsonUtils.syncPackets(e, new UpdateModifiersPacket(this.dynamicModifiers, this.tags)));
}

/** Fires the modifier registry event */
Expand Down Expand Up @@ -175,7 +176,7 @@ protected void apply(Map<ResourceLocation,JsonElement> splashList, ResourceManag
return Optional.of(modifier);
}, TAG_FOLDER);
this.tags = tagLoader.loadAndBuild(pResourceManager);
this.reverseTags = JsonUtils.reverseTags(REGISTRY_KEY, Modifier::getId, tags);
this.reverseTags = GenericTagUtil.reverseTags(REGISTRY_KEY, Modifier::getId, tags);
log.info("Loaded {} modifier tags for {} modifiers in {} ms", tags.size(), this.reverseTags.size(), (System.nanoTime() - timeStep) / 1000000f);

MinecraftForge.EVENT_BUS.post(new ModifiersLoadedEvent());
Expand Down Expand Up @@ -216,9 +217,11 @@ private Modifier loadModifier(ResourceLocation key, JsonElement element, Map<Mod
}

/** Updates the modifiers from the server */
void updateModifiersFromServer(Map<ModifierId,Modifier> modifiers) {
void updateModifiersFromServer(Map<ModifierId,Modifier> modifiers, Map<ResourceLocation,Tag<Modifier>> tags) {
this.dynamicModifiers = modifiers;
this.dynamicModifiersLoaded = true;
this.tags = tags;
this.reverseTags = GenericTagUtil.reverseTags(REGISTRY_KEY, Modifier::getId, tags);
MinecraftForge.EVENT_BUS.post(new ModifiersLoadedEvent());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,31 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import io.netty.handler.codec.DecoderException;
import lombok.RequiredArgsConstructor;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.Tag;
import net.minecraftforge.network.NetworkEvent.Context;
import slimeknights.mantle.network.packet.IThreadsafePacket;
import slimeknights.tconstruct.library.utils.GenericTagUtil;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

/** Packet to sync modifiers */
@RequiredArgsConstructor
public class UpdateModifiersPacket implements IThreadsafePacket {
/** Collection of all modifiers */
private final Map<ModifierId,Modifier> allModifiers;
/** Map of all modifier tags */
private final Map<ResourceLocation,Tag<Modifier>> tags;
/** Collection of non-redirect modifiers */
private Collection<Modifier> modifiers;
/** Map of modifier redirect ID pairs */
private Map<ModifierId,ModifierId> redirects;

public UpdateModifiersPacket(Map<ModifierId,Modifier> map) {
this.allModifiers = map;
}

/** Ensures both the modifiers and redirects lists are calculated, allows one packet to be used multiple times without redundant work */
private void ensureCalculated() {
if (this.modifiers == null || this.redirects == null) {
Expand All @@ -44,6 +47,18 @@ private void ensureCalculated() {
}
}

/** Gets a modifier by the given ID, falling back to the map if needed */
private static Modifier getModifier(Map<ModifierId,Modifier> modifiers, ModifierId id) {
Modifier modifier = ModifierManager.INSTANCE.getStatic(id);
if (modifier == ModifierManager.INSTANCE.getDefaultValue()) {
modifier = modifiers.get(id);
if (modifier == null) {
throw new DecoderException("Unknown modifier " + id);
}
}
return modifier;
}

public UpdateModifiersPacket(FriendlyByteBuf buffer) {
// read in modifiers
int size = buffer.readVarInt();
Expand All @@ -58,17 +73,10 @@ public UpdateModifiersPacket(FriendlyByteBuf buffer) {
size = buffer.readVarInt();
for (int i = 0; i < size; i++) {
ModifierId from = new ModifierId(buffer.readUtf(Short.MAX_VALUE));
ModifierId to = new ModifierId(buffer.readUtf(Short.MAX_VALUE));
Modifier modifier = ModifierManager.INSTANCE.getStatic(to);
if (modifier == ModifierManager.INSTANCE.getDefaultValue()) {
modifier = modifiers.get(to);
if (modifier == null) {
throw new DecoderException("Unknown modifier " + to);
}
}
modifiers.put(from, modifier);
modifiers.put(from, getModifier(modifiers, new ModifierId(buffer.readUtf(Short.MAX_VALUE))));
}
this.allModifiers = modifiers;
this.tags = GenericTagUtil.decodeTags(buffer, id -> getModifier(modifiers, new ModifierId(id)));
}

@Override
Expand All @@ -86,10 +94,11 @@ public void encode(FriendlyByteBuf buffer) {
buffer.writeResourceLocation(entry.getKey());
buffer.writeResourceLocation(entry.getValue());
}
GenericTagUtil.encodeTags(buffer, Modifier::getId, this.tags);
}

@Override
public void handleThreadsafe(Context context) {
ModifierManager.INSTANCE.updateModifiersFromServer(allModifiers);
ModifierManager.INSTANCE.updateModifiersFromServer(allModifiers, tags);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package slimeknights.tconstruct.library.utils;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import net.minecraft.core.Registry;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.Tag;
import net.minecraft.tags.TagKey;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/** Static helpers for generic tag loading */
public class GenericTagUtil {
private GenericTagUtil() {}

/** Creates a map of reverse tags for the given map of tags */
public static <T, I extends ResourceLocation> Map<I,Set<TagKey<T>>> reverseTags(ResourceKey<? extends Registry<T>> registry, Function<T,I> keyMapper, Map<ResourceLocation,Tag<T>> tags) {
Map<I,ImmutableSet.Builder<TagKey<T>>> reverseTags = new HashMap<>();
Function<I,Builder<TagKey<T>>> makeSet = id -> ImmutableSet.builder();
for (Entry<ResourceLocation,Tag<T>> entry : tags.entrySet()) {
TagKey<T> key = TagKey.create(registry, entry.getKey());
for (T value : entry.getValue().getValues()) {
reverseTags.computeIfAbsent(keyMapper.apply(value), makeSet).add(key);
}
}
return reverseTags.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey, entry->entry.getValue().build()));
}

/** Decodes a map of tags from the packet */
public static <T> Map<ResourceLocation,Tag<T>> decodeTags(FriendlyByteBuf buf, Function<ResourceLocation,T> valueGetter) {
ImmutableMap.Builder<ResourceLocation,Tag<T>> builder = ImmutableMap.builder();
int mapSize = buf.readVarInt();
for (int i = 0; i < mapSize; i++) {
ResourceLocation tagId = buf.readResourceLocation();
int tagSize = buf.readVarInt();
ImmutableList.Builder<T> tagBuilder = ImmutableList.builder();
for (int j = 0; j < tagSize; j++) {
tagBuilder.add(valueGetter.apply(buf.readResourceLocation()));
}
builder.put(tagId, new Tag<>(tagBuilder.build()));
}
return builder.build();
}

/** Writes a map of tags to a packet */
public static <T> void encodeTags(FriendlyByteBuf buf, Function<T,ResourceLocation> keyGetter, Map<ResourceLocation,Tag<T>> tags) {
buf.writeVarInt(tags.size());
for (Entry<ResourceLocation,Tag<T>> entry : tags.entrySet()) {
buf.writeResourceLocation(entry.getKey());
List<T> values = entry.getValue().getValues();
buf.writeVarInt(values.size());
for (T value : values) {
buf.writeResourceLocation(keyGetter.apply(value));
}
}
}
}
26 changes: 0 additions & 26 deletions src/main/java/slimeknights/tconstruct/library/utils/JsonUtils.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
package slimeknights.tconstruct.library.utils;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.tags.Tag;
import net.minecraft.tags.TagKey;
import net.minecraft.util.GsonHelper;
import net.minecraftforge.event.OnDatapackSyncEvent;
import net.minecraftforge.registries.IForgeRegistry;
Expand All @@ -21,13 +15,7 @@
import slimeknights.tconstruct.common.network.TinkerNetwork;

import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/** Helpers for a few JSON related tasks */
public class JsonUtils {
Expand Down Expand Up @@ -118,18 +106,4 @@ public static JsonObject withLocation(String key, ResourceLocation value) {
public static JsonObject withType(ResourceLocation type) {
return withLocation("type", type);
}

/** Creates a map of reverse tags for the given map of tags */
public static <T, I extends ResourceLocation> Map<I,Set<TagKey<T>>> reverseTags(ResourceKey<? extends Registry<T>> registry, Function<T,I> keyMapper, Map<ResourceLocation, Tag<T>> tags) {
Map<I,ImmutableSet.Builder<TagKey<T>>> reverseTags = new HashMap<>();
Function<I, Builder<TagKey<T>>> makeSet = id -> ImmutableSet.builder();
for (Entry<ResourceLocation,Tag<T>> entry : tags.entrySet()) {
TagKey<T> key = TagKey.create(registry, entry.getKey());
for (T value : entry.getValue().getValues()) {
reverseTags.computeIfAbsent(keyMapper.apply(value), makeSet).add(key);
}
}
return reverseTags.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey, entry->entry.getValue().build()));
}
}

0 comments on commit 1aaf7aa

Please sign in to comment.