Working command executor with the initial work towards exporting abilities

This commit is contained in:
Malcolm Roberts 2023-12-28 11:40:26 -06:00
parent d9d1b5d3c8
commit 78d44b4260
25 changed files with 26472 additions and 305 deletions

View File

@ -13,7 +13,7 @@ include_directories(${SOURCE_DIR})
file(GLOB_RECURSE SCRIPT_FILES "scripts/*.iss")
file(GLOB_RECURSE LGUI2_FILES "lgui2/*.json")
foreach(FILE ${SCRIPT_FILES})
foreach (FILE ${SCRIPT_FILES})
get_filename_component(FILE_NAME ${FILE} NAME)
string(REGEX REPLACE "[^a-zA-Z0-9]" "_" FILE_IDENTIFIER ${FILE_NAME})
set(HEADER_FILE "${CMAKE_CURRENT_SOURCE_DIR}/scripts/${FILE_NAME}.h")
@ -28,9 +28,9 @@ foreach(FILE ${SCRIPT_FILES})
)
list(APPEND GENERATED_HEADERS ${HEADER_FILE})
endforeach()
endforeach ()
foreach(FILE ${LGUI2_FILES})
foreach (FILE ${LGUI2_FILES})
get_filename_component(FILE_NAME ${FILE} NAME)
string(REGEX REPLACE "[^a-zA-Z0-9]" "_" FILE_IDENTIFIER ${FILE_NAME})
set(HEADER_FILE "${CMAKE_CURRENT_SOURCE_DIR}/lgui2/${FILE_NAME}.h")
@ -48,7 +48,7 @@ foreach(FILE ${LGUI2_FILES})
list(APPEND GENERATED_HEADERS ${HEADER_FILE})
endforeach()
endforeach ()
add_custom_target(GenerateHeaders ALL DEPENDS ${GENERATED_HEADERS})
add_library(ISXMr SHARED ${SOURCE_DIR}/ISXMr.cpp
@ -65,11 +65,25 @@ add_library(ISXMr SHARED ${SOURCE_DIR}/ISXMr.cpp
src/isxeq2/Character.h
src/isxeq2/Actor.cpp
src/isxeq2/Actor.h
src/isxeq2/LSObject.cpp
src/isxeq2/LSObject.h
src/WriteUIFileToDisk.cpp)
src/WriteUIFileToDisk.cpp
src/isxeq2/Point3f.h
src/isxeq2/Ability.cpp
src/isxeq2/Ability.h
src/isxeq2/AbilityInfo.cpp
src/isxeq2/AbilityInfo.h
src/isxeq2/CharacterClass.h
src/isxeq2/AbilityEffect.h
libs/json/json.h
src/Logger.h
src/Commands/ExecutableCommand.h
src/Commands/ExportCommand.cpp
src/Commands/ExportCommand.h
src/isxeq2/ExtensionTLOs.h
src/Commands/CommandExecutor.cpp
src/Commands/CommandExecutor.h)
IF(WIN32)
IF (WIN32)
cmake_host_system_information(
RESULT InnerspacePath
QUERY WINDOWS_REGISTRY
@ -85,22 +99,22 @@ IF(WIN32)
COMMENT "Copying isxmr.dll to ${NormalizedInnerspacePath}"
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:ISXMr> "${NormalizedInnerspacePath}/ISXMr.dll"
)
endif()
endif()
endif ()
endif ()
# Set the path to additional libraries
set(LIBS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/)
# Find isxdk library
find_library(ISXDK_LIBRARY ISXDK HINTS ${LIBS_DIR}/isxdk/lib64/vs16)
if(NOT ISXDK_LIBRARY)
if (NOT ISXDK_LIBRARY)
message(FATAL_ERROR "isxdk library not found")
endif()
endif ()
find_library(ISUI_LIBRARY ISUI HINTS ${LIBS_DIR}/isxdk/lib64/vs16)
if(NOT ISUI_LIBRARY)
if (NOT ISUI_LIBRARY)
message(FATAL_ERROR "isxui library not found")
endif()
endif ()
# Set include directories for isxdk
include_directories(${LIBS_DIR}/isxdk/include)
@ -116,7 +130,7 @@ set_target_properties(ISXMr PROPERTIES
set_property(TARGET ISXMr PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
IF(WIN32)
IF (WIN32)
cmake_host_system_information(
RESULT InnerspacePath
QUERY WINDOWS_REGISTRY
@ -133,5 +147,5 @@ IF(WIN32)
COMMENT "Copying isxmr.dll to ${NormalizedInnerspacePath}"
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:ISXMr> "${NormalizedInnerspacePath}/ISXMr.dll"
)
endif()
endif()
endif ()
endif ()

24766
libs/json/json.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,45 @@
#include <argh.h>
#include <ISXDK.h>
#include <thread>
#include "ISXMr.h"
#include "Logger.h"
#include "Commands/ExportCommand.h"
enum CommandType {
Export,
Test,
NotDefined
};
CommandType GetCommandType(const std::string &command) {
if (command == "export" || command == "e") {
return CommandType::Export;
} else if (command == "test" || command == "t") {
return CommandType::Test;
}
return CommandType::NotDefined;
}
int CMD_Mr(int argc, char *argv[])
{
int CMD_Mr(int argc, char *argv[]) {
const argh::parser cmdl(argv);
pISInterface->Printf("Argc: %s", (cmdl[{"-v", "--verbose"}] ? "ON" : "OFF"));
switch (const auto commandType = GetCommandType(cmdl[1])) {
case CommandType::Export:
executor.AddTask(std::make_shared<ExportCommand>());
break;
case CommandType::Test:
log << LogLevel::Info << "Test command" << std::endl;
break;
default:
logw << "USAGE: mr [e|export]: Export abilities" << std::endl;
break;
}
// if (cmdl[{"-e", "--export"}]) {
// executor.AddTask(std::make_shared<ExportCommand>());
// } else {
// logger << "USAGE: mr [e|export]: Export abilities" << std::endl;
// }
return 0;
}

View File

@ -0,0 +1,55 @@
#include "CommandExecutor.h"
#include "Logger.h"
void CommandExecutor::Shutdown() {
stop = true;
for (auto &[command, future]: tasks) {
if (future.valid()) {
try {
command->RequestStop();
future.wait(); // Wait for the task to finish
future.get(); // Then call get() to handle any exceptions
} catch (const std::exception &e) {
loge << "Exception during task shutdown: " << e.what() << std::endl;
} catch (...) {
loge << "Unknown exception during task shutdown" << std::endl;
}
}
}
tasks.clear();
}
void CommandExecutor::AddTask(std::shared_ptr<ExecutableCommand> command) {
std::lock_guard<std::mutex> lock(queueMutex);
std::future<void> future = std::async(std::launch::async, [command]() {
try {
command->Execute();
} catch (const std::exception &e) {
loge << "Error executing command: " << e.what() << std::endl;
}
});
tasks.push_back({command, std::move(future)});
}
void CommandExecutor::RemoveFinishedTasks() {
std::lock_guard<std::mutex> lock(queueMutex);
std::erase_if(tasks, [](Task &task) {
if (task.future.valid() && task.future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
// Handle exceptions
try {
task.future.get(); // This will rethrow the exception if any
} catch (const std::exception &e) {
loge << "Exception from finished task: " << e.what() << std::endl;
} catch (...) {
loge << "Unknown exception from finished task" << std::endl;
}
return true; // Remove task from the list
}
return false; // Keep the task in the list
});
}

View File

@ -0,0 +1,34 @@
#ifndef COMMANDEXECUTOR_H
#define COMMANDEXECUTOR_H
#include <functional>
#include <future>
#include <mutex>
#include <queue>
#include "ExecutableCommand.h"
class CommandExecutor {
public:
CommandExecutor(): stop(false) {
}
void Shutdown();
void AddTask(std::shared_ptr<ExecutableCommand> command);
void RemoveFinishedTasks();
private:
struct Task {
std::shared_ptr<ExecutableCommand> command;
std::future<void> future;
};
std::vector<Task> tasks;
mutable std::mutex queueMutex;
std::atomic<bool> stop;
};
#endif //COMMANDEXECUTOR_H

View File

@ -0,0 +1,36 @@
#ifndef BASECOMMAND_H
#define BASECOMMAND_H
class ExecutableCommand {
public:
ExecutableCommand() : finished(false) {
}
virtual ~ExecutableCommand() = default;
virtual void Execute() = 0;
void RequestStop() {
stopRequested = true;
}
bool IsStopRequested() const {
return stopRequested;
}
bool IsFinished() const {
return finished;
}
protected:
void MarkFinished() {
finished = true;
}
bool stopRequested = false;
private:
bool finished;
};
#endif //BASECOMMAND_H

View File

@ -0,0 +1,45 @@
#include "ISXMr.h"
#include "ExportCommand.h"
#include <chrono>
#include <future>
#include <thread>
#include "Logger.h"
#include "isxeq2/ExtensionTLOs.h"
AbilityInfo GetAbilityInfo(const int idx) {
const auto ability = ExtensionTLOs::Me().Ability(idx);
while (!ability.IsAbilityInfoAvailable()) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
return ability.GetAbilityInfo();
}
void ExportCommand::Execute() {
try {
log << "Exporting abilities" << endl;
const auto numAbilities = ExtensionTLOs::Me().NumAbilities();
for (int i = 1; i <= numAbilities && !IsStopRequested(); ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
while (!ExtensionTLOs::Me().Ability(i).IsAbilityInfoAvailable() && !IsStopRequested()) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
if (IsStopRequested()) {
log << "Exporting abilities cancelled" << endl;
return;
}
const auto abilityInfo = ExtensionTLOs::Me().Ability(i).GetAbilityInfo();
log << "Exporting " << abilityInfo.Name() << "(" << i << "/" << numAbilities << ")" << endl;
}
} catch (const std::exception &e) {
loge << "Error exporting abilities: " << e.what() << endl;
} catch (...) {
loge << "Unknown error exporting abilities" << endl;
}
log << "Exporting abilities finished" << endl;
}

View File

@ -0,0 +1,16 @@
//
// Created by marob on 12/27/2023.
//
#ifndef EXPORT_H
#define EXPORT_H
#include "ExecutableCommand.h"
class ExportCommand final : public ExecutableCommand {
public:
void Execute() override;
};
#endif //EXPORT_H

View File

@ -18,107 +18,113 @@
#include <iostream>
#include <__msvc_filebuf.hpp>
#include "Logger.h"
#include "isxeq2/Character.h"
#include "../lgui2/test.json.h"
#include "../scripts/bot.iss.h"
#include "Commands/CommandExecutor.h"
#pragma comment(lib,"isxdk.lib")
// The mandatory pre-setup function. Our name is "ISXMr", and the class is ISXMr.
// This sets up a "ModulePath" variable which contains the path to this module in case we want it,
// and a "PluginLog" variable, which contains the path and filename of what we should use for our
// debug logging if we need it. It also sets up a variable "pExtension" which is the pointer to
// our instanced class.
ISXPreSetup("ISXMr",ISXMr);
ISXPreSetup("ISXMr", ISXMr);
// Basic LavishScript datatypes, these get retrieved on startup by our initialize function, so we can
// use them in our Top-Level Objects or custom datatypes
LSType *pStringType=0;
LSType *pIntType=0;
LSType *pUintType=0;
LSType *pBoolType=0;
LSType *pFloatType=0;
LSType *pTimeType=0;
LSType *pByteType=0;
LSType *pIntPtrType=0;
LSType *pBoolPtrType=0;
LSType *pFloatPtrType=0;
LSType *pBytePtrType=0;
LSType *pStringType = 0;
LSType *pIntType = 0;
LSType *pUintType = 0;
LSType *pBoolType = 0;
LSType *pFloatType = 0;
LSType *pTimeType = 0;
LSType *pByteType = 0;
LSType *pIntPtrType = 0;
LSType *pBoolPtrType = 0;
LSType *pFloatPtrType = 0;
LSType *pBytePtrType = 0;
LSType *pPoint3f = 0;
ISInterface *pISInterface=0;
ISInterface *pISInterface = 0;
HISXSERVICE hPulseService;
HISXSERVICE hMemoryService;
HISXSERVICE hHTTPService;
HISXSERVICE hTriggerService;
HISXSERVICE hSystemService;
char Mr_Version[]=EXTENSION_VERSION;
char Mr_Version[] = EXTENSION_VERSION;
// Forward declarations of callbacks
void __cdecl PulseService(bool Broadcast, unsigned int MSG, void *lpData);
void __cdecl MemoryService(bool Broadcast, unsigned int MSG, void *lpData);
void __cdecl TriggerService(bool Broadcast, unsigned int MSG, void *lpData);
void __cdecl HTTPService(bool Broadcast, unsigned int MSG, void *lpData);
void __cdecl SystemService(bool Broadcast, unsigned int MSG, void *lpData);
// The constructor of our class. General initialization cannot be done yet, because we're not given
// the pointer to the Inner Space interface until it is ready for us to initialize. Just set the
// pointer we have to the interface to 0. Initialize data members, too.
ISXMr::ISXMr(void)
{
ISXMr::ISXMr(void) {
}
// Free any remaining resources in the destructor. This is called when the DLL is unloaded, but
// Inner Space calls the "Shutdown" function first. Most if not all of the shutdown process should
// be done in Shutdown.
ISXMr::~ISXMr(void)
{
ISXMr::~ISXMr(void) {
}
// Initialize is called by Inner Space when the extension should initialize.
bool ISXMr::Initialize(ISInterface *p_ISInterface)
{
bool ISXMr::Initialize(ISInterface *p_ISInterface) {
/*
* Most of the functionality in Initialize is completely optional and could be removed or
* changed if so desired. The defaults are simply a suggestion that can be easily followed.
*/
constexpr size_t innerspacePathBufferLength = 255;
char innerspacePathBuffer[innerspacePathBufferLength];
const std::filesystem::path innerspacePath = p_ISInterface->GetInnerSpacePath(innerspacePathBuffer, innerspacePathBufferLength);
const std::filesystem::path innerspacePath = p_ISInterface->GetInnerSpacePath(
innerspacePathBuffer, innerspacePathBufferLength);
std::filesystem::path fullPath = innerspacePath / R"(scripts\mr\ui\test.json)";
if(fullPath.has_parent_path() && !std::filesystem::exists(fullPath.parent_path())) {
if (fullPath.has_parent_path() && !std::filesystem::exists(fullPath.parent_path())) {
std::filesystem::create_directories(fullPath.parent_path());
}
std::ofstream file(fullPath, std::ios::binary);
if(!file) {
if (!file) {
std::cerr << "Error opening file for writing: " << fullPath << std::endl;
}
file.write(reinterpret_cast<const char*>(test_json), test_json_len);
file.write(reinterpret_cast<const char *>(test_json), test_json_len);
file.close();
//__try // exception handling. See __except below.
{
// Keep a global copy of the ISInterface pointer, which is for calling Inner Space API
pISInterface=p_ISInterface;
pISInterface = p_ISInterface;
// Register the extension to make launching and updating the extension easy
RegisterExtension();
// retrieve basic LavishScript data types for use in ISXMr data types
pStringType=pISInterface->FindLSType(const_cast<char*>("string"));
pIntType=pISInterface->FindLSType(const_cast<char*>("int"));
pUintType=pISInterface->FindLSType(const_cast<char*>("uint"));
pBoolType=pISInterface->FindLSType(const_cast<char*>("bool"));
pFloatType=pISInterface->FindLSType(const_cast<char*>("float"));
pTimeType=pISInterface->FindLSType(const_cast<char*>("time"));
pByteType=pISInterface->FindLSType(const_cast<char*>("byte"));
pIntPtrType=pISInterface->FindLSType(const_cast<char*>("intptr"));
pBoolPtrType=pISInterface->FindLSType(const_cast<char*>("boolptr"));
pFloatPtrType=pISInterface->FindLSType(const_cast<char*>("floatptr"));
pBytePtrType=pISInterface->FindLSType(const_cast<char*>("byteptr"));
pStringType = pISInterface->FindLSType(const_cast<char *>("string"));
pIntType = pISInterface->FindLSType(const_cast<char *>("int"));
pUintType = pISInterface->FindLSType(const_cast<char *>("uint"));
pBoolType = pISInterface->FindLSType(const_cast<char *>("bool"));
pFloatType = pISInterface->FindLSType(const_cast<char *>("float"));
pTimeType = pISInterface->FindLSType(const_cast<char *>("time"));
pByteType = pISInterface->FindLSType(const_cast<char *>("byte"));
pIntPtrType = pISInterface->FindLSType(const_cast<char *>("intptr"));
pBoolPtrType = pISInterface->FindLSType(const_cast<char *>("boolptr"));
pFloatPtrType = pISInterface->FindLSType(const_cast<char *>("floatptr"));
pBytePtrType = pISInterface->FindLSType(const_cast<char *>("byteptr"));
pPoint3f = pISInterface->FindLSType(const_cast<char *>("point3f"));
// Connect to commonly used Inner Space services
ConnectServices();
@ -135,8 +141,8 @@ bool ISXMr::Initialize(ISInterface *p_ISInterface)
// Register any text triggers built into ISXMr
RegisterTriggers();
pISInterface->RunScriptFromBuffer("mrbot", reinterpret_cast<const char*>(bot_iss), bot_iss_len);
printf("ISXMr version %s Loaded",Mr_Version);
pISInterface->RunScriptFromBuffer("mrbot", reinterpret_cast<const char *>(bot_iss), bot_iss_len);
printf("ISXMr version %s Loaded", Mr_Version);
return true;
}
@ -145,7 +151,7 @@ bool ISXMr::Initialize(ISInterface *p_ISInterface)
// enable the extension developer to locate and fix the crash condition.
//__except(EzCrashFilter(GetExceptionInformation(),"Crash in initialize routine"))
{
TerminateProcess(GetCurrentProcess(),0);
TerminateProcess(GetCurrentProcess(), 0);
return 0;
}
/*
@ -166,12 +172,12 @@ bool ISXMr::Initialize(ISInterface *p_ISInterface)
* and return from the function as in the sample. The return will not be hit, but the compiler will
* whine without it because it doesn't automatically know that the function will not return.
*/
}
// shutdown sequence
void ISXMr::Shutdown()
{
void ISXMr::Shutdown() {
logw << "Shutting down" << endl;
executor.Shutdown();
// Disconnect from services we connected to
DisconnectServices();
@ -190,63 +196,58 @@ void ISXMr::Shutdown()
* All others are for suggested breakdown of routines, and for example purposes.
*/
void ISXMr::RegisterExtension()
{
void ISXMr::RegisterExtension() {
// add this extension to, or update this extension's info in, InnerSpace.xml.
// This accomplishes a few things. A) The extension can be loaded by name (ISXMr)
// no matter where it resides on the system. B) A script or extension can
// check a repository to determine if there is an update available (and update
// if necessary)
unsigned int ExtensionSetGUID=pISInterface->GetExtensionSetGUID("ISXMr");
if (!ExtensionSetGUID)
{
ExtensionSetGUID=pISInterface->CreateExtensionSet("ISXMr");
unsigned int ExtensionSetGUID = pISInterface->GetExtensionSetGUID("ISXMr");
if (!ExtensionSetGUID) {
ExtensionSetGUID = pISInterface->CreateExtensionSet("ISXMr");
if (!ExtensionSetGUID)
return;
}
pISInterface->SetSetting(ExtensionSetGUID,"Filename",ModuleFileName);
pISInterface->SetSetting(ExtensionSetGUID,"Path",ModulePath);
pISInterface->SetSetting(ExtensionSetGUID,"Version",Mr_Version);
pISInterface->SetSetting(ExtensionSetGUID, "Filename", ModuleFileName);
pISInterface->SetSetting(ExtensionSetGUID, "Path", ModulePath);
pISInterface->SetSetting(ExtensionSetGUID, "Version", Mr_Version);
}
void ISXMr::ConnectServices()
{
void ISXMr::ConnectServices() {
// connect to any services. Here we connect to "Pulse" which receives a
// message every frame (after the frame is displayed) and "Memory" which
// wraps "detours" and memory modifications
hPulseService=pISInterface->ConnectService(this,"Pulse",PulseService);
hMemoryService=pISInterface->ConnectService(this,"Memory",MemoryService);
hPulseService = pISInterface->ConnectService(this, "Pulse", PulseService);
hMemoryService = pISInterface->ConnectService(this, "Memory", MemoryService);
// The HTTP service handles URL retrieval
hHTTPService=pISInterface->ConnectService(this,"HTTP",HTTPService);
hHTTPService = pISInterface->ConnectService(this, "HTTP", HTTPService);
// The Triggers service handles trigger-related functions, including the
// ability to pass text TO the trigger parser, as well as the ability to
// add triggers.
hTriggerService=pISInterface->ConnectService(this,"Triggers",TriggerService);
hTriggerService = pISInterface->ConnectService(this, "Triggers", TriggerService);
// The System service provides general system-related services, including
// a diagnostics message that allows the extension to insert diagnostic
// information for the "diagnostics" command, and extension crash logs.
hSystemService=pISInterface->ConnectService(this,"System",SystemService);
hSystemService = pISInterface->ConnectService(this, "System", SystemService);
}
void ISXMr::RegisterCommands()
{
void ISXMr::RegisterCommands() {
// add any commands
// pISInterface->AddCommand("ISXMr",CMD_ISXMr,true,false);
// pISInterface->AddCommand("ISXMr",CMD_ISXMr,true,false);
#define COMMAND(name,cmd,parse,hide) pISInterface->AddCommand(name,cmd,parse,hide);
#include "Commands.h"
#undef COMMAND
}
void ISXMr::RegisterAliases()
{
void ISXMr::RegisterAliases() {
// add any aliases
}
void ISXMr::RegisterDataTypes()
{
void ISXMr::RegisterDataTypes() {
// add any datatypes
// pMyType = new MyType;
// pISInterface->AddLSType(*pMyType);
@ -257,8 +258,7 @@ void ISXMr::RegisterDataTypes()
#undef DATATYPE
}
void ISXMr::RegisterTopLevelObjects()
{
void ISXMr::RegisterTopLevelObjects() {
// add any Top-Level Objects
//pISInterface->AddTopLevelObject("ISXMr",TLO_ISXMr);
#define TOPLEVELOBJECT(name,funcname) pISInterface->AddTopLevelObject(name,funcname);
@ -266,23 +266,20 @@ void ISXMr::RegisterTopLevelObjects()
#undef TOPLEVELOBJECT
}
void ISXMr::RegisterServices()
{
void ISXMr::RegisterServices() {
// register any services. Here we demonstrate a service that does not use a
// callback
// set up a 1-way service (broadcast only)
// hISXMrService=pISInterface->RegisterService(this,"ISXMr Service",0);
// hISXMrService=pISInterface->RegisterService(this,"ISXMr Service",0);
// broadcast a message, which is worthless at this point because nobody will receive it
// (nobody has had a chance to connect)
// pISInterface->ServiceBroadcast(this,hISXMrService,ISXSERVICE_MSG+1,0);
// pISInterface->ServiceBroadcast(this,hISXMrService,ISXSERVICE_MSG+1,0);
#define SERVICE(_name_,_callback_,_variable_) _variable_=pISInterface->RegisterService(this,_name_,_callback_);
#include "Services.h"
#undef SERVICE
}
void ISXMr::RegisterTriggers()
{
void ISXMr::RegisterTriggers() {
// add any Triggers
}
@ -291,24 +288,24 @@ unsigned int onCloseButtonClickedEventId = 0;
void __cdecl OnGetTargetEvent(int argc, char *argv[], PLSOBJECT lsObj) {
const auto me = pISInterface->IsTopLevelObject("Me");
if(me != nullptr) {
if (me != nullptr) {
LSOBJECT response;
me(0, nullptr, response);
auto characterObject = make_shared<LSObject>(LSObject(response));
Character c(characterObject);
Actor target = c.GetTarget();
string targetName(target.GetName());
printf("Target ID: %d", target.GetId());
Actor target = c.Target();
string targetName(target.Name());
printf("Target ID: %d", target.Id());
printf("Target: %s", targetName.c_str());
LSOBJECT controller;
pISInterface->DataParse("MRBotController", controller);
//printf("Controller Type: %s", controller.Type->GetName());
LSOBJECT targetObj;
controller.Type->GetMemberEx(controller.GetObjectData(), const_cast<char*>("target"), 0, nullptr, targetObj);
controller.Type->GetMemberEx(controller.GetObjectData(), const_cast<char *>("target"), 0, nullptr, targetObj);
//printf("Target Type: %s", targetObj.Type->GetName());
auto targetNameCstr = const_cast<char*>(targetName.c_str());
targetObj.Type->GetMethodEx(targetObj.GetObjectData(), const_cast<char*>("Set"), 1, &targetNameCstr);
auto targetNameCstr = const_cast<char *>(targetName.c_str());
targetObj.Type->GetMethodEx(targetObj.GetObjectData(), const_cast<char *>("Set"), 1, &targetNameCstr);
}
printf("OnGetTargetEvent");
}
@ -325,66 +322,59 @@ void ISXMr::RegisterEvents() {
pISInterface->AttachEventTarget(onCloseButtonClickedEventId, OnCloseButtonClicked);
}
void ISXMr::DisconnectServices()
{
void ISXMr::DisconnectServices() {
// gracefully disconnect from services
if (hPulseService)
pISInterface->DisconnectService(this,hPulseService);
if (hMemoryService)
{
pISInterface->DisconnectService(this,hMemoryService);
pISInterface->DisconnectService(this, hPulseService);
if (hMemoryService) {
pISInterface->DisconnectService(this, hMemoryService);
// memory modifications are automatically undone when disconnecting
// also, since this service accepts messages from clients we should reset our handle to
// 0 to make sure we dont try to continue using it
hMemoryService=0;
hMemoryService = 0;
}
if (hHTTPService)
{
pISInterface->DisconnectService(this,hHTTPService);
if (hHTTPService) {
pISInterface->DisconnectService(this, hHTTPService);
}
if (hTriggerService)
{
pISInterface->DisconnectService(this,hTriggerService);
if (hTriggerService) {
pISInterface->DisconnectService(this, hTriggerService);
}
if (hSystemService)
{
pISInterface->DisconnectService(this,hSystemService);
if (hSystemService) {
pISInterface->DisconnectService(this, hSystemService);
}
}
void ISXMr::UnRegisterCommands()
{
void ISXMr::UnRegisterCommands() {
// remove commands
// pISInterface->RemoveCommand("ISXMr");
// pISInterface->RemoveCommand("ISXMr");
#define COMMAND(name,cmd,parse,hide) pISInterface->RemoveCommand(name);
#include "Commands.h"
#undef COMMAND
}
void ISXMr::UnRegisterAliases()
{
void ISXMr::UnRegisterAliases() {
// remove aliases
}
void ISXMr::UnRegisterDataTypes()
{
void ISXMr::UnRegisterDataTypes() {
// remove data types
#define DATATYPE(_class_,_variable_,_inherits_) pISInterface->RemoveLSType(*_variable_); delete _variable_;
#include "DataTypeList.h"
#undef DATATYPE
}
void ISXMr::UnRegisterTopLevelObjects()
{
void ISXMr::UnRegisterTopLevelObjects() {
// remove Top-Level Objects
// pISInterface->RemoveTopLevelObject("ISXMr");
// pISInterface->RemoveTopLevelObject("ISXMr");
#define TOPLEVELOBJECT(name,funcname) pISInterface->RemoveTopLevelObject(name);
#include "TopLevelObjects.h"
#undef TOPLEVELOBJECT
}
void ISXMr::UnRegisterServices()
{
void ISXMr::UnRegisterServices() {
// shutdown our own services
// if (hISXMrService)
// pISInterface->ShutdownService(this,hISXMrService);
// if (hISXMrService)
// pISInterface->ShutdownService(this,hISXMrService);
#define SERVICE(_name_,_callback_,_variable_) _variable_=pISInterface->ShutdownService(this,_variable_);
#include "Services.h"
@ -399,12 +389,33 @@ void ISXMr::UnRegisterEvents() {
pISInterface->UnregisterEvent(onCloseButtonClickedEventId);
}
int frameCount = 0;
CommandExecutor executor;
std::chrono::milliseconds interval(100);;
std::chrono::steady_clock::time_point nextCleanup = std::chrono::steady_clock::now() + interval;
void __cdecl PulseService(bool Broadcast, const unsigned int MSG, void *lpData) {
if (MSG == PULSE_PULSE) {
// const auto logs = executor.GetAllLogs();
// if (!logs.empty()) {
// pISInterface->Printf("Logs: %d", logs.size());
// }
// for (const auto logEntry: logs) {
// pISInterface->Printf("[%s]: %s", logEntry.GetFormattedTimestamp().c_str(), logEntry.message.c_str());
// }
if (const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); now > nextCleanup) {
try {
executor.RemoveFinishedTasks();
} catch (const std::exception &e) {
loge << "Error removing finished tasks: " << e.what() << endl;
} catch (...) {
loge << "Unknown error removing finished tasks" << endl;
}
nextCleanup = now + interval;
}
void __cdecl PulseService(bool Broadcast, unsigned int MSG, void *lpData)
{
if (MSG==PULSE_PULSE)
{
/*
* "OnPulse"
* This message is received by the extension before each frame is
@ -438,26 +449,21 @@ void __cdecl PulseService(bool Broadcast, unsigned int MSG, void *lpData)
// // }
//
// }
}
}
void __cdecl MemoryService(bool Broadcast, unsigned int MSG, void *lpData)
{
void __cdecl MemoryService(bool Broadcast, unsigned int MSG, void *lpData) {
// no messages are currently associated with this service (other than
// system messages such as client disconnect), so do nothing.
}
void __cdecl TriggerService(bool Broadcast, unsigned int MSG, void *lpData)
{
void __cdecl TriggerService(bool Broadcast, unsigned int MSG, void *lpData) {
// no messages are currently associated with this service (other than
// system messages such as client disconnect), so do nothing.
}
void __cdecl SystemService(bool Broadcast, unsigned int MSG, void *lpData)
{
if (MSG==SYSTEMSERVICE_DIAGNOSTICS)
{
void __cdecl SystemService(bool Broadcast, unsigned int MSG, void *lpData) {
if (MSG == SYSTEMSERVICE_DIAGNOSTICS) {
// Diagnostics sample
/*
FILE *file=(FILE*)lpData;
@ -469,10 +475,8 @@ void __cdecl SystemService(bool Broadcast, unsigned int MSG, void *lpData)
}
}
void __cdecl HTTPService(bool Broadcast, unsigned int MSG, void *lpData)
{
switch(MSG)
{
void __cdecl HTTPService(bool Broadcast, unsigned int MSG, void *lpData) {
switch (MSG) {
#define pReq ((HttpFile*)lpData)
case HTTPSERVICE_FAILURE:
// HTTP request failed to retrieve document

View File

@ -2,34 +2,48 @@
#include <ISXDK.h>
#include <windows.h>
#include "Commands/CommandExecutor.h"
class ISXMr :
public ISXInterface
{
public ISXInterface {
public:
ISXMr(void);
~ISXMr(void);
virtual bool Initialize(ISInterface *p_ISInterface);
virtual void Shutdown();
void RegisterExtension();
void ConnectServices();
void RegisterCommands();
void RegisterAliases();
void RegisterDataTypes();
void RegisterTopLevelObjects();
void RegisterServices();
void RegisterTriggers();
static void RegisterEvents();
void DisconnectServices();
void UnRegisterCommands();
void UnRegisterAliases();
void UnRegisterDataTypes();
void UnRegisterTopLevelObjects();
void UnRegisterServices();
static void UnRegisterEvents();
@ -42,6 +56,8 @@ extern HISXSERVICE hHTTPService;
extern HISXSERVICE hTriggerService;
extern HISXSERVICE hSystemService;
extern CommandExecutor executor;;
extern ISXMr *pExtension;
#define printf pISInterface->Printf
@ -59,20 +75,19 @@ extern ISXMr *pExtension;
#define EzRemoveTrigger(ID) IS_RemoveTrigger(pExtension,pISInterface,hTriggerService,ID)
#define EzCheckTriggers(Text) IS_CheckTriggers(pExtension,pISInterface,hTriggerService,Text)
static LONG EzCrashFilter(_EXCEPTION_POINTERS *pExceptionInfo,const char *szIdentifier,...)
{
unsigned int Code=pExceptionInfo->ExceptionRecord->ExceptionCode;
if (Code==EXCEPTION_BREAKPOINT || Code==EXCEPTION_SINGLE_STEP)
static LONG EzCrashFilter(_EXCEPTION_POINTERS *pExceptionInfo, const char *szIdentifier, ...) {
unsigned int Code = pExceptionInfo->ExceptionRecord->ExceptionCode;
if (Code == EXCEPTION_BREAKPOINT || Code == EXCEPTION_SINGLE_STEP)
return EXCEPTION_CONTINUE_SEARCH;
char szOutput[4096];
szOutput[0]=0;
szOutput[0] = 0;
va_list vaList;
va_start( vaList, szIdentifier );
vsprintf_s(szOutput,szIdentifier, vaList);
va_start(vaList, szIdentifier);
vsprintf_s(szOutput, szIdentifier, vaList);
IS_SystemCrashLog(pExtension,pISInterface,hSystemService,pExceptionInfo,szOutput);
IS_SystemCrashLog(pExtension, pISInterface, hSystemService, pExceptionInfo, szOutput);
return EXCEPTION_EXECUTE_HANDLER;
}
@ -88,6 +103,7 @@ extern LSType *pIntPtrType;
extern LSType *pBoolPtrType;
extern LSType *pFloatPtrType;
extern LSType *pBytePtrType;
extern LSType *pPoint3f;
extern char Mr_Version[];

108
src/Logger.h Normal file
View File

@ -0,0 +1,108 @@
//
// Created by marob on 12/27/2023.
//
#ifndef LOGGER_H
#define LOGGER_H
#include "ISXMr.h"
#include <sstream>
#include <iostream>
#include <iomanip>
enum class LogLevel {
Debug,
Info,
Warning,
Error
};
class Logger {
public:
Logger(const Logger &) = delete;
Logger &operator=(const Logger &) = delete;
static Logger &instance() {
static Logger singleton;
return singleton;
}
void SetLogLevel(LogLevel level) {
currentLogLevel = level;
}
Logger &operator<<(LogLevel level) {
SetLogLevel(level);
return *this;
}
template<typename T>
Logger &operator<<(const T &value) {
std::ostringstream &tss = getThreadLocalStream();
tss << value;
return *this;
}
Logger &operator<<(std::ostream & (*pf)(std::ostream &)) {
std::ostringstream &tss = getThreadLocalStream();
pf(tss);
if (pf == static_cast<std::ostream& (*)(std::ostream &)>(std::endl)) {
string str = tss.str();
pISInterface->Printf(formatMessage(str).c_str());
tss.str("");
tss.clear();
}
return *this;
}
private:
Logger() = default;
LogLevel currentLogLevel = LogLevel::Info;
static std::ostringstream &getThreadLocalStream() {
thread_local std::ostringstream tss;
return tss;
}
static void rtrim_newlines(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](const unsigned char ch) {
return ch != '\n' && ch != '\r';
}).base(), s.end());
}
std::string formatMessage(std::string &message) const {
const auto now = std::chrono::system_clock::now();
const auto now_c = std::chrono::system_clock::to_time_t(now);
std::tm now_tm;
localtime_s(&now_tm, &now_c); // Thread-safe on Windows
std::ostringstream oss;
rtrim_newlines(message);
oss << "[" << std::put_time(&now_tm, "%H:%M:%S") << "] - " << getColorCode(currentLogLevel) << message << "\ax";
// Reset color to default at the end
return oss.str();
}
static std::string getColorCode(const LogLevel level) {
switch (level) {
case LogLevel::Debug: return "\ay"; // Yellow
case LogLevel::Info: return "\ag"; // Green
case LogLevel::Warning: return "\ao"; // Orange
case LogLevel::Error: return "\ar"; // Red
default: return "\aw"; // White
}
}
};
// Global logger instance for ease of access
#define logger Logger::instance()
#define log Logger::instance() << LogLevel::Info
#define logd Logger::instance() << LogLevel::Debug
#define logw Logger::instance() << LogLevel::Warning
#define loge Logger::instance() << LogLevel::Error
#endif //LOGGER_H

40
src/isxeq2/Ability.cpp Normal file
View File

@ -0,0 +1,40 @@
//
// Created by marob on 12/27/2023.
//
#include "Ability.h"
#include <memory>
u_long Ability::Id() const {
return {static_cast<u_long>(this->lsObject->GetMember("ID").Int64)};
}
bool Ability::IsReady() const {
return this->lsObject->GetMember("IsReady").Int;
}
float Ability::TimeUntilReady() const {
return this->lsObject->GetMember("TimeUntilReady").Float;
}
bool Ability::IsQueued() const {
return this->lsObject->GetMember("IsQueued").Int;
}
bool Ability::IsAbilityInfoAvailable() const {
return this->lsObject->GetMember("IsAbilityInfoAvailable").Int;
}
AbilityInfo Ability::GetAbilityInfo() const {
return AbilityInfo(make_shared<LSObject>(this->lsObject->GetMember("ToAbilityInfo")));
}
void Ability::Use() const {
this->lsObject->CallMethod("Use");
}
void Ability::Examine() const {
this->lsObject->CallMethod("Examine");
}

42
src/isxeq2/Ability.h Normal file
View File

@ -0,0 +1,42 @@
//
// Created by marob on 12/27/2023.
//
#ifndef ABILITY_H
#define ABILITY_H
#include "AbilityInfo.h"
#include "ISXMr.h"
#include "LSObject.h"
class Ability {
public:
explicit Ability(const shared_ptr<LSObject> &obj) : lsObject(obj) {}
u_long Id() const;
bool IsReady() const;
float TimeUntilReady() const;
bool IsQueued() const;
// ABility Details
bool IsAbilityInfoAvailable() const;
/// \brief If the ability "details" are not already stored in a cache, then this will return NULL until it is available.
/// Script writers are encouraged to utilize the logic shown in the sample included with the Knowledgebase article
/// "Iterating Abilities and Handling 'abilityinfo' Aquisition". http://forge.isxgames.com/projects/isxeq2/knowledgebase/articles/43
///
/// Due to how ISXEQ2 handles the acquisition of abilityinfo, script writers should check IsAbilityInfoAvailable
/// until it's TRUE before using ToAbilityInfo (as opposed to checking ToAbilityInfo until it's not NULL.) This methodology will avoid spamming the server with requests.
AbilityInfo GetAbilityInfo() const;
// Methods
void Use() const;
void Examine() const;
private:
const shared_ptr<LSObject> lsObject;
};
#endif //ABILITY_H

View File

@ -0,0 +1,34 @@
//
// Created by marob on 12/27/2023.
//
#ifndef ABILITYEFFECT_H
#define ABILITYEFFECT_H
#include <memory>
#include <string>
#include "LSObject.h"
class LSObject;
class AbilityEffect {
public:
explicit AbilityEffect(const std::shared_ptr<LSObject> &obj) {
percentSuccess = obj->GetMember("PercentSuccess").Int;
indentation = obj->GetMember("Indentation").Int;
description = obj->GetMember("Description").CharPtr;
}
int PercentSuccess() const;
int Indentation() const;
std::string Description() const;
private:
int percentSuccess;
int indentation;
std::string description;
};
#endif //ABILITYEFFECT_H

140
src/isxeq2/AbilityInfo.cpp Normal file
View File

@ -0,0 +1,140 @@
#include "AbilityInfo.h"
[[nodiscard]]
string AbilityInfo::Name() const {
return this->name;
}
[[nodiscard]]
string AbilityInfo::Description() const {
return this->description;;
}
//
// string AbilityInfo::Tier() const {
// return this->lsObject->GetMember("Tier").CharPtr;
// }
//
// int AbilityInfo::HealthCost() const {
// return this->lsObject->GetMember("HealthCost").Int;
// }
//
// int AbilityInfo::PowerCost() const {
// return this->lsObject->GetMember("PowerCost").Int;
// }
//
// int AbilityInfo::DissonanceCost() const {
// return this->lsObject->GetMember("DissonanceCost").Int;
// }
//
// int AbilityInfo::SavageryCost() const {
// return this->lsObject->GetMember("SavageryCost").Int;
// }
//
// int AbilityInfo::ConcentrationCost() const {
// return this->lsObject->GetMember("ConcentrationCost").Int;
// }
//
// int AbilityInfo::MainIconID() const {
// return this->lsObject->GetMember("MainIconID").Int;
// }
//
// int AbilityInfo::HOIconID() const {
// return this->lsObject->GetMember("HOIconID").Int;
// }
//
// float AbilityInfo::CastingTime() const {
// return this->lsObject->GetMember("CastingTime").Float;
// }
//
// float AbilityInfo::RecoveryTime() const {
// return this->lsObject->GetMember("RecoveryTime").Float;
// }
//
// float AbilityInfo::RecastTime() const {
// return this->lsObject->GetMember("RecastTime").Float;
// }
//
// float AbilityInfo::MaxDuration() const {
// return this->lsObject->GetMember("MaxDuration").Float;
// }
//
// int AbilityInfo::NumClasses() const {
// return this->lsObject->GetMember("NumClasses").Int;
// }
//
// CharacterClass AbilityInfo::ClassByIndex(const int num) const {
// return CharacterClass(make_shared<LSObject>(LSObject(this->lsObject->GetMember("Class", num))));
// }
//
// CharacterClass AbilityInfo::ClassByName(const string &name) const {
// return CharacterClass(make_shared<LSObject>(LSObject(this->lsObject->GetMember("Class", name))));
// }
//
// int AbilityInfo::NumEffects() const {
// return this->lsObject->GetMember("NumEffects").Int;
// }
//
// int AbilityInfo::BackDropIconID() const {
// return this->lsObject->GetMember("BackDropIconID").Int;
// }
//
// int AbilityInfo::HealthCostPerTick() const {
// return this->lsObject->GetMember("HealthCostPerTick").Int;
// }
//
// int AbilityInfo::PowerCostPerTick() const {
// return this->lsObject->GetMember("PowerCostPerTick").Int;
// }
//
// int AbilityInfo::DissonanceCostPerTick() const {
// return this->lsObject->GetMember("DissonanceCostPerTick").Int;
// }
//
// int AbilityInfo::SavageryCostPerTick() const {
// return this->lsObject->GetMember("SavageryCostPerTick").Int;
// }
//
// int AbilityInfo::MaxAOETargets() const {
// return this->lsObject->GetMember("MaxAOETargets").Int;
// }
//
// bool AbilityInfo::DoesNotExpire() const {
// return this->lsObject->GetMember("DoesNotExpire").Int;
// }
//
// bool AbilityInfo::GroupRestricted() const {
// return this->lsObject->GetMember("GroupRestricted").Int;
// }
//
// bool AbilityInfo::AllowRaid() const {
// return this->lsObject->GetMember("AllowRaid").Int;
// }
//
// bool AbilityInfo::IsBeneficial() const {
// return this->lsObject->GetMember("IsBeneficial").Int;
// }
//
// float AbilityInfo::EffectRadius() const {
// return this->lsObject->GetMember("EffectRadius").Float;
// }
//
// int AbilityInfo::TargetType() const {
// return this->lsObject->GetMember("TargetType").Int;
// }
//
// int AbilityInfo::SpellBookType() const {
// return this->lsObject->GetMember("SpellBookType").Int;
// }
//
// float AbilityInfo::MinRange() const {
// return this->lsObject->GetMember("MinRange").Float;
// }
//
// float AbilityInfo::MaxRange() const {
// return this->lsObject->GetMember("MaxRange").Float;
// }
//
// string AbilityInfo::ToLink() const {
// return this->lsObject->GetMember("ToLink").CharPtr;
// }

217
src/isxeq2/AbilityInfo.h Normal file
View File

@ -0,0 +1,217 @@
#ifndef ABILITYINFO_H
#define ABILITYINFO_H
#include <memory>
#include "CharacterClass.h"
#include "LSObject.h"
class AbilityInfo {
public:
explicit AbilityInfo(const std::shared_ptr<LSObject> &obj) : lsObject(obj) {
this->name = this->lsObject->GetMember("Name").CharPtr;
this->description = this->lsObject->GetMember("Description").CharPtr;
this->tier = this->lsObject->GetMember("Tier").CharPtr;
this->healthCost = this->lsObject->GetMember("HealthCost").Int;
this->powerCost = this->lsObject->GetMember("PowerCost").Int;
this->dissonanceCost = this->lsObject->GetMember("DissonanceCost").Int;
this->savageryCost = this->lsObject->GetMember("SavageryCost").Int;
this->concentrationCost = this->lsObject->GetMember("ConcentrationCost").Int;
this->mainIconID = this->lsObject->GetMember("MainIconID").Int;
this->hOIconID = this->lsObject->GetMember("HOIconID").Int;
this->castingTime = this->lsObject->GetMember("CastingTime").Float;
this->recoveryTime = this->lsObject->GetMember("RecoveryTime").Float;
this->recastTime = this->lsObject->GetMember("RecastTime").Float;
this->maxDuration = this->lsObject->GetMember("MaxDuration").Float;
this->numClasses = this->lsObject->GetMember("NumClasses").Int;
this->numEffects = this->lsObject->GetMember("NumEffects").Int;
this->backDropIconID = this->lsObject->GetMember("BackdropIconID").Int;
this->healthCostPerTick = this->lsObject->GetMember("HealthCostPerTick").Int;
this->powerCostPerTick = this->lsObject->GetMember("PowerCostPerTick").Int;
this->dissonanceCostPerTick = this->lsObject->GetMember("DissonanceCostPerTick").Int;
this->savageryCostPerTick = this->lsObject->GetMember("SavageryCostPerTick").Int;
this->maxAOETargets = this->lsObject->GetMember("MaxAOETargets").Int;
this->doesNotExpire = this->lsObject->GetMember("DoesNotExpire").Int;
this->groupRestricted = this->lsObject->GetMember("GroupRestricted").Int;
this->allowRaid = this->lsObject->GetMember("AllowRaid").Int;
this->isBeneficial = this->lsObject->GetMember("IsBeneficial").Int;
this->effectRadius = this->lsObject->GetMember("EffectRadius").Float;
this->targetType = this->lsObject->GetMember("TargetType").Int;
this->spellBookType = this->lsObject->GetMember("SpellBookType").Int;
this->minRange = this->lsObject->GetMember("MinRange").Float;
this->maxRange = this->lsObject->GetMember("MaxRange").Float;
this->toLink = this->lsObject->GetMember("ToLink").CharPtr;
}
// CharacterClass classByIndex(const int num);
//
// CharacterClass classByName(const string &name);
string Name() const;
string Description() const;
[[nodiscard]] string tier1() const {
return tier;
}
[[nodiscard]] int health_cost() const {
return healthCost;
}
[[nodiscard]] int power_cost() const {
return powerCost;
}
[[nodiscard]] int dissonance_cost() const {
return dissonanceCost;
}
[[nodiscard]] int savagery_cost() const {
return savageryCost;
}
[[nodiscard]] int concentration_cost() const {
return concentrationCost;
}
[[nodiscard]] int main_icon_id() const {
return mainIconID;
}
[[nodiscard]] int h_o_icon_id() const {
return hOIconID;
}
[[nodiscard]] float casting_time() const {
return castingTime;
}
[[nodiscard]] float recovery_time() const {
return recoveryTime;
}
[[nodiscard]] float recast_time() const {
return recastTime;
}
[[nodiscard]] float max_duration() const {
return maxDuration;
}
[[nodiscard]] int num_classes() const {
return numClasses;
}
[[nodiscard]] int num_effects() const {
return numEffects;
}
[[nodiscard]] int back_drop_icon_id() const {
return backDropIconID;
}
[[nodiscard]] int health_cost_per_tick() const {
return healthCostPerTick;
}
[[nodiscard]] int power_cost_per_tick() const {
return powerCostPerTick;
}
[[nodiscard]] int dissonance_cost_per_tick() const {
return dissonanceCostPerTick;
}
[[nodiscard]] int savagery_cost_per_tick() const {
return savageryCostPerTick;
}
[[nodiscard]] int max_aoe_targets() const {
return maxAOETargets;
}
[[nodiscard]] bool does_not_expire() const {
return doesNotExpire;
}
[[nodiscard]] bool group_restricted() const {
return groupRestricted;
}
[[nodiscard]] bool allow_raid() const {
return allowRaid;
}
[[nodiscard]] bool is_beneficial() const {
return isBeneficial;
}
[[nodiscard]] float effect_radius() const {
return effectRadius;
}
[[nodiscard]] int target_type() const {
return targetType;
}
[[nodiscard]] int spell_book_type() const {
return spellBookType;
}
[[nodiscard]] float min_range() const {
return minRange;
}
[[nodiscard]] float max_range() const {
return maxRange;
}
[[nodiscard]] string to_link() const {
return toLink;
}
[[nodiscard]] std::shared_ptr<LSObject> ls_object() const {
return lsObject;
}
private:
string name;
string description;
string tier;
int healthCost;
int powerCost;
int dissonanceCost;
int savageryCost;
int concentrationCost;
int mainIconID;
int hOIconID;
float castingTime;
float recoveryTime;
float recastTime;
float maxDuration;
int numClasses;
int numEffects;
//AbilityEffect Effect[#]
int backDropIconID;
int healthCostPerTick;
int powerCostPerTick;
int dissonanceCostPerTick;
int savageryCostPerTick;
int maxAOETargets;
bool doesNotExpire;
bool groupRestricted;
bool allowRaid;
bool isBeneficial;
float effectRadius;
int targetType;
int spellBookType;
float minRange;
float maxRange;
string toLink;
const std::shared_ptr<LSObject> lsObject;
};
#endif //ABILITYINFO_H

View File

@ -4,136 +4,417 @@
#include "Actor.h"
u_long Actor::GetId() const {
return {static_cast<u_long>(this->lsObject->GetMember("ID").Int64)};
u_long Actor::Id() const {
return static_cast<u_long>(this->lsObject->GetMember("ID").Int64);
}
std::string Actor::GetName() const {
return {this->lsObject->GetMember("Name").CharPtr};
std::string Actor::Name() const {
return this->lsObject->GetMember("Name").CharPtr;
}
std::string Actor::GetLastName() const {
return { this->lsObject->GetMember("LastName").CharPtr };
std::string Actor::LastName() const {
return this->lsObject->GetMember("LastName").CharPtr;
}
int Actor::GetHealthPercentage() const {
int Actor::HealthPercentage() const {
return this->lsObject->GetMember("Health").Int;
}
int Actor::GetPowerPercentage() const {
int Actor::PowerPercentage() const {
return this->lsObject->GetMember("Power").Int;
}
int Actor::GetLevel() const {
int Actor::Level() const {
return this->lsObject->GetMember("Level").Int;
}
int Actor::GetEffectiveLevel() const {
int Actor::EffectiveLevel() const {
return this->lsObject->GetMember("EffectiveLevel").Int;
}
u_int Actor::GetTintFlags() const {
u_int Actor::TintFlags() const {
return this->lsObject->GetMember("TintFlags").Int;
}
std::string Actor::GetVisualVariant() const {
return { this->lsObject->GetMember("VisualVariant").CharPtr };
std::string Actor::VisualVariant() const {
return {this->lsObject->GetMember("VisualVariant").CharPtr};
}
std::string Actor::GetMood() const {
return { this->lsObject->GetMember("Mood").CharPtr };
std::string Actor::Mood() const {
return {this->lsObject->GetMember("Mood").CharPtr};
}
std::string Actor::GetCurrentAnimation() const {
return { this->lsObject->GetMember("CurrentAnimation").CharPtr };
std::string Actor::CurrentAnimation() const {
return {this->lsObject->GetMember("CurrentAnimation").CharPtr};
}
std::string Actor::GetOverlay() const {
return { this->lsObject->GetMember("Overlay").CharPtr };
std::string Actor::Overlay() const {
return {this->lsObject->GetMember("Overlay").CharPtr};
}
std::string Actor::GetAura() const {
return { this->lsObject->GetMember("Aura").CharPtr };
std::string Actor::Aura() const {
return {this->lsObject->GetMember("Aura").CharPtr};
}
std::string Actor::GetGuild() const {
return { this->lsObject->GetMember("Guild").CharPtr };
std::string Actor::Guild() const {
return {this->lsObject->GetMember("Guild").CharPtr};
}
std::string Actor::GetType() const {
return { this->lsObject->GetMember("Type").CharPtr };
std::string Actor::Type() const {
return {this->lsObject->GetMember("Type").CharPtr};
}
std::string Actor::GetSuffixTitle() const {
return { this->lsObject->GetMember("SuffixTitle").CharPtr };
std::string Actor::SuffixTitle() const {
return {this->lsObject->GetMember("SuffixTitle").CharPtr};
}
std::string Actor::GetConColor() const {
return { this->lsObject->GetMember("ConColor").CharPtr };
std::string Actor::ConColor() const {
return {this->lsObject->GetMember("ConColor").CharPtr};
}
std::string Actor::GetRawConColor() const {
std::string Actor::RawConColor() const {
// TODO: Modify to accept a parameter & pass in the string 'raw'
return { this->lsObject->GetMember("RawConColor").CharPtr };
return {this->lsObject->GetMember("RawConColor").CharPtr};
}
std::string Actor::GetFactionStanding() const {
return { this->lsObject->GetMember("FactionStanding").CharPtr };
std::string Actor::FactionStanding() const {
return {this->lsObject->GetMember("FactionStanding").CharPtr};
}
int Actor::GetFaction() const {
int Actor::Faction() const {
return this->lsObject->GetMember("Faction").Int;
}
Actor Actor::GetTarget() const {
Actor Actor::Target() const {
return Actor(make_shared<LSObject>(LSObject(this->lsObject->GetMember("Target"))));
}
Actor Actor::GetPet() const {
Actor Actor::Pet() const {
return Actor(make_shared<LSObject>(LSObject(this->lsObject->GetMember("Pet"))));
}
int Actor::GetThreatToPet() const {
int Actor::ThreatToPet() const {
return this->lsObject->GetMember("ThreatToPet").Int;
}
int Actor::GetThreatToMe() const {
return this->lsObject->GetMember("GetThreatToMe").Int;
int Actor::ThreatToMe() const {
return this->lsObject->GetMember("ThreatToMe").Int;
}
int Actor::GetThreatToNext() const {
return this->lsObject->GetMember("GetThreatToNext").Int;
int Actor::ThreatToNext() const {
return this->lsObject->GetMember("ThreatToNext").Int;
}
float Actor::GetDistance() const {
float Actor::Distance() const {
return this->lsObject->GetMember("Distance").Float;
}
float Actor::GetDistance2d() const {
float Actor::Distance2d() const {
return this->lsObject->GetMember("Distance2D").Float;
}
float Actor::GetX() const {
float Actor::X() const {
return this->lsObject->GetMember("X").Float;
}
float Actor::GetY() const {
float Actor::Y() const {
return this->lsObject->GetMember("Y").Float;
}
float Actor::GetZ() const {
float Actor::Z() const {
return this->lsObject->GetMember("Z").Float;
}
std::string Actor::GetRace() const {
std::string Actor::Race() const {
return {this->lsObject->GetMember("Race").CharPtr};
}
std::string Actor::GetClass() const {
std::string Actor::Class() const {
return {this->lsObject->GetMember("Class").CharPtr};
}
std::string Actor::GetGender() const {
std::string Actor::Gender() const {
return {this->lsObject->GetMember("Gender").CharPtr};
}
Point3f Actor::Location() const {
return Point3f(make_shared<LSObject>(LSObject(this->lsObject->GetMember("Location"))));
}
float Actor::Heading() const {
return this->lsObject->GetMember("Heading").Float;
}
string Actor::HeadingToAsString() const {
return this->lsObject->GetMember("HeadingTo", "AsString").CharPtr;
}
Point3f Actor::Velocity() const {
return Point3f(make_shared<LSObject>(LSObject(this->lsObject->GetMember("Velocity"))));
}
bool Actor::CheckCollision() const {
return this->lsObject->GetMember("CheckCollision").Int;
}
bool Actor::CheckCollision(const float toX, const float toY, const float toZ) const {
return this->lsObject->GetMember("CheckCollision", toX, toY, toZ).Int;
}
float Actor::TargetRingRadius() const {
return this->lsObject->GetMember("TargetRingRadius").Float;
}
float Actor::CollisionRadius() const {
return this->lsObject->GetMember("CollisionRadius").Float;
}
float Actor::CollisionScale() const {
return this->lsObject->GetMember("CollisionScale").Float;
}
u_long Actor::WhoFollowingId() const {
return this->lsObject->GetMember("WhoFollowingID").Int64;
}
string Actor::WhoFollowingName() const {
return this->lsObject->GetMember("WhoFollowing").CharPtr;
}
float Actor::Speed() const {
return this->lsObject->GetMember("Speed").Float;
}
float Actor::SwimmingSpeedModifier() const {
return this->lsObject->GetMember("SwimmingSpeedMod").Float;
}
bool Actor::InMyGroup() const {
return this->lsObject->GetMember("InMyGroup").Int;
}
bool Actor::Interactable() const {
return this->lsObject->GetMember("Interactable").Int;
}
bool Actor::OnFlyingMount() const {
return this->lsObject->GetMember("OnFlyingMount").Int;
}
bool Actor::FlyingUsingMount() const {
return this->lsObject->GetMember("FlyingUsingMount").Int;
}
bool Actor::IsChest() const {
return this->lsObject->GetMember("IsChest").Int;
}
bool Actor::IsBanker() const {
return this->lsObject->GetMember("IsBanker").Int;
}
bool Actor::IsMerchant() const {
return this->lsObject->GetMember("IsMerchant").Int;
}
bool Actor::IsAPet() const {
return this->lsObject->GetMember("IsAPet").Int;
}
bool Actor::IsMyPet() const {
return this->lsObject->GetMember("IsMyPet").Int;
}
bool Actor::IsAfk() const {
return this->lsObject->GetMember("IsAFK").Int;
}
bool Actor::IsLfw() const {
return this->lsObject->GetMember("IsLFW").Int;
}
bool Actor::IsLfg() const {
return this->lsObject->GetMember("IsLFG").Int;
}
bool Actor::IsLinkdead() const {
return this->lsObject->GetMember("IsLinkdead").Int;
}
bool Actor::IsCamping() const {
return this->lsObject->GetMember("IsCamping").Int;
}
bool Actor::IsLocked() const {
return this->lsObject->GetMember("IsLocked").Int;
}
bool Actor::IsAggro() const {
return this->lsObject->GetMember("IsAggro").Int;
}
bool Actor::IsSolo() const {
return this->lsObject->GetMember("IsSolo").Int;
}
bool Actor::IsHeroic() const {
return this->lsObject->GetMember("IsHeroic").Int;
}
bool Actor::IsEpic() const {
return this->lsObject->GetMember("IsEpic").Int;
}
bool Actor::IsNamed() const {
return this->lsObject->GetMember("IsNamed").Int;
}
bool Actor::IsSwimming() const {
return this->lsObject->GetMember("IsSwimming").Int;
}
bool Actor::IsEncounterBroken() const {
return this->lsObject->GetMember("IsEncounterBroken").Int;
}
bool Actor::IsInvisible() const {
return this->lsObject->GetMember("IsInvisible").Int;
}
bool Actor::IsClimbing() const {
return this->lsObject->GetMember("IsClimbing").Int;
}
bool Actor::IsJumping() const {
return this->lsObject->GetMember("IsJumping").Int;
}
bool Actor::IsFalling() const {
return this->lsObject->GetMember("IsFalling").Int;
}
bool Actor::IsFD() const {
return this->lsObject->GetMember("IsFD").Int;
}
bool Actor::IsDead() const {
return this->lsObject->GetMember("IsDead").Int;
}
bool Actor::IsRooted() const {
return this->lsObject->GetMember("IsRooted").Int;
}
bool Actor::CanTurn() const {
return this->lsObject->GetMember("CanTurn").Int;
}
bool Actor::InCombatMode() const {
return this->lsObject->GetMember("InCombatMode").Int;
}
bool Actor::IsCrouching() const {
return this->lsObject->GetMember("IsCrouching").Int;
}
bool Actor::IsSitting() const {
return this->lsObject->GetMember("IsSitting").Int;
}
bool Actor::OnCarpet() const {
return this->lsObject->GetMember("OnCarpet").Int;
}
bool Actor::OnHorse() const {
return this->lsObject->GetMember("OnHorse").Int;
}
bool Actor::ONGriphon() const {
return this->lsObject->GetMember("OnGriphon").Int;
}
bool Actor::IsRunning() const {
return this->lsObject->GetMember("IsRunning").Int;
}
bool Actor::IsWalking() const {
return this->lsObject->GetMember("IsWalking").Int;
}
bool Actor::IsSprinting() const {
return this->lsObject->GetMember("IsSprinting").Int;
}
bool Actor::IsBackingUp() const {
return this->lsObject->GetMember("IsBackingUp").Int;
}
bool Actor::IsStrafingLeft() const {
return this->lsObject->GetMember("IsStrafingLeft").Int;
}
bool Actor::IsStrafingRight() const {
return this->lsObject->GetMember("IsStrafingRight").Int;
}
bool Actor::IsIdle() const {
return this->lsObject->GetMember("IsIdle").Int;
}
int Actor::EncounterSize() const {
return this->lsObject->GetMember("EncounterSize").Int;
}
int Actor::Difficulty() const {
return this->lsObject->GetMember("Difficulty").Int;
}
int Actor::IsInSameEncounter(const u_long id) const {
return this->lsObject->GetMember("IsInSameEncounter", id).Int;
}
int Actor::RaidSize() const {
return this->lsObject->GetMember("RaidSize").Int;
}
string Actor::TagTargetNumber() const {
return this->lsObject->GetMember("TagTargetNumber").CharPtr;
}
string Actor::TagTargetIcon() const {
return this->lsObject->GetMember("TagTargetIcon").CharPtr;
}
int Actor::EffectCount() const {
return this->lsObject->GetMember("EffectCount").Int;
}
void Actor::DoubleClick() const {
this->lsObject->CallMethod("DoubleClick");
}
void Actor::WaypointTo() const {
this->lsObject->CallMethod("WaypointTo");
}
void Actor::DoFace() const {
this->lsObject->CallMethod("DoFace");
}
void Actor::DoTarget() const {
this->lsObject->CallMethod("DoTarget");
}
void Actor::AddLocation(const string &notes) const {
this->lsObject->CallMethod("Location", "Add", notes);
}
void Actor::DeleteLocation() const {
this->lsObject->CallMethod("Location", "Delete");
}
void Actor::RequesteffectsInfo() const {
this->lsObject->CallMethod("RequesteffectsInfo");
}

View File

@ -4,6 +4,7 @@
#include <memory>
#include "LSObject.h"
#include "Point3f.h"
class Actor {
@ -12,43 +13,136 @@ public:
}
// General
u_long GetId() const;
std::string GetName() const;
std::string GetLastName() const;
int GetHealthPercentage() const;
int GetPowerPercentage() const;
int GetLevel() const;
int GetEffectiveLevel() const;
u_int GetTintFlags() const;
std::string GetVisualVariant() const;
std::string GetMood() const;
std::string GetCurrentAnimation() const;
std::string GetOverlay() const;
std::string GetAura() const;
std::string GetGender() const;
std::string GetRace() const;
std::string GetClass() const;
std::string GetGuild() const;
std::string GetType() const;
std::string GetSuffixTitle() const;
std::string GetConColor() const;
std::string GetRawConColor() const;
std::string GetFactionStanding() const;
int GetFaction() const;
Actor GetTarget() const;
Actor GetPet() const;
u_long Id() const;
std::string Name() const;
std::string LastName() const;
int HealthPercentage() const;
int PowerPercentage() const;
int Level() const;
int EffectiveLevel() const;
u_int TintFlags() const;
std::string VisualVariant() const;
std::string Mood() const;
std::string CurrentAnimation() const;
std::string Overlay() const;
std::string Aura() const;
std::string Gender() const;
std::string Race() const;
std::string Class() const;
std::string Guild() const;
std::string Type() const;
std::string SuffixTitle() const;
std::string ConColor() const;
std::string RawConColor() const;
std::string FactionStanding() const;
int Faction() const;
Actor Target() const;
Actor Pet() const;
// Threat
int GetThreatToPet() const;
int GetThreatToMe() const;
int GetThreatToNext() const;
int ThreatToPet() const;
int ThreatToMe() const;
int ThreatToNext() const;
// Location
float GetDistance() const; // Note: This is the distance using three dimensions, which is what the EQ2 client primarily uses for determining ability ranges, etc.
float GetDistance2d() const;
float GetX() const;
float GetY() const;
float GetZ() const;
float Distance() const; // Note: This is the distance using three dimensions, which is what the EQ2 client primarily uses for determining ability ranges, etc.
float Distance2d() const;
float X() const;
float Y() const;
float Z() const;
Point3f Location() const;
float Heading() const;
string HeadingToAsString() const;
Point3f Velocity() const;
bool CheckCollision() const;
bool CheckCollision(const float toX, const float toY, const float toZ) const;
float TargetRingRadius() const;
float CollisionRadius() const;
float CollisionScale() const;
u_long WhoFollowingId() const;
string WhoFollowingName() const;
float Speed() const;
float SwimmingSpeedModifier() const;
// Booleans
bool InMyGroup() const;
bool Interactable() const;
bool OnFlyingMount() const;
bool FlyingUsingMount() const;
bool IsChest() const;
bool IsBanker() const;
bool IsMerchant() const;
bool IsAPet() const;
bool IsMyPet() const;
bool IsAfk() const;
bool IsLfw() const;
bool IsLfg() const;
bool IsLinkdead() const;
bool IsCamping() const;
bool IsLocked() const;
bool IsAggro() const;
bool IsSolo() const;
bool IsHeroic() const;
bool IsEpic() const;
bool IsNamed() const;
bool IsSwimming() const;
bool IsEncounterBroken() const;
bool IsInvisible() const;
bool IsClimbing() const;
bool IsJumping() const;
bool IsFalling() const;
bool IsFD() const;
bool IsDead() const;
bool IsRooted() const;
bool CanTurn() const;
// The following members are mutually exclusive.
bool InCombatMode() const;
bool IsCrouching() const;
bool IsSitting() const;
// The following members are mutually exclusive.
bool OnCarpet() const;
bool OnHorse() const;
bool ONGriphon() const;
// The following members are mutually exclusive.
bool IsRunning() const;
bool IsWalking() const;
bool IsSprinting() const;
// The following members are mutually exclusive.
bool IsBackingUp() const;
bool IsStrafingLeft() const;
bool IsStrafingRight() const;
bool IsIdle() const;
// Encounter Information
int EncounterSize() const;
/// \brief Returns the encounter difficulty as a range of -3 to 3. (-3 = three down arrows, 0 = no arrows, 3 = three up arrows)
int Difficulty() const;
/// \brief Given another actor's ID#, returns TRUE if this actor is in the same encounter.
int IsInSameEncounter(const u_long id) const;
int RaidSize() const;
string TagTargetNumber() const;
string TagTargetIcon() const;
// Effects
int EffectCount() const;
/// \brief Using a Lavishscript Query String allows script writers to search based on ANY of the datatypes members.
// ActorEffect Effect(query, string) const;
// Methods
void DoubleClick() const;
void WaypointTo() const;
void DoFace() const;
void DoTarget() const;
void AddLocation(const string &notes) const;
void DeleteLocation() const;
void RequesteffectsInfo() const;
protected:
const shared_ptr<LSObject> lsObject;

View File

@ -1,33 +1,87 @@
#include "Character.h"
std::string Character::GetArchetype() const {
const auto response = this->lsObject->GetMember("Archetype");
return {response.CharPtr};
std::string Character::Archetype() const {
return this->lsObject->GetMember("Archetype").CharPtr;
}
std::string Character::GetSubClass() const {
const auto response = this->lsObject->GetMember("SubClass");
return {response.CharPtr};
std::string Character::SubClass() const {
return this->lsObject->GetMember("SubClass").CharPtr;
}
std::string Character::GetTradeskillArchtype() const {
const auto response = this->lsObject->GetMember("TSArchetype");
return {response.CharPtr};
std::string Character::TradeskillArchtype() const {
return this->lsObject->GetMember("TSArchetype").CharPtr;
}
std::string Character::GetTradeskillClass() const {
const auto response = this->lsObject->GetMember("TSClass");
return {response.CharPtr};
std::string Character::TradeskillClass() const {
return this->lsObject->GetMember("TSClass").CharPtr;
}
std::string Character::GetTradeskillSubClass() const {
const auto response = this->lsObject->GetMember("TSSubClass");
std::string Character::TradeskillSubClass() const {
return this->lsObject->GetMember("TSSubClass").CharPtr;
}
return {response.CharPtr};
Actor Character::CursorActor() const {
return Actor(make_shared<LSObject>(LSObject(this->lsObject->GetMember("CursorActor"))));
}
bool Character::IsMoving() const {
return this->lsObject->GetMember("IsMoving").Int;
}
bool Character::InGameWorld() const {
return this->lsObject->GetMember("InGameWorld").Int;
}
bool Character::AtCharSelect() const {
return this->lsObject->GetMember("AtCharSelect").Int;
}
float Character::WaterDepth() const {
return this->lsObject->GetMember("WaterDepth").Float;
}
float Character::HeadingTo(const float toX, const float toY, const float toZ) const {
return this->lsObject->GetMember("HeadingTo", toX, toY, toZ).Float;
}
string Character::HeadingToAsString(const float toX, const float toY, const float toZ) const {
return this->lsObject->GetMember("HeadingTo", toX, toY, toZ, "AsString").CharPtr;
}
int Character::VeteranBonus() const {
return this->lsObject->GetMember("VeteranBonus").Int;
}
int Character::Level() const {
return this->lsObject->GetMember("Level").Int;
}
int Character::EffectiveLevel() const {
return this->lsObject->GetMember("EffectiveLevel").Int;
}
int Character::TradeskillLevel() const {
return this->lsObject->GetMember("TSLevel").Int;
}
int Character::APExperience() const {
return this->lsObject->GetMember("APExp").Int;
}
int Character::TotalEarnedAPs() const {
return this->lsObject->GetMember("TotalEarnedAPs").Int;
}
int Character::MaxAPs() const {
return this->lsObject->GetMember("MaxAPs").Int;
}
int Character::NumAbilities() const {
return this->lsObject->GetMember("NumAbilities").Int;
}
Ability Character::Ability(const int index) const {
return Ability::Ability(make_shared<LSObject>(LSObject(this->lsObject->GetMember("Ability", index))));
}

View File

@ -3,17 +3,43 @@
#include <string>
#include "Ability.h"
#include "LSObject.h"
#include "Actor.h"
class Character : public Actor {
public:
explicit Character(const shared_ptr<LSObject> &obj) : Actor(obj) { }
std::string GetArchetype() const;
std::string GetSubClass() const;
std::string GetTradeskillArchtype() const;
std::string GetTradeskillClass() const;
std::string GetTradeskillSubClass() const;
std::string Archetype() const;
std::string SubClass() const;
std::string TradeskillArchtype() const;
std::string TradeskillClass() const;
std::string TradeskillSubClass() const;
Actor CursorActor() const;
// GameData
// Location
bool IsMoving() const;
bool InGameWorld() const;
bool AtCharSelect() const;
float WaterDepth() const;
float HeadingTo(float toX, float toY, float toZ) const;
string HeadingToAsString(float toX, float toY, float toZ) const;
// Experience/Level
int VeteranBonus() const;
int Level() const;
int EffectiveLevel() const;
int TradeskillLevel() const;
int APExperience() const;
int TotalEarnedAPs() const;
int MaxAPs() const;
// Abilities & Recipes
int NumAbilities() const;
Ability Ability(int index) const;
};

View File

@ -0,0 +1,32 @@
//
// Created by marob on 12/27/2023.
//
#ifndef CLASS_H
#define CLASS_H
#include "LSObject.h"
class CharacterClass {
public:
explicit CharacterClass(const shared_ptr<LSObject> &obj) {
name = obj->GetMember("Name").CharPtr;
level = obj->GetMember("Level").Int;
}
string Name() const {
return this->name;
}
int Level() const {
return this->level;
}
private:
string name;
int level;
};
#endif //CLASS_H

View File

@ -0,0 +1,19 @@
#ifndef EXTENSIONTLOS_H
#define EXTENSIONTLOS_H
#include <optional>
#include "Actor.h"
#include "Character.h"
class ExtensionTLOs {
public:
static Character Me() {
const auto me = pISInterface->IsTopLevelObject("Me");
LSOBJECT response;
me(0, nullptr, response);
const auto characterObject = make_shared<LSObject>(LSObject(response));
return Character(characterObject);
}
};
#endif //EXTENSIONTLOS_H

View File

@ -1,11 +0,0 @@
//
// Created by marob on 12/20/2023.
//
#include "LSObject.h"
#include <vector>
#include "ISXMr.h"

View File

@ -6,42 +6,71 @@
#define LSOBJECT_H
#include <ISXDK.h>
#include <vector>
#include <sstream>
#include "ISXMr.h"
template<typename T>
std::string toString(const T &value) {
std::ostringstream oss;
oss << value;
return oss.str();
}
class LSObject {
public:
explicit LSObject (const LSOBJECT &obj) : lsObject(obj) {}
explicit LSObject(const LSOBJECT &obj) : lsObject(obj) {
}
template <typename... Args>
template<typename... Args>
LSOBJECT GetMember(const std::string &memberName, Args... args) {
LSOBJECT response;
const vector<std::string> arguments = {args...};
// Use a fold expression to convert each argument to a string
const std::vector<std::string> arguments = {toString(args)...};
const int argc = arguments.size();
vector<char*> argv;
std::vector<char *> argv;
for(auto &arg : arguments) {
argv.push_back(const_cast<char*>(arg.c_str()));
for (auto &arg: arguments) {
argv.push_back(const_cast<char *>(arg.c_str()));
}
this->lsObject.Type->GetMemberEx(
this->lsObject.GetObjectData(),
const_cast<char*>(memberName.c_str()),
const_cast<char *>(memberName.c_str()),
argc,
argv.data(),
response
);
pISInterface->Printf("%s Type: %s", memberName.c_str(), response.Type->GetName());
return response;
}
template<typename... Args>
void CallMethod(const std::string &methodName, Args... args) {
LSOBJECT response;
// Use a fold expression to convert each argument to a string
const std::vector<std::string> arguments = {toString(args)...};
const int argc = arguments.size();
std::vector<char *> argv;
for (auto &arg: arguments) {
argv.push_back(const_cast<char *>(arg.c_str()));
}
this->lsObject.Type->GetMethodEx(
this->lsObject.GetObjectData(),
const_cast<char *>(methodName.c_str()),
argc,
argv.data());
}
private:
LSOBJECT lsObject;
};
#endif //LSOBJECT_H

42
src/isxeq2/Point3f.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef POINT3F_H
#define POINT3F_H
#include <memory>
#include "LSObject.h"
#include "ISXMr.h"
class Point3f {
public:
explicit Point3f(const shared_ptr<LSObject> &obj) {
x = *obj->GetMember("X").Float64Ptr;
y = *obj->GetMember("Y").Float64Ptr;
z = *obj->GetMember("Z").Float64Ptr;
}
explicit Point3f(const float x, const float y, const float z) : x(x), y(y), z(z) { }
float X() const { return this->x; }
float Y() const { return this->y; }
float Z() const { return this->z; }
void setX(const float x) {
this->x = x;
}
void setY(const float y) {
this->y = y;
}
void setZ(const float z) {
this->z = z;
}
private:
float x;
float y;
float z;
};
#endif //POINT3F_H