2V3-b: click on the ground to walk; read the terrain attribute map
CScreen::SetCursorPosition and CPythonGraphic::SetCursorPosition are the 40250 bodies, so RenderGame builds the pick ray under the cursor each frame. CPythonBackground::GetPickingPoint* march that ray as CMapOutdoor::__PickTerrainHeight does, against the native CMapManager height (PR_FLOAT_TO_INT's x87 rounding becomes floor); object picking waits for CMapOutdoor. CMapManager::isAttrOn reads the packed <map>/<xxxyyy>/attr.atr as CMapOutdoor::isAttrOn + CTerrain::isAttrOn do, and CheckAdvancing with its collision checkers is verbatim (no map objects are registered yet). All of this stays in the pending/platform layer and is marked ADAPTED. port.login_flow clicks the ground below the actor after the key walk. The actor walks to the picked point (334 cm offline), and the fake server sees FUNC_MOVE, then FUNC_WAIT. It also checks that the actor's cell is free and that its terrain block has blocked cells. port.login_live against the real server passed (key 133 cm, click 296 cm), and python_game_render_test.sh passes offline. MT_TEST_MODE=python_ui now adds the 3D surface, so the port route can be played by hand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ff0983d3c8
commit
8b4700f008
@@ -48,6 +48,7 @@
|
||||
#include "UserInterface/StdAfx.h"
|
||||
#include "UserInterface/PythonCharacterManager.h"
|
||||
#include "UserInterface/InstanceBase.h"
|
||||
#include "UserInterface/PythonBackground.h"
|
||||
#include "EterGrnLib/StdAfx.h"
|
||||
#include "EterGrnLib/LODController.h"
|
||||
#include "EterGrnLib/ModelInstance.h"
|
||||
@@ -413,6 +414,54 @@ int main(int argc, char** argv)
|
||||
for (const auto& e : m)
|
||||
std::printf("port_login_flow_test: %s\n", e.c_str());
|
||||
}
|
||||
|
||||
// The terrain attribute map (attr.atr) under the actor: CInstanceBase's block/water/ban-PK checks read it
|
||||
// through CPythonBackground::isAttrOn. The actor stands on a free cell; its 256x256 tile has blocked cells.
|
||||
if (main_instance)
|
||||
{
|
||||
TPixelPosition here = {};
|
||||
main_instance->NEW_GetPixelPosition(&here);
|
||||
CPythonBackground& bg = CPythonBackground::Instance();
|
||||
CHECK(!bg.isAttrOn(here.x, here.y, CTerrainImpl::ATTRIBUTE_BLOCK));
|
||||
const int tx = int(here.x) / CTerrainImpl::TERRAIN_XSIZE * CTerrainImpl::TERRAIN_XSIZE;
|
||||
const int ty = int(here.y) / CTerrainImpl::TERRAIN_YSIZE * CTerrainImpl::TERRAIN_YSIZE;
|
||||
int blocked = 0;
|
||||
for (int y = 0; y < CTerrainImpl::TERRAIN_YSIZE; y += CTerrainImpl::HALF_CELLSCALE)
|
||||
for (int x = 0; x < CTerrainImpl::TERRAIN_XSIZE; x += CTerrainImpl::HALF_CELLSCALE)
|
||||
blocked += bg.isAttrOn(tx + x, ty + y, CTerrainImpl::ATTRIBUTE_BLOCK) ? 1 : 0;
|
||||
std::printf("port_login_flow_test: %d blocked attribute cells in the actor's terrain\n", blocked);
|
||||
CHECK(blocked > 0);
|
||||
}
|
||||
|
||||
// 8. (批次 2V3) Click-to-move: a left click on the ground below the actor reaches game.GameWindow's
|
||||
// OnMouseLeftButtonDown → player.SetMouseState(MBT_LEFT, MBS_PRESS); CPythonPlayer picks the ground
|
||||
// through the cursor ray (CScreen::SetCursorPosition → CPythonBackground::GetPickingPoint) and the
|
||||
// actor walks to it, sending CG_MOVE FUNC_MOVE, then FUNC_WAIT on arrival.
|
||||
const size_t moves_before = server ? server->Events().size() : 0;
|
||||
if (main_instance)
|
||||
main_instance->NEW_GetPixelPosition(&start);
|
||||
PythonBoot::UIMouseButton(1, true, 400, 520);
|
||||
pump_until(0.1, [] { return false; });
|
||||
PythonBoot::UIMouseButton(1, false, 400, 520);
|
||||
CHECK(main_instance && pump_until(3, [&] { return walked() > 100.0f; }));
|
||||
CHECK(main_instance && pump_until(5, [&] { return !main_instance->IsWalking(); }));
|
||||
std::printf("port_login_flow_test: click walked %.0f cm\n", main_instance ? walked() : 0.0f);
|
||||
if (server)
|
||||
{
|
||||
auto click_moves = [&] {
|
||||
std::vector<std::string> out;
|
||||
const auto events = server->Events();
|
||||
for (size_t i = moves_before; i < events.size(); ++i)
|
||||
if (events[i].rfind("game2:move ", 0) == 0)
|
||||
out.push_back(events[i]);
|
||||
return out;
|
||||
};
|
||||
CHECK(pump_until(2, [&] { auto m = click_moves(); return m.size() >= 2 && m.back().rfind("game2:move 0 ", 0) == 0; }));
|
||||
const auto m = click_moves();
|
||||
CHECK(!m.empty() && m.front().rfind("game2:move 1 0 ", 0) == 0);
|
||||
for (const auto& e : m)
|
||||
std::printf("port_login_flow_test: %s\n", e.c_str());
|
||||
}
|
||||
}
|
||||
if (server)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user