This commit is contained in:
Joud Kandeel
2026-05-22 23:11:11 +02:00
parent 8322690897
commit 427c5008ca
17 changed files with 1642 additions and 0 deletions

View File

@@ -0,0 +1,168 @@
#include "ModLoader.h"
static XIDevice* g_device;
static XIContext* g_ctx;
static XIExports g_exp;
eastl::unordered_map<Xuint64, Xvoid*> registeries;
Xuint64 hash_str(Xcstr str) {
Xuint64 h = 0xcbf29ce484222325ULL; // FNV offset basis
while (*str) {
h ^= (Xuint8)(*str++);
h *= 0x100000001b3ULL; // FNV prime
}
// Final mixing (improves avalanche)
h ^= h >> 33;
h *= 0xff51afd7ed558ccdULL;
h ^= h >> 33;
h *= 0xc4ceb9fe1a85ec53ULL;
h ^= h >> 33;
return h;
}
typedef struct {
XIDevice iface;
Xint32 ref;
Xint32 handle;
}DeviceImpl;
typedef struct {
XIContext iface;
Xint32 ref;
}ContextImpl;
Xvoid mce_device_addref(XIDevice* device) {
((DeviceImpl*)device)->ref++;
}
Xvoid mce_device_release(XIDevice* device) {
DeviceImpl* self = (DeviceImpl*)device;
if (--self->ref == 0) {
//printf("[Engine] Device destroyed\n");
}
}
Xint32 mce_device_createQEventBus(XIDevice* device, XHQEventBus* qBus, XQEventBusDescriptor desc) {
Xuint64 hash = hash_str(desc.name);
auto it = registeries.find(hash);
if (it == registeries.end()) {
registeries[hash] = new mce::core::QEventBus(desc.name);
qBus->idx = hash;
return 1;
}
else {
qBus->idx = it->first;
}
return 1;
}
Xvoid mce_device_setXIExports(XIDevice* device, XIExports exp) {
g_exp = exp;
}
Xvoid mce_ctx_addRef(XIContext* ctx) {
((ContextImpl*)ctx)->ref++;
}
Xvoid mce_ctx_release(XIContext* device) {
ContextImpl* self = (ContextImpl*)device;
if (--self->ref == 0) {
//printf("[Engine] Context destroyed\n");
}
}
Xuint32 mce_ctx_postEvent(XHQEventBus* qBus, Xvoid* event, Xconst Xuint64 type) {
auto it = registeries.find(qBus->idx);
if (it != registeries.end()) {
mce::core::QEventBus* _qBus = reinterpret_cast<mce::core::QEventBus*>(it->second);
if (type == XE_EVENT_TYPE_LOG) {
XSEventLog* XAPI_eventLog = reinterpret_cast<XSEventLog*>(event);
mce::event::Log log;
log.channel = XAPI_eventLog->channel;
log.msg = XAPI_eventLog->msg;
log.severity = static_cast<mce::event::Log::Severity>(XAPI_eventLog->severity);
_qBus->post(log);
return 1;
}
}
return XE_ERROR;
}
void zMem(void*& mem, size_t size) {
char* _mem = (char*)mem;
for (size_t i = 0; i < size; i++) {
_mem[i] = 0;
}
}
Xvoid setGlobalQEventBus(mce::core::QEventBus* qBus) {
//auto num = hash_str("mce.core.event.logger_output");
Xuint64 hash = hash_str(qBus->getNamespace().data());
auto it = registeries.find(hash);
if (it == registeries.end()) {
registeries[hash] = qBus;
}
}
Xint32 mce_createDeviceAndContext(XIDevice** device, XIContext** ctx) {
if ((*device) != nullptr && (*ctx) != nullptr) {
return XE_ERROR;
}
*device = new XIDevice();
*ctx = new XIContext();
XIDeviceVTable* device_vtbl = new XIDeviceVTable();
XIContextVTable* ctx_vtbl = new XIContextVTable();
//ZeroMemory(device_vtbl, sizeof(XIDeviceVTable));
//memset(device_vtbl, 0, sizeof(XIDeviceVTable));
if (!device_vtbl && !ctx_vtbl) {
return XE_ERROR;
}
const_cast<XIDeviceVTable*>(device_vtbl)->addRef = mce_device_addref;
const_cast<XIDeviceVTable*>(device_vtbl)->addRef = mce_device_release;
const_cast<XIDeviceVTable*>(device_vtbl)->createQEventBus = mce_device_createQEventBus;
const_cast<XIDeviceVTable*>(device_vtbl)->setXIExports = mce_device_setXIExports;
const_cast<XIContextVTable*>(ctx_vtbl)->addRef = mce_ctx_addRef;
const_cast<XIContextVTable*>(ctx_vtbl)->release = mce_ctx_release;
//const_cast<XIContextVTable*>(ctx_vtbl)->setXIExports = mce_ctx_setXIExports;
const_cast<XIContextVTable*>(ctx_vtbl)->postEvent = mce_ctx_postEvent;
(*device)->vtbl = device_vtbl;
(*ctx)->vtbl = ctx_vtbl;
g_device = (*device);
g_ctx = (*ctx);
return 1;
}
Xint32 mce_destroyDeviceAndContext(XIDevice** device, XIContext** ctx) {
if ((*device) == nullptr || (*ctx) == nullptr) {
return XE_ERROR;
}
delete (*device)->vtbl;
delete (*ctx)->vtbl;
delete* device;
delete* ctx;
return 1;
}
Xconst XIExports mce_pullSessionsExports() {
return g_exp;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#define XAPI_USE_V1_0_0
#include "XAPI.h"
#include <Core/QEventBus.hpp>
Xvoid setGlobalQEventBus(mce::core::QEventBus* qBus);
Xint32 mce_createDeviceAndContext(XIDevice** device, XIContext** ctx);
Xint32 mce_destroyDeviceAndContext(XIDevice** device, XIContext** ctx);
Xconst XIExports mce_pullSessionsExports();

View File

@@ -0,0 +1,141 @@
///---------------------------------------------------------------------------------\\\
/// MIT License \\\
/// \\\
/// Copyright(c) 2026 Joud Kandeel \\\
/// \\\
/// Permission is hereby granted, free of charge, to any person obtaining a copy \\\
/// of this software and associated documentation files(the "Software"), to deal \\\
/// in the Software without restriction, including without limitation the rights \\\
/// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell \\\
/// copies of the Software, and to permit persons to whom the Software is \\\
/// furnished to do so, subject to the following conditions : \\\
/// \\\
/// The above copyright notice and this permission notice shall be included in all\\\
/// copies or substantial portions of the Software. \\\
/// \\\
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \\\
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \\\
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE \\\
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \\\
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \\\
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE \\\
/// SOFTWARE. \\\
///---------------------------------------------------------------------------------\\\
#pragma once
#ifdef XAPI_USE_V1_0_0
#ifndef XAPI_HEADER
#define XAPI_HEADER
#ifdef _WIN32
#ifdef __cplusplus
#define XAPI_EXPORT __declspec(dllexport) extern "C"
#define XAPI_LOCAL
#else
#define XAPI_EXPORT __declspec(dllexport)
#define XAPI_LOCAL
#endif
#else
#define XAPI_EXPORT __attribute__((visibility("default")))
#define XAPI_LOCAL __attribute__((visibility("hidden")))
#endif
#define XAPI_LOCAL
#define XAPI_STDCALL __stdcall
#define XAPI_VERSION 0x01000000u
#define XAPI_NULL (Xvoid*)0
#define XE_ERROR 0xDEADBEEF
#define XE_EVENT_TYPE_LOG 0xA2942192B2001D9E //mce.core.event.logger_output
#define XE_EVENT_LOG_DEBUG 0x07
#define Xconst const
#define Xconstptr const*
#define XInterface struct
#ifdef __cplusplus
extern "C" {
#endif
typedef char Xint8;
typedef short Xint16;
typedef int Xint32;
typedef long long Xint64;
typedef unsigned char Xuint8;
typedef unsigned short Xuint16;
typedef unsigned int Xuint32;
typedef unsigned long long Xuint64;
typedef Xconst char Xconstptr Xcstrcp;
typedef Xconst char* Xcstr;
typedef void Xvoid;
typedef XInterface XIDevice XIDevice;
typedef XInterface XIContext XIContext;
typedef Xconst Xint32(XAPI_STDCALL* XI_createDeviceAndContextFn)(XIDevice**, XIContext**);
typedef Xconst Xint32(XAPI_STDCALL* XI_destroyDeviceAndContextFn)(XIDevice**, XIContext**);
typedef struct {
Xcstrcp name;
Xcstrcp author;
Xint32 version;
Xcstrcp language;// programming language
Xcstrcp sdkName;
Xcstrcp dependencies;
}XAPIDescriptor;
typedef struct {
Xint64 idx;
}XHQEventBus;
typedef struct {
Xcstr name;
Xuint16 maxSize;
}XQEventBusDescriptor;
typedef struct {
Xcstr channel;
Xcstr msg;
Xuint8 severity;
}XSEventLog;
typedef struct {
Xint32(*onShutdown)(Xvoid);
Xint32(*onUpdate)(Xvoid);
Xint32(*onInit)(Xvoid);
}XIExports;
typedef struct {
Xvoid(*addRef)(XIDevice* device);
Xvoid(*release)(XIDevice* device);
Xint32(*createQEventBus)(XIDevice* device, XHQEventBus* qBus, XQEventBusDescriptor desc);
Xvoid(*setXIExports)(XIDevice* device, XIExports exp);
}XIDeviceVTable;
XInterface XIDevice{
Xconst XIDeviceVTable Xconstptr vtbl;
};
typedef struct {
Xvoid(*addRef)(XIContext* ctx);
Xvoid(*release)(XIContext* ctx);
//Xvoid(*setXIExports)(XIExports exp);
Xuint32(*postEvent)(XHQEventBus* qBus, Xvoid* event, Xconst Xuint64 type);
Xuint32(*subscribeEvent)(XHQEventBus* qBus, Xconst Xuint64 type, Xconst Xvoid Xconstptr fn);
}XIContextVTable;
XInterface XIContext{
Xconst XIContextVTable Xconstptr vtbl;
};
#ifdef __cplusplus
}
#endif
#endif
#endif

View File

@@ -0,0 +1,321 @@
-- -
# XAPI — Cross - Engine Modding ABI
XAPI is a **C ABI - based modding interface** designed for voxel / sandbox - style engines.
It provides a **stable, low - level contract** between engine and mods, enabling binary compatibility across different builds, forks, and even entirely separate engines.
-- -
## ✨ Overview
XAPI is not tied to a specific engine implementation.
Instead, it defines a **strict binary interface(ABI)** that any engine can implement and any mod can target.
This allows:
- Mods compiled once to run across multiple engines
- Different codebases to share the same mod ecosystem
- Language - agnostic bindings via C ABI
-- -
## 🧠 Design Philosophy
- **C ABI first** — maximum portability and language interoperability
- **No engine pointers exposed**— mods operate on handles, not raw memory
- **Explicit lifecycle**— no hidden initialization or runtime magic
- **Event - driven communication**— decoupled interaction via event buses
- **Stable contracts over implementations**— behavior defined by spec, not engine internals
-- -
## 🧩 Core Concepts
### 1. Entry Points
Every XAPI module exports three functions :
```c
XAPI_EXPORT XAPIDescriptor XI_query(Xvoid);
XAPI_EXPORT Xint32 XI_main(Xvoid* pParam);
XAPI_EXPORT Xint32 XI_terminate(Xvoid* pParam);
````
* `XI_query` returns mod metadata
* `XI_main` initializes the module
* `XI_terminate` cleans up resources
-- -
### 2. Device & Context
The engine provides :
* `XIDevice` resource and system access
* `XIContext` runtime interaction(events, callbacks)
Mods never construct these manually they are provided by the engine.
-- -
### 3. Function Table(VTable)
All engine interaction is done through function tables :
```c
device->vtbl->createQEventBus(...)
ctx->vtbl->postEvent(...)
```
This ensures :
* ABI stability
* no direct linking against engine internals
-- -
### 4. Event System
XAPI uses an **event - driven architecture**:
* Mods post events via `postEvent`
* Systems subscribe via `subscribeEvent`
* Communication is decoupled and asynchronous
Example :
```c
XSEventLog log;
log.channel = "default";
log.msg = "Hello World";
log.severity = XE_EVENT_LOG_DEBUG;
ctx->vtbl->postEvent(NULL, &log, XE_EVENT_TYPE_LOG);
```
-- -
### 5. Handles Instead of Pointers
All engine - side objects are represented as **handles**, not pointers:
```c
typedef struct {
Xint64 idx;
} XHQEventBus;
```
This ensures :
* memory safety across modules
* engine - side ownership control
* compatibility across implementations
-- -
## 🔄 Module Lifecycle
1. Engine loads module(`.dll`)
2. Calls `XI_query` → retrieves metadata
3. Calls `XI_main`
* provides function pointer to create device / context
* mod initializes and registers callbacks
4. Engine drives execution via callbacks :
* `onInit`
* `onUpdate`
* `onShutdown`
5. Engine calls `XI_terminate` on unload
-- -
## 🧱 CXAPI(C Wrapper)
CXAPI is a thin helper layer built on top of XAPI to simplify usage in C.
It provides :
* global state management
* callback registration
* utility functions(logging, event posting)
Example:
```c
CXAPI_setOnInitCB(onInit);
CXAPI_setOnUpdateCB(onUpdate);
CXAPI_setOnShutdownCB(onShutdown);
```
-- -
## 🌍 Multi - Language Support
Because XAPI is pure C ABI, it can be used from many languages.
Bindings can be created by the community for:
* C / C++ (native)
* Rust
* Zig
* Nim
* Go
* C# (AOT)
* Python(via C API / Cython)
* JavaScript / Lua(via embedded runtimes)
The core project focuses on :
> **C/C++ reference implementation and wrappers**
-- -
## 🔐 Safety Model
* Mods never receive raw engine pointers
* All access goes through validated interfaces
* Engine retains full ownership of resources
* Invalid operations return error codes(`XE_ERROR`)
-- -
## 🔢 Versioning
XAPI uses explicit versioning:
```c
#define XAPI_VERSION 1
```
Future versions must maintain :
* backward compatibility where possible
* strict ABI guarantees
-- -
## 🎯 Goals
* Provide a **portable modding standard**
* Enable **cross - engine compatibility**
* Keep the core **minimal, stable, and predictable**
* Allow higher - level systems to be built on top
-- -
## 🚀 Example(Minimal Mod)
```c
//Globals
XAPIDescriptor desc;
XIExports exports;
XHQEventBus qBus;
XI_createDeviceAndContextFn XI_createDeviceAndContext;
XI_destroyDeviceAndContextFn XI_destroyDeviceAndContext;
XAPI_LOCAL Xint32 onUpdate(Xvoid) {
return 1;
}
XAPI_LOCAL Xint32 onInit(Xvoid) {
return 1;
}
XAPI_LOCAL Xint32 onShutdown(Xvoid) {
return 1;
}
XAPI_EXPORT Xconst XAPIDescriptor XI_query(Xvoid) {
XAPIDescriptor desc;
desc.author = "CDevJoud";
desc.language = "C";
desc.name = "My Mod!";
desc.version = 1;
desc.dependencies = "xapi.sys.q_eventBus";
desc.sdkName = "CXAPI";
return desc;
}
XAPI_EXPORT Xint32 XI_main(Xvoid* pParam) {
XI_createDeviceAndContext = (XI_createDeviceAndContextFn)pParam;
Xconst Xint32 ret = XI_createDeviceAndContext(&device, &ctx);
if (ret != XE_ERROR) {
// request for the APP QEventBus
if (device->vtbl->createQEventBus != XAPI_NULL) {
XQEventBusDescriptor qBusdesc;
qBusdesc.name = "APP";
qBusdesc.maxSize = 0xFFFF;
Xint32 res = device->vtbl->createQEventBus(device, &qBus, qBusdesc);
}
else {
return XE_ERROR; //Fatal Error!
}
exports.onInit = onInit;
exports.onShutdown = onShutdown;
exports.onUpdate = onUpdate;
if (device->vtbl->setXIExports != XAPI_NULL) {
device->vtbl->setXIExports(&device, exports);
}
else {
return XE_ERROR; //Fatal Error!
}
}
XSEventLog log;
log.channel = "default";
log.msg = "Running XAPI!";
log.severity = XE_EVENT_LOG_DEBUG;
ctx->vtbl->postEvent(&qBus, &log, XE_EVENT_TYPE_LOG);
return ret != XE_ERROR;
}
XAPI_EXPORT Xint32 XI_terminate(Xvoid* pParam) {
XI_destroyDeviceAndContext = (XI_destroyDeviceAndContextFn)pParam;
return XI_destroyDeviceAndContext(&device, &ctx) != XE_ERROR;
}
```
---
## 📌 Summary
XAPI is :
* a **specification**, not just an implementation
* a **binary contract**, not a framework
* a **foundation layer** for building mod ecosystems
---
**XAPI is an open specification. Anyone is free to implement it in their own engine or create language bindings.**
## 📄 License
MIT License
Copyright (c) 2026 Joud Kandeel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

120
SampleMod/CXAPI.c Normal file
View File

@@ -0,0 +1,120 @@
#include "CXAPI.h"
XAPIDescriptor desc;
XI_createDeviceAndContextFn XI_createDeviceAndContext;
XI_destroyDeviceAndContextFn XI_destroyDeviceAndContext;
XIDevice* device;
XIContext* ctx;
XIExports exports, cxapiExports;
XHQEventBus qBus;
XAPI_LOCAL Xint32 CXAPI_onUpdate(Xvoid) {
if (cxapiExports.onUpdate != XAPI_NULL) {
cxapiExports.onUpdate();
}
}
XAPI_LOCAL Xint32 CXAPI_onInit(Xvoid) {
if (cxapiExports.onInit != XAPI_NULL) {
cxapiExports.onInit();
}
}
XAPI_LOCAL Xint32 CXAPI_onShutdown(Xvoid) {
if (cxapiExports.onShutdown != XAPI_NULL) {
cxapiExports.onShutdown();
}
}
XAPI_EXPORT Xconst XAPIDescriptor XI_query(Xvoid) {
desc = queryCXAPIDescriptor();
desc.sdkName = "CXAPI";
return desc;
}
XAPI_EXPORT Xint32 XI_main(Xvoid* pParam){
XI_createDeviceAndContext = (XI_createDeviceAndContextFn)pParam;
Xconst Xint32 ret = XI_createDeviceAndContext(&device, &ctx);
if (ret != XE_ERROR) {
initCXAPI();
// request for the APP QEventBus
if (device->vtbl->createQEventBus != XAPI_NULL) {
XQEventBusDescriptor qBusdesc;
qBusdesc.name = "APP";
Xint32 res = device->vtbl->createQEventBus(device, &qBus, qBusdesc);
}
else {
return XE_ERROR; //Fatal Error!
}
CXAPI_logDebug("CXAPI running XAPI on version: 1.0.0, instantiating the mod loading phase!");
exports.onInit = CXAPI_onInit;
exports.onShutdown = CXAPI_onShutdown;
exports.onUpdate = CXAPI_onUpdate;
if (device->vtbl->setXIExports != XAPI_NULL) {
device->vtbl->setXIExports(&device, exports);
}
else {
return XE_ERROR; //Fatal Error!
}
}
CXAPI_logDebug("CXAPI has been instantiated!");
return ret != XE_ERROR;
}
XAPI_EXPORT Xint32 XI_terminate(Xvoid* pParam) {
XI_destroyDeviceAndContext = (XI_destroyDeviceAndContextFn)pParam;
return XI_destroyDeviceAndContext(&device, &ctx) != XE_ERROR;
}
XAPI_LOCAL Xvoid CXAPI_setOnShutdownCB(onShutdownCB cb) {
cxapiExports.onShutdown = cb;
}
XAPI_LOCAL Xvoid CXAPI_setOnInitCB(onInitCB cb) {
cxapiExports.onInit = cb;
}
XAPI_LOCAL Xvoid CXAPI_setOnUpdateCB(onUpdateCB cb) {
cxapiExports.onUpdate = cb;
}
XAPI_LOCAL Xvoid CXAPI_logDebug(Xcstr msg) {
XSEventLog log;
log.channel = "default";
log.msg = msg;
log.severity = XE_EVENT_LOG_DEBUG;
CXAPI_postEvent(XAPI_NULL, &log, XE_EVENT_TYPE_LOG);
}
XHQEventBus CXAPI_createQEventBus(Xcstr name) {
XHQEventBus qBus;
if (device->vtbl->createQEventBus != XAPI_NULL) {
XQEventBusDescriptor qBusdesc;
qBusdesc.name = name;
qBusdesc.maxSize = 0xFFFF;
device->vtbl->createQEventBus(device, &qBus, qBusdesc);
}
else {
qBus.idx = 0;
}
return qBus;
}
Xuint32 CXAPI_postEvent(XHQEventBus* _qBus, Xvoid* event, Xconst Xuint64 type) {
XHQEventBus thisQbus;
if (_qBus == XAPI_NULL) {
thisQbus.idx = qBus.idx;
}
else {
thisQbus.idx = _qBus->idx;
}
return (ctx->vtbl->postEvent != XAPI_NULL) ? ctx->vtbl->postEvent(&thisQbus, event, type) : XE_ERROR;
}

19
SampleMod/CXAPI.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#define XAPI_USE_V1_0_0
#include "XAPI.h"
typedef Xint32(XAPI_STDCALL onShutdownCB)(Xvoid);
typedef Xint32(XAPI_STDCALL onInitCB)(Xvoid);
typedef Xint32(XAPI_STDCALL onUpdateCB)(Xvoid);
XAPI_LOCAL Xvoid initCXAPI();
XAPI_LOCAL XAPIDescriptor queryCXAPIDescriptor();
XAPI_LOCAL XHQEventBus CXAPI_createQEventBus(Xcstr name);
XAPI_LOCAL Xuint32 CXAPI_postEvent(XHQEventBus* qBus, Xvoid* event, Xconst Xuint64 type);
XAPI_LOCAL Xvoid CXAPI_logDebug(Xcstr msg);
XAPI_LOCAL Xvoid CXAPI_setOnShutdownCB(onShutdownCB cb);
XAPI_LOCAL Xvoid CXAPI_setOnInitCB(onInitCB cb);
XAPI_LOCAL Xvoid CXAPI_setOnUpdateCB(onUpdateCB cb);

34
SampleMod/MyMod.c Normal file
View File

@@ -0,0 +1,34 @@
#include "CXAPI.h"
XAPI_LOCAL Xint32 onInit(Xvoid);
XAPI_LOCAL Xint32 onUpdate(Xvoid);
XAPI_LOCAL Xint32 onShutdown(Xvoid);
XAPI_LOCAL XAPIDescriptor queryCXAPIDescriptor() {
XAPIDescriptor desc;
desc.author = "CDevJoud";
desc.language = "C";
desc.name = "My Mod!";
desc.version = 1;
desc.dependencies = "mce.core.*";
return desc;
}
XAPI_LOCAL Xvoid initCXAPI() {
CXAPI_setOnInitCB(onInit);
CXAPI_setOnUpdateCB(onUpdate);
CXAPI_setOnShutdownCB(onShutdown);
}
XAPI_LOCAL Xint32 onInit(Xvoid) {
CXAPI_logDebug("Hello From MyMod!Joud!");
return 1;
}
XAPI_LOCAL Xint32 onUpdate(Xvoid) {
return 1;
}
XAPI_LOCAL Xint32 onShutdown(Xvoid) {
return 1;
}

164
SampleMod/SampleMod.vcxproj Normal file
View File

@@ -0,0 +1,164 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CXAPI.c" />
<ClCompile Include="MyMod.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="CXAPI.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{43a5cfef-b842-465d-94e5-b2af0bbaceae}</ProjectGuid>
<RootNamespace>SampleMod</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(SolutionDir)\Minecraft-Community-Edition\Mod\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(SolutionDir)\Minecraft-Community-Edition\Mod\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(SolutionDir)\Minecraft-Community-Edition\Mod\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(SolutionDir)\Minecraft-Community-Edition\Mod\;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;SAMPLEMOD_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;SAMPLEMOD_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;SAMPLEMOD_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpp23</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;SAMPLEMOD_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<BufferSecurityCheck>true</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CXAPI.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MyMod.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="CXAPI.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<Nullable>enable</Nullable>
<UseUwp>true</UseUwp>
<DefaultLanguage>en-US</DefaultLanguage>
<IsAotCompatible>true</IsAotCompatible>
<DisableRuntimeMarshalling>true</DisableRuntimeMarshalling>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<BaseOutputPath>Z:\mce\x64</BaseOutputPath>
<IlcExportUnmanagedEntrypoints>true</IlcExportUnmanagedEntrypoints>
<PublishAot>true</PublishAot>
</PropertyGroup>
</Project>

254
SampleModC#/XAPI.cs Normal file
View File

@@ -0,0 +1,254 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Text;
#pragma warning disable CS8500
// ==========================
// BASIC TYPES
// ==========================
using Xint8 = System.SByte;
using Xint16 = System.Int16;
using Xint32 = System.Int32;
using Xint64 = System.Int64;
using Xuint8 = System.Byte;
using Xuint16 = System.UInt16;
using Xuint32 = System.UInt32;
using Xuint64 = System.UInt64;
// ==========================
// CONSTANTS
// ==========================
public static class XE {
public const Xuint32 ERROR = 0xDEADBEEF;
public const Xuint64 EVENT_TYPE_LOG = 0xA2942192B2001D9E;
public const Xuint8 EVENT_LOG_DEBUG = 0x07;
}
// ==========================
// STRUCTS
// ==========================
[StructLayout(LayoutKind.Sequential)]
public unsafe struct XHQEventBus {
public Xint64 idx;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct XQEventBusDescriptor {
public Xint8* name;
public Xuint16 maxSize;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct XSEventLog {
public Xint8* channel;
public Xint8* msg;
public Xuint8 severity;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct XAPIDescriptor {
public Xint8* name;
public Xint8* author;
public Xint32 version;
public Xint8* language;
public Xint8* sdkName;
public Xint8* dependencies;
}
// ==========================
// FORWARD TYPES
// ==========================
public unsafe struct XIDevice {
public XIDeviceVTable* vtbl;
}
public unsafe struct XIContext {
public XIContextVTable* vtbl;
}
// ==========================
// VTABLES
// ==========================
public unsafe struct XIDeviceVTable {
public delegate* unmanaged[Stdcall]<XIDevice*, void> addRef;
public delegate* unmanaged[Stdcall]<XIDevice*, void> release;
public delegate* unmanaged[Stdcall]<XIDevice*, XHQEventBus*, XQEventBusDescriptor, Xint32> createQEventBus;
public delegate* unmanaged[Stdcall]<XIDevice*, XIExports, void> setXIExports;
}
public unsafe struct XIContextVTable {
public delegate* unmanaged[Stdcall]<XIContext*, void> addRef;
public delegate* unmanaged[Stdcall]<XIContext*, void> release;
//public delegate* unmanaged[Stdcall]<XIExports, void> setXIExports;
public delegate* unmanaged[Stdcall]<XHQEventBus*, void*, Xuint64, Xuint32> postEvent;
public delegate* unmanaged[Stdcall]<XHQEventBus*, Xuint64, void*, Xuint32> subscribeEvent;
}
// ==========================
// EXPORT CALLBACKS
// ==========================
public unsafe struct XIExports {
public delegate* unmanaged[Stdcall]<int> onShutdown;
public delegate* unmanaged[Stdcall]<int> onUpdate;
public delegate* unmanaged[Stdcall]<int> onInit;
}
// ==========================
// FUNCTION POINTER TYPES
// ==========================
public unsafe class XAPIFunctions {
public delegate* unmanaged[Stdcall]<XIDevice**, XIContext**, Xint32> CreateDeviceAndContext;
public delegate* unmanaged[Stdcall]<XIDevice**, XIContext**, Xint32> DestroyDeviceAndContext;
}
// ==========================
// GLOBAL STATE
// ==========================
public unsafe static class CSX {
public static XIDevice* device;
public static XIContext* ctx;
public static XHQEventBus qBus;
// ======================
// INIT
// ======================
public static void Init(void* fn) {
var create = (delegate* unmanaged[Stdcall]<XIDevice**, XIContext**, int>)fn;
XIDevice* dev = null;
XIContext* context = null;
int ret = create(&dev, &context);
if (ret == XE.ERROR)
return;
// create default event bus
XQEventBusDescriptor desc;
desc.name = CString("APP");
desc.maxSize = 0xFFFF;
device = dev;
ctx = context;
XHQEventBus hQEventBus;
if (device != null) {
if (device->vtbl != null) {
if (device->vtbl->createQEventBus != null) {
device->vtbl->createQEventBus(device, &hQEventBus, desc);
qBus = hQEventBus;
} else {
return;
}
}
}
}
// ======================
// LOGGING
// ======================
public static void LogDebug(string msg) {
XSEventLog log;
log.channel = CString("default");
log.msg = CString(msg);
log.severity = XE.EVENT_LOG_DEBUG;
PostEvent(null, &log, XE.EVENT_TYPE_LOG);
}
// ======================
// EVENTS
// ======================
public static Xuint32 PostEvent(XHQEventBus* bus, void* ev, Xuint64 type) {
XHQEventBus target;
if (bus == null)
target = qBus;
else
target = *bus;
return ctx->vtbl->postEvent(&target, ev, type);
}
// ======================
// STRING HELPER
// ======================
public static sbyte* CString(string s) {
byte[] bytes = Encoding.ASCII.GetBytes(s + "\0");
fixed (byte* p = bytes)
return (sbyte*)p;
}
}
// ==========================
// EXAMPLE MOD IMPLEMENTATION
// ==========================
public unsafe static class MyMod {
// callbacks
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
public static int OnInit() {
CSX.LogDebug("Hello from C# XAPI mod!");
return 1;
}
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
public static int OnUpdate() {
//CSX.LogDebug("This is Update");
return 1;
}
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
public static int OnShutdown() {
return 1;
}
static XIExports exp;
// ======================
// EXPORTS
// ======================
[UnmanagedCallersOnly(EntryPoint = "XI_main")]
public static int XI_main(void* p) {
CSX.Init(p);
exp.onInit = &OnInit;
exp.onUpdate = &OnUpdate;
exp.onShutdown = &OnShutdown;
CSX.device->vtbl->setXIExports(CSX.device, exp);
return 1;
}
[UnmanagedCallersOnly(EntryPoint = "XI_query", CallConvs = new[] { typeof(CallConvStdcall) })]
public static XAPIDescriptor XI_query() {
XAPIDescriptor desc;
desc.name = CSX.CString("C# Mod");
desc.author = CSX.CString("CDevJoud");
desc.version = 1;
desc.language = CSX.CString("C#");
desc.sdkName = CSX.CString("XAPI-CS");
desc.dependencies = CSX.CString("mce.core.*");
return desc;
}
[UnmanagedCallersOnly(EntryPoint = "XI_terminate")]
public static void XI_terminate(void* p) {
var destroy = (delegate* unmanaged[Stdcall]<XIDevice**, XIContext**, int>)p;
XIDevice* dev = null;
XIContext* context = null;
destroy(&dev, &context);
CSX.device = dev;
CSX.ctx = context;
}
}

28
SampleModCpp/MyMod.cpp Normal file
View File

@@ -0,0 +1,28 @@
#include "XPP.hpp"
class MyMod : public IXPP {
public:
MyMod();
~MyMod();
XAPIDescriptor query() override {
return XAPIDescriptor();
}
int onInit() override {
XPP::logDebug("Hello C++");
return 1;
}
int onUpdate() override {
return 1;
}
int onShutdown() override {
return 1;
}
}mod;
MyMod::MyMod() {
XPP::initXPP(&mod);
}
MyMod::~MyMod() {
}

View File

@@ -0,0 +1,155 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="MyMod.cpp" />
<ClCompile Include="XPP.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="XPP.hpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{62121dc8-0ebd-43f8-8d30-85db30a3574d}</ProjectGuid>
<RootNamespace>SampleModCpp</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(SolutionDir)\Minecraft-Community-Edition\Mod\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(SolutionDir)\Minecraft-Community-Edition\Mod\;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;SAMPLEMODCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;SAMPLEMODCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;SAMPLEMODCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpp23</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;SAMPLEMODCPP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpp23</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="MyMod.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="XPP.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="XPP.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

124
SampleModCpp/XPP.cpp Normal file
View File

@@ -0,0 +1,124 @@
#include "XPP.hpp"
IXPP* XPP::_instance;
XI_createDeviceAndContextFn XI_createDeviceAndContext;
XI_destroyDeviceAndContextFn XI_destroyDeviceAndContext;
XHQEventBus qBus;
XIDevice* device;
XIContext* ctx;
XIExports exports;
XPP& XPP::getSingleton() {
static XPP xpp;
return xpp;
}
void XPP::initXPP(IXPP* instance) {
_instance = instance;
}
void XPP::logDebug(const std::string& msg) {
XSEventLog log;
log.channel = "default";
log.msg = msg.c_str();
log.severity = XE_EVENT_LOG_DEBUG;
XPP::postEvent(nullptr, &log, XE_EVENT_TYPE_LOG);
}
IXPP* XPP::getModInstance() {
return _instance;
}
XHQEventBus CXAPI_createQEventBus(Xcstr name) {
XHQEventBus qBus;
if (device->vtbl->createQEventBus != XAPI_NULL) {
XQEventBusDescriptor qBusdesc;
qBusdesc.name = name;
qBusdesc.maxSize = 0xFFFF;
device->vtbl->createQEventBus(device, &qBus, qBusdesc);
}
else {
qBus.idx = 0;
}
return qBus;
}
XHQEventBus XPP::createQEventBus(const std::string& name) {
XHQEventBus qBus;
if (device->vtbl->createQEventBus != XAPI_NULL) {
XQEventBusDescriptor qBusDesc;
qBusDesc.name = name.c_str();
qBusDesc.maxSize = 0xFFFF;
device->vtbl->createQEventBus(device, &qBus, qBusDesc);
}
else {
qBus.idx = 0;
}
return qBus;
}
int XPP::postEvent(XHQEventBus* _qBus, Xvoid* event, Xconst Xuint64 type) {
XHQEventBus thisQbus;
if (_qBus == XAPI_NULL) {
thisQbus.idx = qBus.idx;
}
else {
thisQbus.idx = _qBus->idx;
}
return (ctx->vtbl->postEvent != XAPI_NULL) ? ctx->vtbl->postEvent(&thisQbus, event, type) : XE_ERROR;
}
extern "C" XAPI_EXPORT XAPIDescriptor XI_query(Xvoid) {
auto& instance = XPP::getSingleton();
auto desc = instance.getModInstance()->query();
desc.sdkName = "XPP";
return desc;
}
extern "C" XAPI_EXPORT Xint32 XI_main(Xvoid* pParam) {
XI_createDeviceAndContext = (XI_createDeviceAndContextFn)pParam;
Xconst Xint32 ret = XI_createDeviceAndContext(&device, &ctx);
if (ret != XE_ERROR) {
if (device != XAPI_NULL && ctx != XAPI_NULL) {
if (device->vtbl != XAPI_NULL && ctx->vtbl != XAPI_NULL) {
if (device->vtbl->createQEventBus != XAPI_NULL) {
XQEventBusDescriptor desc{};
desc.maxSize = 0xFFFF;
desc.name = "APP";
device->vtbl->createQEventBus(device, &qBus, desc);
}
else {
return XE_ERROR;
}
exports.onInit = []() -> Xint32 {return XPP::getSingleton().getModInstance()->onInit(); };
exports.onUpdate = []() -> Xint32 {return XPP::getSingleton().getModInstance()->onUpdate(); };
exports.onShutdown = []() -> Xint32 {return XPP::getSingleton().getModInstance()->onShutdown(); };
if (device->vtbl->setXIExports != XAPI_NULL) {
device->vtbl->setXIExports(device, exports);
}
else {
return XE_ERROR;
}
}
else {
return XE_ERROR;
}
}
else {
return XE_ERROR;
}
}
XPP::getSingleton().logDebug("XPP loaded up successfully! XAPI version v1.0.0");
return ret;
}
extern "C" XAPI_EXPORT Xint32 XI_terminate(Xvoid* pParam) {
XI_destroyDeviceAndContext = (XI_destroyDeviceAndContextFn)pParam;
auto ret = XI_destroyDeviceAndContext(&device, &ctx);
return ret;
}

28
SampleModCpp/XPP.hpp Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#define XAPI_USE_V1_0_0
#include "XAPI.h"
#include <string>
class IXPP {
public:
virtual ~IXPP() {
}
virtual XAPIDescriptor query() = 0;
virtual int onInit() = 0;
virtual int onUpdate() = 0;
virtual int onShutdown() = 0;
};
class XPP {
public:
static XPP& getSingleton();
static void initXPP(IXPP* instance);
static void logDebug(const std::string& msg);
static IXPP* getModInstance();
static XHQEventBus createQEventBus(const std::string& name);
static int postEvent(XHQEventBus* _qBus, Xvoid* event, Xconst Xuint64 type);
private:
static IXPP* _instance;
};