diff --git a/README.md b/README.md index 762a6324..3b0f053f 100644 --- a/README.md +++ b/README.md @@ -23,5 +23,6 @@ Roadmap Known Bug Workarounds ===================== -* Burrito launches off-center or on the wrong monitor - * This seems to be WM dependant. on Gnome it can be solved by holding down the super key and dragging burrito to the right position. +* Burrito launches off-center or on the wrong monitor (This seems to be WM dependant.) + * On Gnome and KDE it can be solved by holding down the super key and dragging burrito to the right position. + * On KDE it is also possible to use [window-rules](https://docs.kde.org/stable5/en/kwin/kcontrol/windowspecific/examples.html) to set the position or a target monitor automatically by adding a new rule to `System Settings → Window Behavior → Window Rules` and setting `window class (application)` to `burrito`. diff --git a/Spatial.gd b/Spatial.gd index d31d934a..419248cc 100644 --- a/Spatial.gd +++ b/Spatial.gd @@ -66,6 +66,22 @@ onready var markers_ui := $Control/Dialogs/CategoriesDialog/MarkersUI as Tree onready var markers_3d := $Markers3D as Spatial onready var markers_2d := $Control/Markers2D as Node2D +# Variables that store informations about ui scaling +# The ui-size as read from the link can have the values [0=small; 1=normal; 2=large; 3=larger] +var ui_size: int = 1 +# This dictionary holds the left and right margin for the main button for every ui-scale +const button_margin = { + 0: {"left": 292, "right": 318}, # small + 1: {"left": 323, "right": 352}, # normal + 2: {"left": 361, "right": 394}, # large + 3: {"left": 395, "right": 431} # larger +} +const minimap_scale = { + 0: {"offset": 32, "factor": 0.9}, # small + 1: {"offset": 36, "factor": 1}, # normal + 2: {"offset": 40, "factor": 1.11}, # large + 3: {"offset": 44, "factor": 1.22} # larger +} # Called when the node enters the scene tree for the first time. func _ready(): @@ -269,7 +285,7 @@ func decode_frame_packet(spb: StreamPeerBuffer): if (!map_is_open): map_size = Vector2(compass_width, compass_height) if !compass_is_top_right: - map_corner = get_viewport().size - Vector2(compass_width, compass_height + 36) + map_corner = get_viewport().size - Vector2(compass_width, compass_height + self.minimap_scale[self.ui_size]["offset"]) else: map_corner = Vector2(get_viewport().size.x - compass_width, 0) @@ -341,6 +357,20 @@ func decode_context_packet(spb: StreamPeerBuffer): # vs radians. 70deg = 1.22173rad and 25deg = 0.4363323rad. We should redo # this to just be a radian to degree conversion. + # Calculations to dynamically place the main icon/button + self.ui_size = int(identity["uisz"]) + # If the value is not part of the dictionary use the "normal" size. + if !self.button_margin.has(self.ui_size): + self.ui_size = 1 + + $Control/GlobalMenuButton.margin_left = self.button_margin[self.ui_size]["left"] + $Control/GlobalMenuButton.margin_right = self.button_margin[self.ui_size]["right"] + if !is_any_dialog_visible(): + set_minimal_mouse_block() + + compass_width = compass_width * self.minimap_scale[self.ui_size]["factor"] + compass_height = compass_height * self.minimap_scale[self.ui_size]["factor"] + if self.map_id != old_map_id: print("New Map") var old_texture_path: String = "" @@ -371,8 +401,8 @@ func reset_minimap_masks(reset_3d: bool = true): var compass_corner1 = Vector2(0, 0) var compass_corner2 = viewport_size if !map_is_open && !compass_is_top_right: - compass_corner1 = Vector2(viewport_size.x-self.compass_width, 36) - compass_corner2 = compass_corner1 + Vector2(self.compass_width, self.compass_height) + compass_corner1 = Vector2(viewport_size.x-compass_width, self.minimap_scale[self.ui_size]["offset"]) + compass_corner2 = compass_corner1 + Vector2(compass_width, compass_height) elif !map_is_open && compass_is_top_right: compass_corner1 = viewport_size - Vector2(self.compass_width, self.compass_height) compass_corner2 = compass_corner1 + Vector2(self.compass_width, self.compass_height) @@ -910,11 +940,16 @@ func _on_main_menu_toggle_pressed(): $Control/Dialogs/MainMenu.show() set_maximal_mouse_block() -func _on_Dialog_hide(): +func is_any_dialog_visible(): for dialog in $Control/Dialogs.get_children(): if dialog.visible: - return - set_minimal_mouse_block() + return true + return false + + +func _on_Dialog_hide(): + if !is_any_dialog_visible(): + set_minimal_mouse_block() func _on_LoadTrail_pressed(): diff --git a/burrito_link/CMakeLists.txt b/burrito_link/CMakeLists.txt index fc25597e..a58d1154 100644 --- a/burrito_link/CMakeLists.txt +++ b/burrito_link/CMakeLists.txt @@ -37,5 +37,5 @@ target_link_libraries(${DX11LIB} PRIVATE "ws2_32") set_target_properties(${DX11LIB} PROPERTIES PREFIX "" SUFFIX "" - LINK_FLAGS "../deffile.def -Wl,--allow-shlib-undefined -Wl,-O1 -shared -static -static-libgcc -static-libstdc++ -Wl,--file-alignment=4096 -lm -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32" + LINK_FLAGS "../deffile.def -Wl,--allow-shlib-undefined,--no-insert-timestamp -Wl,-O1 -shared -static -static-libgcc -static-libstdc++ -Wl,--file-alignment=4096 -lm -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32" ) diff --git a/burrito_link/burrito_link.c b/burrito_link/burrito_link.c index b5f5dc64..c32e28c2 100644 --- a/burrito_link/burrito_link.c +++ b/burrito_link/burrito_link.c @@ -13,15 +13,22 @@ #define PACKET_METADATA 2 #define PACKET_LINK_TIMEOUT 3 +// The max buffer size for data that is being sent to burrito over the UDP socket +#define MAX_BUFFER_SIZE 1024 -// The max buffer size for data that is being sent to burriot over the UDP socket -#define MaxBufferSize 1024 +// Number of uiTicks that should pass between when each "heavy" packet is sent. +#define HEAVY_DATA_INTERVAL 500 + +// Define the port and address we are trying to connect to. The address is a +// loopback address because we are trying to talk to another process running on +// the same machine. +#define COMMUNICATION_PORT 4242 +#define COMMUNICATION_IPV4 "127.0.0.1" // A state variable to keep track of the previous cycle's map_id to determine // if the map_id has changed in this cycle. int last_map_id = 0; - // Do a rolling average on the player position because that seems to be // Roughly what the camera position is doing and doing this will remove // some weird jitter I hope @@ -51,27 +58,46 @@ struct rolling_average_5 playerz_avg; float fAvatarAveragePosition[3]; -// global variables -// mumble link pointer + +// Handle to the shared memory. This is kept so that the handle can be closed +// when the program exits because Windows will only release the shared memory +// once all handles are closed. +HANDLE handle_lm; + +// The pointer to the mapped view of the file. This should be unmapped before +// `handle_lm` is closed. +LPCTSTR mapped_lm; + +// Pointer to the mapped LinkedMem object. Only available after initMumble() +// is called. struct LinkedMem *lm = NULL; -// mumble context pointer into the `lm` variable above. +// Pointer to the mapped MumbleContext object found at `lm->context`. Only +// available after initMumble() is called. struct MumbleContext *lc = NULL; + +// How many "clocks", as defined by CLOCKS_PER_SECOND and by the return value +// of clock(), will elapse before the program should time out. If this is left +// at 0 burrito link will never time out. long program_timeout = 0; -long program_startime = 0; +// What was the value of `clock()` when the program started. This is used with +// program_timeout to determine if the program should time out or continue. +long program_startime = 0; -// handle to the shared memory of Mumble link . close at the end of program. windows will only release the shared memory once ALL handles are closed, -// so we don't have to worry about other processes like arcdps or other overlays if they are using this. -HANDLE handle_lm; -// the pointer to the mapped view of the file. close before handle. -LPCTSTR mapped_lm; +//////////////////////////////////////////////////////////////////////////////// +// initMumble +// +// Creates or reads a shared memory object named "MumbleLink" which has the +// data from Guild Wars 2. We must create the memory object if it does not +// exist because, while Guild Wars 2 will write to it if it exists, it will not +// create it if it does not already exist. +// +// Reference: https://docs.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory +//////////////////////////////////////////////////////////////////////////////// void initMumble() { - // creates a shared memory IF it doesn't exist. otherwise, it returns the existing shared memory handle. - // reference: https://docs.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory - size_t BUF_SIZE = sizeof(struct LinkedMem); handle_lm = CreateFileMapping( @@ -116,7 +142,7 @@ void initMumble() { // This function attempts to read that property and return it. //////////////////////////////////////////////////////////////////////////////// uint32_t x11_window_id_from_windows_process_id(uint32_t windows_process_id) { - // Get and send the linux x server window id + // Get and send the Linux x server window id UINT32 x11_window_id = 0; HWND window_handle = NULL; BOOL CALLBACK EnumWindowsProcMy(HWND hwnd, LPARAM lParam) { @@ -135,7 +161,7 @@ uint32_t x11_window_id_from_windows_process_id(uint32_t windows_process_id) { x11_window_id = (size_t)possible_x11_window_id; } // else { - // printf("No Linux ID\n"); + // printf("No Linux x11 window ID found\n"); // } return x11_window_id; } @@ -147,14 +173,12 @@ uint32_t x11_window_id_from_windows_process_id(uint32_t windows_process_id) { // memory block and sending the memory over to burrito over a UDP socket. //////////////////////////////////////////////////////////////////////////////// int connect_and_or_send() { - WSADATA wsaData; - SOCKET SendingSocket; - SOCKADDR_IN ReceiverAddr; - int Port = 4242; int BufLength = 1024; - char SendBuf[MaxBufferSize]; + char SendBuf[MAX_BUFFER_SIZE]; int TotalByteSent; + // Setup and Initialize Winsock library + WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("Client: WSAStartup failed with error %d\n", WSAGetLastError()); @@ -167,10 +191,10 @@ int connect_and_or_send() { else { printf("Client: The Winsock DLL status is %s.\n", wsaData.szSystemStatus); } - // Create a new socket to receive datagrams on. + // Create a new socket to send datagrams on. + SOCKET SendingSocket; SendingSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (SendingSocket == INVALID_SOCKET) { // Print error message printf("Client: Error at socket(): %d\n", WSAGetLastError()); @@ -185,39 +209,43 @@ int connect_and_or_send() { printf("Client: socket() is OK!\n"); } - /*Set up a SOCKADDR_IN structure that will identify who we - will send datagrams to. - For demonstration purposes, let's assume our receiver's IP address is 127.0.0.1 - and waiting for datagrams on port 5150.*/ - + // Setup the destination where we want to send the parsed data to. + SOCKADDR_IN ReceiverAddr; ReceiverAddr.sin_family = AF_INET; - - ReceiverAddr.sin_port = htons(Port); - - ReceiverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + ReceiverAddr.sin_port = htons(COMMUNICATION_PORT); + ReceiverAddr.sin_addr.s_addr = inet_addr(COMMUNICATION_IPV4); int count = 0; - DWORD lastuitick = 0; + DWORD last_ui_tick = 0; // Send data packages to the receiver(Server). do { + // Trigger the builtin auto close timeout if a timeout was set. Send a + // message to burrito that the program hit its timeout so that burrito + // can decide if it should launch a new instance of burrito link or not. if (program_timeout != 0 && clock() - program_startime > program_timeout) { - BufLength = 1; - // Set the first byte of the packet to indicate this packet is a `Heaver Context Updater` packet + // Set the first and only byte of the packet to indicate this + // packet is a `Packet Link Timeout` packet. SendBuf[0] = PACKET_LINK_TIMEOUT; + BufLength = 1; + TotalByteSent = sendto(SendingSocket, SendBuf, BufLength, 0, (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr)); if (TotalByteSent != BufLength) { printf("Not all Bytes Sent"); } - printf("Breaking out due to timeout"); + printf("Exiting due to timeout being reached."); break; } - if (lm->uiTick == lastuitick) { + + // If uiTick is the same value as it was the previous loop then Guild + // Wars 2 has not updated any data. Sleep for 1ms and check again. + if (lm->uiTick == last_ui_tick) { Sleep(1); continue; } - lastuitick = lm->uiTick; + last_ui_tick = lm->uiTick; + // Update the player position to calculate the new rolling average. replace_point_in_rolling_average(&playerx_avg, lm->fAvatarPosition[0]); replace_point_in_rolling_average(&playery_avg, lm->fAvatarPosition[1]); replace_point_in_rolling_average(&playerz_avg, lm->fAvatarPosition[2]); @@ -227,9 +255,10 @@ int connect_and_or_send() { fAvatarAveragePosition[1] = get_rolling_average(&playery_avg); fAvatarAveragePosition[2] = get_rolling_average(&playerz_avg); - BufLength = 1; - // Set the first byte of the packet to indicate this packet is a `Per Frame Updater` packet + // Set the first byte of the packet to indicate this packet is a + // `Per Frame Updater` packet SendBuf[0] = PACKET_FRAME; + BufLength = 1; memcpy(SendBuf + BufLength, lm->fCameraPosition, sizeof(lm->fCameraPosition)); BufLength += sizeof(lm->fCameraPosition); @@ -240,9 +269,6 @@ int connect_and_or_send() { memcpy(SendBuf + BufLength, fAvatarAveragePosition, sizeof(fAvatarAveragePosition)); BufLength += sizeof(fAvatarAveragePosition); - // memcpy(SendBuf+BufLength, lm->fAvatarPosition, sizeof(lm->fAvatarPosition)); - // BufLength += sizeof(lm->fAvatarPosition); - float map_offset_x = lc->playerX - lc->mapCenterX; memcpy(SendBuf + BufLength, &map_offset_x, sizeof(map_offset_x)); BufLength += sizeof(map_offset_x); @@ -260,13 +286,8 @@ int connect_and_or_send() { memcpy(SendBuf + BufLength, &lc->uiState, sizeof(lc->uiState)); BufLength += sizeof(lc->uiState); - // UINT32 - - // printf("map_offset_x: %f\n", lc->playerX - lc->mapCenterX); - // printf("map_offset_y: %f\n", lc->playerY - lc->mapCenterY); - // printf("mapScale: %f\n", lc->mapScale); - // printf("compassRotation: %f\n", lc->compassRotation); // radians - // printf("UI State: %i\n", lc->uiState); // Bitmask: Bit 1 = IsMapOpen, Bit 2 = IsCompassTopRight, Bit 3 = DoesCompassHaveRotationEnabled, Bit 4 = Game has focus, Bit 5 = Is in Competitive game mode, Bit 6 = Textbox has focus, Bit 7 = Is in Combat + // memcpy(SendBuf + BufLength, &lc->mountIndex, sizeof(lc->mountIndex)); + // BufLength += sizeof(lc->mountIndex); TotalByteSent = sendto(SendingSocket, SendBuf, BufLength, 0, (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr)); if (TotalByteSent != BufLength) { @@ -278,41 +299,11 @@ int connect_and_or_send() { // the current state of the game. if (count == 0 || lc->mapId != last_map_id) { last_map_id = lc->mapId; - BufLength = 1; - // Set the first byte of the packet to indicate this packet is a `Heaver Context Updater` packet - SendBuf[0] = PACKET_METADATA; - // printf("hello world\n"); - // printf("%ls\n", lm->description); - - printf("%ls\n", lm->identity); - - // printf("%i\n", lc->mapId); - // printf("\n", lc->serverAddress); // contains sockaddr_in or sockaddr_in6 - // printf("Map Id: %i\n", lc->mapId); - // printf("Map Type: %i\n", lc->mapType); - // printf("shardId: %i\n", lc->shardId); - // printf("instance: %i\n", lc->instance); - // printf("buildId: %i\n", lc->buildId); - // printf("UI State: %i\n", lc->uiState); // Bitmask: Bit 1 = IsMapOpen, Bit 2 = IsCompassTopRight, Bit 3 = DoesCompassHaveRotationEnabled, Bit 4 = Game has focus, Bit 5 = Is in Competitive game mode, Bit 6 = Textbox has focus, Bit 7 = Is in Combat - // printf("compassWidth %i\n", lc->compassWidth); // pixels - // printf("compassHeight %i\n", lc->compassHeight); // pixels - // printf("compassRotation: %f\n", lc->compassRotation); // radians - // printf("playerX: %f\n", lc->playerX); // continentCoords - // printf("playerY: %f\n", lc->playerY); // continentCoords - // printf("mapCenterX: %f\n", lc->mapCenterX); // continentCoords - // printf("mapCenterY: %f\n", lc->mapCenterY); // continentCoords - // printf("mapScale: %f\n", lc->mapScale); - // printf("\n", UINT32 processId; - // printf("mountIndex: %i\n", lc->mountIndex); - - // New things for the normal packet - - // Things for the context packet - // printf("compassWidth %i\n", lc->compassWidth); // pixels - // printf("compassHeight %i\n", lc->compassHeight); // pixels - // printf("Map Id: %i\n", lc->mapId); - // printf("%ls\n", lm->identity); + // Set the first byte of the packet to indicate this packet is a + // `Heaver Context Updater` packet. + SendBuf[0] = PACKET_METADATA; + BufLength = 1; memcpy(SendBuf + BufLength, &lc->compassWidth, sizeof(lc->compassWidth)); BufLength += sizeof(lc->compassWidth); @@ -324,44 +315,36 @@ int connect_and_or_send() { BufLength += sizeof(lc->mapId); uint32_t x11_window_id = x11_window_id_from_windows_process_id(lc->processId); - memcpy(SendBuf + BufLength, &x11_window_id, sizeof(x11_window_id)); BufLength += sizeof(x11_window_id); - // Convert and send the JSON 'identity' payload - char utf8str[1024]; - - UINT32 converted_size = WideCharToMultiByte( - CP_UTF8, - 0, - lm->identity, - -1, - utf8str, - 1024, - NULL, - NULL); - - // printf("UTF8 Length: %i\n", converted_size); - // printf("%s\n", utf8str); - - // UINT16 identity_size = wcslen(lm->identity); - memcpy(SendBuf + BufLength, &converted_size, sizeof(converted_size)); - BufLength += sizeof(converted_size); - - memcpy(SendBuf + BufLength, utf8str, converted_size); - BufLength += converted_size; + // Convert the JSON 'identity' payload from widechar to utf8 + // encoded char and send. + char utf8_identity[1024]; + UINT32 utf8_identity_size = WideCharToMultiByte( + CP_UTF8, // CodePage + 0, // dwFlags + lm->identity, // lpWideCharStr + -1, // cchWideChar + utf8_identity, // lpMultiByteStr + 1024, // cbMultiByte + NULL, // lpDefaultChar + NULL); // lpUsedDefaultChar + memcpy(SendBuf + BufLength, &utf8_identity_size, sizeof(utf8_identity_size)); + BufLength += sizeof(utf8_identity_size); + memcpy(SendBuf + BufLength, utf8_identity, utf8_identity_size); + BufLength += utf8_identity_size; TotalByteSent = sendto(SendingSocket, SendBuf, BufLength, 0, (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr)); if (TotalByteSent != BufLength) { printf("Not all Bytes Sent"); } - // break; } // Update the count for the `Heaver Context Updater` packet and reset // it to 0 when it hits a threshold value. count += 1; - if (count > 500) { + if (count > HEAVY_DATA_INTERVAL) { count = 0; } } while (TRUE); @@ -393,6 +376,14 @@ int connect_and_or_send() { return 0; } +//////////////////////////////////////////////////////////////////////////////// +// run_link +// +// The entry point for all burrito link processes. This is called by either the +// command line entry point, or by a dll entry point. It initializes any global +// that and then launches the infinite loop of reading data from shared memory +// and sending the data over the wire to burrito. +//////////////////////////////////////////////////////////////////////////////// void run_link() { playerx_avg.index = 0; playery_avg.index = 0; @@ -404,8 +395,11 @@ void run_link() { } //////////////////////////////////////////////////////////////////////////////// -// The main function initializes some global variables and shared memory. Then -// calls the connect_and_or_send process which loops until termination. +// main +// +// The entry point to burrito link when called as an executable. Sets up any +// data that needs to be configured for just command line executions, then +// calls run_link() which sets up all other state necessary for burrito link. //////////////////////////////////////////////////////////////////////////////// int main(int argc, char **argv) { for (int i = 0; i < argc; i++) { diff --git a/burrito_link/deffile.def b/burrito_link/deffile.def index eb57a4e1..54e4b774 100644 --- a/burrito_link/deffile.def +++ b/burrito_link/deffile.def @@ -5,3 +5,4 @@ EXPORTS D3D11CoreCreateDevice get_init_addr get_release_addr + GetAddonDef diff --git a/burrito_link/dllmain.c b/burrito_link/dllmain.c index 62ea9ef3..0ba510e5 100644 --- a/burrito_link/dllmain.c +++ b/burrito_link/dllmain.c @@ -1,8 +1,10 @@ -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #include #include #include #include +// Forward declare the run_link() function defined in burrito_link.c +void run_link(); #ifndef true #define true TRUE @@ -16,9 +18,6 @@ #define nullptr 0 #endif -#define CEXTERN extern - - //////////////////////////////////////////////////////////////////////////////// // GetOriginalD3D11Module // @@ -60,7 +59,6 @@ void FreeD3D11Module() { } - //////////////////////////////////////////////////////////////////////////////// // D3D11CreateDeviceAndSwapChainOriginal // @@ -88,7 +86,7 @@ D3D11CreateDeviceAndSwapChainFunc D3D11CreateDeviceAndSwapChainOriginal = nullpt // A proxy function that calls the original d3d11.dll's // D3D11CreateDeviceAndSwapChain function, then returns the result. //////////////////////////////////////////////////////////////////////////////// -CEXTERN HRESULT WINAPI D3D11CreateDeviceAndSwapChain( +extern HRESULT WINAPI D3D11CreateDeviceAndSwapChain( IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, @@ -152,7 +150,7 @@ D3D11CreateDeviceFunc D3D11CreateDeviceOriginal = nullptr; // A proxy function that call the original d3d11.dll's D3D11CreateDevice // function, then returns the result. //////////////////////////////////////////////////////////////////////////////// -CEXTERN HRESULT WINAPI D3D11CreateDevice( +extern HRESULT WINAPI D3D11CreateDevice( IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, @@ -208,7 +206,7 @@ D3D11CoreCreateDeviceFunc D3D11CoreCreateDeviceOriginal = nullptr; // A proxy function that call the original d3d11.dll's D3D11CoreCreateDevice // function, then returns the result. //////////////////////////////////////////////////////////////////////////////// -CEXTERN HRESULT WINAPI D3D11CoreCreateDevice( +extern HRESULT WINAPI D3D11CoreCreateDevice( IDXGIFactory * pFactory, IDXGIAdapter * pAdapter, UINT Flags, @@ -235,14 +233,13 @@ CEXTERN HRESULT WINAPI D3D11CoreCreateDevice( } -// Forward declare the run_link() function defined in burrito_link.c -void run_link(); - -// Call the burrito link function from the thread. -// TODO: There is something odd here that causes a crash as gw2 is exiting. -// Because gw2 is exiting the crash does not really matter. I am guessing it -// has something to do with how we handle the infinite wait loop inside -// burrito_link and that we dont clean it up ever. +//////////////////////////////////////////////////////////////////////////////// +// BurritoLinkThread +// +// A helper function that calls the burrito link run_link() function. It exists +// so that it can be passed into the Windows API CreateThread and can be run +// within a the new thread instead of the DLL's main thread. +//////////////////////////////////////////////////////////////////////////////// void WINAPI BurritoLinkThread() { run_link(); return; @@ -282,7 +279,7 @@ void start_burrito_link_thread() { // stop_burrito_link_thread // // Kills a burrito link thread if there is a burrito link thread running. This -// is nessasry to avoid an error message on exit. +// is necessary to avoid an error message on exit. //////////////////////////////////////////////////////////////////////////////// void stop_burrito_link_thread() { if (burrito_link_thread_handle != nullptr) { @@ -313,24 +310,20 @@ BOOL WINAPI DllMain( DWORD fdwReason, // reason for calling DllMain LPVOID lpvReserved // Reserved ) { - // printf("FUNCTION: 2 C DllMain "); // Perform actions based on the reason for calling. switch(fdwReason) { // Do process initialization. Return false if initialization fails. case DLL_PROCESS_ATTACH: - // TODO: Here is where we want to create a new process. printf("DLL_PROCESS_ATTACH\n"); start_burrito_link_thread(); break; // Do thread-specific initialization. case DLL_THREAD_ATTACH: - // printf("DLL_THREAD_ATTACH\n"); break; // Do thread-specific cleanup. case DLL_THREAD_DETACH: - // printf("DLL_THREAD_DETACH\n"); break; // Do process cleanup @@ -403,3 +396,55 @@ uintptr_t mod_release() { extern __declspec(dllexport) void* get_release_addr() { return mod_release; } + + +//////////////////////////////////////////////////////////////////////////////// +// Raidcore Nexus +// +// GetAddonDef() +// +// +// +// These function is present to allow nexus to recognize this dll as a addon. +// These function is the only function that is required all others are optional. +//////////////////////////////////////////////////////////////////////////////// +struct AddonDefinition { + /* required */ + signed int Signature; /* Raidcore Addon ID, set to random unqiue negative integer if not on Raidcore */ + signed int APIVersion; /* Determines which AddonAPI struct revision the Loader will pass, use the NEXUS_API_VERSION define from Nexus.h */ + const char* Name; /* Name of the addon as shown in the library */ + struct AddonVersion { + signed short Major; + signed short Minor; + signed short Build; + signed short Revision; + } Version; + const char* Author; /* Author of the addon */ + const char* Description; /* Short description */ + void* Load; /* Pointer to Load Function of the addon */ + void* Unload; /* Pointer to Unload Function of the addon. Not required if EAddonFlags::DisableHotloading is set. */ + signed int Flags; /* Information about the addon */ + + /* update fallback */ + signed int Provider; /* What platform is the the addon hosted on */ + const char* UpdateLink; /* Link to the update resource */ + +} AddonDef; + +extern __declspec(dllexport) struct AddonDefinition* GetAddonDef() +{ + AddonDef.Signature = -1032686481; + AddonDef.APIVersion = 6; // taken from Nexus.h + AddonDef.Name = "Burrito Link"; + AddonDef.Version.Major = 0; + AddonDef.Version.Minor = 0; + AddonDef.Version.Build = 0; + AddonDef.Version.Revision = 1; + AddonDef.Author = "AsherGlick"; + AddonDef.Description = "Automatically provides the link for Burrito."; + AddonDef.Load = start_burrito_link_thread; + AddonDef.Unload = stop_burrito_link_thread; + AddonDef.Flags = 0; + + return &AddonDef; +} diff --git a/scripts/taco_to_burrito.py b/scripts/taco_to_burrito.py index d1443c70..f8356c96 100644 --- a/scripts/taco_to_burrito.py +++ b/scripts/taco_to_burrito.py @@ -12,6 +12,8 @@ source_path: str = "" target_path: str = "" +unnamed_count: int = 0 + def main(): if len(sys.argv) != 3: print(f"USAGE: {sys.argv[0]} SRC_DIR DEST_DIR") @@ -50,11 +52,44 @@ def eprint(*args, **kwargs): print(eprint_title) print(" ", *args, **kwargs) +other_ignored_tags = set([ + "achievementBit", + "tip-name", + "tip-description", + "achievementId", + "autotrigger", + "copy", + "copy-message", + "triggerrange", + "autotrigger", + "bh-color", + "bh-DisplayName", + "bh-heightOffset", + "bh-iconSize", + "bh-inGameVisibility", + "bh-mapVisibility", + "bh-miniMapVisibility", + "bh-name", + "bounce", + "bounce-height", + "copy", + "copy-message", + "inGameVisibility", + "Name", + "profession", + "triggerrange", +]) + +################################################################################ +# Strips namespace from tags +################################################################################ +def get_tag(element): + return element.tag.rpartition('}')[-1] ################################################################################ # ################################################################################ -def parse_marker_category(marker_category_node, base=""): +def parse_marker_category(marker_category_node, base="", parent_limited_attribs={}): required_keys = set(["DisplayName", "name" ]) allowed_keys = set([ "iconFile", @@ -76,12 +111,12 @@ def parse_marker_category(marker_category_node, base=""): "texture", "trailScale", # Ignored "scaleOnMapWithZoom", # Ignored - ]) + ]) | other_ignored_tags metadata_tree = {} - if marker_category_node.tag != "MarkerCategory": + if get_tag(marker_category_node) != "MarkerCategory": eprint("MarkerCategory Child not MarkerCategory", marker_category_node.tag) attribs = marker_category_node.attrib @@ -94,7 +129,7 @@ def parse_marker_category(marker_category_node, base=""): eprint("key {} missing from marker category".format(required_key)) - limited_attribs = {} + limited_attribs = {k:v for (k, v) in parent_limited_attribs.items()} if "iconFile" in attribs: limited_attribs["icon_file"] = attribs["iconFile"] @@ -110,12 +145,19 @@ def parse_marker_category(marker_category_node, base=""): limited_attribs["texture"] = attribs["texture"] - name = attribs["name"] + name = None + if "name" in attribs: + name = attribs["name"] + + if name == None: + global unnamed_count + name = "Unnamed"+str(unnamed_count) + unnamed_count += 1 metadata_tree[base + name] = limited_attribs for child in marker_category_node: - subtree = parse_marker_category(child, base + name + ".") + subtree = parse_marker_category(child, base + name + ".", parent_limited_attribs=limited_attribs) for elem in subtree: metadata_tree[elem] = subtree[elem] @@ -126,11 +168,10 @@ def parse_marker_category(marker_category_node, base=""): ################################################################################ def convert_markers(xml_path: str, output_dir: str): set_eprint_title(xml_path) - # print(xml_path) tree = ET.parse(xml_path) root = tree.getroot() - if root.tag != "OverlayData": + if get_tag(root) != "OverlayData": eprint("Root not OverlayData", root.tag) if root.attrib != {}: @@ -140,14 +181,14 @@ def convert_markers(xml_path: str, output_dir: str): eprint("Root has {} children instead of the expected 2".format(len(root))) return - if root[0].tag != "MarkerCategory": + if get_tag(root[0]) != "MarkerCategory": eprint("First element of root is {} not MarkerCategory".format(root[0].tag)) else: marker_metadata = parse_marker_category(root[0]) # print(marker_metadata) - if root[1].tag != "POIs": + if get_tag(root[1]) != "POIs": eprint("Second element of root is {} not POIs".format(root[1].tag)) else: burrito_marker_data = parse_icons_and_paths(root[1], marker_metadata, os.path.dirname(xml_path)) @@ -198,7 +239,7 @@ def parse_icons_and_paths(poi_node, marker_metadata, dirname=""): "resetLength", # Ignored "info", # Ignored "infoRange", # Ignored - ]) + ]) | other_ignored_tags required_trail_attrib = set([ "texture", @@ -213,7 +254,7 @@ def parse_icons_and_paths(poi_node, marker_metadata, dirname=""): "mapVisibility", # Ignored "miniMapVisibility", # Ignored "fadeNear", # Ignored - ]) + ]) | other_ignored_tags burrito_marker_data = {} @@ -222,7 +263,7 @@ def parse_icons_and_paths(poi_node, marker_metadata, dirname=""): if len(child) > 0: eprint("POI element has children") - if child.tag == "POI": + if get_tag(child) == "POI": attribs = child.attrib for present_key in attribs: if present_key not in required_poi_attrib and present_key not in allowed_poi_attrib: @@ -261,7 +302,7 @@ def parse_icons_and_paths(poi_node, marker_metadata, dirname=""): "texture": copyimage(icon_path) }) - elif child.tag == "Trail": + elif get_tag(child) == "Trail": attribs = child.attrib for present_key in attribs: if present_key not in required_trail_attrib and present_key not in allowed_trail_attrib: @@ -353,6 +394,9 @@ def copyimage(image_path): def open_trail_format(trl_path: str) -> Tuple[int, List[float]]: + if not os.path.exists(trl_path): + eprint("Cannot find file {}".format(trl_path)) + return (0, []) with open(trl_path, 'rb') as f: file_bytes = f.read()