chores: Minor Optimizations

This commit is contained in:
Anon 2026-04-03 16:40:54 +02:00 committed by GitHub
commit 3557239c43
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 113 additions and 25 deletions

View file

@ -1,3 +1,4 @@
using System;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Nodes;
@ -23,10 +24,46 @@ public static class Json
public static JsonNode? ParseJson(string? json)
{
if (string.IsNullOrWhiteSpace(json)) return null;
ReadOnlySpan<char> text = json.AsSpan().TrimStart();
if (!LooksLikeJson(text))
return JsonValue.Create(json);
try { return JsonNode.Parse(json); }
catch (JsonException) { return JsonValue.Create(json); }
}
private static bool LooksLikeJson(ReadOnlySpan<char> text)
{
if (text.IsEmpty)
return false;
return text[0] switch
{
'{' or '"' => true,
'[' => LooksLikeJsonArray(text[1..]),
'-' => text.Length > 1 && char.IsAsciiDigit(text[1]),
>= '0' and <= '9' => true,
't' or 'f' or 'n' => true,
_ => false
};
}
private static bool LooksLikeJsonArray(ReadOnlySpan<char> text)
{
text = text.TrimStart();
if (text.IsEmpty)
return false;
return text[0] switch
{
']' or '{' or '[' or '"' => true,
'-' => text.Length > 1 && char.IsAsciiDigit(text[1]),
>= '0' and <= '9' => true,
't' or 'f' or 'n' => true,
_ => false
};
}
/// <summary>
/// Escape a string for embedding inside a JSON string literal.
/// Uses System.Text.Json serialization and strips the surrounding quotes.
@ -52,4 +89,4 @@ public static class JsonNodeExtensions
JsonValue val when val.TryGetValue<string>(out var s) => s,
_ => node.ToJsonString()
};
}
}

View file

@ -232,8 +232,8 @@ namespace MinecraftClient.Mapping
int tentativeGScore = current.GScore + (int)current.Location.DistanceSquared(neighbor);
// If the neighbor is not in the GScoreDict OR its current tentativeGScore is lower than the previously saved one:
if (!gScoreDict.ContainsKey(neighbor) ||
(gScoreDict.ContainsKey(neighbor) && tentativeGScore < gScoreDict[neighbor]))
if (!gScoreDict.TryGetValue(neighbor, out int existingGScore) ||
tentativeGScore < existingGScore)
{
// Save the new relation between the neighbored block and the current one
cameFrom[neighbor] = current.Location;

View file

@ -12,9 +12,9 @@ namespace MinecraftClient.Mapping
{
/// <summary>
/// The chunks contained into the Minecraft world
/// Tuple<int, int>: Tuple<chunkX, chunkZ>
/// (int ChunkX, int ChunkZ): chunkX, chunkZ
/// </summary>
private ConcurrentDictionary<Tuple<int, int>, ChunkColumn> chunks = new();
private ConcurrentDictionary<(int ChunkX, int ChunkZ), ChunkColumn> chunks = new();
/// <summary>
/// The dimension info of the world
@ -49,12 +49,12 @@ namespace MinecraftClient.Mapping
{
get
{
chunks.TryGetValue(new(chunkX, chunkZ), out ChunkColumn? chunkColumn);
chunks.TryGetValue((chunkX, chunkZ), out ChunkColumn? chunkColumn);
return chunkColumn;
}
set
{
Tuple<int, int> chunkCoord = new(chunkX, chunkZ);
var chunkCoord = (chunkX, chunkZ);
if (value is null)
chunks.TryRemove(chunkCoord, out _);
else
@ -361,7 +361,7 @@ namespace MinecraftClient.Mapping
/// <param name="loadCompleted">Whether the ChunkColumn has been fully loaded</param>
public void StoreChunk(int chunkX, int chunkY, int chunkZ, int chunkColumnSize, Chunk? chunk, bool loadCompleted)
{
ChunkColumn chunkColumn = chunks.GetOrAdd(new(chunkX, chunkZ), (_) => new(chunkColumnSize));
ChunkColumn chunkColumn = chunks.GetOrAdd((chunkX, chunkZ), (_) => new(chunkColumnSize));
chunkColumn[chunkY] = chunk;
if (loadCompleted)
chunkColumn.FullyLoaded = true;

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -19,7 +20,7 @@ namespace MinecraftClient.Physics
private static readonly Aabb[] FullBlockArray = { FullBlock };
private static readonly Aabb[] EmptyArray = Array.Empty<Aabb>();
private static Dictionary<int, Aabb[]>? stateToShape;
private static FrozenDictionary<int, Aabb[]>? stateToShape;
private static Dictionary<string, object>? prismarineBlocks;
private static Dictionary<int, Aabb[]>? prismarineShapes;
@ -136,14 +137,21 @@ namespace MinecraftClient.Physics
private static void BuildStateMap()
{
stateToShape = new Dictionary<int, Aabb[]>();
var builder = new Dictionary<int, Aabb[]>();
if (prismarineBlocks is null || prismarineShapes is null)
{
stateToShape = builder.ToFrozenDictionary();
return;
}
var palette = Block.Palette;
var dict = GetPaletteDict(palette);
if (dict is null) return;
if (dict is null)
{
stateToShape = builder.ToFrozenDictionary();
return;
}
// Group consecutive state IDs by Material to find state ranges per block
var materialRanges = new Dictionary<Material, List<(int start, int end)>>();
@ -182,20 +190,20 @@ namespace MinecraftClient.Physics
{
var shapes = prismarineShapes.GetValueOrDefault(singleShapeId, EmptyArray);
for (int sid = start; sid <= end; sid++)
stateToShape[sid] = shapes;
builder[sid] = shapes;
}
else if (blockShapeData is List<int> shapeIdList)
{
for (int i = 0; i < stateCount && (globalStateOffset + i) < shapeIdList.Count; i++)
{
int shapeId = shapeIdList[globalStateOffset + i];
stateToShape[start + i] = prismarineShapes.GetValueOrDefault(shapeId, EmptyArray);
builder[start + i] = prismarineShapes.GetValueOrDefault(shapeId, EmptyArray);
}
}
globalStateOffset += stateCount;
}
}
stateToShape = builder.ToFrozenDictionary();
}
/// <summary>

View file

@ -3918,26 +3918,42 @@ namespace MinecraftClient.Protocol.Handlers
/// <param name="packetData">packet Data</param>
private void SendPacket(int packetId, IEnumerable<byte> packetData)
{
byte[] payload = packetData as byte[] ?? packetData.ToArray();
if (handler.GetNetworkPacketCaptureEnabled())
{
var clone = packetData.ToList();
handler.OnNetworkPacket(packetId, clone, currentState == CurrentState.Login, false);
handler.OnNetworkPacket(packetId, payload.ToList(), currentState == CurrentState.Login, false);
}
//log.Info($"[C -> S] Sending packet {packetId:X} > {dataTypes.ByteArrayToString(packetData.ToArray())}");
//The inner packet
var thePacket = dataTypes.ConcatBytes(DataTypes.GetVarInt(packetId), packetData.ToArray());
byte[] packetIdBytes = DataTypes.GetVarInt(packetId);
byte[] thePacket = new byte[packetIdBytes.Length + payload.Length];
Buffer.BlockCopy(packetIdBytes, 0, thePacket, 0, packetIdBytes.Length);
Buffer.BlockCopy(payload, 0, thePacket, packetIdBytes.Length, payload.Length);
if (compression_treshold >= 0) //Compression enabled?
{
thePacket = thePacket.Length >= compression_treshold
? dataTypes.ConcatBytes(DataTypes.GetVarInt(thePacket.Length), ZlibUtils.Compress(thePacket))
: dataTypes.ConcatBytes(DataTypes.GetVarInt(0), thePacket);
byte[] compressedHeader = thePacket.Length >= compression_treshold
? DataTypes.GetVarInt(thePacket.Length)
: DataTypes.GetVarInt(0);
byte[] compressedPayload = thePacket.Length >= compression_treshold
? ZlibUtils.Compress(thePacket)
: thePacket;
byte[] compressedPacket = new byte[compressedHeader.Length + compressedPayload.Length];
Buffer.BlockCopy(compressedHeader, 0, compressedPacket, 0, compressedHeader.Length);
Buffer.BlockCopy(compressedPayload, 0, compressedPacket, compressedHeader.Length, compressedPayload.Length);
thePacket = compressedPacket;
}
//log.Debug("[C -> S] Sending packet " + packetId + " > " + dataTypes.ByteArrayToString(dataTypes.ConcatBytes(dataTypes.GetVarInt(thePacket.Length), thePacket)));
socketWrapper.SendDataRAW(dataTypes.ConcatBytes(DataTypes.GetVarInt(thePacket.Length), thePacket));
byte[] packetLengthBytes = DataTypes.GetVarInt(thePacket.Length);
byte[] fullPacket = new byte[packetLengthBytes.Length + thePacket.Length];
Buffer.BlockCopy(packetLengthBytes, 0, fullPacket, 0, packetLengthBytes.Length);
Buffer.BlockCopy(thePacket, 0, fullPacket, packetLengthBytes.Length, thePacket.Length);
socketWrapper.SendDataRAW(fullPacket);
}
/// <summary>

View file

@ -4,8 +4,6 @@ MCC.LoadBot(new PacketCadenceCaptureBot());
//MCCScript Extensions
using System.Threading;
public class PacketCadenceCaptureBot : ChatBot
{
private const int CaptureDurationSeconds = 5;

View file

@ -21,6 +21,7 @@ EOF
SERVER_DIR="${1:-}"
MC_VERSION="${2:-}"
PROFILE="${3:-}"
SERVER_PORT=""
if [[ -z "$SERVER_DIR" || -z "$MC_VERSION" || -z "$PROFILE" ]]; then
usage >&2
@ -62,6 +63,21 @@ wait_for_file_pattern() {
return 1
}
wait_for_rcon_port_free() {
local timeout="${1:-30}"
local elapsed=0
while (( elapsed < timeout )); do
if ! ss -ltn '( sport = :25575 )' 2>/dev/null | grep -Fq ':25575'; then
return 0
fi
sleep 1
((elapsed += 1))
done
echo "Timed out waiting for RCON port 25575 to become free" >&2
return 1
}
cleanup() {
if [[ -n "${MCC_PID:-}" ]] && kill -0 "$MCC_PID" 2>/dev/null; then
echo "quit" >> "$INPUT_FILE" 2>/dev/null || true
@ -76,12 +92,24 @@ cleanup() {
fi
tmux kill-session -t "$SESSION_NAME" 2>/dev/null || true
wait_for_rcon_port_free 30 || true
}
trap cleanup EXIT
prepare_config() {
bash "$REPO_ROOT/.skills/mcc-integration-testing/scripts/prepare_offline_mcc_config.sh" "$CFG" "$MC_VERSION" CursorBot >/dev/null
MCC_TEST_ACCOUNT_TYPE=mojang MCC_TEST_PASSWORD=- \
bash "$REPO_ROOT/.skills/mcc-integration-testing/scripts/prepare_offline_mcc_config.sh" \
"$REPO_ROOT/MinecraftClient.ini" "$CFG" "$MC_VERSION" CursorBot >/dev/null
sed_in_place \
-e "s#^Server = .*#Server = { Host = \"localhost\", Port = $SERVER_PORT }#" \
-e 's/TerrainAndMovements = false/TerrainAndMovements = true/' \
-e 's/InventoryHandling = false/InventoryHandling = true/' \
-e 's/EntityHandling = false/EntityHandling = true/' \
-e 's/AutoRespawn = false/AutoRespawn = true/' \
"$CFG"
disable_noisy_bots_in_ini "$CFG"
}
send_mcc_command() {
@ -156,7 +184,7 @@ modern_mob_and_effects() {
bash "$REPO_ROOT/.skills/mcc-integration-testing/scripts/preflight_test_env.sh" "$SERVER_DIR" >/dev/null
bash "$REPO_ROOT/.skills/mcc-integration-testing/scripts/reset_shared_test_state.sh" --all >/dev/null
prepare_config
wait_for_rcon_port_free 30 || true
rm -f "$MCC_LOG" "$INPUT_FILE"
bash "$REPO_ROOT/.skills/mcc-integration-testing/scripts/ensure_offline_server.sh" "$SERVER_DIR" >/dev/null
@ -167,6 +195,7 @@ fi
mc-start "$SERVER_DIR" >/dev/null
wait_for_server_ready "$SERVER_DIR" || exit 1
prepare_config
: > "$INPUT_FILE"