ALIENQuake

Converting huge project from Au3 to multiplatform GUI application

4 posts in this topic

#1 ·  Posted (edited)

Hello everyone,

Finally I decide to ask hard question about one of the project which I currently maintain:

Big World Setup aka mod installer for infinity engine games like BG, IWD, PST etc

Project page: https://bitbucket.org/BigWorldSetup/bigworldsetup/overview

More screenshot: https://forums.beamdog.com/discussion/44476/tool-big-world-setup-bws-mod-manager-for-baldurs-gate-enhanced-edition-trilogy-for-windows/p1

General Features

  • downloading mods (please see remarks!)
  • easy mod installation
  • correct install order of mods/components
  • handle mod and components conflicts and auto solve them
  • easy backup creation/restoring
  • ability to add you own mods

Internal Features (every single feature which you see here is already working in autoit)

Spoiler

Big World Setup features list for developing new version of it:

 

General guides:
- next version of Big World Setup should not be named "Big World Setup <something>"
- threat changing of the options by players as hacking of the pentagon
- ideally, next BWS should be developed using language which doesn't require compilation for rapid development/recreation of every important features of old BWS

 

What things next Big World Setup don't need:
- beautiful GUI:

 

Next BWS needs a GUI Framework which will be able to dynamically add/modify/remove mod components/provided values directly from the mod list in order to add new mod components directly via right-click at mod name > "Add new component"

 

Auto-Update of the main application:
- this should be the first feature which you should develop and test. Do not make the same mistake as 90% of application aka "we will develop auto-update later, now we will just point to archive download" - it will stay this way forever
- proper, best and flawless auto-update process, exactly the same which Spotify application has:

1. No popups, questions, confirmation dialog etc for auto-update
2. Application silently check for updates
3. when it finds it, it  silently download and extract new version of the application to update folder
4. at the next start of the application, it will check if there is a new folder with new version of the app
5. if yes, app will be launched from the new folder
6. exept when the installation process was stoped and the application will resume already ongoing weidu mods installation

- this way, users will always get latest version of the app without any interference and without possibility to break ongoing installation with changes made to install order

 


Main Features:
- support for single game: BG2, BG1EE, BG2EE, IWD1, IWD1EE, IWD2, PST, PSTEE
- support for multi games: BGT, EET
- auto-detection of the game paths ( registry, default location )
- detection of the proper game installations for games with different releases (BG1/BG2 CD's full installation)
- detection of the missing patches for classic version of the games
- verifying clean installation state of the games, no files inside overide + empty weidu log
- creating and restoring special backups of the games which skips Data\* files for much smaller size

- ability to choose multiple languages for available mods list: PO,EN,GE means 'give me all mods in polish and use it as main language, when there is no polish, choose english, if there is no polish or english, choose greman, dont show mods without atleast one of the selected language)

 

Compilation of mods aka Custom Mod Packs
- build-in compilation of the mods: minimal, recommended, standard, expert + few user-made compilation
- enabling expert components should be possible only by choosing expert compilation
- different colors/icons for different mods category (expert=red, recommended=green)

 

Downloading:
- multi-thread mods download from various filehosting
- some of the filehosting require workarounds

 

Extraction:
- proper extraction of the mods archive, including taking care of unnecessary duplicated folders
- hacking of the NSIS installers which doesn't provide a way to extract the mod files unless extracted
  (invoke exe, redirect and wait for extraction, kill NSIS process)
- OverwriteFiles function


Conflicts types:
- All mods/components depend another, so the mods will not be allowed to be installed alone. Only in a bunch of all mods.
- Multiple mods/components need another (to coexist). The mods X1, X2, [...Xn] need Y if installed together. Y is not needed if any of X is missing.
- One mod/component need multiple others. The mod X needs Y1, Y2, [...Yn] to be installed. This does not mean that Y1 needs Y2.

- One (or more) components need one of multiple possible components. So if any of the components on the right are installed, the dependency is solved.

- Advanced conflict - check Splits String by ':' (lets call it area). If one of the items is selected (or all of a group if '&' is used), it's displayed as a conflict. Advantage to normal conflicts: *Mods in an area are not treated as conflicts. *Mods can have conflicts in groups. So if two combined mods have a conflict with a third one, this is the ways to go.
The mods X1, X2, [...Xn] all have a conflict with Y. X1 and X2 do not have a conflict, so they can be installed without problems.

- One mod needs another - not opposite
- One or more mod has conflicts with another
- One or more component has conflicts with another. You can use combination of (-) and (number).

- Mods that depend on BGT/EET, a special language-selection or a version of the game are listed in the Game.ini's [Purge]-section. These are not shown in the selection-menu if the conditions are not matched, so people don't get confused.
- a connection for some specific fix for another mod but only for main language of the mods translation that is on top of "BWS Translation" section.


Conflicts Solve:
- automatically
- manually via GUI
 

Additional Logic:
- continue installation
- report errors
- pause when errors occur
- ignore errors and continue installation
- do not pause installation for skipped components

 

Saving and loading user chosen mod/component lists
- export/import of the mod selection along with custom user answers

 

Comandline hook:
- save all output without affecting performance
- detect certain events (weidu errors, weidu skipped components)
- providing answers to questions displayed inside commandline

 

Save game backups
- since every installation is different, next BWS should backup all save games

 

Logging/Debbuging
- log for checking if the mod packages are online
- log for mod extraction
- log for weidu installation

 

It look as simple GUI application but it has quite complicated logic regarding "handle mod and components conflicts and auto solve them" - this is most important feature of the app.

This app needs to be converted into multi-platform GUI application because Enhanced Editions of the game can be played on OSX and Linux also. But for the past 6 years, there wasn't a single gamer/developer who would try to convert this app using multi-platform language and GUI. 

This is the moment when I'm asking for help:

- Which language would suit the best for multi-platform GUI application?  c#,python,java or other?

- Is there any general approach for such conversion? 

- Does autoit community/developer have some experience with converting autoit GUI applications into multi-platform GUI app by using multi-platform language like c#,python,java

- Is there someone who isn't scared by looking at the source code of the application and feature list to help me with converting or even begin with creating multi-platform GUI app template which will just simply run the same commandline for every system ? 

If there is something else which you would know, pleas ask and I will try to answer my best.

 

Edited by ALIENQuake

Share this post


Link to post
Share on other sites



One last thing: If we are talking about paid work, how much it would cost? It's hard to say how long it would take to recreate most important features but I would say it's minimum 3 months.

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

 

Maybe my suspended project may help

 

First start with running the exampels under

https://github.com/gileli121/CU3-Library/tree/master/Examples/main

The examples cover all the functions (https://github.com/gileli121/CU3-Library/blob/master/gui.h) I wrote.
use the examples and play with them in depth.

I do not have much time at the moment to give a lot of support. I checked the functions but that does not guarantee they are bug free. If you find a problem, please report it (inside github platform) 

 

I would note that I am not going to continue to develop these functions in the coming months. Feel free to implement any missing function you need.
please share the code of these missing functions so I'll add them later (of course, I will mention the name of author).
If you want me to add missing functions in my project page, follow the same  standard of organizing the code:

  • If you make new function for GUI - The function must be inside gui.h under "CU3_NAMESPACE_START" .
  • If the function have the same name of it's parallel function (in Autoit), the function must be the same also in it's parameters and behavior (as described in the Help file of Autoit)
  • If the function is not exactly the same like in Autoit, The function name must end with "_C"
  • Use the the standard retun type "CU3_CTRL" If necessary.  If you think to change this standard, do it after very careful thought.
    • Don't make any changes that will force you to change the functions I worte

 

 

EDIT:

Oops, I had a misunderstanding .. I thought you wanted to do this work yourself. I understand that you are asking someone else to do it .. I do not have time to perform such work. I am currently busy with other things. 

 

Edited by gil900

Share this post


Link to post
Share on other sites

Currently locked and under review by the Mod team for:

  • Check whether this is in conflict with our Forum rules.
  • "rent-a-coder" type question.

Jos


Visit the SciTE4AutoIt3 Download page for the latest versions  - Beta files                                How to post scriptsource        Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.

  • Similar Content

    • JSmith312
      By JSmith312
      Hello Everyone! 
      I'm attempting to create a checklist app that performs other functions. For performance, I would like to check the box, then have the button to the right enabled. After that button is pressed, the second checkbox is enabled, and ready to be checked, allowing the second button to be pressed. After the second button is pressed, the completion/exit button is enabled/shown. I have my code that currently creates the GUI, creates the checkbox, but when you check it it enables the button and the next checkbox. Can't seem to figure out a Case for GUISetOnEvent. Any assistance would be appreciated!
      #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <StaticConstants.au3> #include <EditConstants.au3> #include <MsgBoxConstants.au3> ; Below is the GUI interface _DeploymentProcess() Func _DeploymentProcess() $aStep1 = GUICreate("Deployment Process", 475, 345, 500, 175) $CBcStep1 = GUICtrlCreateCheckbox("1. Step 01.", 15, 25, 300, 25) $BTNS1 = GUICtrlCreateButton("Email 01", 365, 25, 90, 20) $CBcStep2 = GUICtrlCreateCheckbox("2. Step 02.", 15, 50, 300, 25) $BTNS2 = GUICtrlCreateButton("Email 02", 365, 50, 90, 20) GUICtrlSetState($CBcStep2, $GUI_DISABLE) GUICtrlSetState($BTNS1, $GUI_DISABLE) $CBcStep3 = GUICtrlCreateButton("Hurray! You're Complete!", 85, 276, 300, 60) GUICtrlSetState($CBcStep3, $GUI_SHOW) ; Below are the button and checkbox enables/disables. GUISetState(@SW_SHOW) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE GUIDelete($aStep1) Return ; Step 1 Case $CBcStep1 If GUICtrlRead($CBcStep1) = $GUI_CHECKED Then GUICtrlSetState($BTNS1, $GUI_ENABLE) GUICtrlSetState($CBcStep2, $GUI_ENABLE) Else GUICtrlSetState($BTNS1, $GUI_DISABLE) GUICtrlSetState($CBcStep2, $GUI_DISABLE) EndIf ; Step 2 Case $CBcStep2 If GUICtrlRead($CBcStep2) = $GUI_CHECKED Then GUICtrlSetState($BTNS2, $GUI_ENABLE) GUICtrlSetState($CBcStep3, $GUI_ENABLE) Else GUICtrlSetState($BTNS2, $GUI_DISABLE) GUICtrlSetState($CBcStep3, $GUI_DISABLE) EndIf Case $CBcStep3 If GUICtrlRead($CBcStep2) = $GUI_CHECKED Then GUICtrlSetState($BTNS10, $GUI_ENABLE) GUICtrlSetState($CBcStep3, $GUI_SHOW) Else GUICtrlSetState($CBcStep3, $GUI_EVENT_CLOSE) EndIf Case $GUI_EVENT_CLOSE, $CBcStep3 #comments-end Exit EndSwitch WEnd EndFunc  
    • JLogan3o13
      By JLogan3o13
      Not one usually to post non-AutoIt things, but as I have this question on StackExchange I thought I would throw it up here as well for any of our C# folks:
      I currently have an AutoIt GUI that calls a powershell script; the intent is to allow low-level technicians to batch create VMs in vSphere. Due to some changes in requirements from the customer, I am re-writing as a wpf app. The app itself is complete and working; this is more of a curiosity question.
      I have two methods attached to buttons on the GUI - one to pull all the data out of a listview and export to csv and another to do the reverse; importing from csv to the listview element. I wrote the export first, and went with manipulating the Excel application:
      private void Launch(object sender, RoutedEventArgs e) { Microsoft.Office.Interop.Excel.Application oExcel = new Microsoft.Office.Interop.Excel.Application(); oExcel.Visible = true; Microsoft.Office.Interop.Excel.Workbook oWorkBook = oExcel.Workbooks.Add(Microsoft.Office.Interop.Excel.XlSheetType.xlWorksheet); Microsoft.Office.Interop.Excel.Worksheet oSheet = (Microsoft.Office.Interop.Excel.Worksheet)oExcel.ActiveSheet; int row = 2; //allow for header row int column = 1; oSheet.Cells[1, 1] = "Name"; oSheet.Cells[1, 2] = "CPU"; oSheet.Cells[1, 3] = "RAM"; oSheet.Cells[1, 4] = "IP Address"; oSheet.Cells[1, 5] = "Subnet Mask"; oSheet.Cells[1, 6] = "Port Group"; oSheet.Cells[1, 7] = "Default Gateway"; oSheet.Cells[1, 8] = "DNS"; oSheet.Cells[1, 9] = "Description"; oSheet.Cells[1, 10] = "Template"; oSheet.Cells[1, 11] = "Host"; oSheet.Cells[1, 12] = "Site"; oSheet.Cells[1, 13] = "Folder"; oSheet.Cells[1, 14] = "DataStore"; oSheet.Cells[1, 15] = "Patch Method"; oSheet.Cells[1, 16] = "HDD1Size"; oSheet.Cells[1, 17] = "HDD1Format"; oSheet.Cells[1, 18] = "HDD2Size"; oSheet.Cells[1, 19] = "HDD2Format"; oSheet.Cells[1, 20] = "HDD3Size"; oSheet.Cells[1, 21] = "HDD3Format"; oSheet.Cells[1, 22] = "HDD4Size"; oSheet.Cells[1, 23] = "HDD4Format"; oSheet.Cells[1, 24] = "HDD5Size"; oSheet.Cells[1, 25] = "HDD5Format"; foreach (var oVM in MyItems) { oSheet.Cells[row, column] = oVM.Name; oSheet.Cells[row, (column + 1)] = oVM.CPU; oSheet.Cells[row, (column + 2)] = oVM.RAM; oSheet.Cells[row, (column + 3)] = oVM.IP; oSheet.Cells[row, (column + 4)] = oVM.Subnet; oSheet.Cells[row, (column + 5)] = oVM.PortGroup; oSheet.Cells[row, (column + 6)] = oVM.Gateway; oSheet.Cells[row, (column + 7)] = oVM.DNS; oSheet.Cells[row, (column + 8)] = oVM.Description; oSheet.Cells[row, (column + 9)] = oVM.Template; oSheet.Cells[row, (column + 10)] = oVM.Host; oSheet.Cells[row, (column + 11)] = oVM.Site; oSheet.Cells[row, (column + 12)] = oVM.Folder; oSheet.Cells[row, (column + 13)] = oVM.Datastore; oSheet.Cells[row, (column + 14)] = oVM.Patch; oSheet.Cells[row, (column + 15)] = oVM.HDD1Size; oSheet.Cells[row, (column + 16)] = oVM.HDD1Format; oSheet.Cells[row, (column + 17)] = oVM.HDD2Size; oSheet.Cells[row, (column + 18)] = oVM.HDD2Format; oSheet.Cells[row, (column + 19)] = oVM.HDD3Size; oSheet.Cells[row, (column + 20)] = oVM.HDD3Format; oSheet.Cells[row, (column + 21)] = oVM.HDD4Size; oSheet.Cells[row, (column + 22)] = oVM.HDD4Format; oSheet.Cells[row, (column + 23)] = oVM.HDD5Size; oSheet.Cells[row, (column + 24)] = oVM.HDD5Format; row++; } oExcel.Application.ActiveWorkbook.SaveAs(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\example", 6); } It works, but it is slow. I have Excel set to visible for testing, and it is a good 6 or 7 seconds on a pretty high end box before the app even pops up.  It then takes another 2 seconds to populate 11 rows (this could be in the hundreds of rows at some point).
      I then wrote the code for the reverse, and decided to try a StreamReader object. The result, surprisingly, was almost immediate:
      OpenFileDialog xls = new OpenFileDialog(); xls.Multiselect = false; xls.Filter = "CSV files (*.csv)|*.csv"; xls.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); xls.ShowDialog(); string ins; if (xls.FileName != null) { FileStream srcFS; srcFS = new FileStream(xls.FileName, FileMode.Open); StreamReader srcSR = new StreamReader(srcFS, System.Text.Encoding.Default); do { ins = srcSR.ReadLine(); if (ins != null) { string[] parts = ins.Split(','); MyItems.Add(new MyItem { Name = parts[0], CPU = parts[1], RAM = parts[2], IP = parts[3], Subnet = parts[4], PortGroup = parts[5], Gateway = parts[6], DNS = parts[7], Description = parts[8], Template = parts[9], Host = parts[10], Site = parts[11], Folder = parts[12], Datastore = parts[13], Patch = parts[14], HDD1Size = parts[15], HDD1Format = parts[16], HDD2Size = parts[17], HDD2Format = parts[18], HDD3Size = parts[19], HDD3Format = parts[20], HDD4Size = parts[21], HDD4Format = parts[22], HDD5Size = parts[23], HDD5Format = parts[24] }); } } while (ins != null); srcSR.Close(); } }  
      So, I thought I would go back and change the export to use the same method:
      FileStream srcFS; srcFS = new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\testingout.csv", FileMode.CreateNew, FileAccess.Write); StreamWriter srcWrt = new StreamWriter(srcFS, System.Text.Encoding.Default); StringBuilder header = new StringBuilder(); header.Append("Name").Append(',') .Append("CPU").Append(',') .Append("RAM").Append(',') .Append("IP Address").Append(',') .Append("Port Group").Append(',') .Append("Default Gateway").Append(',') .Append("DNS").Append(',') .Append("Description").Append(',') .Append("Template").Append(',') .Append("Host").Append(',') .Append("Site").Append(',') .Append("Folder").Append(',') .Append("Datastore").Append(',') .Append("Patch").Append(',') .Append("HDD1Size").Append(',') .Append("HDD1Format").Append(',') .Append("HDD2Size").Append(',') .Append("HDD2Format").Append(',') .Append("HDD3Size").Append(',') .Append("HDD3Format").Append(',') .Append("HDD4Size").Append(',') .Append("HDD4Format").Append(',') .Append("HDD5Size").Append(',') .Append("HDDFormat").Append(','); srcWrt.WriteLine(header); foreach (MyItem item in MyItems) { StringBuilder builder = new StringBuilder(); builder.Append(item.Name).Append(',') .Append(item.CPU).Append(',') .Append(item.RAM).Append(',') .Append(item.IP).Append(',') .Append(item.Subnet).Append(',') .Append(item.PortGroup).Append(',') .Append(item.Gateway).Append(',') .Append(item.DNS).Append(',') .Append(item.Description).Append(',') .Append(item.Template).Append(',') .Append(item.Host).Append(',') .Append(item.Site).Append(',') .Append(item.Folder).Append(',') .Append(item.Datastore).Append(',') .Append(item.Patch).Append(',') .Append(item.HDD1Size).Append(',') .Append(item.HDD1Format).Append(',') .Append(item.HDD2Size).Append(',') .Append(item.HDD2Format).Append(',') .Append(item.HDD3Size).Append(',') .Append(item.HDD3Format).Append(',') .Append(item.HDD4Size).Append(',') .Append(item.HDD4Format).Append(',') .Append(item.HDD5Size).Append(',') .Append(item.HDD5Format); srcWrt.WriteLine(builder); } MessageBox.Show("Task Complete"); What surprised me is this method is exponentially slower; on the order of 40 seconds to return the MsgBox. I also noticed that even though the loop is complete and shows the message, is seems the stream is still writing. If I open the file too quickly it shows that it is still in use by "Another User". So by the time the file is available to me it is actually closer to a minute for an 11-line csv.
      I'm just curious at the difference in speed read vs write using FileStream. Is it something I borked on implementation (eminently possible) or is this a known issue? If interacting with Excel is the way to go (not ideal) is there something I could do to shorten the initial lag?
    • RoundChecker
      By RoundChecker
      Hi everyone,

      Is there a way to determine whether the script that is running, is already running, without using;
       
      If WinExists ?

      Or is there a way to use "If WinExists" to determine the script itself?

      The reason I am asking this is because if I want someone to run the .Exe I have and they rename it to whatever they want, how could I then determine in the script to check if there's already an .Exe open, or the script itself is already open?

      Should I use Class, or how do I achieve this?

      Thanks in advance.
    • svenjatzu
      By svenjatzu
      Id like to build a little helpertool for my boss in office but i dont know how to sart it.
      thats no complicated task. im working for an insurancecenter and have to search the customers in different orders and different tags.
      due to my boss is old and not really commen with pc he saves the customers without system.
      eg, customer andreas statham got an insurenca for his car then i got to search for
      andreas statham car, andreas car statham, car andreas statham, statham andreas car, statham car andreas, car statham andreass etc to find all the files from this customer in the harddrive.
      some customers also are fmiliarnamed in one file like andreas statam and monika rog are married an both got a carinsurance then i got to earch for
      andreas statham monika rog car, andreas statham monika car rog,.... this can take real long to find the right customer if i do it from hand.
      how can i realise this someone in here got an excamlple script or has any sugestion?
       
       
    • X_xkijux_x
      By X_xkijux_x
      Ok so im using this program. clarify for school. I would like to have a program that takes every word i type in microsoft word and searches on it in claryfi. is this possible. I would like to have the program not stopping me from typing more after that word. Like when i type a word it auto search it on clarify without making me stop typing and if i want to change i can do that and if im fine that word i can just keep typing and it will search after the next word.