Group level edits across inspector and canvas gestures, preserve legacy maps, and expose opt-in switch/key door bindings without changing wire layouts. Refresh studio and pause UI with UE5-inspired surfaces and content drawer. Verify 162 editor and 307 ASM checks plus renderer parity.
106 lines
6.7 KiB
C++
106 lines
6.7 KiB
C++
static void RunStudioEditorChecks() {
|
||
EditorApp app;
|
||
app.LoadLevel("../assets/map.dat");
|
||
auto original=app.CaptureSnapshot();
|
||
auto before=original;
|
||
app.RecordLevelEdit(before,71);
|
||
Check(app.undoStack.empty(),"selection-only gesture creates no undo entry");
|
||
app.playerStartX=7;
|
||
app.RecordLevelEdit(before,71);
|
||
before=app.CaptureSnapshot(); app.playerStartX=8; app.RecordLevelEdit(before,71);
|
||
Check(app.undoStack.size()==1,"continuous inspector gesture creates exactly one snapshot");
|
||
app.RecordLevelEdit(app.CaptureSnapshot(),0);
|
||
before=app.CaptureSnapshot(); app.floorColor=0; app.RecordLevelEdit(before,72);
|
||
Check(app.undoStack.size()==2,"next property edit gets an independent snapshot");
|
||
app.Undo(); Check(app.playerStartX==8 && app.floorColor==original.floorColor,"undo palette preserves preceding transform");
|
||
app.Undo(); Check(EditorApp::SameLevel(app.CaptureSnapshot(),original),"undo continuous transform restores initial state");
|
||
app.Redo(); app.Redo(); Check(app.playerStartX==8 && app.floorColor==0,"redo restores both authored edits");
|
||
app.Undo(); before=app.CaptureSnapshot(); app.ceilingColor=123; app.RecordLevelEdit(before,0);
|
||
Check(app.redoStack.empty(),"new edit after undo invalidates redo branch");
|
||
|
||
before=app.CaptureSnapshot();
|
||
app.sprites[0].x+=10; app.sprites[0].scale=131072; app.sprites[0].textureId=13;
|
||
SetSpriteEntityData(app.sprites[0],ENTITY_ARCHETYPE_GUARD,55,3,8);
|
||
app.transitions[0].targetSpawnX=9; app.transitions[0].targetAngle=128;
|
||
strcpy_s(app.transitions[0].targetMap,"other.dat");
|
||
app.cutscene.flags=CUTSCENE_AUTOPLAY;
|
||
app.RecordLevelEdit(before,0);
|
||
app.draggingLightRadiusIdx=2; app.strokeSnapshotTaken=true; app.Undo();
|
||
Check(EditorApp::SameLevel(app.CaptureSnapshot(),before),"snapshot restores sprite parameters portal names and cutscene flags together");
|
||
Check(app.draggingLightRadiusIdx==-1 && !app.strokeSnapshotTaken,"undo cancels light-radius drag and paint stroke");
|
||
for(int i=0;i<80;++i) {before=app.CaptureSnapshot(); app.floorColor=i+1; app.RecordLevelEdit(before,0);}
|
||
Check(app.undoStack.size()==64,"history remains bounded to sixty-four snapshots");
|
||
|
||
BinaryLevel level; std::string error;
|
||
ReadLevelFile("../assets/map.dat",level,error);
|
||
level.cells[10*32+10]=CELL_DOOR;
|
||
SetSwitchDoor(level.sprites[0],10,10,true);
|
||
Check(ValidateLevel(level,error) && HasSwitchDoor(level.sprites[0]),"switch binding uses existing v5 sprite bytes");
|
||
level.cells[10*32+10]=CELL_EMPTY;
|
||
Check(!ValidateLevel(level,error),"switch binding cannot target a non-door cell");
|
||
level.cells[10*32+10]=CELL_DOOR;
|
||
level.sprites.push_back(level.sprites[0]);
|
||
Check(!ValidateLevel(level,error),"duplicate door bindings are rejected");
|
||
level.sprites.pop_back(); level.sprites[0].flags|=0x20000000;
|
||
Check(!ValidateLevel(level,error),"out-of-bounds switch target is rejected");
|
||
|
||
// Drive actual ImGui inspector controls, not a duplicate model of UI edits.
|
||
ImGui::CreateContext();
|
||
auto& io=ImGui::GetIO(); io.IniFilename=nullptr; io.DisplaySize=ImVec2(1400,1000); io.DeltaTime=1.0f/60;
|
||
unsigned char* pixels; int w,h; io.Fonts->GetTexDataAsRGBA32(&pixels,&w,&h);
|
||
app.LoadLevel("../assets/map.dat"); app.selectedSpriteIdx=-1; app.selectedTransitionIdx=-1;
|
||
auto frame=[&](const char* target, const char* text) {
|
||
if(text) io.AddInputCharactersUTF8(text);
|
||
ImGui::NewFrame();
|
||
ImGui::SetNextWindowPos(ImVec2(0,0)); ImGui::SetNextWindowSize(ImVec2(600,950));
|
||
ImGui::Begin("InspectorTest",nullptr,ImGuiWindowFlags_NoSavedSettings);
|
||
if(target) {
|
||
auto& g=*ImGui::GetCurrentContext();
|
||
g.NavActivateId=g.NavActivateDownId=ImGui::GetID(target); g.NavActivateFlags=ImGuiActivateFlags_PreferInput;
|
||
}
|
||
app.RenderInspector();
|
||
ImGui::End(); ImGui::Render();
|
||
};
|
||
frame(nullptr,nullptr);
|
||
frame("Spawn X",nullptr);
|
||
frame(nullptr,"7");
|
||
io.AddKeyEvent(ImGuiKey_Enter,true); frame(nullptr,nullptr);
|
||
io.AddKeyEvent(ImGuiKey_Enter,false); frame(nullptr,nullptr);
|
||
Check(app.playerStartX==7 && app.undoStack.size()==1,"real inspector spawn input records original authored state");
|
||
app.Undo(); Check(app.playerStartX==2,"real inspector spawn input can be undone");
|
||
app.Redo(); Check(app.playerStartX==7,"real inspector spawn input can be redone");
|
||
app.selectedSpriteIdx=0;
|
||
frame(nullptr,nullptr);
|
||
auto oldX=app.sprites[0].x; auto count=app.undoStack.size();
|
||
frame("Позиция X",nullptr); frame(nullptr,"6");
|
||
io.AddKeyEvent(ImGuiKey_Enter,true); frame(nullptr,nullptr);
|
||
io.AddKeyEvent(ImGuiKey_Enter,false); frame(nullptr,nullptr);
|
||
Check(app.sprites[0].x==384 && app.undoStack.size()==count+1,"real sprite inspector transform participates in history");
|
||
app.Undo(); Check(app.sprites[0].x==oldX,"real sprite inspector undo restores raw world coordinates");
|
||
app.selectedSpriteIdx=-1; app.selectedTransitionIdx=0;
|
||
auto oldSpawn=app.transitions[0].targetSpawnX; count=app.undoStack.size();
|
||
frame(nullptr,nullptr); frame("Целевой Spawn X",nullptr); frame(nullptr,"11");
|
||
io.AddKeyEvent(ImGuiKey_Enter,true); frame(nullptr,nullptr);
|
||
io.AddKeyEvent(ImGuiKey_Enter,false); frame(nullptr,nullptr);
|
||
Check(app.transitions[0].targetSpawnX==11 && app.undoStack.size()==count+1,"real portal destination input records a transaction");
|
||
app.Undo(); Check(app.transitions[0].targetSpawnX==oldSpawn,"real portal destination undo restores original spawn");
|
||
app.selectedTransitionIdx=-1;
|
||
auto oldPalette=app.CaptureSnapshot(); count=app.undoStack.size();
|
||
frame(nullptr,nullptr); frame("Хоррор",nullptr); frame(nullptr,nullptr);
|
||
Check(app.ceilingColor==0x003B0710 && app.undoStack.size()==count+1,"real environment preset records both colors once");
|
||
app.Undo(); Check(app.ceilingColor==oldPalette.ceilingColor && app.floorColor==oldPalette.floorColor,
|
||
"real environment preset undo restores ceiling and floor");
|
||
app.viewportMode=2; app.showCutsceneTimeline=false;
|
||
auto uiBefore=app.CaptureSnapshot(); count=app.undoStack.size();
|
||
for (float width : {1000.0f,1360.0f,1920.0f}) {
|
||
io.DisplaySize=ImVec2(width,840);
|
||
app.contentDrawerOpen=true;
|
||
ImGui::NewFrame(); app.RenderUI(); ImGui::Render();
|
||
ImGui::NewFrame(); app.RenderUI(); ImGui::Render();
|
||
}
|
||
Check(ImGui::GetDrawData()->TotalVtxCount>0 && app.editDepth==0,
|
||
"full workspace and content drawer render at supported window widths");
|
||
Check(EditorApp::SameLevel(uiBefore,app.CaptureSnapshot()) && app.undoStack.size()==count,
|
||
"workspace layout and content browsing do not dirty authored history");
|
||
ImGui::DestroyContext();
|
||
}
|