mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Some stuff
This commit is contained in:
parent
cbdac759b3
commit
732ca561a1
5 changed files with 101 additions and 28 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit f41af0fb88626f1579d3c4370b32b901f3c4d3c2
|
Subproject commit 27e8873e9f4633421e736757574b502a8d65e79d
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
using Dalamud.Game.ClientState.Objects.Enums;
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Penumbra.String;
|
using Penumbra.String;
|
||||||
|
|
||||||
|
|
@ -157,7 +159,8 @@ public partial class ActorManager
|
||||||
((FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)actor)->NameID);
|
((FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)actor)->NameID);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateNpc(ObjectKind.BattleNpc, ((FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)actor)->NameID, actor->ObjectIndex);
|
return CreateNpc(ObjectKind.BattleNpc, ((FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)actor)->NameID,
|
||||||
|
actor->ObjectIndex);
|
||||||
}
|
}
|
||||||
case ObjectKind.EventNpc: return CreateNpc(ObjectKind.EventNpc, actor->DataID, actor->ObjectIndex);
|
case ObjectKind.EventNpc: return CreateNpc(ObjectKind.EventNpc, actor->DataID, actor->ObjectIndex);
|
||||||
case ObjectKind.MountType:
|
case ObjectKind.MountType:
|
||||||
|
|
@ -206,7 +209,7 @@ public partial class ActorManager
|
||||||
|
|
||||||
public ActorIdentifier CreatePlayer(ByteString name, ushort homeWorld)
|
public ActorIdentifier CreatePlayer(ByteString name, ushort homeWorld)
|
||||||
{
|
{
|
||||||
if (!VerifyWorld(homeWorld) || !VerifyPlayerName(name))
|
if (!VerifyWorld(homeWorld) || !VerifyPlayerName(name.Span))
|
||||||
return ActorIdentifier.Invalid;
|
return ActorIdentifier.Invalid;
|
||||||
|
|
||||||
return new ActorIdentifier(IdentifierType.Player, ObjectKind.Player, homeWorld, 0, name);
|
return new ActorIdentifier(IdentifierType.Player, ObjectKind.Player, homeWorld, 0, name);
|
||||||
|
|
@ -230,26 +233,25 @@ public partial class ActorManager
|
||||||
|
|
||||||
public ActorIdentifier CreateOwned(ByteString ownerName, ushort homeWorld, ObjectKind kind, uint dataId)
|
public ActorIdentifier CreateOwned(ByteString ownerName, ushort homeWorld, ObjectKind kind, uint dataId)
|
||||||
{
|
{
|
||||||
if (!VerifyWorld(homeWorld) || !VerifyPlayerName(ownerName) || !VerifyOwnedData(kind, dataId))
|
if (!VerifyWorld(homeWorld) || !VerifyPlayerName(ownerName.Span) || !VerifyOwnedData(kind, dataId))
|
||||||
return ActorIdentifier.Invalid;
|
return ActorIdentifier.Invalid;
|
||||||
|
|
||||||
return new ActorIdentifier(IdentifierType.Owned, kind, homeWorld, dataId, ownerName);
|
return new ActorIdentifier(IdentifierType.Owned, kind, homeWorld, dataId, ownerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Checks SE naming rules. </summary>
|
/// <summary> Checks SE naming rules. </summary>
|
||||||
private static bool VerifyPlayerName(ByteString name)
|
public static bool VerifyPlayerName(ReadOnlySpan<byte> name)
|
||||||
{
|
{
|
||||||
// Total no more than 20 characters + space.
|
// Total no more than 20 characters + space.
|
||||||
if (name.Length is < 5 or > 21)
|
if (name.Length is < 5 or > 21)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var split = name.Split((byte)' ');
|
|
||||||
|
|
||||||
// Forename and surname, no more spaces.
|
// Forename and surname, no more spaces.
|
||||||
if (split.Count != 2)
|
var splitIndex = name.IndexOf((byte)' ');
|
||||||
|
if (splitIndex < 0 || name[(splitIndex + 1)..].IndexOf((byte)' ') >= 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
static bool CheckNamePart(ByteString part)
|
static bool CheckNamePart(ReadOnlySpan<byte> part)
|
||||||
{
|
{
|
||||||
// Each name part at least 2 and at most 15 characters.
|
// Each name part at least 2 and at most 15 characters.
|
||||||
if (part.Length is < 2 or > 15)
|
if (part.Length is < 2 or > 15)
|
||||||
|
|
@ -260,27 +262,83 @@ public partial class ActorManager
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Every other symbol needs to be lowercase letter, hyphen or apostrophe.
|
// Every other symbol needs to be lowercase letter, hyphen or apostrophe.
|
||||||
if (part.Skip(1).Any(c => c != (byte)'\'' && c != (byte)'-' && c is < (byte)'a' or > (byte)'z'))
|
var last = (byte)'\0';
|
||||||
return false;
|
for (var i = 1; i < part.Length; ++i)
|
||||||
|
{
|
||||||
|
var current = part[i];
|
||||||
|
if (current is not ((byte)'\'' or (byte)'-' or (>= (byte)'a' and <= (byte)'z')))
|
||||||
|
return false;
|
||||||
|
|
||||||
var hyphens = part.Split((byte)'-');
|
// Hyphens can not be used in succession, after or before apostrophes or as the last symbol.
|
||||||
// Apostrophes can not be used in succession, after or before apostrophes.
|
if (last is (byte)'\'' && current is (byte)'-')
|
||||||
return !hyphens.Any(p => p.Length == 0 || p[0] == (byte)'\'' || p.Last() == (byte)'\'');
|
return false;
|
||||||
|
if (last is (byte)'-' && current is (byte)'-' or (byte)'\'')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
last = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
return part[^1] != (byte)'-';
|
||||||
}
|
}
|
||||||
|
|
||||||
return CheckNamePart(split[0]) && CheckNamePart(split[1]);
|
return CheckNamePart(name[..splitIndex]) && CheckNamePart(name[(splitIndex + 1)..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Checks SE naming rules. </summary>
|
||||||
|
public static bool VerifyPlayerName(ReadOnlySpan<char> name)
|
||||||
|
{
|
||||||
|
// Total no more than 20 characters + space.
|
||||||
|
if (name.Length is < 5 or > 21)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Forename and surname, no more spaces.
|
||||||
|
var splitIndex = name.IndexOf(' ');
|
||||||
|
if (splitIndex < 0 || name[(splitIndex + 1)..].IndexOf(' ') >= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
static bool CheckNamePart(ReadOnlySpan<char> part)
|
||||||
|
{
|
||||||
|
// Each name part at least 2 and at most 15 characters.
|
||||||
|
if (part.Length is < 2 or > 15)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Each part starting with capitalized letter.
|
||||||
|
if (part[0] is < 'A' or > 'Z')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Every other symbol needs to be lowercase letter, hyphen or apostrophe.
|
||||||
|
var last = '\0';
|
||||||
|
for (var i = 1; i < part.Length; ++i)
|
||||||
|
{
|
||||||
|
var current = part[i];
|
||||||
|
if (current is not ('\'' or '-' or (>= 'a' and <= 'z')))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Hyphens can not be used in succession, after or before apostrophes or as the last symbol.
|
||||||
|
if (last is '\'' && current is '-')
|
||||||
|
return false;
|
||||||
|
if (last is '-' && current is '-' or '\'')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
last = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
return part[^1] != '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
return CheckNamePart(name[..splitIndex]) && CheckNamePart(name[(splitIndex + 1)..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Checks if the world is a valid public world or ushort.MaxValue (any world). </summary>
|
/// <summary> Checks if the world is a valid public world or ushort.MaxValue (any world). </summary>
|
||||||
private bool VerifyWorld(ushort worldId)
|
public bool VerifyWorld(ushort worldId)
|
||||||
=> Worlds.ContainsKey(worldId);
|
=> Worlds.ContainsKey(worldId);
|
||||||
|
|
||||||
/// <summary> Verify that the enum value is a specific actor and return the name if it is. </summary>
|
/// <summary> Verify that the enum value is a specific actor and return the name if it is. </summary>
|
||||||
private static bool VerifySpecial(SpecialActor actor)
|
public static bool VerifySpecial(SpecialActor actor)
|
||||||
=> actor is >= SpecialActor.CharacterScreen and <= SpecialActor.Portrait;
|
=> actor is >= SpecialActor.CharacterScreen and <= SpecialActor.Portrait;
|
||||||
|
|
||||||
/// <summary> Verify that the object index is a valid index for an NPC. </summary>
|
/// <summary> Verify that the object index is a valid index for an NPC. </summary>
|
||||||
private static bool VerifyIndex(ushort index)
|
public static bool VerifyIndex(ushort index)
|
||||||
{
|
{
|
||||||
return index switch
|
return index switch
|
||||||
{
|
{
|
||||||
|
|
@ -291,7 +349,7 @@ public partial class ActorManager
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Verify that the object kind is a valid owned object, and the corresponding data Id. </summary>
|
/// <summary> Verify that the object kind is a valid owned object, and the corresponding data Id. </summary>
|
||||||
private bool VerifyOwnedData(ObjectKind kind, uint dataId)
|
public bool VerifyOwnedData(ObjectKind kind, uint dataId)
|
||||||
{
|
{
|
||||||
return kind switch
|
return kind switch
|
||||||
{
|
{
|
||||||
|
|
@ -302,7 +360,7 @@ public partial class ActorManager
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool VerifyNpcData(ObjectKind kind, uint dataId)
|
public bool VerifyNpcData(ObjectKind kind, uint dataId)
|
||||||
=> kind switch
|
=> kind switch
|
||||||
{
|
{
|
||||||
ObjectKind.BattleNpc => BNpcs.ContainsKey(dataId),
|
ObjectKind.BattleNpc => BNpcs.ContainsKey(dataId),
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ internal class ObjectIdentification : IObjectIdentifier
|
||||||
var (begin, _) = FindIndexRange((List<(ulong, IReadOnlyList<Item>)>)_weapons,
|
var (begin, _) = FindIndexRange((List<(ulong, IReadOnlyList<Item>)>)_weapons,
|
||||||
((ulong)setId << 32) | ((ulong)weaponType << 16) | variant,
|
((ulong)setId << 32) | ((ulong)weaponType << 16) | variant,
|
||||||
0xFFFFFFFFFFFF);
|
0xFFFFFFFFFFFF);
|
||||||
return begin >= 0 ? _weapons[begin].Item2 : null;
|
return begin >= 0 ? _weapons[begin].Item2 : Array.Empty<Item>();
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 99f3b4f3c7fd9f83b0741089e8808566a0bbdde5
|
Subproject commit 81539a968f6bfbb78c34ae1094cce88ae4c9ac88
|
||||||
|
|
@ -10,6 +10,7 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Dalamud.Game.ClientState.Objects.Enums;
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.String;
|
||||||
|
|
||||||
namespace Penumbra.Collections;
|
namespace Penumbra.Collections;
|
||||||
|
|
||||||
|
|
@ -20,20 +21,34 @@ public class IndividualCollections
|
||||||
public readonly Dictionary< ActorIdentifier, ModCollection > Individuals;
|
public readonly Dictionary< ActorIdentifier, ModCollection > Individuals;
|
||||||
|
|
||||||
public IndividualCollections( ActorManager manager )
|
public IndividualCollections( ActorManager manager )
|
||||||
{
|
=> _manager = manager;
|
||||||
_manager = manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanAdd( IdentifierType type, string name, ushort homeWorld, ObjectKind kind, uint dataId )
|
public bool CanAdd( IdentifierType type, string name, ushort homeWorld, ObjectKind kind, uint dataId )
|
||||||
{
|
{
|
||||||
_manager.
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanAdd( IdentifierType type, string name, ushort homeWorld, ObjectKind kind, IReadOnlyList< uint > dataIds )
|
public bool Add( string displayName, ActorIdentifier identifier, ModCollection collection )
|
||||||
|
=> Add( displayName, identifier, collection, Array.Empty< uint >() );
|
||||||
|
|
||||||
|
public bool Add( string displayName, ActorIdentifier identifier, ModCollection collection, IEnumerable< uint > additionalIds )
|
||||||
{
|
{
|
||||||
|
if( Individuals.ContainsKey( identifier ) )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//var identifiers = additionalIds
|
||||||
|
// .Select( id => CanAdd( identifier.Type, identifier.PlayerName, identifier.HomeWorld, identifier.Kind, id, out var value ) ? value : ActorIdentifier.Invalid )
|
||||||
|
// .Prepend( identifier )
|
||||||
|
// .ToArray();
|
||||||
|
//if( identifiers.Any( i => !i.IsValid || i.DataId == identifier.DataId ) )
|
||||||
|
//{
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class ModCollection
|
public partial class ModCollection
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue