(Feat) Add Animation
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#include "Engine/LocalPlayer.h"
|
||||
#include "GameMapsSettings.h"
|
||||
#include "InputMappingContext.h"
|
||||
#include "KeyboardLayout.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "SessionSubsystem.h"
|
||||
#include "SurvivalUserSettings.h"
|
||||
@@ -233,13 +234,131 @@ void USurvivalGameInstance::RegisterMappableContexts()
|
||||
return;
|
||||
}
|
||||
|
||||
bool bRegisteredAnyContext = false;
|
||||
|
||||
for (const TObjectPtr<UInputMappingContext>& Context : MappableContexts)
|
||||
{
|
||||
if (Context)
|
||||
{
|
||||
bRegisteredAnyContext = true;
|
||||
// Idempotent : le moteur ignore un contexte deja connu, on peut donc
|
||||
// rappeler cette fonction sans precaution.
|
||||
InputSettings->RegisterInputMappingContext(Context);
|
||||
}
|
||||
}
|
||||
|
||||
// APRES l'enregistrement et jamais avant : le profil de touches ne connait un
|
||||
// mapping -- donc sa touche par defaut -- qu'une fois son IMC declare. Appeler
|
||||
// la conversion plus tot la ferait tourner sur un profil vide, sans erreur ni
|
||||
// effet, ce qui est le pire des cas a diagnostiquer.
|
||||
//
|
||||
// UNE SEULE FOIS par session, en revanche. Cette fonction est aussi le point
|
||||
// d'entree du rafraichissement de l'onglet Touches, appele apres CHAQUE
|
||||
// remappage : y laisser la conversion reprendrait sa touche au joueur qui a
|
||||
// choisi celle de l'IMC -- la lettre W sur un AZERTY est identique au defaut,
|
||||
// donc indiscernable d'un mapping auquel personne n'a touche.
|
||||
if (bRegisteredAnyContext && !bKeyboardLayoutApplied)
|
||||
{
|
||||
bKeyboardLayoutApplied = true;
|
||||
ApplyKeyboardLayoutToDefaultKeys();
|
||||
}
|
||||
}
|
||||
|
||||
void USurvivalGameInstance::ApplyKeyboardLayoutToDefaultKeys()
|
||||
{
|
||||
const ULocalPlayer* LocalPlayer = GetFirstGamePlayer();
|
||||
if (!LocalPlayer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UEnhancedInputLocalPlayerSubsystem* Subsystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>();
|
||||
UEnhancedInputUserSettings* InputSettings = Subsystem ? Subsystem->GetUserSettings() : nullptr;
|
||||
const UEnhancedPlayerMappableKeyProfile* Profile = InputSettings ? InputSettings->GetActiveKeyProfile() : nullptr;
|
||||
|
||||
if (!Profile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// On COLLECTE avant d'appliquer, au lieu de mapper au fil de la lecture.
|
||||
// MapPlayerKey ecrit dans les memes lignes que celles qu'on parcourt : muter un
|
||||
// conteneur pendant son iteration invalide les iterateurs des que le stockage
|
||||
// est reorganise. Le bug qui en sort est intermittent et ne ressemble a rien.
|
||||
struct FPendingRemap
|
||||
{
|
||||
FName MappingName;
|
||||
EPlayerMappableKeySlot Slot;
|
||||
FKey LayoutKey;
|
||||
};
|
||||
|
||||
TArray<FPendingRemap> PendingRemaps;
|
||||
|
||||
for (const TPair<FName, FKeyMappingRow>& Row : Profile->GetPlayerMappingRows())
|
||||
{
|
||||
for (const FPlayerKeyMapping& Mapping : Row.Value.Mappings)
|
||||
{
|
||||
// Le joueur a deja choisi cette touche : son choix fait autorite, meme
|
||||
// s'il est incoherent avec sa disposition. C'est aussi ce qui rend la
|
||||
// fonction idempotente -- notre propre conversion compte comme un choix
|
||||
// des qu'elle est posee, donc on ne repasse jamais dessus.
|
||||
if (Mapping.IsCustomized())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const FKey DefaultKey = Mapping.GetDefaultKey();
|
||||
const FKey LayoutKey = KeyboardLayout::RemapKeyToActiveLayout(DefaultKey);
|
||||
|
||||
// Clavier QWERTY, touche insensible a la disposition, ou manette : la
|
||||
// conversion rend la touche d'origine et il n'y a rien a ecrire. Sans ce
|
||||
// test on poserait une surcharge identique au defaut sur chaque mapping,
|
||||
// et "Reinitialiser" n'aurait plus rien a reinitialiser.
|
||||
if (LayoutKey == DefaultKey)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PendingRemaps.Add({ Row.Key, Mapping.GetSlot(), LayoutKey });
|
||||
}
|
||||
}
|
||||
|
||||
// Journalise AVANT de sortir, et donc meme quand il n'y a rien a faire. C'est
|
||||
// la seule trace lisible quand un testeur signale des touches inattendues, et
|
||||
// le cas "0 touche" est justement celui qu'il faut pouvoir distinguer du
|
||||
// silence : sans cette ligne, un clavier QWERTY et un systeme qui n'a pas
|
||||
// tourne du tout produisent exactement le meme log, c'est-a-dire aucun.
|
||||
//
|
||||
// Un KLID se lit en deux temps : "0000040C" est un AZERTY francais, "00000409"
|
||||
// un QWERTY US. Un utilisateur francais sur clavier QWERTY rend bien 00000409,
|
||||
// parce que c'est la DISPOSITION qui est journalisee, pas la langue -- et c'est
|
||||
// exactement la distinction sur laquelle une detection par pays se tromperait.
|
||||
UE_LOG(LogTemp, Log, TEXT("USurvivalGameInstance : disposition clavier [%s], %d touche(s) a traduire depuis le QWERTY de reference."),
|
||||
*KeyboardLayout::GetActiveLayoutId(), PendingRemaps.Num());
|
||||
|
||||
if (PendingRemaps.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (const FPendingRemap& Remap : PendingRemaps)
|
||||
{
|
||||
FMapPlayerKeyArgs Args;
|
||||
Args.MappingName = Remap.MappingName;
|
||||
Args.Slot = Remap.Slot;
|
||||
Args.NewKey = Remap.LayoutKey;
|
||||
|
||||
FGameplayTagContainer FailureReason;
|
||||
InputSettings->MapPlayerKey(Args, FailureReason);
|
||||
|
||||
if (!FailureReason.IsEmpty())
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("USurvivalGameInstance : conversion de '%s' vers '%s' refusee (%s)."),
|
||||
*Remap.MappingName.ToString(), *Remap.LayoutKey.ToString(), *FailureReason.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
// Pousse les surcharges dans les contextes deja actifs : le pawn n'a rien a
|
||||
// rebrancher, les touches sont bonnes des la premiere image.
|
||||
InputSettings->ApplySettings();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user