Pilot für eine generierte Figur: der Kohlenbeißer g01 kommt als Meshy-Ergebnis in den Port und ersetzt dort das Phase-4-Modell. Eine Figur genügt, um Pipeline, Bild und Leistung zu bewerten; Anatomie, Gesichter und Haare bleiben Künstler-Sculpts oder lizenzierte Packs (Vorgabe vom 1. Oktober). - Meshy-Pipeline unter tools/meshy/: API-Client (meshy.py, Ledger, Schlüssel nie geloggt) und Blender-Generator (build_figure.py) aus den unveränderten Downloads in assets-source/meshy/g01/. Export über den Manifest-Eintrag kohlenbeisser mit "replaces": "g01"; LuneUnitLibraryBuilder hängt die Figur zusätzlich unter der Godot-ID ein. - UV-Material AI_Kohlenbeisser (Familie authored): die Karten der Figur selbst, Lava-Glut aus der Albedo-Alpha (Meshy 7.1 ohne Emission-Map) mit _Glow 1,25. - Schatten ohne Normalen-Versatz (LuneShadowBias, _ShadowNormalScale 0): die UV-Naht-Kopien tragen geknickte Normalen; URP ApplyShadowBias zog helle Nähte durch den Schatten. Die Figur wirft nur mit Tiefen-Bias. - GPU-Batched-Skinning (PlayerSettings.meshDeformation, LuneProjectSetup): 35 Meshy-Kohlenbeißer kosteten mit CPU-Skinning rund 1 ms Haupt- und 1,7 ms Render-Thread je Bild. - LuneBenchmark: -luneBenchmarkRound und -luneBenchmarkArmy (Figuren-Stress). LuneAssetPreview: LUNE_ONLY für Vorher/Nachher, Trefferframe aus der Kontaktzeit des Manifests. FigureViewsTests (Explicit) für die vier Spielmomente der Figur. - Tests: EditMode 29/29, PlayMode 14/14 (6 Explicit), Verify 718/0, Player-Selbsttest 30/30, Kerntests 457/457, Fingerabdrücke unverändert (DCE95C96556F3A1A, 7B8E43AEFC0D60C5). - Leistung (A/B im selben Fenster, 35x g01): Meshy -21 % Mid (109,7 zu 138,8) und -13 % Karte (91,7 zu 105,6) gegenüber Phase-4. GPU-Skinning hebt Mid um 7-27 % und entlastet Haupt- und Render-Thread. Standard-Partie ab Runde 21 ohne g01 im Bild: drei Varianten bis 6 %. - Doku: U5-VISUAL (U5.5), PORT-QA, PORT-STATUS, KNOWN-BEHAVIOR-DIFFERENCES; Bilder screenshots/u5.5/ und u5.5-gpu/, Rohdaten logs/u5.5/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
4.1 KiB
C#
92 lines
4.1 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Linq;
|
|
using Luneraria.Core;
|
|
using Luneraria.View;
|
|
using NUnit.Framework;
|
|
using UnityEngine;
|
|
using UnityEngine.TestTools;
|
|
|
|
namespace Luneraria.UI.Tests
|
|
{
|
|
/// <summary>
|
|
/// U5.5 pilot pictures of one figure in the real game (the Meshy Kohlenbeißer against the
|
|
/// Phase-4 model it replaces): the human seat plays the Glutpakt, buys the starter army and
|
|
/// four Kohlenbeißer (g01) in round 3, and the camera shows them in the planning formation,
|
|
/// in the HUD portrait and in the fight on the own lane, close (zoom 12) and at the benchmark's
|
|
/// lane distance (zoom 22). Like HudViewsTests, commands go straight to the match followed by
|
|
/// the preview rebuild. A capture tool, not part of the suite:
|
|
/// -testFilter "Luneraria.UI.Tests.FigureViewsTests"; LUNE_EVIDENCE names the folder below
|
|
/// docs/port/screenshots (default u5.5/spiel).
|
|
/// </summary>
|
|
[Explicit("Bildwerkzeug: nur gezielt per -testFilter")]
|
|
public sealed class FigureViewsTests
|
|
{
|
|
/// <summary>The human seat 1 plays the Glutpakt, as do the bots of seats 2 and 5.</summary>
|
|
static readonly string[] Bunds = { "wurzelbund", "glutpakt", "glutpakt", "wurzelbund", "wurzelbund", "glutpakt" };
|
|
|
|
string _folder;
|
|
|
|
IEnumerator Shot(HudSession s, string label)
|
|
{
|
|
yield return s.Shot(_folder + label + ".png");
|
|
}
|
|
|
|
static void Send(HudSession s, Command command)
|
|
{
|
|
CommandResult result = s.Match.Submit(HudSession.Human, command);
|
|
Assert.IsTrue(result.Ok, command.Type + ": " + result.Message);
|
|
s.Game.RebuildPreview();
|
|
s.Sync();
|
|
}
|
|
|
|
/// <summary>The own Kohlenbeißer on the field: the one nearest to the enemy (the front of the fight).</summary>
|
|
static LuneUnit Front(HudSession s)
|
|
{
|
|
int team = s.Me.Team;
|
|
return s.Match.Combat.Units.Where(u => u.Alive && u.Team == team && u.Def.Id == "g01")
|
|
.OrderByDescending(u => u.Progress).FirstOrDefault();
|
|
}
|
|
|
|
[UnityTest, Timeout(900000)]
|
|
public IEnumerator Kohlenbeisser()
|
|
{
|
|
string evidence = Environment.GetEnvironmentVariable("LUNE_EVIDENCE");
|
|
_folder = "docs/port/screenshots/" + (string.IsNullOrEmpty(evidence) ? "u5.5/spiel" : evidence) + "/";
|
|
var s = new HudSession();
|
|
yield return s.Open(1920, 1080, seed: 4, bunds: Bunds);
|
|
s.Match.RoundNumber = 3;
|
|
s.Me.Draft.Gold = 900;
|
|
yield return s.Starter();
|
|
s.Leave();
|
|
for (int i = 0; i < 4; i++)
|
|
Send(s, Command.Buy("g01", s.Me.Lane));
|
|
yield return new WaitForSecondsRealtime(.4f);
|
|
RosterEntry first = s.Me.Draft.Roster.First(e => e.TypeId == "g01");
|
|
// The planning preview stands the army in its formation on the own lane.
|
|
LuneUnit waiting = s.View.Preview?.Units.FirstOrDefault(u => u.Team == s.Me.Team && u.Def.Id == "g01");
|
|
Assert.IsNotNull(waiting, "Kohlenbeißer in the planning preview");
|
|
s.Rig.LookAt(waiting.Position, 12f, true);
|
|
yield return new WaitForSecondsRealtime(.5f);
|
|
yield return Shot(s, "01-aufstellung-nah");
|
|
s.Hud.SelectUnit(first.Uid);
|
|
yield return new WaitForSecondsRealtime(.4f);
|
|
yield return Shot(s, "02-portraet");
|
|
s.Hud.ClearSelection();
|
|
s.Game.Key(KeyCode.Space);
|
|
yield return HudSession.Frames(1);
|
|
Assert.AreEqual(LuneMatchRunner.Stage.Combat, s.Runner.Current, "combat of round 3");
|
|
yield return s.Fight(7.0);
|
|
s.Driver.Paused = true;
|
|
LuneUnit front = Front(s);
|
|
Assert.IsNotNull(front, "a Kohlenbeißer on the field");
|
|
s.Rig.LookAt(front.Position, 12f, true);
|
|
yield return new WaitForSecondsRealtime(.5f);
|
|
yield return Shot(s, "03-kampf-nah");
|
|
s.Rig.LookAt(front.Position, 22f, true);
|
|
yield return new WaitForSecondsRealtime(.5f);
|
|
yield return Shot(s, "04-kampf-lane");
|
|
s.Close();
|
|
}
|
|
}
|
|
}
|