Angepasste Garage, verbessertes Icon Asset system, range der türme vorschau beim ziehen

This commit is contained in:
PBM2H25BEB committed 2026-11-05 07:52:47 +01:00
1 parent 5486444dde
commit 5af8655c97
59 files changed
+12079 -457

No files matched your search

@@ -0,0 +1,112 @@
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.EventSystems;
using DepthsOfGreed.HandbookUI;
[InitializeOnLoad]
public static class UINotesValidation
{
static UINotesValidation(){if(SessionState.GetBool("NotesValidation",false))EditorApplication.playModeStateChanged+=Ready;}
public static void Validate(){EditorSceneManager.OpenScene("Assets/Scenes/Tim_Test_UI.unity");SessionState.SetBool("NotesValidation",true);EditorApplication.playModeStateChanged+=Ready;EditorApplication.EnterPlaymode();}
static void Check(bool condition,string message){if(!condition)throw new Exception(message);}
static void Ready(PlayModeStateChange state)
{
if(state!=PlayModeStateChange.EnteredPlayMode)return;SessionState.SetBool("NotesValidation",false);EditorApplication.playModeStateChanged-=Ready;
int stage=0;double due=EditorApplication.timeSinceStartup+1;SupplyBasementController c=null;HandbookStatisticsController stats=null;SupplyContractTestBackend supply=null;UIOverviewTestBackend battle=null;BasementBattleOverview monitor=null;HandbookTowerCatalog catalog=null;float truckX=0;Camera main=null;
EditorApplication.CallbackFunction run=null;run=()=>
{
if(EditorApplication.timeSinceStartup<due)return;
try
{
if(stage==0)
{
c=UnityEngine.Object.FindFirstObjectByType<SupplyBasementController>();main=Camera.main;catalog=AssetDatabase.LoadAssetAtPath<HandbookTowerCatalog>("Assets/HandbookData/TestTurmkatalog.asset");
Check(c.roomView && c.roomView.roomCanvas.renderMode==RenderMode.WorldSpace && c.roomView.roomCanvas.transform.position.x>30,"Room exists outside game area");
Check(c.basementView.activeInHierarchy && !c.roomView.IsVisible && main.enabled,"Room active while hidden, main camera active");
var combat=new CombatDefinition{range=5,minimumRange=1.5f,rotation=RotationMode.Free,attackShape=AttackShape.Cone,coneAngle=60,forwardAngleOffset=90};
Check(AttackRangeGeometry.CoverageAngle(combat)==360,"Rotating cone covers full circle");
Check(!AttackRangeGeometry.CanReach(combat,Vector2.zero,Vector2.up,0) && AttackRangeGeometry.CanReach(combat,Vector2.zero,Vector2.up*3,0),"Minimum range respected");
combat.coverage=AttackCoverage.Sector;Check(AttackRangeGeometry.CanReach(combat,Vector2.zero,Vector2.up*3,0) && !AttackRangeGeometry.CanReach(combat,Vector2.zero,Vector2.right*3,0),"Cone angle and orientation");
combat.coverage=AttackCoverage.Circle;combat.unlimitedRange=true;Check(AttackRangeGeometry.CanReach(combat,Vector2.zero,Vector2.right*1000,0),"Unlimited range has no false maximum");
truckX=c.truck.anchoredPosition.x;
typeof(SupplyBasementController).GetField("truckPauseUntil",System.Reflection.BindingFlags.Instance|System.Reflection.BindingFlags.NonPublic).SetValue(c,0f);
stage=1;due=EditorApplication.timeSinceStartup+.8;
}
else if(stage==1)
{
Check(Mathf.Abs(c.truck.anchoredPosition.x-truckX)>.1f,"Truck preview continues outside basement");
var howitzer=catalog.towers.First(t=>t.id=="ammo_4");Check(howitzer.combat.minimumRange>0,"Howitzer minimum seeded");
var range=UnityEngine.Object.FindFirstObjectByType<AttackRangePreview>(FindObjectsInactive.Include);
c.handbook.Open(0);Check(c.placement.Begin(howitzer,main.WorldToScreenPoint(new Vector3(3.5f,0,0))),"Begin range preview");
Check(range.gameObject.activeInHierarchy && range.minimumEdge.gameObject.activeSelf && range.outerEdge.loop,"Annular placement preview");
stage=2;due=EditorApplication.timeSinceStartup+.7;
}
else if(stage==2)
{
c.placement.Move(main.WorldToScreenPoint(new Vector3(3.5f,0,0)));
Capture(main,c.handbook.GetComponentInParent<Canvas>(),c.GetComponentInParent<Canvas>(),"range-preview.png");c.placement.Cancel();
supply=new GameObject("TEST_ONLY_Supply").AddComponent<SupplyContractTestBackend>();
supply.state.channels=new[]{new SupplyChannelState{kind=SupplyKind.Physical,storage=180,storageCapacity=300,buffer=60,bufferCapacity=100,consumedPerSecond=2}};
supply.state.towers=new[]{new TowerSupplyState{type=catalog.towers.First(t=>t.id=="ammo_0"),instanceId=811,magazine=12,magazineCapacity=30,consumedPerSecond=2}};
c.BindSupplyBackend(supply);c.handbook.Open(1);stats=UnityEngine.Object.FindFirstObjectByType<HandbookStatisticsController>();stats.Refresh();
Check(stats.channelRates[0].text.Contains("120 / min") && stats.channelTimes[0].text.Contains("00:30"),"Measured rates and reserve estimate");
Check(stats.towerNames[0].text.Contains("811") && stats.towerMagazines[0].text=="12 / 30","Per-instance magazine and rate");
stats.SetUnit(false);stats.Refresh();Check(stats.channelRates[0].text.Contains("2 / s"),"Rate unit conversion");
Check(HandbookStatisticsController.FormatRate(null,true)=="—" && HandbookStatisticsController.Estimate(60,0)=="kein Verbrauch","Unknown differs from zero");
stats.SetUnit(true);stats.Refresh();stage=3;due=EditorApplication.timeSinceStartup+.4;
}
else if(stage==3)
{
Capture(main,c.handbook.GetComponentInParent<Canvas>(),c.GetComponentInParent<Canvas>(),"statistics-preview.png");
battle=new GameObject("TEST_ONLY_CombatOverview").AddComponent<UIOverviewTestBackend>();
battle.state.floorName="Ebene 2";battle.state.gates=new[]{new GateOverviewState{direction=GateDirection.North,health=100,maxHealth=100},new GateOverviewState{direction=GateDirection.East,health=80,maxHealth=100,isOpen=true},new GateOverviewState{direction=GateDirection.South,health=100,maxHealth=100},new GateOverviewState{direction=GateDirection.West,health=100,maxHealth=100}};
monitor=UnityEngine.Object.FindFirstObjectByType<BasementBattleOverview>();monitor.BindCombatBackend(battle);monitor.SendMessage("Update");
Check(monitor.gateLabels[0].text.Contains("100") && monitor.gateLabels[1].text.Contains("offen"),"Gate state and open gate separate");
battle.state.gates[0].health=20;battle.state.gates[0].underAttack=true;battle.state.gates[0].hitSequence++;
c.UseLift();stage=4;due=EditorApplication.timeSinceStartup+1.7;
}
else if(stage==4)
{
Check(c.IsInBasement && c.roomView.IsVisible && c.basementView.activeInHierarchy && c.roomView.roomCamera.enabled && main.enabled,"Only view changes, both rooms stay active");
Check(monitor.gateLabels[0].text.Contains("20") && monitor.gateLabels[0].text.Contains("!"),"Gate damage appears in basement");
Check(monitor.gateIcons[0].color.r>monitor.gateIcons[0].color.g,"Critical gate warning color");
var pointer=new PointerEventData(EventSystem.current){position=RectTransformUtility.WorldToScreenPoint(c.roomView.roomCamera,c.connectionButtons[0].transform.position)};
var hits=new List<RaycastResult>();EventSystem.current.RaycastAll(pointer,hits);
Check(hits.Any(hit=>hit.gameObject==c.connectionButtons[0].gameObject),"World-space room buttons receive UI pointer hits");
c.roomView.roomCamera.aspect=2.5f;c.roomView.SendMessage("LateUpdate");
Check(((RectTransform)c.roomView.roomCanvas.transform).rect.width>=2699,"Room expands to wide screen");
Capture(c.roomView.roomCamera,null,c.GetComponentInParent<Canvas>(),"basement-monitor-preview.png");
c.UseLift();stage=5;due=EditorApplication.timeSinceStartup+1.7;
}
else
{
Check(!c.IsInBasement && !c.roomView.roomCamera.enabled && c.basementView.activeInHierarchy && main.enabled,"Return keeps room and main simulation active");
Debug.Log("UI_NOTES_VALIDATION_OK: separate active room, background preview, attack/minimum/sector ranges, statistics, unit conversion and gate alerts.");EditorApplication.update-=run;EditorApplication.Exit(0);
}
}
catch(Exception e){EditorApplication.update-=run;Debug.LogException(e);EditorApplication.Exit(1);}
};EditorApplication.update+=run;
}
static void Capture(Camera camera,Canvas book,Canvas lift,string filename)
{
if(SystemInfo.graphicsDeviceType==GraphicsDeviceType.Null)return;
var target=new RenderTexture(1920,1080,24);target.Create();camera.targetTexture=target;camera.aspect=1920f/1080;
var room=camera.GetComponentInParent<BasementRoomView>();if(room)room.SendMessage("LateUpdate");
int oldMask=camera.cullingMask;camera.cullingMask|=1;
if(book){book.renderMode=RenderMode.ScreenSpaceCamera;book.worldCamera=camera;book.planeDistance=1;book.sortingOrder=100;}
lift.renderMode=RenderMode.ScreenSpaceCamera;lift.worldCamera=camera;lift.planeDistance=.5f;lift.sortingOrder=200;
Canvas.ForceUpdateCanvases();RenderPipeline.SubmitRenderRequest(camera,new UniversalRenderPipeline.SingleCameraRequest{destination=target});
var previous=RenderTexture.active;RenderTexture.active=target;var texture=new Texture2D(1920,1080,TextureFormat.RGB24,false);texture.ReadPixels(new Rect(0,0,1920,1080),0,0);texture.Apply();RenderTexture.active=previous;
var folder=Path.Combine(Path.GetDirectoryName(Application.dataPath),"Logs","HandbookValidation");Directory.CreateDirectory(folder);File.WriteAllBytes(Path.Combine(folder,filename),texture.EncodeToPNG());
UnityEngine.Object.DestroyImmediate(texture);camera.targetTexture=null;camera.cullingMask=oldMask;target.Release();UnityEngine.Object.DestroyImmediate(target);if(book)book.renderMode=RenderMode.ScreenSpaceOverlay;lift.renderMode=RenderMode.ScreenSpaceOverlay;
}
}