Author Topic: [EventScript] Client event optimizations, packages and case-insensitivity  (Read 1694 times)

This issue is quite complicated, but I'll try to explain what I want to accomplish and what I've currently done as detailed as possible.

What I want to do
My Add-On EventScript currently uses findText on the client for GuiPopUpMenuCtrl to get the id for an event in a selection. However, this function is case-sensitive, which resulted in a suggestion to solve.

Therefore, I planned to override/package four functions that handled the registration of event names and NT names, giving me a lookup table for names, also indirectly giving me a case-insensitive way to get names.
Code: [Select]
clientCmdRegisterInputEvent
clientCmdRegisterOutputEvent
SimGroup::CLIENTaddNTName
SimGroup::CLIENTremoveNTName

What I have done
I found out that the last two was actually possible to override completely, replacing the existing functionality with one that is significantly faster.

The two first is an another story. I've checked through trace, but they are untraceable. I tried override, but they are not called by BL, but when I call them manually, they are called normally. When I package them, it's the same as override.

Here is a pastebin with what I've done so far: event_table.cs

Possible solutions
  • Package WrenchEventsDlg, so when opened it'll just generate the lookup table on the fly. This is worse performance-wise, as it means that it'll be called each time when opening the window instead of when the user joins the server.
  • Generate the table locally before going through the events to reduce the maximum lookup to a minimum. Could work, but as this script parsing is done in one run, it means that there could be a possibility of small lag when there is lots of events that needs to be parsed. Especially for output events.
  • Just don't do it. It's not worth the effort and are considered micro-optimization. It's not that big of a hit to the performance than one might thing, considering that everyone else is doing it. At worst, you'll have 60 lookups on a list of 60 events, which is only 3600 iterations in total.
  • Package GuiPopUpMenuCtrl::add and store the table list in there, ignoring the findText entirely. Two problems arise here: It will be added for all lists and therefore will be a really ugly way to add such thing; If the same value is added twice, then this wont work, but luckily it wont as events are limited that way anyway.

Anyone got a better solution?
Feel free to discuss better possible solutions, or maybe if you got an answer to how to fix this, as that would be the best optimization on all cases.
« Last Edit: November 28, 2017, 03:13:54 PM by mctwist »

why not just make another popup text with all lowercase ones and search your objects through that one

Possible, but wouldn't it be easier to make a table from the start? It's most probably faster as well, but I haven't seen how findText works under the hood.

As I got the NTNames to work, and I can assume that event names wont change after server start, there is a chance that I'll do as Electrk suggested on Discord with generating the table once when opening the event window.

Did a quick script for the first possible solution. Not tested, but should work. A similar approach can be reused for the local solution.

Code: [Select]
package EventTableClientPackage
{
// When opening the events dialog
function WrenchEventsDlg::onWake(%this)
{
Parent::onWake(%this);

// Generate once
// In normal conditions, this will work correctly
// One could keep track on amount of events and add them as one goes
if (%this.haveTable)
return;
%this.haveTable = true;

// Make sure there's no leftovers
deleteVariables("$InputEvent_Table*");
deleteVariables("$OutputEvent_Table*");

// Note: ClassList is not used anywhere on the default client,
// therefore might be created by an Add-On. Create it to make sure
// we have it.
if ($InputEvent_ClassList $= "")
$InputEvent_ClassList = "fxDTSBrick";

// Input events
%count = getWordCount($InputEvent_ClassList);
for (%i = 0; %i < %count; %i++)
{
%class = getWord($InputEvent_ClassList, %i);
for (%n = 0; %n < $InputEvent_Count[%class]; %n++)
{
$InputEvent_Table[%class, $InputEvent_Name[%class, %n]] = %n;
}
}

// Output events
%count = getWordCount($OutputEvent_ClassList);
for (%i = 0; %i < %count; %i++)
{
%class = getWord($OutputEvent_ClassList, %i);
for (%n = 0; %n < $OutputEvent_Count[%class]; %n++)
{
$OutputEvent_Table[%class, $OutputEvent_Name[%class, %n]] = %n;
}
}
}
};
activatePackage(EventTableClientPackage);

I'm still looking for a fix for my issue, though, as it should be possible to somehow override or package the client commands.

And now a script for solution 4.

Code: [Select]
package EventTableClientPackage
{
// Add new text entry with id to popup menu controller
function GuiPopUpMenuCtrl::add(%this, %entryText, %entryID, %entryScheme)
{
Parent::add(%this, %entryText, %entryID, %entryScheme);

if (%this.table[%entryText] $= "")
{
%this.table[%entryText] = %entryID;
%this.count += 0;
%this.list[%this.count] = %entryText;
%this.count++;
}
}

// Find text in popup menu controller
function GuiPopUpMenuCtrl::findText(%this, %text)
{
if (%this.table[%text] !$= "")
return %this.table[%text];
return Parent::findText(%this, %text);
}

// Clear popup menu controller
function GuiPopUpMenuCtrl::clear(%this)
{
for (%i = 0; %i < %this.count; %i++)
{
%this.table[%this.list[%i]] = "";
%this.list[%i] = "";
}
%this.count = "";
Parent::clear(%this);
}
};
activatePackage(EventTableClientPackage);

I have tested it, but I do know that this will replace the functionality that people might use. That leaves for question if this is way too dirty and is only a "quick fix".

But, the best part with this is that this makes it possible for EventScript to handle parameter lists without having to be exact values. This also completely replaces my previous optimization on NTNames, as it uses this system as well.
« Last Edit: November 28, 2017, 09:02:49 AM by mctwist »

The last solution have been pushed. If anyone is against it, then please tell me an alternative version that is better. I do hope this wont destroy how Add-Ons uses this feature. Vanilla Blockland seem to work correctly.

I updated the script, making it optional support for the new addition of case-insensitiviness, makes it possible to go around the issue of breaking other mods while still giving them the support to this kind of feature.