Author Topic: Movies - new possibilities for modding  (Read 6094 times)

0 Members and 1 Guest are viewing this topic.

Offline Mart

Re: Movies - new possibilities for modding
« Reply #15 on: July 14, 2015, 02:31:41 PM »
And the code for playuv15.exe substitute.
What it does in this "project" iteration, is save the movie file name to TERX_movie folder and by its presence give signal to the terx_movie.exe to play the movie.
The presence time is hardcoded to 1 second (old function sleep(1); ) however, if your windows would be very busy, and terx_movie.exe got no CPU time in that second, it would miss the play order. This way of doing detection is not really perfect, I can do it better next time, but for over 99% of cases it works.

Compiled with freeware c++ compiler MinGW.
g++ -m32 name.cpp -o playuv15.exe

flag -m32 forces 32bit executable, when being on 64bit system.
name.cpp is name of text c++ code file.

Code: [Select]
#include <windows.h>
#include <cstdlib>
#include <string>
#include <unistd.h>
#include <tchar.h>
#include <fstream>
using namespace std;
const char g_szClassName[] = "smacxWindowFfplay";

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    FreeConsole();
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;
    //Step 1: Registering the Window Class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
    if(!RegisterClassEx(&wc))
    {
        ::MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
    // getting command line
    TCHAR cmdline[4096] ;
    TCHAR* argv[4096] ;
    int argc = 0 ;
    _tcscpy( cmdline, GetCommandLine() ) ;
    argv[argc] = _tcstok( cmdline, TEXT(" \t") ) ;
    while( argv[argc] != 0 )
    {
        argc++ ;
        argv[argc] = _tcstok( 0, TEXT(" \t") ) ;
    }
    // name of the movie to play
    string sargv = argv[argc-1];
    // saving the name to the file
    std::ofstream ofs(".\\TERX_movie\\movie.txt",std::ofstream::out);
    ofs << sargv;
    ofs.close();
    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "Playing ...",
        WS_ICONIC,
        CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
        NULL, NULL, hInstance, NULL);
    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
    ShowWindow(hwnd, SW_SHOWMINIMIZED);
    UpdateWindow(hwnd);
    sleep(1);

 // Step 3: The Message Loop
    ::PostMessage(hwnd, WM_CLOSE, 0, 0);
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}// end of WinMain

Offline Mart

Re: Movies - new possibilities for modding
« Reply #16 on: July 14, 2015, 02:47:56 PM »
And terx_movie.exe
This file should go to main game folder. This is monitoring executable. It launches terranx.exe and then waits for playuv15 to appear, then plays the appropriate movie, then waits further. It quits right after there is no terranx.exe process.
Important: You should rather use one game instance, like do not fire the smax game twice or more simultaneously.
SMAX should be launched with it, otherwise you will see no movies (replaced playuv15.exe).
Like the post previously, compiled with MinGW:
g++ -m32 name.cpp -o terx_movie.exe -lpsapi
flag -lpsapi is required for proper linking of psapi.h

Code: [Select]

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <tlhelp32.h>
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <unistd.h>
#include <psapi.h>
#include <sstream>
#include <fstream>
#include <vector>
using namespace std;
void suspend(DWORD processId);
void resume(DWORD processId);
string ExePath();

int main( int argc, char *argv[] )
{
FreeConsole();
HWND hWnd1 = NULL;
HWND hWnd2 = NULL;
vector<string> vNameShort;
vector<string> vNameFull;
string nameShort;
string nameFull;
bool replace = false;
std::size_t found;
//for testing and message boxes
std::stringstream os;
// read movie names from movies2
    string folder = ExePath();
    folder.append("\\movies2\\");
    char search_path[200];
    sprintf(search_path, "%s*.*", folder.c_str());
    WIN32_FIND_DATA fd;
    HANDLE hFind = ::FindFirstFile(search_path, &fd);
    if(hFind != INVALID_HANDLE_VALUE) {
        do {
            if(! (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
                vNameFull.push_back(fd.cFileName);   
            }
        }while(::FindNextFile(hFind, &fd));
        ::FindClose(hFind);
    }
    // creating the second vector
    for(int i=0;i<vNameFull.size();++i){
        found= vNameFull[i].find('.');
        if (found!=std::string::npos){
            nameShort = vNameFull[i].substr(0,found);
        }
        vNameShort.push_back(nameShort);
    }
// Starting terranx.exe
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );
    CreateProcess( "terranx.exe",
        NULL,
        NULL,
        NULL,
        FALSE,
        0,              //CREATE_NO_WINDOW
        NULL,
        NULL,
        &si,
        &pi ) ;
// Loop
while(true){
usleep(300*1000);
// finding working smacx
hWnd1 = FindWindow(NULL,"Sid Meier's Alpha Centauri");
if(hWnd1==NULL){
// no terranx.exe so quiting
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
    return 0;
}
else{
// check if playuv15 is launched
hWnd2 = FindWindow(NULL,"Playing ...");

if(hWnd2!=NULL){
usleep(100*1000);
    DWORD pid;
// find state of smax window, save it
    WINDOWPLACEMENT wp;
    wp.length = sizeof(WINDOWPLACEMENT);
   
    RECT rect1;
    rect1.left = 0;
    rect1.right = 0;
    rect1.top = 800;
    rect1.bottom = 600;
    POINT p1,p2;
    p1.x = 0;
    p1.y = 0;
    WINDOWPLACEMENT wp1;
    wp1.length = sizeof(WINDOWPLACEMENT);
    wp1.flags = WPF_ASYNCWINDOWPLACEMENT;
    wp1.showCmd = 6;
    wp1.ptMinPosition = p1;
    wp1.ptMaxPosition = p1;
    wp1.rcNormalPosition = rect1;
   
    GetWindowPlacement(hWnd1,&wp);
    // change to windowed, or normal state
    SetWindowPlacement(hWnd1,&wp1);
    SetWindowPos(hWnd1,HWND_BOTTOM,0,0,800,600,SWP_NOMOVE);
// find terranx process
// suspend the process
    DWORD aProcesses[1024], cbNeeded, cProcesses;
    bool ret = false;
    ret = EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded );
    if ( !ret )
    {
        ::MessageBox(
            NULL,
            "Enumerating processes problem",
            "Message",
            MB_ICONEXCLAMATION | MB_OK
        );
        return 1;
    }
    // Calculate how many process identifiers were returned.
    cProcesses = cbNeeded / sizeof(DWORD);
    // Print the name and process identifier for each process.
    for ( int i = 0; i < cProcesses; i++ )
    {
        if( aProcesses[i] != 0 )
        {
            DWORD processID = aProcesses[i];
            TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>"); 
            // Get a handle to the process.
            HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID );
            // Get the process name.
            if (NULL != hProcess )
            {
                HMODULE hMod;
                DWORD cbNeeded;
                if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod),&cbNeeded) )
                {
                    GetModuleBaseName( hProcess, hMod, szProcessName,
                                       sizeof(szProcessName)/sizeof(TCHAR) );
                }
            }
            if(!strcmp(szProcessName,"terranx.exe")){
                pid = processID;
                suspend(processID);
            }
        }
    }
// find name of the movie to play and play it, waiting for completion
    string str1;
    string stroptions;
    string nameToPlay = "";
    nameShort = "";
    std::ifstream infile;
    infile.open(".\\TERX_movie\\movie.txt",ios::in);
    getline(infile,nameToPlay);
    nameFull = nameToPlay;
    found=nameFull.find('.');
    if (found!=std::string::npos){
        nameShort = nameFull.substr(0,found);
    }
    if(nameShort != ""){
        // choosing which folder to play
        replace = false;
        for(int i=0;i<vNameShort.size();++i){
            if((replace==false)&&(0==nameShort.compare(vNameShort[i]))){
                replace = true;
                nameToPlay = vNameFull[i];
            }
        }
    }
    infile.close();
    std::ifstream infile2;
    infile2.open(".\\TERX_movie\\ffplay_options.txt",ios::in);
    getline(infile2,stroptions);
    infile2.close();
    str1 = " ";
    str1.append(stroptions);
    str1.append(" ");
    str1.append(nameToPlay);
    // trying to pass LPCTSTR...
    char s[255] = "";
    strcpy(s, str1.c_str());
    LPCTSTR sls;
    sls = s;
    // and folders
    LPCTSTR whichFolder;
    if(replace){
        whichFolder = _T(".\\movies2");
    }else{
        whichFolder = _T(".\\movies");
    }
    SHELLEXECUTEINFO ShExecInfo = {0};
    ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
    ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS|SEE_MASK_NO_CONSOLE ;
    ShExecInfo.hwnd = NULL;
    ShExecInfo.lpVerb = NULL;
    ShExecInfo.lpFile = "ffplay.exe";       
    ShExecInfo.lpParameters = sls;   
    ShExecInfo.lpDirectory = whichFolder;
    ShExecInfo.nShow = SW_SHOWMAXIMIZED;
    ShExecInfo.hInstApp = NULL;
    if(!ShellExecuteEx(&ShExecInfo))
    {
        ::MessageBox(
        NULL,
        "Failed to create process, and start ffplay",
        "Message",
        MB_ICONEXCLAMATION | MB_OK
        );
        return -1;
    }
    else{
    WaitForSingleObject(ShExecInfo.hProcess,INFINITE);
    }
// resume terranx process
    resume(pid);
// restore window to its state
    SetWindowPlacement(hWnd1,&wp);
    SetFocus(hWnd1);
    SetActiveWindow(hWnd1);
// end of playing procedure, delete movie name file.
}
}//end of if handle to window terranx found
}//end while true
}// end of main

void suspend(DWORD processId)
{
    stringstream stros;
    stros << processId;     
    HANDLE hThreadSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    THREADENTRY32 threadEntry;
    threadEntry.dwSize = sizeof(THREADENTRY32);
    Thread32First(hThreadSnapshot, &threadEntry);
    do
    {
        if (threadEntry.th32OwnerProcessID == processId)
        {
            HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE,
                threadEntry.th32ThreadID);
            SuspendThread(hThread);
            CloseHandle(hThread);
        }
    } while (Thread32Next(hThreadSnapshot, &threadEntry));
    CloseHandle(hThreadSnapshot);
}

void resume(DWORD processId)
{
    HANDLE hThreadSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    THREADENTRY32 threadEntry;
    threadEntry.dwSize = sizeof(THREADENTRY32);
    Thread32First(hThreadSnapshot, &threadEntry);
    do
    {
        if (threadEntry.th32OwnerProcessID == processId)
        {
            HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE,
                threadEntry.th32ThreadID);
            ResumeThread(hThread);
            CloseHandle(hThread);
        }
    } while (Thread32Next(hThreadSnapshot, &threadEntry));
    CloseHandle(hThreadSnapshot);
}

string ExePath() {
    char buffer[MAX_PATH];
    GetModuleFileName( NULL, buffer, MAX_PATH );
    string::size_type pos = string( buffer ).find_last_of( "\\/" );
    return string( buffer ).substr( 0, pos);
}

Offline Mart

Re: Movies - new possibilities for modding
« Reply #17 on: July 14, 2015, 02:56:49 PM »
That's for now. I would say, this solution is 80-90% satisfactory.
Having an additional process, that monitors terranx.exe is potentially good for other tricks with the game. It may be a drawback though. Sometimes I forget to launch the game with it and click terranx.exe instead. Having a link would probably work much better.

I hope to get soon better knowledge of how Windows work, for example there is this application "Free Alarm Clock" that forces my smax in full screen to windowed mode to play the alarm.
How do they do it? Both processes are not probably connected. So this alarm app is using some proper commands to put its window to the front, and even force a DirectX game out of full screen.
So I am looking for this solution now.

Offline Mart

Re: Movies - new possibilities for modding
« Reply #18 on: July 20, 2015, 12:04:09 PM »
And there is something, that repeats itself, not sure why.
When I start terx_movie.exe, after some longer time not playing SMACX, intro movie does not start. Apparantly, "observer" does not catch playuv15 in time. I usually have more processes started on a computer, so that may be a factor.

Some other way of writing this "observer" app would be better. I have some idea already.
Still, looking for "playuv15 only" solution is preferred.

Offline Mart

Re: Movies - new possibilities for modding
« Reply #19 on: August 24, 2015, 12:39:50 AM »
I have seen, there is already several downloads of the demo.
any comments on how it works?

Online Buster's Uncle

  • With community service, I
  • Ascend
  • *
  • Posts: 49412
  • €131
  • View Inventory
  • Send /Gift
  • Because there are times when people just need a cute puppy  Soft kitty, warm kitty, little ball of fur  A WONDERFUL concept, Unity - & a 1-way trip that cost 400 trillion & 40 yrs.  
  • AC2 is my instrument, my heart, as I play my song.
  • Planet tales writer Smilie Artist Custom Faction Modder AC2 Wiki contributor Downloads Contributor
    • View Profile
    • My Custom Factions
    • Awards
Re: Movies - new possibilities for modding
« Reply #20 on: August 24, 2015, 12:47:25 AM »
I've passed to question along to the Facebook AC players group.

Offline DrazharLn

Re: Movies - new possibilities for modding
« Reply #21 on: August 25, 2015, 12:55:54 PM »
Can you tell us more about this Unity mod?

Offline Mart

Re: Movies - new possibilities for modding
« Reply #22 on: August 25, 2015, 04:43:32 PM »
It is larger rules overhaul. I did not set complete changes scope yet, being open to new possibilities.
Some time ago (already several years ago) I made version 0.3, which was before scient's patch. Now, with more modding capabilities much more can be made. So what I have now is already quite different from v0.3

Most important highlights:
- making research rate slower in late game, but not in early game.
- decrease of micromanagement, making ICS less of a good strategy
- redesigning some facilities, "policies"
- some tricks with units: pseudo-facilities
- modifying some chassis, foils and copters would work differently, this is going around some hard-coded stuff
- "flattening" energy, so incomes do not go so high up in later game, this is connected to research speed.

I am planning new movies, but it takes time...
I have already done most of changes for new version in alphax.txt, so probably could post it soon. Graphics though needs adjusting.

----
And probably this new feature also needs to be mentioned:
- redesigning some unit abilities. Some appear sooner/have different "allow" values, so their effects are somewhat different.
- and many more.

Offline DrazharLn

Re: Movies - new possibilities for modding
« Reply #23 on: August 26, 2015, 09:29:08 AM »
Thanks for working on this, Mart, it sounds really interesting. I look forward to trying the finished product and I'll help test this film replacement when I have some time at home.

Offline Mart

Re: Movies - new possibilities for modding
« Reply #24 on: August 31, 2015, 06:09:15 PM »
DrazharLn, thank you!

As for movies, at present the biggest problem is, that the replacement executable, which is started by smacx does not have enough privileges to force it out of foreground for time of movie play. I am not sure, if that can be easily done. My knowledge of windows is not that good in this area. SMACX does seem to do it, though, with its original playuv15.exe. The thing is, the replacement "playuv15.exe" would serve only as launcher/manager of new movies and ffplay.exe would actually play movies. So it is ffplay.exe that needs to make smacx(terranx.exe) to go out of foreground and let it play the movie.

The demo uses different solution, where there is yet another executable ("manager"), that launches smacx (terranx.exe), thus as parent process it can force it to go out of foreground and allow ffplay.exe to show the movie.
I do not consider this solution as the best, since one (person playing the game) actually must use it instead of terranx.exe to launch the game. Also, the manager must be active "observing" if terranx.exe launches playuv15.exe.

Offline DrazharLn

Re: Movies - new possibilities for modding
« Reply #25 on: August 31, 2015, 09:42:25 PM »
As for movies, at present the biggest problem is, that the replacement executable, which is started by smacx does not have enough privileges to force it out of foreground for time of movie play... SMACX does seem to do it, though, with its original playuv15.exe.


terran(x).exe doesn't actually call playuv15.exe. You can delete it and SMAC will happily play the movies. The playuv code is actually contained within the terran(x).exe binaries.

I'm afraid I don't know the Windows APIs either. I think Plotinus changed the movie playing behaviour and has them played by playuv directly, so you could look at what he's doing (source code is available but not commented very much) or just try replacing playuv15 with your own thing while running PRACX.

Quote
The thing is, the replacement "playuv15.exe" would serve only as launcher/manager of new movies and ffplay.exe would actually play movies. So it is ffplay.exe that needs to make smacx(terranx.exe) to go out of foreground and let it play the movie.


I got SMAC to call a batch file that called ffplay in a previous experiment, I think I got videos to be played OK and don't remember them being played in the background, but I'm not entirely sure. I can't remember exactly what I was doing, but here's the thread where I talked about it: http://alphacentauri2.info/index.php?topic=8500.0

Quote
The demo uses different solution, where there is yet another executable ("manager"), that launches smacx (terranx.exe), thus as parent process it can force it to go out of foreground and allow ffplay.exe to show the movie.

I do not consider this solution as the best, since one (person playing the game) actually must use it instead of terranx.exe to launch the game. Also, the manager must be active "observing" if terranx.exe launches playuv15.exe.


That doesn't sound like a particularly bad solution to me.

I can't find the demo.zip. Is it still uploaded somewhere and would you like it tested?

Online Buster's Uncle

  • With community service, I
  • Ascend
  • *
  • Posts: 49412
  • €131
  • View Inventory
  • Send /Gift
  • Because there are times when people just need a cute puppy  Soft kitty, warm kitty, little ball of fur  A WONDERFUL concept, Unity - & a 1-way trip that cost 400 trillion & 40 yrs.  
  • AC2 is my instrument, my heart, as I play my song.
  • Planet tales writer Smilie Artist Custom Faction Modder AC2 Wiki contributor Downloads Contributor
    • View Profile
    • My Custom Factions
    • Awards
Re: Movies - new possibilities for modding
« Reply #26 on: August 31, 2015, 09:57:15 PM »
If SMAC will do:  http://alphacentauri2.info/index.php?action=downloads;sa=view;down=66

I had the X demo on a Computer Games+ disk back in the day, if only I could find it...

Are we talking about the same thing?

Offline Mart

Re: Movies - new possibilities for modding
« Reply #27 on: August 31, 2015, 10:25:59 PM »
... I think Plotinus changed the movie playing behaviour and has them played by playuv directly, so you could look at what he's doing (source code is available but not commented very much) or just try replacing playuv15 with your own thing while running PRACX.

Yes, I can see it there. I have not read all the PRACX code, but Plotinus possibly took care of the smacx window going into background, or yielding "topmost" status to playuv15, since with the patch we can see the movies ok, even though they are really played by this external playuv15.exe?

And that gives me an idea of modifying pracx.dll in hex editor. That could work.
Quote
I got SMAC to call a batch file that called ffplay in a previous experiment, I think I got videos to be played OK and don't remember them being played in the background, but I'm not entirely sure. I can't remember exactly what I was doing, but here's the thread where I talked about it: http://alphacentauri2.info/index.php?topic=8500.0
...

I'm checking it now...

Offline Mart

Re: Movies - new possibilities for modding
« Reply #28 on: September 02, 2015, 09:26:06 PM »
...
That doesn't sound like a particularly bad solution to me.
Yes, I will have to take a look into IPC, interprocess communication.
The way it is now, there are problems with "catching" playuv15 launch.
And I am not using any of IPc, just an on-the-go solution.

Offline DrazharLn

Re: Movies - new possibilities for modding
« Reply #29 on: September 03, 2015, 08:55:29 AM »
Yes, I can see it there. I have not read all the PRACX code, but Plotinus possibly took care of the smacx window going into background, or yielding "topmost" status to playuv15, since with the patch we can see the movies ok, even though they are really played by this external playuv15.exe?

And that gives me an idea of modifying pracx.dll in hex editor. That could work.

Looking at the code, the call to playuv15 is very simple, one of the parameters might be controlling yielding focus, I suppose, but I don't know for sure.

There should be no need to edit pracx.dll in a hex editor (and it would be better for future development if you did not). You can just edit the c++ source code and compile your own modified .dll.

Are we talking about the same thing?

'Fraid not. I was talking about Mart's demo of this hack.

 

* User

Welcome, Guest. Please login or register.
Did you miss your activation email?


Login with username, password and session length

Select language:

* Community poll

SMAC v.4 SMAX v.2 (or previous versions)
-=-
24 (7%)
XP Compatibility patch
-=-
9 (2%)
Gog version for Windows
-=-
103 (32%)
Scient (unofficial) patch
-=-
40 (12%)
Kyrub's latest patch
-=-
14 (4%)
Yitzi's latest patch
-=-
89 (28%)
AC for Mac
-=-
3 (0%)
AC for Linux
-=-
6 (1%)
Gog version for Mac
-=-
10 (3%)
No patch
-=-
16 (5%)
Total Members Voted: 314
AC2 Wiki Logo
-click pic for wik-

* Random quote

Have you ever wondered why clouds behave in such familiar ways when each specimen is so unique? Or why the energy exchange market is so unpredictable? In the coming age we must develop and apply nonlinear mathematical models to real world phenomena. We shall seek, and find, the hidden fractal keys which can unravel the chaos around us.
~ Academician Prokhor Zakharov, University Commencement

* Select your theme

*
Templates: 5: index (default), PortaMx/Mainindex (default), PortaMx/Frames (default), Display (default), GenericControls (default).
Sub templates: 8: init, html_above, body_above, portamx_above, main, portamx_below, body_below, html_below.
Language files: 4: index+Modifications.english (default), TopicRating/.english (default), PortaMx/PortaMx.english (default), OharaYTEmbed.english (default).
Style sheets: 0: .
Files included: 45 - 1228KB. (show)
Queries used: 37.

[Show Queries]