2V2-e.2: Godot consumer of the 3D draw commands, offline screenshot
python_3d_surface.gd turns RenderGame's recorded draws into meshes under a camera read back from SetPerspective; textures come from the 40250 packs. GetFarClip and the CMapManager ctor ported verbatim. Until the environment is ported, lit draws with no light/ambient are shown unshaded (stand-in). script/python_game_render_test.sh runs system.py login -> select -> game against port_fake_login_server (or --live via MT_LIVE_*) and screenshots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5bfa13c5cc
commit
1fe8a4b643
@@ -12,9 +12,12 @@ auto CMapManager::GetHeight(float, float) -> float
|
||||
return mt_platform_stub_return<float>();
|
||||
}
|
||||
|
||||
CMapManager::CMapManager()
|
||||
CMapManager::CMapManager() : mc_pcurEnvironmentData(NULL)
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
m_pkMap = NULL;
|
||||
m_isSoftwareTilingEnableReserved=false;
|
||||
|
||||
// Initialize();
|
||||
}
|
||||
|
||||
CMapManager::~CMapManager()
|
||||
|
||||
@@ -76,6 +76,9 @@ auto CPythonBackground::GetWarpMapName() -> const char *
|
||||
CPythonBackground::CPythonBackground()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
// PORT: the one member the stand-in's ported GetFarClip reads (PythonBackground.cpp:210); the
|
||||
// view distance sets and Initialize() come with the unit.
|
||||
m_eViewDistanceNum=0;
|
||||
}
|
||||
|
||||
CPythonBackground::~CPythonBackground()
|
||||
@@ -95,10 +98,20 @@ auto CPythonBackground::GetPickingPointWithRayOnlyTerrain(const CRay &, D3DXVECT
|
||||
return mt_platform_stub_return<bool>();
|
||||
}
|
||||
|
||||
auto CPythonBackground::GetFarClip() -> float
|
||||
// 40250 PythonBackground.cpp:173 (CPythonApplication::RenderGame's SetPerspective); m_pkMap stays null
|
||||
// until the map is ported, so this is the 50000 far clip.
|
||||
float CPythonBackground::GetFarClip()
|
||||
{
|
||||
MT_PLATFORM_STUB();
|
||||
return mt_platform_stub_return<float>();
|
||||
if (!m_pkMap)
|
||||
return 50000.0f;
|
||||
|
||||
if (m_ViewDistanceSet[m_eViewDistanceNum].m_fFarClip==0.0f)
|
||||
{
|
||||
TraceError("CPythonBackground::GetFarClip m_eViewDistanceNum=%d", m_eViewDistanceNum);
|
||||
m_ViewDistanceSet[m_eViewDistanceNum].m_fFarClip=25600.0f;
|
||||
}
|
||||
|
||||
return m_ViewDistanceSet[m_eViewDistanceNum].m_fFarClip;
|
||||
}
|
||||
|
||||
auto CPythonBackground::Render() -> void
|
||||
|
||||
@@ -219,6 +219,12 @@ if(BUILD_TESTING AND CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME)
|
||||
add_test(NAME port.login_flow
|
||||
COMMAND $<TARGET_FILE:port_login_flow_test> ${MT_40250_CLIENT} ${MT_PYTHON_STDLIB_ZIP})
|
||||
set_tests_properties(port.login_flow PROPERTIES SKIP_RETURN_CODE 77)
|
||||
# 2V2-e: the same fake server as a process, for the Godot-driven render run
|
||||
# (script/python_game_render_test.sh).
|
||||
add_executable(port_fake_login_server ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_fake_login_server_main.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_login_flow_server.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../net/classic/classic_cipher.cpp)
|
||||
target_link_libraries(port_fake_login_server PRIVATE port_platform)
|
||||
# 2V1-e: the same path against a live 40250 server; skipped unless MT_LIVE_* is set (see the test).
|
||||
add_test(NAME port.login_live
|
||||
COMMAND $<TARGET_FILE:port_login_flow_test> ${MT_40250_CLIENT} ${MT_PYTHON_STDLIB_ZIP} live)
|
||||
|
||||
@@ -9,12 +9,18 @@
|
||||
// unit, which has to stay compilable next to godot-cpp.
|
||||
#include "platform/ScriptLib/PythonBoot.h"
|
||||
#include "platform/EterLib/UIRenderCommands.h"
|
||||
#include "platform/EterLib/RenderCommands3D.h"
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#include <godot_cpp/classes/image.hpp>
|
||||
#include <godot_cpp/variant/dictionary.hpp>
|
||||
#include <godot_cpp/variant/packed_byte_array.hpp>
|
||||
#include <godot_cpp/variant/packed_color_array.hpp>
|
||||
#include <godot_cpp/variant/packed_float32_array.hpp>
|
||||
#include <godot_cpp/variant/packed_int32_array.hpp>
|
||||
#include <godot_cpp/variant/packed_vector2_array.hpp>
|
||||
#include <godot_cpp/variant/packed_vector3_array.hpp>
|
||||
|
||||
using namespace godot;
|
||||
|
||||
@@ -117,6 +123,107 @@ Ref<Image> Metin2PythonHost::memory_texture(const String &name, int64_t known_re
|
||||
return Image::create_from_data(texture.width, texture.height, false, Image::FORMAT_RGBA8, rgba);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
PackedFloat32Array floats(const float *values, int count) {
|
||||
PackedFloat32Array out;
|
||||
out.resize(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
out[i] = values[i];
|
||||
return out;
|
||||
}
|
||||
|
||||
Color argb_color(std::uint32_t argb) {
|
||||
return Color(((argb >> 16) & 255) / 255.0f, ((argb >> 8) & 255) / 255.0f, (argb & 255) / 255.0f,
|
||||
((argb >> 24) & 255) / 255.0f);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Array Metin2PythonHost::render3d_draws() {
|
||||
Array out;
|
||||
for (const Render3DDraw &draw : Render3DDraws()) {
|
||||
Dictionary item;
|
||||
item["world"] = floats(draw.world, 16);
|
||||
item["view"] = floats(draw.view, 16);
|
||||
item["proj"] = floats(draw.proj, 16);
|
||||
item["texture0"] = String::utf8(draw.texture0.c_str());
|
||||
item["texture1"] = String::utf8(draw.texture1.c_str());
|
||||
item["pretransformed"] = draw.pretransformed;
|
||||
item["lines"] = draw.lines;
|
||||
|
||||
PackedVector3Array positions;
|
||||
positions.resize(static_cast<int64_t>(draw.positions.size() / 3));
|
||||
for (int64_t i = 0; i < positions.size(); ++i)
|
||||
positions[i] = Vector3(draw.positions[i * 3], draw.positions[i * 3 + 1], draw.positions[i * 3 + 2]);
|
||||
item["positions"] = positions;
|
||||
if (!draw.rhw.empty())
|
||||
item["rhw"] = floats(draw.rhw.data(), static_cast<int>(draw.rhw.size()));
|
||||
if (!draw.normals.empty()) {
|
||||
PackedVector3Array normals;
|
||||
normals.resize(static_cast<int64_t>(draw.normals.size() / 3));
|
||||
for (int64_t i = 0; i < normals.size(); ++i)
|
||||
normals[i] = Vector3(draw.normals[i * 3], draw.normals[i * 3 + 1], draw.normals[i * 3 + 2]);
|
||||
item["normals"] = normals;
|
||||
}
|
||||
auto uvs = [](const std::vector<float> &values) {
|
||||
PackedVector2Array out;
|
||||
out.resize(static_cast<int64_t>(values.size() / 2));
|
||||
for (int64_t i = 0; i < out.size(); ++i)
|
||||
out[i] = Vector2(values[i * 2], values[i * 2 + 1]);
|
||||
return out;
|
||||
};
|
||||
if (!draw.uv0.empty())
|
||||
item["uv0"] = uvs(draw.uv0);
|
||||
if (!draw.uv1.empty())
|
||||
item["uv1"] = uvs(draw.uv1);
|
||||
if (!draw.diffuse.empty()) {
|
||||
PackedColorArray colors;
|
||||
colors.resize(static_cast<int64_t>(draw.diffuse.size()));
|
||||
for (int64_t i = 0; i < colors.size(); ++i)
|
||||
colors[i] = argb_color(draw.diffuse[i]);
|
||||
item["diffuse"] = colors;
|
||||
}
|
||||
PackedInt32Array indices;
|
||||
indices.resize(static_cast<int64_t>(draw.indices.size()));
|
||||
for (int64_t i = 0; i < indices.size(); ++i)
|
||||
indices[i] = static_cast<int32_t>(draw.indices[i]);
|
||||
item["indices"] = indices;
|
||||
|
||||
item["alpha_blend"] = static_cast<int64_t>(draw.alpha_blend);
|
||||
item["src_blend"] = static_cast<int64_t>(draw.src_blend);
|
||||
item["dest_blend"] = static_cast<int64_t>(draw.dest_blend);
|
||||
item["alpha_test"] = static_cast<int64_t>(draw.alpha_test);
|
||||
item["alpha_ref"] = static_cast<int64_t>(draw.alpha_ref);
|
||||
item["alpha_func"] = static_cast<int64_t>(draw.alpha_func);
|
||||
item["cull_mode"] = static_cast<int64_t>(draw.cull_mode);
|
||||
item["z_enable"] = static_cast<int64_t>(draw.z_enable);
|
||||
item["z_write"] = static_cast<int64_t>(draw.z_write);
|
||||
item["z_func"] = static_cast<int64_t>(draw.z_func);
|
||||
item["lighting"] = static_cast<int64_t>(draw.lighting);
|
||||
item["texture_factor"] = static_cast<int64_t>(draw.texture_factor);
|
||||
item["fog_enable"] = static_cast<int64_t>(draw.fog_enable);
|
||||
item["color_op"] = static_cast<int64_t>(draw.color_op[0]);
|
||||
item["alpha_op"] = static_cast<int64_t>(draw.alpha_op[0]);
|
||||
item["material_diffuse"] = Color(draw.material_diffuse[0], draw.material_diffuse[1],
|
||||
draw.material_diffuse[2], draw.material_diffuse[3]);
|
||||
item["material_ambient"] = Color(draw.material_ambient[0], draw.material_ambient[1],
|
||||
draw.material_ambient[2], draw.material_ambient[3]);
|
||||
item["material_emissive"] = Color(draw.material_emissive[0], draw.material_emissive[1],
|
||||
draw.material_emissive[2], draw.material_emissive[3]);
|
||||
item["light0"] = draw.light0;
|
||||
item["light0_direction"] = Vector3(draw.light0_direction[0], draw.light0_direction[1],
|
||||
draw.light0_direction[2]);
|
||||
item["light0_diffuse"] = Color(draw.light0_diffuse[0], draw.light0_diffuse[1], draw.light0_diffuse[2],
|
||||
draw.light0_diffuse[3]);
|
||||
item["light0_ambient"] = Color(draw.light0_ambient[0], draw.light0_ambient[1], draw.light0_ambient[2],
|
||||
draw.light0_ambient[3]);
|
||||
item["ambient"] = argb_color(draw.ambient);
|
||||
out.push_back(item);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void Metin2PythonHost::stop() {
|
||||
PythonBoot::Stop();
|
||||
}
|
||||
@@ -149,6 +256,7 @@ void Metin2PythonHost::ui_key(int, bool) {}
|
||||
void Metin2PythonHost::ui_update() {}
|
||||
Array Metin2PythonHost::ui_render_commands() { return Array(); }
|
||||
Ref<Image> Metin2PythonHost::memory_texture(const String &, int64_t) { return Ref<Image>(); }
|
||||
Array Metin2PythonHost::render3d_draws() { return Array(); }
|
||||
|
||||
void Metin2PythonHost::stop() {
|
||||
}
|
||||
@@ -171,6 +279,7 @@ void Metin2PythonHost::_bind_methods() {
|
||||
ClassDB::bind_static_method("Metin2PythonHost", D_METHOD("ui_render_commands"), &Metin2PythonHost::ui_render_commands);
|
||||
ClassDB::bind_static_method("Metin2PythonHost", D_METHOD("memory_texture", "name", "known_revision"),
|
||||
&Metin2PythonHost::memory_texture, DEFVAL(-1));
|
||||
ClassDB::bind_static_method("Metin2PythonHost", D_METHOD("render3d_draws"), &Metin2PythonHost::render3d_draws);
|
||||
ClassDB::bind_static_method("Metin2PythonHost", D_METHOD("stop"), &Metin2PythonHost::stop);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,10 @@ public:
|
||||
// The pixels of a "mem:<id>@<revision>" image command (the CGraphicFontTexture glyph pages) as an
|
||||
// RGBA8 Image; null when the texture is gone or its revision is still `known_revision`.
|
||||
static godot::Ref<godot::Image> memory_texture(const godot::String &name, int64_t known_revision);
|
||||
// The 3D draw calls of the last ui_update() (RenderCommands3D.h), one Dictionary each: "world",
|
||||
// "view", "proj" (PackedFloat32Array, D3D row-vector layout), vertex arrays, "indices", "texture0"
|
||||
// and the blend/depth/cull/lighting state.
|
||||
static godot::Array render3d_draws();
|
||||
static void stop();
|
||||
|
||||
protected:
|
||||
|
||||
Reference in New Issue
Block a user