LordAshes / TaleSpire-BeyondLinkViaChrome

Unofficial TaleSpire plugin to extract D&D Beyond data, using Chrome Extension, and make it available in TS.
MIT License
0 stars 0 forks source link

Cannot perform runtime binding on a null reference #10

Open Trogdor-TheBurninator opened 4 months ago

Trogdor-TheBurninator commented 4 months ago

Getting "injection.js:207 WebSocket connection to 'ws://127.0.0.1:[port]/' failed" error

Have tried swapping through a few ports and verifying that they're open in both router and internal firewalls. (though I'm pretty sure that wouldn't affect localhost.)

Fired up the beyondlinkserver.exe manually ("beyondlinkserver [port]" from cmd)

Its gets as far as proficiencies before the null reference error. ( Char is named: "Miracle Macs'alangelo", but it seems to have missed that as well?)

[ -> BeyondLinkData ]

.Name = .Level = .Race = Variant Human .Class = Cleric 4 .AC = 16 .HP.Current = 35 .HP.Max = 35 .HD.Used = 0 .HD.Total = 5 .Prof =

Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform runtime binding on a null reference at CallSite.Target(Closure , CallSite , Object ) at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0) at CallSite.Target(Closure , CallSite , Object ) at LordAshes.BeyondLinkData.Evaluate(Dictionary2 level, String hierarchy) at LordAshes.BeyondLinkData.ProcessData(Dictionary2 data, String rootDataFolder) at LordAshes.BeyondLinkServer.ProcessMessage(String browserSent) at LordAshes.WebsocketServer.OnAccept(IAsyncResult result) at System.Net.LazyAsyncResult.Complete(IntPtr userToken) at System.Net.ContextAwareResult.CompleteCallback(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Net.ContextAwareResult.Complete(IntPtr userToken) at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken) at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped nativeOverlapped) at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped pOVERLAP)

LordAshes commented 4 months ago

It looks like certain aspects so the characters are not being collected and this may be the cause of the exception.

Start without Talespire running, and BeyondLinkServer running manually. If I recall this should generate local files with the collected data. Verify that all data collected is correct (i.e. there are no empty data properties). If there are, as you seem to imply there are, then you need to adjust the Browser Extension code to locate it and gather it correctly. Most likely DndBeyond changed some of the class names for some of the information. Once you have it collecting the correct data locally, then run Talespire to see if it can pass the info into Talesire.

On Sat, Jul 6, 2024 at 12:28 PM Trogdor-TheBurninator < @.***> wrote:

Getting "injection.js:207 WebSocket connection to 'ws://127.0.0.1:[port]/' failed" error

Have tried swapping through a few ports and verifying that they're open in both router and internal firewalls. (though I'm pretty sure that wouldn't affect localhost.)

Fired up the beyondlinkserver.exe manually ("beyondlinkserver [port]" from cmd)

Its gets as far as proficiencies before the null reference error. ( Char is named: "Miracle Macs'alangelo", but it seems to have missed that as well?)

[ -> BeyondLinkData ]

.Name = .Level = .Race = Variant Human .Class = Cleric 4 .AC = 16 .HP.Current = 35 .HP.Max = 35 .HD.Used = 0 .HD.Total = 5 .Prof =

Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform runtime binding on a null reference at CallSite.Target(Closure , CallSite , Object ) at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0) at CallSite.Target(Closure , CallSite , Object ) at LordAshes.BeyondLinkData.Evaluate(Dictionary2 level, String hierarchy) at LordAshes.BeyondLinkData.ProcessData(Dictionary2 data, String rootDataFolder) at LordAshes.BeyondLinkServer.ProcessMessage(String browserSent) at LordAshes.WebsocketServer.OnAccept(IAsyncResult result) at System.Net.LazyAsyncResult.Complete(IntPtr userToken) at System.Net.ContextAwareResult.CompleteCallback(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Net.ContextAwareResult.Complete(IntPtr userToken) at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken) at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped nativeOverlapped) at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped pOVERLAP)

— Reply to this email directly, view it on GitHub https://github.com/LordAshes/TaleSpire-BeyondLinkViaChrome/issues/10, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGQ5Y6HQL3SDKNHGT6NHHGLZLALKDAVCNFSM6AAAAABKOSA3Y6VHI2DSMVQWIX3LMV43ASLTON2WKOZSGM4TGNRSGA4DMNA . You are receiving this because you are subscribed to this thread.Message ID: @.***>

Trogdor-TheBurninator commented 4 months ago

ran "BeyondLinkServer [port] learn" and was able to get a more complete list of what it's not able to grab. Content.json

Digging into injection.js i think the 'fail to find' on name is due to a few things. I think special chars (' , ! etc) would cause an issue. The class it resides in has also changed. ("MuiTypography-root MuiTypography-h4 ddb-character-app-sn0l9p" in injection.js is now MuiTypography-root MuiTypography-h4 ddb-character-app-15ddtxx in the HTML - tried updating that div name, still wasnt able to find it.)

HTML and JS are deffo not my forte, but i think it has to do with changes to the underlying structure of many of the fields it cant find. (the names seem mostly correct, just where the values live that changed. move speed also changed: "ct-quick-info__box ct-quick-info__box--speed")

My guess is that when this script was written, they were all pretty similarly structured. (<div class="ddbc-armor-class-box__value ">16</div>) but now the values it couldnt find (stats, saves, ability scores, and skills) are contained in an unnammed span.

Proficiency value, for example, now lives in: <div class="ct-proficiency-bonus-box__value "><span class="styles_numberDisplay__Rg1za styles_signed__scf97 styles_large__3C8uq"><span class="styles_sign__NdR6X styles_largeSign__V9-jS styles_labelSignColor__Klmbs" aria-label="plus">+</span><span>2</span></span></div>

AI wrote the code, so its probs entirely garbage, but i feel like an approach like this might work: (eg: ignore the styled and named spans)

function GetModifier(header) {
    const valueDiv = document.querySelector(`.${header} .ct-proficiency-bonus-box__value`);
    if (valueDiv) {
        const valueSpan = valueDiv.querySelector('span:not([class*="styles_"]):not(:has([class*="styles_"]))');
        return valueSpan.textContent;    }  }

But im not good enough with JS to debug that and integrate it to test.

LordAshes commented 4 months ago

If I recall correctly, the current injection code parses the HTML as strings with a bunch of helper functions to do so. It currently is not parsing it as DOM objects. I don't recall the reason for that. However, it amounts to the same things:

The code needs to find the location of the various pieces of data in order to retrieve the data.

That data is then pushed out of the browser space using websockets which the Beyond Link Server captures and writes to files. Finally the actual Talespire plugin portion reads the data from the files.

So if the DnD Beyond locations have changed, someone needs to find where they are now and update the injection code either using the string operation function that are there now or using a DOM representation like the one suggested by the AI. In either case the code requires context. So using the GetModifier() function suggested by the AI would work as long as you first find the section for each roll and use the GetModifier() function on that subset of the DOM. Otherwise you will get modifiers but you will have no idea what they are for.

The issue here is that I am really providing the Beyond Link Server and the Talespire Plugin portion. Yes, I wrote the initial Browser Extension but I am not really maintaining that portion of it because that is a Dnd Beyond thing and not a Talepsire thing. Technically, as far as I can tell, there is nothing wrong with the Beyond Link Server or the Talespire Beyond Link Plugin. The issue is with the data being fed to it.

My suggestion would be to reach out in Unofficial Talespire Modding Discord and see if anyone has already updated the extension and, if not, if anyone wants to take on the task. I will not be doing that any time soon since we have more pressing issues like broken plugins.

Lord Ashes

On Mon, Jul 8, 2024 at 3:05 PM Trogdor-TheBurninator < @.***> wrote:

ran "BeyondLinkServer [port] learn" and was able to get a more complete list of what it's not able to grab. Content.json https://github.com/user-attachments/files/16133175/Content.json

Digging into injection.js i think the 'fail to find' on name is due to a few things. I think special chars (' , ! etc) would cause an issue. The class it resides in has also changed. ("MuiTypography-root MuiTypography-h4 ddb-character-app-sn0l9p" in injection.js is now MuiTypography-root MuiTypography-h4 ddb-character-app-15ddtxx in the HTML - tried updating that div name, still wasnt able to find it.)

HTML and JS are deffo not my forte, but i think it has to do with changes to the underlying structure of many of the fields it cant find. (the names seem mostly correct, just where the values live that changed. move speed also changed: "ct-quick-infobox ct-quick-infobox--speed")

My guess is that when this script was written, they were all pretty similarly structured. ( 16 ) but now the values it couldnt find (stats, saves, ability scores, and skills) are contained in an unnammed span.

Proficiency value, for example, now lives in:

+2

AI wrote the code, so its probs entirely garbage, but i feel like an approach like this might work: (eg: ignore the styled and named spans)

function GetModifier(header) { const valueDiv = document.querySelector(.${header} .ct-proficiency-bonus-box__value); if (valueDiv) { const valueSpan = valueDiv.querySelector('span:not([class="styles_"]):not(:has([class="styles_"]))'); return valueSpan.textContent; } }

But im not good enough with JS to debug that and integrate it to test.

— Reply to this email directly, view it on GitHub https://github.com/LordAshes/TaleSpire-BeyondLinkViaChrome/issues/10#issuecomment-2214964213, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGQ5Y6GXRRWYUSH3BRUBRUTZLLPHLAVCNFSM6AAAAABKOSA3Y6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMJUHE3DIMRRGM . You are receiving this because you commented.Message ID: @.***>