找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2370|回复: 5

[X-Plane] 【X-Plane11/12 插件开发】Part 1 - 插件开发介绍

[复制链接]
发表于 2023-5-24 04:22:44 | 显示全部楼层 |阅读模式
本帖最后由 5271081文字狱 于 2023-5-24 14:10 编辑

长文预告!

同步发表于https://zhuanlan.zhihu.com/p/631698120,如有不足之处欢迎指正,共同学习进步。系列教程/笔记目的在于帮助广大飞友以及开发者创造属于自己的插件,亦可协助科研人员进行定制化的仿真模拟等。



相关链接:Part 2 - 数据读取


引言
为什么要进行XP的插件开发:
笔者之前从事过DCS的插件开发,主要用于战术模拟以及飞控测试。但由于DCS的历史性原因,其文档较为老旧且附带大量俄语。做一些简单的插件尚可,但要进行复杂的开发则较为困难。XP作为军民两用航空模拟器的佼佼者,提供了实时计算的空气动力学数据以及最接近真实的飞行模拟体验。笔者的终极目标是想尝试做一些XP周边的软硬件,如家庭座舱,飞控算法测试等。
X-Plane (XP) 提供了官方SDK(Software Development Kit,软件开发包),为插件开发提供了良好的环境、全面的文档。插件使用C++编写,为.xpl后缀的动态链接库形式。其中一些较为著名且常用的插件包括:
  • BetterPushback: 推出
  • BetterMouseYoke: 鼠标摇杆
  • AviTab: 飞行平板
  • DataRefTool / DataRefEditor: 飞行参数查找及修改
  • FlyWithLua: Lua接口插件开发的中间件
其中 FlyWithLua 提供了使用Lua进行插件开发的接口,例如BetterMouseYoke就是基于Lua开发。若您想参考更多有关资料,请查阅:FlyWithLua 。本教程使用XP原生SDK进行插件开发,不会涉及Lua。 用FlyWithLua 的好处(猜测)应该是能更快地开发一些跨平台的插件(由于用Lua编写不涉及系统环境)。

目前了解到的至少需要熟悉以下技能点:
  • 初级C++
  • 熟悉Visual Studio (2017及以上版本)作为C++开发的IDLE
  • 笔者使用Windows 11系统,尚未接触在Linux或者Mac下的插件开发
参考资料:
  • @alirezaghaderi up主的系列课程(youtube)
  • XP官方开发教程


SDK的安装以及第一个插件示例: Hello X-Plane
效果图:


(该插件将建立一个窗口并显示文字)
详细步骤:
预备工作
下载并安装Visual Studio (2017及以上版本),并安装响应Windows下开发C++的工具链。
若使用Mac或者Linux系统,使用最新版本的XCode或者gcc也可,但后续的配置工作可能稍为繁琐。

下载X-Plane官网的SDK开发包
https://developer.x-plane.com/sdk/plugin-sdk-downloads/


注意对应的版本。如果使用XP10则下载XPLM300即可。
下载完成并解压得到以下文件结构:


下载XP官网示例项目
本示例使用的是XP官网提供的“HelloWorld”项目:https://developer.x-plane.com/sdk/plugin-sdk-sample-code/


下载VS版本
解压并打开VS项目
若使用VS2017以上版本则会提示升级工具集,直接升级到最新即可。
打开Hello-World-SDK-3.cpp文件:

构建项目
项目目录中有一个SDK文件夹,实际上就是我们稍早前下载的SDK包。如果没有的话或者版本不对手动添加即可。注意目录。
构建项目前需要先检查配置:右键项目名-属性
使用Debug或者Release配置均可,注意保持配置属性和实际构建时的属性一致。建议直接使用默认的Debug配置。
C/C++-常规-附加包含目录,发现已经配置好了SDK中的头文件的XPLM以及Widgets目录。
接下来,链接器-常规:已经配置好了SDK文件夹中的链接库Libraries-Win(如果是Mac平台就添加Mac文件夹)
此时配置完成,可以重新生成解决方案:
生成的插件在项目的Debug-plugins 文件夹内,里面包含了64平台下的.xpl文件
接下来用正常方法安装插件即可,将生成的Hello-World-SDK-3文件夹放到X-Plane11主目录的Resources-Plugins文件夹下。也可以放置到某机型文件夹的Plugins文件夹内,例如笔者放到了Cessna 172中,这样该插件就只对该特定机型有效。
运行效果
打开XP,选择C172(若采用第二种插件安装方法)
至此安装成功!

代码解释及修改
主题代码一共一百多行,目的是构建.xpl这个动态链接库。其中包含了创建窗口,添加文字等。笔者认为没有必要完全搞懂每一行代码的意思,重要的是能把项目构建流程先搞懂,能够在源代码上稍微修改主要功能即可。
  1. // Downloaded from https://developer.x-plane.com/code-sample/hello-world-sdk-3/

  2. #include "XPLMDisplay.h"
  3. #include "XPLMGraphics.h"
  4. #include <string.h>
  5. #if IBM
  6.     #include <windows.h>
  7. #endif
  8. #if LIN
  9.     #include <GL/gl.h>
  10. #elif __GNUC__
  11.     #include <OpenGL/gl.h>
  12. #else
  13.     #include <GL/gl.h>
  14. #endif

  15. #ifndef XPLM300
  16.     #error This is made to be compiled against the XPLM300 SDK
  17. #endif

  18. // An opaque handle to the window we will create
  19. static XPLMWindowID g_window;

  20. // Callbacks we will register when we create our window
  21. void                draw_hello_world(XPLMWindowID in_window_id, void * in_refcon);
  22. int                 dummy_mouse_handler(XPLMWindowID in_window_id, int x, int y, int is_down, void * in_refcon) { return 0; }
  23. XPLMCursorStatus    dummy_cursor_status_handler(XPLMWindowID in_window_id, int x, int y, void * in_refcon) { return xplm_CursorDefault; }
  24. int                 dummy_wheel_handler(XPLMWindowID in_window_id, int x, int y, int wheel, int clicks, void * in_refcon) { return 0; }
  25. void                dummy_key_handler(XPLMWindowID in_window_id, char key, XPLMKeyFlags flags, char virtual_key, void * in_refcon, int losing_focus) { }

  26. PLUGIN_API int XPluginStart(
  27.                             char *      outName,
  28.                             char *      outSig,
  29.                             char *      outDesc)
  30. {
  31.     strcpy(outName, "HelloWorld3Plugin");
  32.     strcpy(outSig, "xpsdk.examples.helloworld3plugin");
  33.     strcpy(outDesc, "A Hello World plug-in for the XPLM300 SDK.");

  34.     XPLMCreateWindow_t params;
  35.     params.structSize = sizeof(params);
  36.     params.visible = 1;
  37.     params.drawWindowFunc = draw_hello_world;
  38.     // Note on "dummy" handlers:
  39.     // Even if we don't want to handle these events, we have to register a "do-nothing" callback for them
  40.     params.handleMouseClickFunc = dummy_mouse_handler;
  41.     params.handleRightClickFunc = dummy_mouse_handler;
  42.     params.handleMouseWheelFunc = dummy_wheel_handler;
  43.     params.handleKeyFunc = dummy_key_handler;
  44.     params.handleCursorFunc = dummy_cursor_status_handler;
  45.     params.refcon = NULL;
  46.     params.layer = xplm_WindowLayerFloatingWindows;
  47.     // Opt-in to styling our window like an X-Plane 11 native window
  48.     // If you're on XPLM300, not XPLM301, swap this enum for the literal value 1.
  49.     params.decorateAsFloatingWindow = xplm_WindowDecorationRoundRectangle;

  50.     // Set the window's initial bounds
  51.     // Note that we're not guaranteed that the main monitor's lower left is at (0, 0)...
  52.     // We'll need to query for the global desktop bounds!
  53.     int left, bottom, right, top;
  54.     XPLMGetScreenBoundsGlobal(&left, &top, &right, &bottom);
  55.     params.left = left + 50;
  56.     params.bottom = bottom + 150;
  57.     params.right = params.left + 200;
  58.     params.top = params.bottom + 200;

  59.     g_window = XPLMCreateWindowEx(&params);

  60.     // Position the window as a "free" floating window, which the user can drag around
  61.     XPLMSetWindowPositioningMode(g_window, xplm_WindowPositionFree, -1);
  62.     // Limit resizing our window: maintain a minimum width/height of 100 boxels and a max width/height of 300 boxels
  63.     XPLMSetWindowResizingLimits(g_window, 200, 200, 300, 300);
  64.     XPLMSetWindowTitle(g_window, "Sample Window");

  65.     return g_window != NULL;
  66. }

  67. PLUGIN_API void XPluginStop(void)
  68. {
  69.     // Since we created the window, we'll be good citizens and clean it up
  70.     XPLMDestroyWindow(g_window);
  71.     g_window = NULL;
  72. }

  73. PLUGIN_API void XPluginDisable(void) { }
  74. PLUGIN_API int  XPluginEnable(void)  { return 1; }
  75. PLUGIN_API void XPluginReceiveMessage(XPLMPluginID inFrom, int inMsg, void * inParam) { }

  76. void    draw_hello_world(XPLMWindowID in_window_id, void * in_refcon)
  77. {
  78.     // Mandatory: We *must* set the OpenGL state before drawing
  79.     // (we can't make any assumptions about it)
  80.     XPLMSetGraphicsState(
  81.                          0 /* no fog */,
  82.                          0 /* 0 texture units */,
  83.                          0 /* no lighting */,
  84.                          0 /* no alpha testing */,
  85.                          1 /* do alpha blend */,
  86.                          1 /* do depth testing */,
  87.                          0 /* no depth writing */
  88.                          );

  89.     int l, t, r, b;
  90.     XPLMGetWindowGeometry(in_window_id, &l, &t, &r, &b);

  91.     float col_white[] = {1.0, 1.0, 1.0}; // red, green, blue

  92.     XPLMDrawString(col_white, l + 10, t - 20, "Hello world!", NULL, xplmFont_Proportional);
  93. }
复制代码

例如,代码的最后一行的“Hello world!”显然是窗口显示的文字,我们可以改成"Hello X-Plane!":
  1. XPLMDrawString(col_white, l + 10, t - 20, "Hello X-Plane!", NULL, xplmFont_Proportional);
复制代码

在代码的73行左右我们可以更改窗口的标题:

  1. XPLMSetWindowTitle(g_window, "Sample Window");
复制代码
将”Sample Window”改为”Hello X-Plane” :

  1. XPLMSetWindowTitle(g_window, "Hello X-Plane");
复制代码
此时重新构建插件,就可以得到置顶效果图中的样式。
代码中还有很多值得玩味和尝试修改的地方,如有兴趣不妨一试。例如以下三行代码可以更改插件自身的属性:插件名字,签名以及描述等。
  1. strcpy(outName, "HelloWorld3Plugin");
  2. strcpy(outSig, "xpsdk.examples.helloworld3plugin");
  3. strcpy(outDesc, "A Hello World plug-in for the XPLM300 SDK.");
复制代码


注:该插件虽然看似简单,但涉及到窗口绘制以及显示的功能,若要从0开始开发还是有不少难度。这个示例主要是为了能够对插件构建及开发流程有个直观感受。下一节将从DataRef开始着手XP的数据获取工作。XP几乎提供了一切飞行参数,包括飞机姿态、运动学数据、动力学数据、航电、仪表数据等,以及如何对可读写数据进行更改,有了它们就可以do everything you want。


评分

参与人数 1金币 +30 支持 +1 收起 理由
AllenLin + 30 + 1

查看全部评分

发表于 2023-5-24 08:38:09 | 显示全部楼层
很棒的开发者文档,支持一下!😋

点评

逛论坛都要黑一下我家咯咯😅  发表于 2023-5-24 16:14
黑魔王  发表于 2023-5-24 16:05
回复

使用道具 举报

发表于 2023-5-24 09:18:38 | 显示全部楼层
技术流大佬!先收藏了,以备后用
回复

使用道具 举报

发表于 2023-5-25 06:40:16 | 显示全部楼层
技术贴,有水平,值得大赞。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表