Skip to content

Commit

Permalink
v3.9 dev. progress
Browse files Browse the repository at this point in the history
Version 4 MCBS files that now support modded `StatType`s.
  • Loading branch information
TheCSDev committed Feb 20, 2024
1 parent fb6ea53 commit 269cf8a
Show file tree
Hide file tree
Showing 12 changed files with 720 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ private StatsProviderIO() {}
* still maintaining support for the older chunks.
* @apiNote TLDR; Only increase if backwards compatibility is impossible.
*/
public static final int FILE_VERSION = 2;
public static final int FILE_VERSION = 4;
/* # File version history:
* 1 - Since v3.0-alpha.1 - Initial version
* 2 - Since v3.0-alpha.3 - Major changes to the player badge system
* 3 - Since v3.9 - Support for modded stat types
* 3 - Since v3.9 - [Reserved for special use-case]
* 4 - Since v3.9 - Support for modded stat types
*/
// ==================================================
/**
Expand All @@ -61,12 +62,13 @@ public static final void write(PacketByteBuf buffer, IStatsProvider statsProvide
buffer.writeBytes("RIFF".getBytes(US_ASCII));

//write data
write_file(buffer, statsProvider);
write_file(buffer, statsProvider, FILE_VERSION);
}

@SuppressWarnings("deprecation")
private static final void write_file(PacketByteBuf buffer, IStatsProvider statsProvider)
private static final void write_file(PacketByteBuf buffer, IStatsProvider statsProvider, int fileVersion)
{
if(fileVersion < 1) throw new IllegalArgumentException("Attempting to write file version < 1.");

//create the buffer
final var buffer_file = new PacketByteBuf(Unpooled.buffer());

Expand All @@ -76,12 +78,13 @@ private static final void write_file(PacketByteBuf buffer, IStatsProvider statsP
buffer_file.writeBytes(FILE_EXTENSION.toUpperCase().getBytes(US_ASCII));

//write the file version
buffer_file.writeIntLE(FILE_VERSION);
buffer_file.writeIntLE(fileVersion);

//write chunks
switch(FILE_VERSION)
switch(fileVersion)
{
case 2: StatsProviderIO_fv2.write_fileChunks(buffer_file, statsProvider); break;
case 4: StatsProviderIO_fv4.write_fileChunks(buffer_file, statsProvider); break;
default: break;
}

Expand Down Expand Up @@ -130,7 +133,6 @@ public static final void read(PacketByteBuf buffer, IEditableStatsProvider stats
catch(IllegalHeaderException | UnsupportedFileVersionException exc) { buffer.resetReaderIndex(); throw exc; }
}
// --------------------------------------------------
@SuppressWarnings("deprecation")
private static final void read_file(PacketByteBuf buffer_file, IEditableStatsProvider statsProvider)
throws IllegalHeaderException, UnsupportedFileVersionException
{
Expand All @@ -146,6 +148,7 @@ private static final void read_file(PacketByteBuf buffer_file, IEditableStatsPro
switch(fileVersion)
{
case 2: StatsProviderIO_fv2.read_fileChunks(buffer_file, statsProvider); break;
case 4: StatsProviderIO_fv4.read_fileChunks(buffer_file, statsProvider); break;
default: throw new UnsupportedFileVersionException(Integer.toString(fileVersion));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.UUID;
import java.util.stream.Collectors;

import org.jetbrains.annotations.ApiStatus.Internal;
import org.jetbrains.annotations.Nullable;

import com.google.common.collect.Lists;
Expand All @@ -29,10 +30,9 @@
* A class containing {@link StatsProviderIO} logic for file version 2.
* @apiNote Used for backwards-compatibility. Internal use only!
*/
public final @Deprecated class StatsProviderIO_fv2
@Internal
public final class StatsProviderIO_fv2
{
// ==================================================
public static final int FILE_VERSION = 2; //Must always be 2
// ==================================================
static final void write_fileChunks(PacketByteBuf buffer_file, IStatsProvider statsProvider)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
package io.github.thecsdev.betterstats.api.util.io;

import static io.github.thecsdev.tcdcommons.api.util.TextUtils.literal;
import java.util.Objects;

import org.jetbrains.annotations.Nullable;

import io.github.thecsdev.betterstats.api.util.stats.SUPlayerBadgeStat;
import io.github.thecsdev.tcdcommons.api.util.exceptions.UnsupportedFileVersionException;
import io.netty.buffer.Unpooled;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.registry.Registries;
import net.minecraft.stat.StatType;
import net.minecraft.util.Identifier;

public class StatsProviderIO_fv4
{
// ==================================================
static final void write_fileChunks(PacketByteBuf buffer_file, IStatsProvider statsProvider)
{
write_fileChunk("metadata", buffer_file, statsProvider);
write_fileChunk("stats", buffer_file, statsProvider);
write_fileChunk("tcdcommons:player_badges", buffer_file, statsProvider);
}
// --------------------------------------------------
private static final void write_fileChunk(String chunkId, PacketByteBuf buffer_file, IStatsProvider statsProvider)
{
//create a buffer for the chunk, and write the chunk ID to it
PacketByteBuf buffer_chunk = new PacketByteBuf(Unpooled.buffer());
buffer_chunk.writeString(chunkId);

//obtain and write chunk data to the chunk buffer
switch(chunkId)
{
case "metadata": write_fileChunk_metadata(buffer_chunk, statsProvider); break;
case "stats": write_fileChunk_stats(buffer_chunk, statsProvider); break;
case "tcdcommons:player_badges": write_fileChunk_playerBadges(buffer_chunk, statsProvider); break;
default: break;
}

//write the chunk data buffer to the file buffer
buffer_file.writeIntLE(buffer_chunk.readableBytes());
buffer_file.writeBytes(buffer_chunk);
buffer_chunk.release();
}
// --------------------------------------------------
private static final void write_fileChunk_metadata(PacketByteBuf buffer_chunk, IStatsProvider statsProvider)
{
//obtain the stats display name as string
final var statsNameText = statsProvider.getDisplayName();
final var statsName = (statsNameText != null) ? statsNameText.getString() : "-";

//write name and game profile
buffer_chunk.writeString(statsName);
StatsProviderIO.writeGameProfile(buffer_chunk, statsProvider.getGameProfile());
}
// --------------------------------------------------
@SuppressWarnings("unchecked")
private static final void write_fileChunk_stats(PacketByteBuf buffer_chunk, IStatsProvider statsProvider)
{
//iterate all stat types, and write their corresponding stat data one by one
for(final var statType : Registries.STAT_TYPE)
{
//create a buffer for the stat type chunk, and write the chunk ID to it
PacketByteBuf buffer_st = new PacketByteBuf(Unpooled.buffer());
buffer_st.writeString(Objects.toString(Registries.STAT_TYPE.getId(statType))); //write chunk id

//write the stats data for the given stats type, to the stats type buffer
write_fileChunk_stats_statType(buffer_st, statsProvider, (StatType<Object>)statType); //write chunk data

//write the stat type buffer data to the chunk buffer
buffer_chunk.writeIntLE(buffer_st.readableBytes());
buffer_chunk.writeBytes(buffer_st);
buffer_st.release();
}
}

private static final void write_fileChunk_stats_statType(
PacketByteBuf buffer_st, IStatsProvider statsProvider, StatType<Object> statType)
{
//obtain the registry, and iterate all of its items
final var registry = statType.getRegistry();
for(final var registryItem : registry)
{
//obtain the stat value for the given registry item
//also skip "zero" stats, as they do not have a value
final int statValue = statsProvider.getStatValue(statType, registryItem);
if(statValue == 0) continue;

//obtain the id of the registry item
final var registryItemId = registry.getId(registryItem);

//write stat id and value
buffer_st.writeString(registryItemId.getNamespace().equals(Identifier.DEFAULT_NAMESPACE) ?
registryItemId.getPath() : Objects.toString(registryItemId)); //write stat id
buffer_st.writeIntLE(statValue); //write stat value
}
}
// --------------------------------------------------
private static final void write_fileChunk_playerBadges(PacketByteBuf buffer_chunk, IStatsProvider statsProvider)
{
//obtain a map of mod stats
final var stats = SUPlayerBadgeStat.getPlayerBadgeStatsByModGroups(statsProvider, stat -> !stat.isEmpty());

//iterate groups, and write their data
for(final var entry : stats.entrySet())
{
//obtain the group id and its stats
final var groupModId = entry.getKey();
final var groupStats = entry.getValue();

//write the group id and its length
buffer_chunk.writeString(groupModId);
buffer_chunk.writeVarInt(groupStats.size());

//write group entries
for(final var stat : groupStats)
{
buffer_chunk.writeString(stat.getStatID().getPath());
buffer_chunk.writeVarInt(stat.value);
}
}
}
// ==================================================
static final void read_fileChunks(PacketByteBuf buffer_file, IEditableStatsProvider statsProvider)
throws IllegalHeaderException, UnsupportedFileVersionException
{
//read chunks
while(buffer_file.readableBytes() > 0)
{
//read next chunk's size, and check it
final int chunkSize = buffer_file.readIntLE();
if(buffer_file.readableBytes() < chunkSize)
throw new IllegalHeaderException(
"chunk size >= " + chunkSize,
"chunk size == " + buffer_file.readableBytes());

//read the chunk data
//(creates a view of the original buffer, so it doesn't have to be released separately)
final var buffer_chunk = new PacketByteBuf(buffer_file.readSlice(chunkSize));
final var chunkId = buffer_chunk.readString();
switch(chunkId)
{
case "metadata": read_fileChunk_metadata(buffer_chunk, statsProvider); break;
case "stats": read_fileChunk_stats(buffer_chunk, statsProvider); break;
case "tcdcommons:player_badges": read_fileChunk_playerBadges(buffer_chunk, statsProvider); break;
default: break;
}
}
}
// --------------------------------------------------
private static final void read_fileChunk_metadata(PacketByteBuf buffer_chunk, IEditableStatsProvider statsProvider)
{
statsProvider.setDisplayName(literal(buffer_chunk.readString()));
statsProvider.setGameProfile(StatsProviderIO.readGameProfile(buffer_chunk));
}
// --------------------------------------------------
private static final void read_fileChunk_stats(PacketByteBuf buffer_chunk, IEditableStatsProvider statsProvider)
throws IllegalHeaderException
{
//keep reading chunks as they come in
while(buffer_chunk.readableBytes() > 0)
{
//read next chunk's size, and check it
final int chunkSize = buffer_chunk.readIntLE(); //read stats type chunk size
if(buffer_chunk.readableBytes() < chunkSize)
throw new IllegalHeaderException(
"chunk size >= " + chunkSize,
"chunk size == " + buffer_chunk.readableBytes());

//read the chunk data
//(creates a view of the original buffer, so it doesn't have to be released separately)
final var buffer_st = new PacketByteBuf(buffer_chunk.readSlice(chunkSize)); //read stats type chunk data
read_fileChunk_stats_statType(buffer_st, statsProvider);
}
}

@SuppressWarnings("unchecked")
private static final void read_fileChunk_stats_statType(PacketByteBuf buffer_st, IEditableStatsProvider statsProvider)
{
//read the stat type identifier
final var statTypeId = new Identifier(buffer_st.readString());

//obtain the stat type and check if it exists
final @Nullable var statType = Registries.STAT_TYPE.containsId(statTypeId) ?
(StatType<Object>)Registries.STAT_TYPE.getOrEmpty(statTypeId).get() : null;
if(statType == null) return;
final var statTypeRegistry = statType.getRegistry();

//read stats one by one
while(buffer_st.readableBytes() > 0)
{
//read stat id and stat value
final Identifier statId = new Identifier(buffer_st.readString());
final int statValue = buffer_st.readIntLE();

//obtain the registry item, null check it, and store its value to the stats provider
final @Nullable var item = statTypeRegistry.getOrEmpty(statId).orElse(null);
if(item == null) continue;
statsProvider.setStatValue(statType, item, statValue);
}
}
// --------------------------------------------------
private static final void read_fileChunk_playerBadges(PacketByteBuf buffer_chunk, IEditableStatsProvider statsProvider)
{
while(buffer_chunk.readableBytes() > 0)
{
//read the next mod id and how many entries it has
final String modId = buffer_chunk.readString();
final int entryCount = buffer_chunk.readVarInt();

//read all entries for the corresponding mod id
for(int i = 0; i < entryCount; i++)
{
//read player badge stat data
final String playerBadgeIdPath = buffer_chunk.readString();
final int value = buffer_chunk.readVarInt();

//obtain mob, and store its stats
final Identifier playerBadgeId = new Identifier(modId, playerBadgeIdPath);
statsProvider.setPlayerBadgeValue(playerBadgeId, value);
}
}
}
// ==================================================
}

This file was deleted.

Loading

0 comments on commit 269cf8a

Please sign in to comment.