Retera / WarsmashModEngine

An emulation engine to improve Warcraft III modding
GNU Affero General Public License v3.0
256 stars 45 forks source link

Store names, tooltips etc. in CUnit, CItem etc. to support natives #36

Open tdauth opened 1 year ago

tdauth commented 1 year ago

I haven't found any name, tooltip, description or other text fields in CUnit and CItem. I only found a name field in CUnitType.

Maybe the stuff is stored somewhere else?

I want to support natives like these:

constant native GetUnitName         takes unit whichUnit returns string
constant native GetItemName     takes item whichItem returns string
native BlzSetItemName                              takes item whichItem, string name returns nothing
native BlzSetItemDescription                       takes item whichItem, string description returns nothing
native BlzGetItemDescription                       takes item whichItem returns string
native BlzSetItemTooltip                           takes item whichItem, string tooltip returns nothing
native BlzGetItemTooltip                           takes item whichItem returns string
native BlzSetItemExtendedTooltip                   takes item whichItem, string extendedTooltip returns nothing
native BlzGetItemExtendedTooltip                   takes item whichItem returns string
native BlzSetItemIconPath                          takes item whichItem, string iconPath returns nothing
native BlzGetItemIconPath                          takes item whichItem returns string
native BlzSetUnitName                              takes unit whichUnit, string name returns nothing
native BlzSetHeroProperName                        takes unit whichUnit, string heroProperName returns nothing

No high priority but I am just wondering how to achieve this.

Retera commented 1 year ago

What's in a name? Would a meat wagon by any other name smell as sweet?

You raise an interesting ideological question. The Blz natives are included in the existing set of defined natives in some places, but the original stated goal of the Warsmash project in other places was to emulate the Warcraft III: Frozen Throne Patch 1.22 client from before the Activision merger.

So, you may have caught on to the fact that I was not entirely consistent. A year or two ago I created a branch called blasphemy where the "Classic" graphics mode of Patch 1.32 could be used with Warsmash as the source of asset data (which is a substantial technical undertaking given that all textures and models are in a different format on 1.32 than on 1.22, and also the 1.32 archive is in a different archive format to contain the assets). Eventually, for the sake of personal convenience of being able to "test the map" for any map file thrown at me even if it came from 1.32 and beyond, I merged the blasphemy branch into the main line and so I guess my project has been "blasphemous" to its own original vision for a few years now.

You may have noticed that I stopped at 1.32 and did not configure Warsmash to properly support loading 1.33+ assets as the source of data for the Warsmash system. If you think about it, there is nothing that I personally gain from supporting that other than clout with other people who only have the official version of the game, so to the extent that I build a project for myself to meet the needs of my modding, supporting 1.35 for example offers me almost nothing of value.

But I did start claiming to people on the Hive Workshop that Warsmash would officially support 1.29 rather than 1.22 as a possible target for just downloading it and running it. I figured that more people would have 1.29, because it was the patch chosen by the Hive users for their "Community Edition."

So, the reason that I say all this -- getting back to your natives in question -- is to ask ideologically about what we are trying to do with this project, and whether we want to support arbitrary individual object name overwrites. If my goal was to teach someone new to programming how Warcraft III as a concept works and is played, gumming up my code with support for all the Reforged formats and 1.30+ shifting around of asset locations in the game and all that basically makes the code more complex with no added gain. The features like "widescreen" or whatever from "newer patches" can be loaded on Warsmash on the older patch of assets, because the code side is not constrained like that.

I might find that if I had an open source system that emulated Patch 1.22 that I would expressly want the evolution after that point to go in a different direction than Reforged and to not have Blz natives but instead have my own vision for the future. For example, in this vision maybe the game UI is pluggable and can support map developers redefining the concept of a "name" for a unit within the context of their specific map and how its map specific UI functions work. If that were the case, then having the rule that "all units of the same type share the same name" could be a rule that potentially increases performance in the base case of an RTS play where only Hero units have unique names.

So, when we talk about adding BlzSetUnitName (unlike with BlzSetHeroProperName which doesn't have this problem), we are talking about editing the RTS game system to potentially become less efficient. Similarly, the CAbility subsystem in Warsmash has evolved while I was working on it, and more recently I was finding that trying to have these performance concerns and construct the concept of abilities in a way that used symbol tables via plain Java classes at every level instead of one file for the "Ability" that reads from World Editor like a Wc3 map developer would probably want... results in slower development. And almost no one cares about performance.

Thus, it would probably take 20 minutes to add BlzSetUnitName native to the system but it makes me pause for a moment to think about how this may be an invasion of the human society problem into my system that was trying to, in part, create an opportunity for human minds to explore the direction that they might have taken the Warcraft III concept if it had been without the modern influence of Bobby Kotick and by extension the Reforged that is affected by our modern social climate, and the push for example to add these natives that might worsen performance and have annoying prefixes like Blz on their name. If 2017 had seen Blizzard decide to shut down Warcraft III and publish the source code so that open source communities created their own "Reforgeds" from 2017 - 2023, we might exist in a world where BlzSetUnitName did not exist, and rather whatever map you have and wherever you needed a dynamic mechanism like a hero name for a nonhero, you would be able to implement that dynamic mechanism in a way that would be more robust and wouldn't alter the performance of the game simulation when people just want to play Frozen Throne melee matches, for example.

Since the project is open source and you can take your own fork in whatever direction you want, everything that I just said might be a whole lot of nothing. To answer the question, "What's in a name?" we can select the function name CUnitType.getName() and then use CTRL+SHIFT+G in Eclipse IDE or the ALT+F7 in the IntelliJ IDEA to list references to this function. Upon doing this, we can see that the function is used:

  1. In the JASS native GetObjectName
  2. In some error logging somewhere that doesn't affect gameplay
  3. In the command card when some ability requires a unit, and the requirement is not met and must be shown in yellow
  4. In the hover text over neutral units, such as Gold Mine or Goblin Merchant
  5. In the MeleeUI function to refresh what is shown upon selecting a new unit, where "Name" is shown at the center top of the unit command card

If you change these five places to load text from a different location in the code (such as a theoretical new function you add called CUnit.getName() instead of CUnitType.getName()) then you could instantly have a version of the game going where "name" would be a unit specific concept. I cannot imagine that this would take long to implement. But the reason I wrote everything else up to this point is that it might be worth remembering that when you do this, the memory size of the CUnit class will probably increase for every unit regardless of whether the map being played uses this BlzSetUnitName function that you aspire to introduce. And maybe no one cares about enlarging the CUnit class -- there is already probably junk in the Warsmash class that was not in every unit on Blizzard's game, and was pulled out to exist only in specific abilities on Blizzard's game, already. But I do not match them 1:1 because I do not have their code, and have only been writing ideas based on conjecture about the game experience that I wanted to have in my system. In addition, I encountered two Warcraft III binary hackers debating on the Hive Workshop Discord server a few weeks ago, where they claimed that they had reverse engineered the Blizzard game and determined that the CUnit structure used in that game is substantially larger on the Reforged patches than on their old predecessors such as Patch 1.26. But does anyone actually have any performance issues with Reforged? Generally I don't. Last time I checked, Reforged was running more smoothly on my PC than the Warsmash simulations in many cases, probably because that company was developing it professionally and would have had substantially more people and development time than what Warsmash has had to this point.

bearU369 commented 1 year ago

I haven't found any name, tooltip, description or other text fields in CUnit and CItem. I only found a name field in CUnitType.

Maybe the stuff is stored somewhere else?

I want to support natives like these:

constant native GetUnitName         takes unit whichUnit returns string
constant native GetItemName     takes item whichItem returns string
native BlzSetItemName                              takes item whichItem, string name returns nothing
native BlzSetItemDescription                       takes item whichItem, string description returns nothing
native BlzGetItemDescription                       takes item whichItem returns string
native BlzSetItemTooltip                           takes item whichItem, string tooltip returns nothing
native BlzGetItemTooltip                           takes item whichItem returns string
native BlzSetItemExtendedTooltip                   takes item whichItem, string extendedTooltip returns nothing
native BlzGetItemExtendedTooltip                   takes item whichItem returns string
native BlzSetItemIconPath                          takes item whichItem, string iconPath returns nothing
native BlzGetItemIconPath                          takes item whichItem returns string
native BlzSetUnitName                              takes unit whichUnit, string name returns nothing
native BlzSetHeroProperName                        takes unit whichUnit, string heroProperName returns nothing

No high priority but I am just wondering how to achieve this.

Maybe it's possible to add additional String variables for displaying custom name/description though I'm not yet sure how their name/description are being rendered in the UI.

Retera commented 1 year ago

If it helps, there is a divide between the network-sync logic and the render logic, such that "CUnit" has gameplay behaviors and "RenderUnit" has rendering stuff. As such, the render-equivalent of CUnitType has some type information. Tooltips and icon informations are usually stored in IconUI stuff (AbilityDataUI handles a lot of that, and probably needs a rename/refactor since it's doing stuff with units too).

The idea for dividing this up would be to support running the game logic without rendering to the screen, such as from a server. That is not supported yet, but this code was split up with the idea of making it possible to support that in the future.