Validate sprite specifier states (#3075)

This commit is contained in:
Leon Friedrich
2022-07-28 11:17:40 +12:00
committed by GitHub
parent 786ecdb8b1
commit ee2d266d6b
3 changed files with 108 additions and 18 deletions

View File

@@ -0,0 +1,45 @@
using Robust.Client.ResourceManagement;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
namespace Robust.Client.Serialization;
[TypeSerializer]
public sealed class ClientSpriteSpecifierSerializer : SpriteSpecifierSerializer
{
public override ValidationNode ValidateRsi(ISerializationManager serializationManager,
MappingDataNode node,
IDependencyCollection dependencies,
ISerializationContext? context)
{
if (!node.TryGet("sprite", out var pathNode) || pathNode is not ValueDataNode valuePathNode)
{
return new ErrorNode(node, "Sprite specifier has missing/invalid sprite node");
}
if (!node.TryGet("state", out var stateNode) || stateNode is not ValueDataNode valueStateNode)
{
return new ErrorNode(node, "Sprite specifier has missing/invalid state node");
}
var res = dependencies.Resolve<IResourceCache>();
var rsiPath = SharedSpriteComponent.TextureRoot / valuePathNode.Value;
if (!res.TryGetResource(rsiPath, out RSIResource? resource))
{
return new ErrorNode(node, "Failed to load RSI");
}
if (!resource.RSI.TryGetState(valueStateNode.Value, out _))
{
return new ErrorNode(node, "Invalid RSI state");
}
return new ValidatedValueNode(node);
}
}

View File

@@ -0,0 +1,53 @@
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
using Robust.Shared.Utility;
namespace Robust.Server.Serialization;
[TypeSerializer]
public sealed class ServerSpriteSpecifierSerializer : SpriteSpecifierSerializer
{
public override ValidationNode ValidateRsi(ISerializationManager serializationManager,
MappingDataNode node,
IDependencyCollection dependencies,
ISerializationContext? context)
{
if (!node.TryGet("sprite", out var pathNode) || pathNode is not ValueDataNode valuePathNode)
{
return new ErrorNode(node, "Sprite specifier has missing/invalid sprite node");
}
if (!valuePathNode.Value.EndsWith(".rsi")) // required so that resource path validation checks for the meta.json.
{
return new ErrorNode(node, "sprite node does not end in .rsi");
}
if (!node.TryGet("state", out var stateNode) || stateNode is not ValueDataNode valueStateNode)
{
return new ErrorNode(node, "Sprite specifier has missing/invalid state node");
}
var path = serializationManager.ValidateNode(typeof(ResourcePath),
new ValueDataNode($"{SharedSpriteComponent.TextureRoot / valuePathNode.Value}"), context);
if (path is ErrorNode) return path;
// RSI meta-data & misc related functions are client only, so the server can't easily fully validate them.
// However, as some sprites may be specified in server-exclusive prototypes, we should still try and check that
// the state exists. So lets just check if the state .png exists, without properly validating the RSI's
// meta.json
var statePath = serializationManager.ValidateNode(typeof(ResourcePath),
new ValueDataNode($"{SharedSpriteComponent.TextureRoot / valuePathNode.Value / valueStateNode.Value}.png"), context);
if (statePath is ErrorNode) return statePath;
return new ValidatedValueNode(node);
}
}

View File

@@ -1,6 +1,8 @@
using System;
using Robust.Shared.ContentPack;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Markdown;
@@ -13,8 +15,7 @@ using static Robust.Shared.Utility.SpriteSpecifier;
namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
[TypeSerializer]
public sealed class SpriteSpecifierSerializer :
public abstract class SpriteSpecifierSerializer :
ITypeSerializer<Texture, ValueDataNode>,
ITypeSerializer<EntityPrototype, ValueDataNode>,
ITypeSerializer<Rsi, MappingDataNode>,
@@ -123,24 +124,15 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
IDependencyCollection dependencies,
ISerializationContext? context)
{
if (!node.TryGet("sprite", out var pathNode) || pathNode is not ValueDataNode valuePathNode)
{
return new ErrorNode(node, "Sprite specifier has missing/invalid sprite node");
}
if (!node.TryGet("state", out var stateNode) || stateNode is not ValueDataNode)
{
return new ErrorNode(node, "Sprite specifier has missing/invalid state node");
}
var path = serializationManager.ValidateNode(typeof(ResourcePath),
new ValueDataNode($"{SharedSpriteComponent.TextureRoot / valuePathNode.Value}"), context);
if (path is ErrorNode) return path;
return new ValidatedValueNode(node);
// apparently explicit interface implementations can't be abstract.
return ValidateRsi(serializationManager, node, dependencies, context);
}
public abstract ValidationNode ValidateRsi(ISerializationManager serializationManager,
MappingDataNode node,
IDependencyCollection dependencies,
ISerializationContext? context);
public DataNode Write(ISerializationManager serializationManager, Texture value, bool alwaysWrite = false,
ISerializationContext? context = null)
{