Skip to content

Commit

Permalink
feat: init devtools
Browse files Browse the repository at this point in the history
  • Loading branch information
engsr6982 committed Feb 17, 2025
1 parent bf280ca commit 56fdaa3
Show file tree
Hide file tree
Showing 8 changed files with 409 additions and 12 deletions.
21 changes: 16 additions & 5 deletions src/Command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,18 @@
#include <mc/world/level/GameType.h>



#include "magic_enum.hpp"

#include "pland/Config.h"
#include "pland/GUI.h"
#include "pland/PLand.h"
#include "pland/utils/Utils.h"

#ifdef LD_DEVTOOL
#include "devtools/DevTools.h"
#endif


namespace land {

#define CHECK_TYPE(ori, out, type) \
Expand Down Expand Up @@ -118,13 +122,11 @@ static auto const Operator = [](CommandOrigin const& ori, CommandOutput& out, Op
if (db.isOperator(uid)) {
mc::sendText(out, "{} 已经是管理员,请不要重复添加"_tr(name));
} else {
db.addOperator(uid);
mc::sendText(out, "{} 已经被添加为管理员"_tr(name));
if (db.addOperator(uid)) mc::sendText(out, "{} 已经被添加为管理员"_tr(name));
}
} else {
if (db.isOperator(uid)) {
db.removeOperator(uid);
mc::sendText(out, "{} 已经被移除管理员"_tr(name));
if (db.removeOperator(uid)) mc::sendText(out, "{} 已经被移除管理员"_tr(name));
} else {
mc::sendText(out, "{} 不是管理员,无需移除"_tr(name));
}
Expand Down Expand Up @@ -285,6 +287,15 @@ bool LandCommand::setup() {
.required("data_file")
.execute(Lambda::Import);

#ifdef LD_DEVTOOL
// pland devtool
cmd.overload().text("devtool").execute([](CommandOrigin const& ori, CommandOutput&) {
if (ori.getOriginType() == CommandOriginType::DedicatedServer) {
devtools::show();
}
});
#endif

return true;
}

Expand Down
52 changes: 52 additions & 0 deletions src/devtools/DevTools.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#ifdef LD_DEVTOOL
#include "DevTools.h"
#include "mod/MyMod.h"
#include <thread>


namespace land::devtools {


//---------------------------------------------------------------------------
// Global variables
//---------------------------------------------------------------------------
GLFWwindow* G_Window = nullptr; // 全局窗口指针
ImGui::FileBrowser* G_FileBrowser = nullptr; // 全局文件浏览器指针
std::thread G_RenderThread; // 全局渲染线程指针
std::atomic<bool> G_RenderThreadRunning; // 全局渲染线程是否运行


//---------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------
extern void RenderDevTools(); // RenderDevTools.cc

void init() {
G_RenderThreadRunning = true;
G_RenderThread = std::thread(&RenderDevTools);
}

void show() {
if (G_Window) {
glfwShowWindow(G_Window);
} else {
my_mod::MyMod::getInstance().getSelf().getLogger().error("DevTools window not initialized");
}
}

void hide() {
if (G_Window) glfwHideWindow(G_Window);
}

void destroy() {
if (G_RenderThreadRunning) {
G_RenderThreadRunning = false;
if (G_RenderThread.joinable()) {
G_RenderThread.join();
}
}
}


} // namespace land::devtools
#endif // LD_DEVTOOL
35 changes: 35 additions & 0 deletions src/devtools/DevTools.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once
#include <atomic>
#ifdef LD_DEVTOOL
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#include "imgui_internal.h"
#include <thread>

#include "GL/glew.h"
#include "GLFW/glfw3.h"

#include "imfilebrowser.h"


namespace land::devtools {


extern GLFWwindow* G_Window; // 全局窗口指针
extern ImGui::FileBrowser* G_FileBrowser; // 全局文件浏览器指针
extern std::thread G_RenderThread; // 全局渲染线程指针
extern std::atomic<bool> G_RenderThreadRunning; // 全局渲染线程是否运行

extern void init();

extern void show();

extern void hide();

extern void destroy();


} // namespace land::devtools

#endif // LD_DEVTOOL
206 changes: 206 additions & 0 deletions src/devtools/RenderDevTools.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
#include "GLFW/glfw3.h"
#include "imgui.h"
#ifdef LD_DEVTOOL
#include "devtools/DevTools.h"
#include "mod/MyMod.h"
#include "pland/Global.h"


namespace land::devtools {

//---------------------------------------------------------------------------
// 全局处理器
//---------------------------------------------------------------------------
void HandleGlfwError(int error, const char* description) {
my_mod::MyMod::getInstance().getSelf().getLogger().error("GLFW Error: {}: {}", error, description);
}

void HandleWindowClose(GLFWwindow* window) {
glfwSetWindowShouldClose(window, GLFW_FALSE);
hide();
}

//---------------------------------------------------------------------------
// 预声明
//---------------------------------------------------------------------------
namespace internal {
extern void ShowAboutWindow(bool* open); // internal/AboutWindow.cc
extern void ShowLandCacheWindow(bool* open); // internal/LandCacheWindow.cc
} // namespace internal

//---------------------------------------------------------------------------
// 全局标志位
//---------------------------------------------------------------------------
bool F_ShowAboutWindow = false;
bool F_ShowLandCacheWindow = false;

void CheckAndHandleFlags() {
if (F_ShowAboutWindow) {
internal::ShowAboutWindow(&F_ShowAboutWindow);
}
if (F_ShowLandCacheWindow) {
internal::ShowLandCacheWindow(&F_ShowLandCacheWindow);
}
}


//---------------------------------------------------------------------------
// 渲染窗口
//---------------------------------------------------------------------------
void RenderDevTools() {
glfwSetErrorCallback(HandleGlfwError); // 设置GLFW错误回调函数
if (!glfwInit()) {
my_mod::MyMod::getInstance().getSelf().getLogger().error("Failed to initialize GLFW");
return;
}

const char* glslVersion = "#version 130";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // 设置OpenGL版本
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // 设置窗口默认不可见

{
float xScale, yScale;
GLFWmonitor* monitor = glfwGetPrimaryMonitor(); // 获取主显示器
glfwGetMonitorContentScale(monitor, &xScale, &yScale); // 获取主显示器缩放比例
G_Window = glfwCreateWindow(
static_cast<int>(600 * xScale),
static_cast<int>(360 * yScale),
"PLand - DevTools",
nullptr,
nullptr
);
if (!G_Window) {
my_mod::MyMod::getInstance().getSelf().getLogger().error("Failed to create GLFW window");
return;
}

glfwSetWindowCloseCallback(G_Window, HandleWindowClose); // 设置窗口关闭回调函数
glfwMakeContextCurrent(G_Window); // 设置当前上下文
glfwSwapInterval(1); // 设置垂直同步

if (glewInit() != GLEW_OK) {
my_mod::MyMod::getInstance().getSelf().getLogger().error("Failed to initialize GLEW");

glfwDestroyWindow(G_Window);
glfwTerminate(); // 终止GLFW
G_Window = nullptr;
return;
}
}

// 初始化ImGui
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // 启用键盘导航
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // 启用Docking
ImGui::StyleColorsDark();

// 初始化ImGui与GLFW的绑定
ImGui_ImplGlfw_InitForOpenGL(G_Window, true); // ImGui <> GLFW
ImGui_ImplOpenGL3_Init(glslVersion); // ImGui <> OpenGL

// 初始化文件浏览器
G_FileBrowser = new ImGui::FileBrowser(
ImGuiFileBrowserFlags_EnterNewFilename | // 允许输入新文件名
ImGuiFileBrowserFlags_CreateNewDir // 允许创建新目录
);
auto dir = my_mod::MyMod::getInstance().getSelf().getDataDir();
G_FileBrowser->SetPwd(dir); // 设置默认目录

// 线程主循环
while (/* !glfwWindowShouldClose(G_Window) && */ G_RenderThreadRunning) {
glfwPollEvents();

if (!glfwGetWindowAttrib(G_Window, GLFW_VISIBLE)) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue; // 窗口不可见时跳过渲染
}

static float prevScale = 0;
float xScale, yScale;
glfwGetWindowContentScale(G_Window, &xScale, &yScale);
if (prevScale != xScale) {
prevScale = xScale;

auto fontPath = "C:/Windows/Fonts/msyh.ttc";
io.Fonts->Clear();
io.Fonts
->AddFontFromFileTTF(fontPath, std::round(15 * xScale), nullptr, io.Fonts->GetGlyphRangesChineseFull());
io.Fonts->Build();
ImGui_ImplOpenGL3_DestroyFontsTexture();
ImGui_ImplOpenGL3_CreateFontsTexture();
auto style = ImGuiStyle();
style.ScaleAllSizes(xScale);
}

// 渲染ImGui
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();

// 创建DockSpace(用于布局)
auto dockspaceId = ImGui::DockSpaceOverViewport();
static std::once_flag firstTime;
std::call_once(firstTime, [&] {
ImGui::DockBuilderDockWindow("领地缓存表", dockspaceId);
ImGui::DockBuilderDockWindow("关于", dockspaceId);
ImGui::DockBuilderFinish(dockspaceId);
});

// 菜单栏
if (ImGui::BeginMainMenuBar()) {
if (ImGui::BeginMenu("文件")) {
ImGui::Text("TODO: 待实现");
ImGui::EndMenu();
}
if (ImGui::BeginMenu("查看")) {
ImGui::MenuItem("领地缓存表", nullptr, &F_ShowLandCacheWindow);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("帮助")) {
ImGui::MenuItem("关于", nullptr, &F_ShowAboutWindow);
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}

CheckAndHandleFlags(); // 处理标志

// 处理文件浏览器
G_FileBrowser->Display();
if (G_FileBrowser->HasSelected()) {
auto path = G_FileBrowser->GetSelected();
// TODO: 处理文件选择
G_FileBrowser->ClearSelected();
}

// 渲染
ImGui::Render();
int displayW;
int displayH;
glfwGetFramebufferSize(G_Window, &displayW, &displayH);
glViewport(0, 0, displayW, displayH);
glClearColor(0.1F, 0.1F, 0.1F, 1.0F);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(G_Window);
}

// 清理资源
delete G_FileBrowser;
G_FileBrowser = nullptr;

ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();

glfwDestroyWindow(G_Window);
G_Window = nullptr;
glfwTerminate();
}


} // namespace land::devtools
#endif // LAND_DEVTOOL
23 changes: 23 additions & 0 deletions src/devtools/internal/AboutWindow.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifdef LD_DEVTOOL
#include "devtools/DevTools.h"


namespace land::devtools::internal {


void ShowAboutWindow(bool* open) {
if (!ImGui::Begin("关于", open)) {
ImGui::End();
return;
}

ImGui::Text("PLand DevTools - 开发者工具");
ImGui::Text("此工具用于快捷调试、查看、修改 PLand 插件的运行状态");
ImGui::Separator();
ImGui::Text("Built with Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
ImGui::End();
}


} // namespace land::devtools::internal
#endif // LD_DEVTOOL
Loading

0 comments on commit 56fdaa3

Please sign in to comment.