Retera / WarsmashModEngine

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

Add some How to run in IDE to README and load icons from data source #37

Open tdauth opened 1 year ago

tdauth commented 1 year ago

Due to the discussion in https://github.com/Retera/WarsmashModEngine/issues/15 I decided to add a section to the README which helped me and to load the icons from a data source since the resources were not found.

Besides, it checks for the [Emulator] now and stops if it does not exist and prints the working directory to avoid confusion.

I do not know how to use -load for a file which is inside one of the MPQ archives like Maps/scenario/(4)warchasers.w3n. Does this work? If this works, some example would also be useful.

Retera commented 1 year ago

A few questions/suggestions from looking at this so far:

  1. It looks like the suggested INI configuration that you created is set to load both Activision Blizzard format data "CASC", and then also a repeat of that data in the old Blizzard format "MPQ" from before the Activision merger. However, one of the MPQs is missing for non-English users, which is named war3local.mpq and does not appear on English installations. I think that your current configuration appears to try to suggest a one-solution-fits-all configuration to solve a problem where currently I do not actually think that one solution fits all cases on the Warsmash Engine. For example, if I want to load from Patch 1.22 then I would use the "MPQ" designations, and if I wanted to load from Patch 1.32 then I would use "CASC" designations. But currently these systems error out if the designated MPQ or CASC archives do not exist on the computer. As such, my concern is that providing a suggested configuration that requires the user to have both Reforged and Frozen Throne installed on the computer is probably going to be misleading to users and decrease the number of users who can figure out how to set it up. It would probably be preferable to have two example configurations, where one is for Reforged and one is for Frozen Throne. The Reforged configuration would load no MPQ files, and the Frozen Throne configuration would load no CASC data. Any user who is using a transitional version of Frozen Throne released in a prepatch of Reforged, where they have Frozen Throne format data in a Reforged format archive, will not be supported because of encoding issues with the transitional versions and the third party libraries that I use. If my life depended on it, I could support them, but I have not made extensive efforts to do so at this time. It is possible for those users to extract their game data into a folder and run Warsmash in folder mode if they must absolutely use those transitional versions. So, with all this being the case, I would discourage the config file that loads from both Reforged and Frozen Throne and requires both on the computer.
  2. It appears that the default suggestion you created assumes the user to be running the application from the root directory of the entire WarsmashModEngine repository. Unfortunately, the getFile method on the DataSource interface is a legacy method and is not what you expect. This method performs a copy operation to a temporary directory, which will cause unnecessary extra copy operations. So the getAbsolutePath() that you are trying to use to designate the file path for the LibGDX system's application icon assignment may, in at least some cases, be pointing to C:\Users\<me>\AppData\Local\Temp\RMSExtract\resources\Icon16.png or something like this, because the underlying utilities are spaghetti code copied from Retera Model Studio. Because of this, getResourceAsStream is a preferred method on the DataSource interface of Warsmash because it can load assets in-place using only the RAM of the computer hardware and not the HDD, and so getFile should be discouraged. This is why I was loading the icon resources as standard LibGDX assets in the way that LibGDX normally does, which is different from everything else in Warsmash that generally has its own asset loading system to process asset loading with the Warcraft III style instead of the LibGDX style. Unfortunately, although DataSourceFileHandle class exists in Warsmash as a go-between that allows us to pass a Warsmash asset resolution path into the LibGDX assets pipeline, the LibGDX FileHandle class is not used for their LWJGL2 desktop application icon bindings. So they only allow a file path, when in this case from the standpoint of Warsmash there is no file. It may be that the art data exists within an MPQ or within a CASC. In our specific case, it does not, but in the sense of an open-ended future expectation, I would expect users to be able to enjoy a Warsmash bundle with its icon inside of a resources.mpq perhaps. Unfortunately, the only way to do that currently, per your suggested change, is to introduce an unnecessary added file copy operation for that case. Is it worth it? Now that I'm saying this, who knows, maybe it is? But I wanted to explain what the code is doing here so that you do not simply feel that you "got it to work" but also understand why it was how it was, and the deeper behaviors behind why it worked for you. In the past, when I was younger, I believed that an infinite number of writes to the hard drive -- for every asset loading operation from within an MPQ for example -- was fine. However, my hard drives used to die more often back then. Now, instead, I prefer to use the RAM hardware by loading the image data into program variables but not into files. So I was just fighting with LibGDX basically. But the reason it did not work for you is that you were not running the game as LibGDX games usually are run, where the working directory would be the LibGDX assets directory. To that end, my concern is that your suggestion is nonstandard and different than what we get if we just clone the repo and use ./gradlew desktop:runGame to launch the game in the way that I see as the normal expectation -- which is also a way that uses the LibGDX assets directory as the current working directory (to be like any other LibGDX game created with their project generator).
  3. If the path to your .w3x file is relative, it has to be found from your working directory. is not entirely true, because it may refer to a file within the Warsmash DataSource classes, even if that map file does not exist on the hard drive of the computer but rather inside some archive. It is written in such a way that it should be possible to load and play a map like that without ever having the map actually extracted to disk as a file, anywhere. Instead, the data is read as program variables using the RAM hardware and not the long term file system hardware (not the hard drive device).

So basically, the way that I have been usually running this project from source is like this:

 |-war3install
 |  |-War3.mpq
 |  |-War3x.mpq
 |  |-War3xLocal.mpq
 |  |-War3Patch.mpq
 |-warsmash
 |  |-core
 |  |  |-assets
 |  |  |  |-warsmash.ini
 |  |  |  |-resources
 |  |  |  |  |-Icon16.png
 |  |  |  |  |-Icon32.png
 |  |  |  |  |-Icon64.png
 |  |  |  |  |-Icon128.png
 |  |-desktop
 |  |-gradlew
 |  |-resources

To describe what these are, and why they are there, one easy thing to do would be search online how to get started with the LibGDX game engine and how to create a new LibGDX project with their gradle project generator app. That is, after all, how Warsmash began.

If you create a new game project with the LibGDX project generator, using the same over-simplified formatting as above, your project would be formatted something like this:

 |-mygame
 |  |-core
 |  |  |-assets
 |  |  |  |-SomeExample.jpg
 |  |-desktop
 |  |-gradlew

The idea is that you can instantly open this project in most major Java IDEs, like Eclipse or IntelliJ, and have the LibGDX game project open and run without additional user effort for first-time users. Running the run gradle task (whether from the IDE or even from command line by literally typing ./gradlew run) is generally expected to instantly open the newly created game and pop up an otherwise blank window that renders the example image. The reason for the division between a core folder and a desktop folder is that LibGDX is capable of targeting multiple hardware platforms. For example, depending on your choices when generating a LibGDX project, you might have an android folder or an html folder. By writing the majority of LibGDX code inside the core module, we achieve a future where running the desktop or android or html module as a lightweight wrapper around the write-once, run-anywhere core module becomes quite easy. Yes, I have played Warsmash on my Android phone, natively as an APK file and not under any kind of crazy emulation of a different operating system. However, in this case, Warsmash is a bad example. There are many other LibGDX games that do this which are less complex.

At this stage in the design of Warsmash, however, I was faced with the problem that I wanted to re-use code that I already had from my Java Swing desktop 3D model editor for Warcraft III that would ask the user to locate a Warcraft III installation, and then provide me an API to access assets stored within that Warcraft III installation. This was code that I used over the last 10 years to have Java access to Warcraft III assets conveniently by their file path. For Warsmash, I wanted this same system to run, but in a way that requires the user to have a legitimate copy of Warcraft III from Blizzard that would include assets I do not provide to the user. This must be so, because unlike the usual LibGDX use case where the entire game is packaged into a Java JAR (or APK in Android's case, etc), Warsmash does not package the entire game into itself because I do not have any permission nor authority from Blizzard Entertainment to provide you their proprietary 3D character models, and as such I do not provide you those files. Because I was never going to provide users with the Warcraft III files anyway, it made more sense to copy the asset resolution system (the DataSource Java interface) from my old Java Swing desktop 3D model editor hobby project, rather than to require users to place their Warcraft III art into the LibGDX assets directory and recompile and repackage their own Warsmash bundle for each user in order to play the game. However, unlike the Java Swing desktop 3D model editor hobby project, I was convinced that I would want to have multiple targets for Warsmash -- as in different mods, with different sets of units or art files -- that I could switch between. To that end, rather than to have the user select the location of the Warcraft III install on their computer one time and then remember it forever, I opted for my system to use an INI file to designate the location of assets used by the Warcraft III simulator, which would be loaded independently from LibGDX's assets folder and standard use case.

So, as you have probably already guessed, this is why there is only a file warsmash.ini and very few other files in the assets directory of the LibGDX game. Generally, my intention was to not use LibGDX assets and to only use Warsmash assets. Using our same, oversimplified examples again, the structure now looked like this:

 |-mygame
 |  |-core
 |  |  |-assets
 |  |  |  |-warsmash.ini
 |  |-desktop
 |  |-gradlew

At this point, ./gradlew run after cloning the repo would fail, because the user must customize their warsmash.ini file so that it refers to the MPQ files from a Frozen Throne installation, which are not included with Warsmash repo and never will be.

So, that is why we get to the next example, which has a second top-level directory at a different location on the computer that I shall simply represent as war3install:

 |-war3install
 |  |-War3.mpq
 |  |-War3x.mpq
 |  |-War3xLocal.mpq
 |  |-War3Patch.mpq
 |-mygame
 |  |-core
 |  |  |-assets
 |  |  |  |-warsmash.ini
 |  |-desktop
 |  |-gradlew

After using the above structure for perhaps a year, I reached a point in time at which I wanted the Warsmash system to have some assets of its own that are Warcraft III simulator assets not LibGDX assets. In particular, this also means they are files that any individual W3X or W3M style of map could override, if the map was Warsmash-aware and contained an imported replacement whose file path matched the Warsmash asset file path.

It was at this point in the evolution of the project when I added a resources folder to the top-level code repo:

 |-war3install
 |  |-War3.mpq
 |  |-War3x.mpq
 |  |-War3xLocal.mpq
 |  |-War3Patch.mpq
 |-mygame
 |  |-core
 |  |  |-assets
 |  |  |  |-warsmash.ini
 |  |-desktop
 |  |-gradlew
 |  |-resources

Normally on LibGDX, users were able to build and compile their project using the Gradle task named dist (which could be run from command line with ./gradlew desktop:dist or even simply ./gradlew dist). This LibGDX task would create a JAR typically located at mygame/desktop/build/libs/desktop-1.0.jar which contained the entire game, and offered click-to-play for any user who had Java installed on their computer with the capability to double-click on JAR files. So, the release process for building a Warsmash release in its earliest version was as follows:

  1. Use an MPQ tool to create a single resources.mpq file that contained all of the contents of the resources folder in the above example, which were "Warcraft III simulator-level assets" created as a part of Warsmash (of which there are very few).
  2. Use ./gradlew dist to create the desktop-1.0.jar as described above.
  3. Create a warsmash.ini where all of the file paths to the MPQ files were ../war3.mpq relative paths that looked for "one level above".
  4. Create a ZIP containing exactly the above files:
 |-Warsmash.zip
 |  |-resources.mpq
 |  |-desktop-1.0.jar
 |  |-warsmash.ini

Even for an inexperienced user, if you were to send the user the above described ZIP file and tell them to put the ZIP inside of their "Warcraft III: Frozen Throne" folder and then double click on the desktop-1.0.jar, the expected behavior was that then this user would see Warsmash open up and play.

However, in my experience, end-users on Windows computers hate Java with a passion because of the Java Updater from the 2000s. For the end users, the word "Java" refers to an orange coffee icon that cost them productivity years ago. It makes them upset, and if we ask them to install it, then they will become upset and be turned away. Knowing this, at some point in the lifetime of Warsmash, a GitHub contributor talked me into using Java 17 instead of Java 8. For Java 17, it is possible to use some built-in newer Java utilities that are less commonly used with LibGDX. (As far as I have heard, LibGDX is most often used for making Android games, and Android stopped updating their Java version for the whole system around Java 8 for a pretty long lag time behind when Oracle was trying to push out new versions of Desktop PC Java.) So, I came to understand that there was the "jpackage" utility available on these newer Java versions, which would incorporate the Java runtime and all its necessarily licenses and files into the build along with the actual JAR of the Java code. Using this, I am able to provide the end user with a clickable icon that works even on a Windows computer where Java is not installed. You can download an example of the latest version of this style of release from here: https://www.hiveworkshop.com/threads/warsmash-mod-engine-alpha.331765/

The layout is basically as follows:

 |-Warsmash.zip
 |  |-bin
 |  |-conf
 |  |-include
 |  |-legal
 |  |-lib
 |  |-resources
 |  |-Warsmash.exe
 |  |-warsmash.ini

As such, this is a folder that can be added into a Warcraft III: Frozen Throne Patch 1.29 installation directory, and then the non-technical user can double-click on Warsmash.exe, and then the game will run. The folders are basically all added by the jpackage utility to contain the necessary systems to run Warsmash, all except for the resources folder. In this case, I more recently decided that in the spirit of open source it may be better for end-users if the resources are provided as a folder rather than an MPQ archive.

In order to make my life easy when using jpackage, I found that one convenient way to have gradle build into this format was the "badass runtime plugin" for Java, which can be included from the gradle build. Unfortunately, this plugin was not designed specifically for LibGDX and it overwrites the Gradle task named run with something that sets the current working directory to the root of the project, instead of to the standard LibGDX assets directory in the manner expected for LibGDX. Because of this problem, within about the last year, I changed Warsmash so that it still has the old LibGDX easy-to-use run task, but to avoid the name conflict the working LibGDX task is now named runGame. So, from my standpoint, running ./gradlew run in a terminal for Warsmash is broken garbage now, but running ./gradlew runGame in Warsmash is the good working solution that now allows us to run a game with very little configuration of the repo other than the necessary warsmash.ini.

It was about this time that I wanted to change the icon of the running application, and then I ran into the problem that the LibGDX bindings for LWJGL2 (for OpenGL basically) do not allow the user to specify a program variable containing image data as the icon of the application. They only allow a file path, which is then resolved by the LibGDX asset resolving code and not by the Warsmash asset resolving code.

So if you remember our example from before, this is why I then introduced the intentionally-redundant name resources to the Warsmash code repository, so that we have now two folders named resources:

 |-warsmash
 |  |-core
 |  |  |-assets
 |  |  |  |-resources
 |  |-resources

One of these folders -- the folder located at core/assets/resources -- is within the standard LibGDX assets folder and so its contents can be loaded as LibGDX assets for the purpose of being used as the application icons.

The other of these folders -- the one located at ./resources -- is to be referenced by warsmash.ini in the Warsmash file system, so that its contents are Warsmash-specific files but that a user could choose to override from within a custom Warsmash map.

The reason that these two folders were chosen to have the same name is that when I bundle and release a build of Warsmash, which now is simply achieved by ./gradlew runtime (and not ./gradlew dist from LibGDX), I can put these two folders together as one in the ./resources folder of the end result.

However, until that time, the two types of assets remain split in a very obvious way that is true to form for LibGDX.

I would not by any stretch declare that this is the best system that could be conceived, but it is the system that I have now. And I think that if you are going to write the de-facto guide to help new users to run the system, you should know what I have described to this point in order to apply this knowledge to simplify what new users have to deal with.

Edit: And so, what I do to setup Warsmash on a new computer, is:

  1. Install the Warcraft from blizzard
  2. Install Java 17
  3. Clone the Warsmash repo
  4. Edit the warsmash.ini to either MPQ or CASC but not both
  5. Test run the code using ./gradlew runGame

As far as I know, it should not be more complicated than these 5 steps, except for hardware that does not support OpenGL 4+ spec.

tdauth commented 1 year ago

Okay sry that is far too much information for a simple request like this. You can also use your 5 steps if you like to. For me with IntelliJ IDEA wit was the easiest to create a new run configuration. I am not sure if anybody wants to run the game and then start maps etc. There should be at least an example of how to start it directly with a map in addition.

The ini file should have listed possible examples but yes it makes no sense this way. A link to the folder with example warsmash.ini files should be enough.

Btw. it is a bit annoying to change the counter and the numbers 00, 01, 02, 03 etc.

About the icons: IntelliJ somehow does not load the resources automatically when running a main method it would be helpful to make this work somehow.

Retera commented 1 year ago

I did not mean to imply that all of my mad ramblings should be in the example readme. But I was hoping that by noting them here for us to know as developers, it might provide you even more information to make an even better readme for starter users. Does that interest you?

tdauth commented 1 year ago

I would simply add the most simple way to make it work in an IDE, so a starter can load his/her map with breakpoints in an IDE. For my pull request I would have changed it to an Reforged only ini and noted that there are other example ini files for Frozen Throne etc.

I think the current text "How to Build" does not really help to debug a map in Warsmash. Also simply running ./gradlew runGame and loading your map won't help you debugging it with break points.

Maybe I could rename it to "Debug Map with Warsmash" instead. My goal is to run a map in the IDE with Warsmash to use the IDE's features.

linsmod commented 11 months ago

1) About the debugging configuration. Look at the right corner to the image, the debugging configuration can be stored into project file in IDEA. after do this, it in the folder {PROJECT_ROOT}.idea\runConfigurations. it can be added into git if helped.

image

linsmod commented 11 months ago

2) About the MPQ resources configuration style 00, 01, 02, to make it simple, a pull request is sent. it uses a "for in size()" style. https://github.com/Retera/WarsmashModEngine/pull/46

Retera commented 10 months ago

Looking again at the current state of this pull request, the DesktopLauncher changes seem fairly good in general but your updated README includes information about how to run Warsmash with Reforged, which is no longer supported because Reforged updated to a new game data format that isn't supported on Warsmash. For what it's worth, their new format isn't perfectly supported on Reforged itself, either. It is not a priority for me to update Warsmash to support the new Reforged format, and no one to my knowledge has even opened a GitHub issue asking about the problem.

So, with that in mind, Warsmash is probably targeted to Frozen Throne/Warcraft 3 fans instead, who would most likely have some game install that uses the 2003 MDX model format to store 3d files. Because even the "classic" assets on Reforged are in their new format, it's not convenient and doesn't feel like a good use of time for Warsmash to keep updating to retain parity with that.

In addition to recommending a non-Reforged, non-CASC configuration in the basic README, I would also suggest not advising users to change or manipulate the current working directory of the game when launching it. In general, doing that is likely to waste more of their time than it would save. I think it is better to tell users to always use the desktop:runGame gradle target, which already has the correct working directory for the given files. (For example, "copy the warsmash.ini into your working directory" is not a needed step if the user always uses desktop:runGame and therefore automatically uses core/assets/ as the working directory, per the nature of all other default LibGDX game projects.)

What is your opinion on the changes that I made to the README a month or so ago? Are they a step in the direction you would have wanted, even though they are different than what you suggested? Would you be interested in creating a version of this pull request that includes the changes to DesktopLauncher but maybe uses different wording in the README that doesn't encourage Reforged -- unless your pull request also fixes the Warsmash data parsers to support the new Reforged format for this year?

tdauth commented 2 months ago

I think it is fine in now but you could add the screenshot by linsmod to the "From IntelliJ IDE" section. I think it might be the easiest way to start your map and debug it which is probably what most users want.