[Mod] Highlight Structures on Map

MrFangsMrFangs Join Date: 2013-03-27 Member: 184474Members, Reinforced - Shadow Posts: 313 Fully active user
I recently had an idea for a commander quality-of-life feature, which I suggested in another thread:
MrFangs wrote: »
An even better feature might be to highlight all structures of a certain type on the map. Of course, not all the time, but only one structure type at a time. To avoid adding new buttons for this, it could automatically activate whenever a structure is selected for building: For example, you select "Crag" from the commander menu, but instead of left-clicking to place it, you hold the map key, and all existing Crags on the map are highlighted. This should fit well with the UI flow as you could jump immediately to the location that does *not* have a Crag by clicking the map.

Instead of waiting for someone to add this, I decided to learn NS2 modding and create this as a mod :) And here's the first version: http://steamcommunity.com/sharedfiles/filedetails/?id=308092512

637x358.resizedimage

So far, it's working as intended (with the exception below). Please take a look and let me know what you think! If enough people consider this useful, maybe this could even be included into the standard UI?

There is one technical issue with it - mod compatibility. I'm using the .event file approach, as I understand that this is the current/preferred way to bootstrap a mod. However, when I combine it with NS2+, for example, the mod simply stops working. There are no errors on the console, but no Print output either - the mod simply isn't loaded. The only standard class that I overwrite (as there is no matching hook) is GUIMinimap, and as far as I can see, NS2+ does not overwrite that file. Does anyone have an idea why this is happening, or how to debug this? (May I even invoke @Mendasp‌ ? :) )

This is the directory layout of the mod, as downloaded and installed from the workshop:
.modinfo
lua
lua\entry
lua\entry\HighlightStructuresOnMap.entry
lua\GUIMinimap.lua
lua\HighlightStructures.lua
lua\HighlightStructuresOnMap_Client.lua

HighlightStructuresOnMap.entry:
modEntry = [[
Client: lua/HighlightStructuresOnMap_Client.lua,
Priority: 5
]]

HighlightStructuresOnMap_Client.lua
Script.Load("lua/Client.lua")
Print("HighlightStructuresOnMap v0.5 loaded")

And this is the inclusion from the modified GUIMinimap.lua:
...
Script.Load("lua/GUIMinimapConnection.lua")
// mod start
Script.Load("lua/HighlightStructures.lua")
// mod end
...
There are two other places where the code from HighlightStructures.lua is actually invoked, but they should not be relevant to the question why the mod isn't being loaded at all (I think). Any pointers how to debug this?

Also, is there a way to replace a standard file (like GUIMinimap.lua) with a subclass or wrapper, and invoke methods of the replaced class from it? (For example, overriding a method, and then calling super.theMethod() somewhere inside it?) This would be more robust than just overwriting the file.

Comments

  • MendaspMendasp I touch maps in inappropriate places Valencia, Spain Join Date: 2002-07-05 Member: 884Members, NS1 Playtester, Contributor, Constellation, NS2 Playtester, Squad Five Gold, NS2 Map Tester, Reinforced - Shadow, WC 2013 - Shadow, Retired Community Developer Posts: 4,177 Advanced user
    edited August 2014
    I do actually override stuff in GUIMinimap and as a matter of fact I replace the entire local function that you're trying to mod, so your code is never actually running, but I'm not actually replacing the file, it's done through hooks.

    On the other hand, you don't really need the entry system if you're going to end up replacing a file to do the mod, might as well load your file from the overwritten one and use your code directly.

    The funny thing is I'm overriding the function to do something similar (coloring player blips).

    I'll have a quick look at resolving this.

    Edit: I've published an update and your mod should work now.
    Post edited by Mendasp on
  • MrFangsMrFangs Join Date: 2013-03-27 Member: 184474Members, Reinforced - Shadow Posts: 313 Fully active user
    Hi Mendasp, thanks for the quick response.
    Mendasp wrote: »
    I do actually override stuff in GUIMinimap and as a matter of fact I replace the entire local function that you're trying to mod, so your code is never actually running, but I'm not actually replacing the file, it's done through hooks.
    Ah, ok... that's a good pointer. I assumed that a script could only be overridden by a file in the exact same location. Now I've looked at how NS2+ handles GUIMinimap, and I think I understand the approach. Unless I'm missing something, I should be able to rewrite my mod so it does not need to modify GUIMinimap.lua at all. Basically like this (untested):
    local originalUpdateStaticBlips
    originalUpdateStaticBlips = Class_ReplaceMethod( "GUIMinimap", "UpdateStaticBlips",
    function(self)
    	originalUpdateStaticBlips(self)
    	local staticBlips = PlayerUI_GetStaticMapBlips()
    	// ... and then iterate over staticBlips and modify matching entries' color+layer
    end)
    

    The only thing I don't know yet is if I'll need any local variables of GUIMinimap (which I may not have access to). Or can you access them by injecting a new function via Class_AddMethod(...)?
    Class_AddMethod("GUIMinimap", "GetThatLocalValueThatINeed", 
    function(self)
    	return kLocalVariableOfGUIMinimap;  // is this possible?
    end)
    

    On the other hand, you don't really need the entry system if you're going to end up replacing a file to do the mod, might as well load your file from the overwritten one and use your code directly.
    I did it this way because I was hoping I could avoid overwriting files at all. And as long as I had to overwrite, I wanted to keep the changes as small as possible, also to make upgrading to a new version of NS2 easier. But the ReplaceMethod approach is far better anyway, if I can get it working.

    The funny thing is I'm overriding the function to do something similar (coloring player blips).
    Maybe this would be a good place for a predefined hook, then? (PostUpdateStaticBlips or something?) I have no clue how much this affects performance, though.
  • MrFangsMrFangs Join Date: 2013-03-27 Member: 184474Members, Reinforced - Shadow Posts: 313 Fully active user
    Mendasp wrote: »
    Edit: I've published an update and your mod should work now.

    Ah , that's great :)

    I'll still try to adapt my mod so it's safe against other mods that do the same thing - and to do it the right way. Thanks for the help!
  • MendaspMendasp I touch maps in inappropriate places Valencia, Spain Join Date: 2002-07-05 Member: 884Members, NS1 Playtester, Contributor, Constellation, NS2 Playtester, Squad Five Gold, NS2 Map Tester, Reinforced - Shadow, WC 2013 - Shadow, Retired Community Developer Posts: 4,177 Advanced user
    edited August 2014
    MrFangs wrote: »
    Hi Mendasp, thanks for the quick response.
    Mendasp wrote: »
    I do actually override stuff in GUIMinimap and as a matter of fact I replace the entire local function that you're trying to mod, so your code is never actually running, but I'm not actually replacing the file, it's done through hooks.
    Ah, ok... that's a good pointer. I assumed that a script could only be overridden by a file in the exact same location. Now I've looked at how NS2+ handles GUIMinimap, and I think I understand the approach. Unless I'm missing something, I should be able to rewrite my mod so it does not need to modify GUIMinimap.lua at all. Basically like this (untested):
    local originalUpdateStaticBlips
    originalUpdateStaticBlips = Class_ReplaceMethod( "GUIMinimap", "UpdateStaticBlips",
    function(self)
    	originalUpdateStaticBlips(self)
    	local staticBlips = PlayerUI_GetStaticMapBlips()
    	// ... and then iterate over staticBlips and modify matching entries' color+layer
    end)
    

    The only thing I don't know yet is if I'll need any local variables of GUIMinimap (which I may not have access to). Or can you access them by injecting a new function via Class_AddMethod(...)?
    Class_AddMethod("GUIMinimap", "GetThatLocalValueThatINeed", 
    function(self)
    	return kLocalVariableOfGUIMinimap;  // is this possible?
    end)
    

    The thing is that is a local function, so you can't override it like that (and no, you can't get locals like that). The options you have in that case is either fully replacing it (what I was doing before) or just sort of run it again with your changes...

    What I was doing is using the Elixer functions to replace the local function with my own version which was basically copy & pasted the original with a few modifications. The change that I've done now so your mod runs is to stop replacing the local function and only run the bits of code I need after the original runs (in GUIMinimap:Update) and changing the color of certain blips if it's needed.

    Take a look at the Elixer library to deal with local variables and functions. https://github.com/sclark39/NS2Elixer
    There's also plenty of usage of it in NS2Plus.
  • remiremi remedy [blu.knight] Join Date: 2003-11-18 Member: 23112Members, Super Administrators, Forum Admins, NS2 Developer, NS2 Playtester Posts: 2,689 admin
    edited August 2014
    There's a thread in the modding forum somewhere about how to use that elixer utility stuff too.

    edit: Here you go: http://forums.unknownworlds.com/discussion/134944/elixer-cross-mod-compatible-utility-library-for-modders
    [ Rek | Reklys | remedy | remi.D | blu.knight | Psyke | Sky ]
    I have way too many names.
Sign In or Register to comment.