Skip to content

Commit

Permalink
Cache more stuff to improve joining sync performance
Browse files Browse the repository at this point in the history
  • Loading branch information
Patbox committed Aug 20, 2023
1 parent 3a4d3c1 commit 3bde037
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 26 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fabric_version=0.83.0+1.20.1

maven_group = eu.pb4

mod_version = 0.5.10
mod_version = 0.5.11

minecraft_version_supported = ">=1.20-"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public final class PolymerItemGroupUtils {
* Even called on synchronization of ItemGroups
*/
public static final SimpleEvent<ItemGroupEventListener> LIST_EVENT = new SimpleEvent<>();
private static final Map<ItemGroupKey, Contents> CONTENT_CACHE = new HashMap<>();

private PolymerItemGroupUtils() {
}
Expand All @@ -37,14 +38,20 @@ public static Contents getContentsFor(ServerPlayerEntity player, ItemGroup group
}

public static Contents getContentsFor(ItemGroup group, RegistryWrapper.WrapperLookup lookup, FeatureSet featureSet, boolean operator) {
try {
return ((ItemGroupExtra) group).polymer$getContentsWith(featureSet, operator, lookup);
} catch (Throwable t) {
// Some 1.20 mods use client classes in their item groups because vanilla doesn't call them on the server anymore
// Catch instead of letting the game crash, even though it's their fault...
PolymerImpl.LOGGER.warn("Failed to load contents for an ItemGroup", t);
return new Contents(List.of(), List.of());
var key = new ItemGroupKey(getId(group), operator);
var value = CONTENT_CACHE.get(key);
if (value == null) {
try {
value = ((ItemGroupExtra) group).polymer$getContentsWith(featureSet, operator, lookup);
} catch (Throwable t) {
// Some 1.20 mods use client classes in their item groups because vanilla doesn't call them on the server anymore
// Catch instead of letting the game crash, even though it's their fault...
PolymerImpl.LOGGER.warn("Failed to load contents for an ItemGroup", t);
value = new Contents(List.of(), List.of());
}
CONTENT_CACHE.put(key, value);
}
return value;
}

/**
Expand Down Expand Up @@ -110,6 +117,10 @@ public static Identifier getId(ItemGroup group) {
return x;
}

public static void invalidateItemGroupCache() {
CONTENT_CACHE.clear();
}

@FunctionalInterface
public interface ItemGroupEventListener {
void onItemGroupGet(ServerPlayerEntity player, ItemGroupListBuilder builder);
Expand All @@ -123,4 +134,6 @@ public interface ItemGroupListBuilder {

public record Contents(Collection<ItemStack> main, Collection<ItemStack> search) {
}

private record ItemGroupKey(Identifier identifier, boolean operator) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,9 @@ public static Identifier getServerIdentifier(ItemStack itemStack) {

@Nullable
private static Identifier getIdentifierFrom(NbtCompound compound, String nbtKey) {
String id = compound.getString(nbtKey);
if (id != null && !id.isEmpty()) {
return Identifier.tryParse(id);
var id = compound.get(nbtKey);
if (id instanceof NbtString string) {
return Identifier.tryParse(string.asString());
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,32 @@
import org.jetbrains.annotations.ApiStatus;

import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;

@ApiStatus.Internal
public record PolymerBlockStateEntry(Map<String, String> states, int numId, int blockId) implements BufferWritable {
public static final IdentityHashMap<BlockState, PolymerBlockStateEntry> CACHE = new IdentityHashMap<>();

public void write(PacketByteBuf buf, int version, ServerPlayNetworkHandler handler) {
buf.writeVarInt(numId);
buf.writeVarInt(blockId);
buf.writeMap(states, PacketByteBuf::writeString, PacketByteBuf::writeString);
}

public static PolymerBlockStateEntry of(BlockState state, ServerPlayNetworkHandler player, int version) {
var list = new HashMap<String, String>();

for (var entry : state.getEntries().entrySet()) {
list.put(entry.getKey().getName(), ((Property) (Object) entry.getKey()).name(entry.getValue()));
var value = CACHE.get(state);
if (value == null) {
var list = new HashMap<String, String>();

for (var entry : state.getEntries().entrySet()) {
list.put(entry.getKey().getName(), ((Property) (Object) entry.getKey()).name(entry.getValue()));
}
value = new PolymerBlockStateEntry(list, Block.STATE_IDS.getRawId(state), Registries.BLOCK.getRawId(state.getBlock()));
CACHE.put(state, value);
}

return new PolymerBlockStateEntry(list, Block.STATE_IDS.getRawId(state), Registries.BLOCK.getRawId(state.getBlock()));
return value;
}

public static PolymerBlockStateEntry read(PacketByteBuf buf, int version) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,27 @@

public record PolymerItemGroupContent(Identifier identifier, List<ItemStack> stacksMain, List<ItemStack> stacksSearch) implements ServerPacketWriter {
public static PolymerItemGroupContent of(ItemGroup group, ServerPlayNetworkHandler handler) {
var stacksMain = new ArrayList<ItemStack>();
var stacksSearch = new ArrayList<ItemStack>();
List<ItemStack> stacksMain;
List<ItemStack> stacksSearch;

var anyContent = PolymerItemGroupUtils.isPolymerItemGroup(group);
var contents = PolymerItemGroupUtils.getContentsFor(handler.player, group);

for (var item : contents.main()) {
if (anyContent || PolymerItemUtils.isPolymerServerItem(item) || PolymerImplUtils.isServerSideSyncableEntry(Registries.ITEM, item.getItem())) {
stacksMain.add(item);
if (PolymerItemGroupUtils.isPolymerItemGroup(group)) {
stacksMain = List.copyOf(contents.main());
stacksSearch = List.copyOf(contents.search());
} else {
stacksMain = new ArrayList<>();
stacksSearch = new ArrayList<>();
for (var item : contents.main()) {
if (PolymerItemUtils.isPolymerServerItem(item, handler.player) || PolymerImplUtils.isServerSideSyncableEntry(Registries.ITEM, item.getItem())) {
stacksMain.add(item);
}
}
}

for (var item : contents.search()) {
if (anyContent || PolymerItemUtils.isPolymerServerItem(item) || PolymerImplUtils.isServerSideSyncableEntry(Registries.ITEM, item.getItem())) {
stacksSearch.add(item);
for (var item : contents.search()) {
if (PolymerItemUtils.isPolymerServerItem(item, handler.player) || PolymerImplUtils.isServerSideSyncableEntry(Registries.ITEM, item.getItem())) {
stacksSearch.add(item);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package eu.pb4.polymer.core.mixin.item;

import eu.pb4.polymer.core.api.item.PolymerItemGroupUtils;
import eu.pb4.polymer.core.impl.networking.packets.PolymerBlockStateEntry;
import net.minecraft.server.MinecraftServer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(MinecraftServer.class)
public class MinecraftServerMixin {
@Inject(method = "runServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;setupServer()Z"))
private void polymerCore$beforeSetup(CallbackInfo info) {
PolymerItemGroupUtils.invalidateItemGroupCache();
}

@Inject(method = "runServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;createMetadata()Lnet/minecraft/server/ServerMetadata;", ordinal = 0))
private void polymerCore$beforeStartTicking(CallbackInfo info) {
PolymerBlockStateEntry.CACHE.clear();
PolymerItemGroupUtils.invalidateItemGroupCache();
}

@Inject(method = "shutdown", at = @At("TAIL"))
private void polymerCore$shutdown(CallbackInfo info) {
PolymerBlockStateEntry.CACHE.clear();
PolymerItemGroupUtils.invalidateItemGroupCache();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package eu.pb4.polymer.core.mixin.item;

import eu.pb4.polymer.core.api.item.PolymerItemGroupUtils;
import eu.pb4.polymer.core.api.utils.PolymerSyncUtils;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.util.List;

@Mixin(PlayerManager.class)
public abstract class PlayerManagerMixin {
@Shadow public abstract List<ServerPlayerEntity> getPlayerList();

@Inject(method = "onDataPacksReloaded", at = @At("HEAD"))
private void polymerCore$invalidateItemGroups(CallbackInfo ci) {
PolymerItemGroupUtils.invalidateItemGroupCache();
for (var player : this.getPlayerList()) {
PolymerSyncUtils.synchronizeCreativeTabs(player.networkHandler);
}
}
}
2 changes: 2 additions & 0 deletions polymer-core/src/main/resources/polymer-core.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@
"item.ItemGroupsMixin",
"item.ItemStackContentMixin",
"item.ItemStackMixin",
"item.MinecraftServerMixin",
"item.MiningToolItemAccessor",
"item.NbtCompoundFallbackMixin",
"item.NbtCompoundMixin",
"item.PlayerManagerMixin",
"item.ServerPlayNetworkHandlerMixin",
"item.StonecutterScreenHandlerMixin",
"item.packet.PacketByteBufMixin",
Expand Down

0 comments on commit 3bde037

Please sign in to comment.