Chronocrash Modders Tools

ChronoCrash Modders Tools 0.7.8

No permission to download
Heres the problematic script, whenever i have it in the animation - "d = spawn(); " gets removed .
So to reproduce try to add this to animtion, save, reopen, modify, save , reopen, eventually it will remove d = spawn.
It is convoluted script that i plan to make more compact but still, it does remove the line and shouldnt.So im kinda afraid what other things already got removed and i did not noticed.
Multiple characters have this script and everytime i save the character - this line with d spawn is removed , so it cant be just coincidence, something is triggering it.

Code:
anim    pain3
    loop    0
    bbox    0 0 0 0
    sound    data/chars/skelswo/pain.wav
@script
void self = getlocalvar("self");
void opp = getentityproperty(self, "opponent");
void    a;
void    b;
void    c;
void    d;
void    e;
void    f;
void    g;
void    h;
void    i;
void    j;
void    k;
void    l;
void    m;
void    n;
int x = getentityproperty(self,"x");
int z = getentityproperty(self,"z");
if ( opp   &&  (frame == 1)){
changeentityproperty(self, "a", 0 );
changeentityproperty(self, "z",  getentityproperty(opp, "z" ) -2 );
changeentityproperty(self, "velocity", 5, 0, 0);
clearspawnentry();
setspawnentry("name", "harpon");
a = spawn();
changeentityproperty(a, "animation", openborconstant("ANI_FOLLOW1"));
bindentity(a, self, 0, 0, 0, -1, 0,1);
clearspawnentry();
setspawnentry("name", "harpon");
b = spawn();
changeentityproperty(b, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(b, self, 0, 0, 0, -1, 0,1);
         
clearspawnentry();
setspawnentry("name", "harpon");
c = spawn();
changeentityproperty(c, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(c, self, 70, 0, 0, -1, 0,1);
         
clearspawnentry();
setspawnentry("name", "harpon");
d = spawn();
changeentityproperty(d, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(d, self, 140, 0, 0, -1, 0,1);

clearspawnentry();
setspawnentry("name", "harpon");
e = spawn();
changeentityproperty(e, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(e, self, 210, 0, 0, -1, 0,1);

clearspawnentry();
setspawnentry("name", "harpon");
f = spawn();
changeentityproperty(f, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(f, self, 280, 0, 0, -1, 0,1);

clearspawnentry();
setspawnentry("name", "harpon");
g = spawn();
changeentityproperty(g, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(g, self, 350, 0, 0, -1, 0,1);

clearspawnentry();
setspawnentry("name", "harpon");
h = spawn();
changeentityproperty(h, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(h, self, 420, 0, 0, -1, 0,1);

clearspawnentry();
setspawnentry("name", "harpon");
i = spawn();
changeentityproperty(i, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(i, self, 490, 0, 0, -1, 0,1);

clearspawnentry();
setspawnentry("name", "harpon");
j = spawn();
changeentityproperty(j, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(j, self, 560, 0, 0, -1, 0,1);

clearspawnentry();
setspawnentry("name", "harpon");
k = spawn();
changeentityproperty(k, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(k, self, 630, 0, 0, -1, 0,1);

clearspawnentry();
setspawnentry("name", "harpon");
l = spawn();
changeentityproperty(l, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(l, self, 700, 0, 0, -1, 0,1);

clearspawnentry();
setspawnentry("name", "harpon");
m = spawn();
changeentityproperty(m, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(m, self, 770, 0, 0, -1, 0,1);

clearspawnentry();
setspawnentry("name", "harpon");
n = spawn();
changeentityproperty(n, "animation", openborconstant("ANI_FOLLOW2"));
bindentity(n, self, 840, 0, 0, -1, 0,1);
        }
        if ( opp   &&  (getentityproperty(self, "direction")==1)&&(frame == 1)){
            changeentityproperty(self, "a", 0 );
            changeentityproperty(self, "z",  getentityproperty(opp, "z" ) -2 );
        changeentityproperty(self, "velocity", 5, 0, 0);
        }
        if(frame == 3){
        changeentityproperty(self, "velocity", 0, 0, 0);
        }  
                if ( frame == 9){
        changeentityproperty(self, "velocity", -12, 0, 0);
         bindentity(a, self, 60, 0, 0, -1, 0,1);
         bindentity(b ,self, 60, 0, 0, -1, 0,1);
         bindentity(c ,self, 130, 0, 0, -1, 0,1);
         bindentity(d, self, 200, 0, 0, -1, 0,1);
bindentity(e, self, 270, 0, 0, -1, 0,1);
bindentity(f, self, 340, 0, 0, -1, 0,1);
bindentity(g, self, 410, 0, 0, -1, 0,1);
bindentity(h, self, 480, 0, 0, -1, 0,1);
bindentity(i, self, 550, 0, 0, -1, 0,1);
bindentity(j, self, 620, 0, 0, -1, 0,1);
bindentity(k, self, 690, 0, 0, -1, 0,1);
bindentity(l, self, 760, 0, 0, -1, 0,1);
bindentity(m, self, 830, 0, 0, -1, 0,1);
bindentity(n, self, 900, 0, 0, -1, 0,1);
        }
        if ((getentityproperty(self, "direction")==1)&&(frame == 9)){
        changeentityproperty(self, "velocity", 12, 0, 0);
     }
             if ((getentityproperty(self, "direction")==0)&&(frame == 9)){
        changeentityproperty(self, "velocity", -12, 0, 0);
     }
    if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(n , "x") -40)&&(    getentityproperty(n, "name")  == "harpon"  )){  
killentity(n);
         }
    if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(m , "x") -40)&&(    getentityproperty(m, "name")  == "harpon"  )){  
killentity(m);
killentity(n);
         }
         if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(l , "x") -40)&&(    getentityproperty(l, "name")  == "harpon"  )){  
killentity(l);
killentity(m);
         }
         if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(k , "x") -40)&&(    getentityproperty(k, "name")  == "harpon"  )){  
killentity(k);
killentity(l);
killentity(m);
         }
             if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(j , "x") -40)&&(    getentityproperty(j, "name")  == "harpon"  )){  
killentity(j);
killentity(k);
killentity(l);
killentity(m);
         }
    if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(i , "x") -40)&&(    getentityproperty(i, "name")  == "harpon"  )){  
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
         }
    if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(h , "x") -40)&&(    getentityproperty(h, "name")  == "harpon"  )){  
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
         }
         if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(g , "x") -40)&&(    getentityproperty(g, "name")  == "harpon"  )){  
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
         }
         if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(f , "x") -40)&&(    getentityproperty(f, "name")  == "harpon"  )){  
killentity(f);
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
         }
    if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(e , "x") -40)&&(    getentityproperty(e, "name")  == "harpon"  )){  
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
         }
    if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(d , "x") -40)&&(    getentityproperty(d, "name")  == "harpon"  )){  
killentity(d);
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
         }
     if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(c , "x") -40)&&(    getentityproperty(c, "name")  == "harpon"  )){  
killentity(c);
killentity(d);
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
         }
    if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(b , "x") -40)&&(    getentityproperty(b, "name")  == "harpon"  )){  
killentity(b);
killentity(c);
killentity(d);
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
         }
             if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(a , "x") -40)&&(    getentityproperty(a, "name")  == "harpon"  )){  
killentity(a);
killentity(b);
killentity(c);
killentity(d);
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
         }

         if    ((getentityproperty(self, "direction")==0)&&(    getentityproperty(opp, "x")    >=     getentityproperty(self , "x") -120)&&(    getentityproperty(a, "name")  == "harpon"  )){  
killentity(a);
killentity(b);
killentity(c);
killentity(d);
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
        void self = getlocalvar("self");
        changeentityproperty(self, "velocity", 0, 0, 0);
  performattack(self, openborconstant("ANI_FOLLOW1"));
        }
    if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(n , "x") +40)&&(    getentityproperty(n, "name")  == "harpon"  )){  
killentity(n);
         }
    if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(m , "x") +40)&&(    getentityproperty(m, "name")  == "harpon"  )){  
killentity(m);
killentity(n);
         }
         if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(l , "x") +40)&&(    getentityproperty(l, "name")  == "harpon"  )){  
killentity(l);
killentity(m);
         }
         if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(k , "x") +40)&&(    getentityproperty(k, "name")  == "harpon"  )){  
killentity(k);
killentity(l);
killentity(m);
         }
             if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(j , "x") +40)&&(    getentityproperty(j, "name")  == "harpon"  )){  
killentity(j);
killentity(k);
killentity(l);
killentity(m);
         }
    if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(i , "x") +40)&&(    getentityproperty(i, "name")  == "harpon"  )){  
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
         }
    if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(h , "x") +40)&&(    getentityproperty(h, "name")  == "harpon"  )){  
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
         }
         if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(g , "x") +40)&&(    getentityproperty(g, "name")  == "harpon"  )){  
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
         }
         if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(f , "x") +40)&&(    getentityproperty(f, "name")  == "harpon"  )){  
killentity(f);
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
         }
    if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(e , "x") +40)&&(    getentityproperty(e, "name")  == "harpon"  )){  
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
         }
    if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(d , "x") +40)&&(    getentityproperty(d, "name")  == "harpon"  )){  
killentity(d);
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
         }
     if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(c , "x") +40)&&(    getentityproperty(c, "name")  == "harpon"  )){  
killentity(c);
killentity(d);
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
         }
    if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(b , "x") +40)&&(    getentityproperty(b, "name")  == "harpon"  )){  
killentity(b);
killentity(c);
killentity(d);
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
         }
             if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(a , "x") +40)&&(    getentityproperty(a, "name")  == "harpon"  )){  
killentity(a);
killentity(b);
killentity(c);
killentity(d);
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
         }

         if    ((getentityproperty(self, "direction")==1)&&(    getentityproperty(opp, "x")    <=     getentityproperty(self , "x") +120)&&(    getentityproperty(a, "name")  == "harpon"  )){  
killentity(a);
killentity(b);
killentity(c);
killentity(d);
killentity(e);
killentity(f);
killentity(g);
killentity(h);
killentity(i);
killentity(j);
killentity(k);
killentity(l);
killentity(m);
killentity(n);
        void self = getlocalvar("self");
        changeentityproperty(self, "velocity", 0, 0, 0);
  performattack(self, openborconstant("ANI_FOLLOW1"));
        }  
    @end_script
    delay  2
            @cmd    changeentityproperty getlocalvar("self") "subject_to_hole" 0
shadowcoords 48 228
    offset    174 299
 
alphamask      data/chars/skelswo/pain_003-mask.png
frame           data/chars/skelswo/pain_003.png
shadowcoords 48 228
offset    170 299
             bbox 0 0 0 0
alphamask      data/chars/skelswo/pain_003-mask.png
frame           data/chars/skelswo/pain_003.png
          delay  7
shadowcoords 48 228
offset    174 299
alphamask      data/chars/skelswo/pain_003-mask.png
frame           data/chars/skelswo/pain_003.png
shadowcoords 44 228
offset    170 299
alphamask      data/chars/skelswo/pain_003-mask.png
frame           data/chars/skelswo/pain_003.png
shadowcoords 48 228
offset    174 299
alphamask      data/chars/skelswo/pain_003-mask.png
frame           data/chars/skelswo/pain_003.png
shadowcoords 44 228
offset    170 299
alphamask      data/chars/skelswo/pain_003-mask.png
frame           data/chars/skelswo/pain_003.png
shadowcoords 48 228
offset    174 299
alphamask      data/chars/skelswo/pain_003-mask.png
frame           data/chars/skelswo/pain_003.png
shadowcoords 44 228
offset    170 299
alphamask      data/chars/skelswo/pain_003-mask.png
frame           data/chars/skelswo/pain_003.png
shadowcoords 48 228
offset    174 299
alphamask      data/chars/skelswo/pain_003-mask.png
frame           data/chars/skelswo/pain_003.png
shadowcoords 37 237
offset    171 296
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
    @cmd    changeentityproperty getlocalvar("self") "subject_to_hole" 1
    @cmd    changeentityproperty getlocalvar("self") "subject_to_gravity" 1
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
alphamask      data/chars/skelswo/fall_001-mask.png
frame           data/chars/skelswo/fall_001.png
shadowcoords 44 228
    offset    174 299
    bbox    139 75 76 224
delay  7
alphamask      data/chars/skelswo/pain_001-mask.png
frame           data/chars/skelswo/pain_001.png
offset    170 299
alphamask      data/chars/skelswo/pain_001-mask.png
frame           data/chars/skelswo/pain_001.png
 
@bWWd Ok thanks for the report. This was related to a specific issue that was made a lot more prominent with recent changes.

Basically, there was a bug with "dropv" detection, a little typo made it detect every line starting with one of the letters of "dropv", followed by a white space (in your case it was with a line starting with "d ", but it could happen with any line starting with an isolated "r'", "o", "p" or "v" as well).

It's probably a bug that was here since a long time but because it was only triggered if a line started with a single isolated letter (among 5), no one probably lost a lot of data due to this. Anyway I'm currently uploading a fix.
 
I remember a talk about this tool that goes through the mod and creates a copy of data folder but only with the files that are actually used by entities so it removes leftovers that arent used, i plan to write the tool but maybe its already good ? Where i can find it ?
 
I remember a talk about this tool that goes through the mod and creates a copy of data folder but only with the files that are actually used by entities so it removes leftovers that arent used, i plan to write the tool but maybe its already good ? Where i can find it ?
It's in "Tools" (menu bar) then "Tool Dialog" then "Prepare PAK".

There's also "Orphan finder" which is basically the opposite, but I'm not sure that one is finished. IIRC no one gave me any report for that yet.

"Prepare PAK" is working I think, and there's a description of how it works built in the app.
 
YEah it looks i have to build it , orphans finder shows this :

Traceback (most recent call last):

File "gui\orphans.py", line 106, in process

PermissionError: [Errno 13] Permission denied: 'D:/OpenBORwork/data'



Prepare pak is copying everything from specified folder, unused frames and all, and i want to remove all unused files
 
Prepare pak is copying everything from specified folder, unused frames and all, and i want to remove all unused files
No it doesn't. I think the only thing that is copied without filters is sound, and the reason is that those can be referenced with script/variable without every be full referenced (like for random sounds).

EDIT : Here's the relevant code for PAK, it's pretty short, and you can clearly see that it doesn't copy everything. You can use this code if you want to build your own ;)

Code:
def process(self):
        dataPath = settings.get_option('general/data_path', '')
        dig = True
        files = []

        baseFolder = self.charsFolder.text()
       
        dstroot = self.outCharsFolder.text()
       
        if(baseFolder == dstroot):
            QtWidgets.QMessageBox.information(self, _('Warning'), _('Workbase path and publish path must be different'))
            return

        exclude = (
            baseFolder + '/misc',
        )

        modelFiles = []
        spriteFiles = []

        f = open(os.path.join(dataPath, 'models.txt'), 'r')
        data = f.readlines()
        p = re.compile('^[^#](.*)data/chars/(.*).txt')

        for line in data:
            m = p.search(line)
            if m:
                modelFiles.append(m.group(2) + '.txt')

        #print modelFiles


        p = re.compile('^[^#](.*)data/chars/([^/]*)([^.]*)(.*)')
        #p2 = re.compile('^[^#](.*)data\\chars\\([^.]*)(.*)')
        for modelFile in modelFiles:
            f = open(baseFolder + os.sep + modelFile, 'r') # 'r'
           
            data = f.readlines()

            for line in data:
                m = p.search(line)
                #print line
                #print ''
                #print '________________________'
                #print ''
                if m:
                    #spriteFiles.append(baseFolder + os.sep + m.group(2)[0:-1])
                    extension = m.group(4)[0:4]
                    print (extension)
                    pos = extension.find('\r')
                    if pos != -1:
                        extension = extension[0:pos]
                    spriteFiles.append(m.group(2) + m.group(3) + extension)
                #else:
                    #m = p2.search(line)
                    #if m:
                        #spriteFiles.append(m.group(2) + m.group(3)[0:4])

        #print spriteFiles

        files = spriteFiles + modelFiles

        size = 0
       
        settings.set_option('pak/chars_out_path', dstroot)
        for f in files:
            srcfile = f
            dstdir =  os.path.join(dstroot, os.path.dirname(srcfile))
            try:
                os.makedirs(dstdir)
            except OSError:
                pass
            try:  
                shutil.copy(baseFolder + os.sep + srcfile, dstdir)
                #size += os.path.getsize(f)
            except:
                pass
        print (size)


        # ***** COPY OTHER FILES, such as .wav sound files *****
       
        def scanFolder(folder, dig, files):
           
            def checkFileInterest(folder, filename, extension):
                if extension in OTHERS and filename[0:5] != '_src_':
                    try:
                        files.append((folder, filename))
                        recovered_paths.append(folder + os.sep + filename)
                    except UnicodeDecodeError:
                        error_paths.append(folder + os.sep + filename)



           
            for f in os.listdir(folder):
                if f[0] != '.':
                    if os.path.isfile(os.path.join(folder, f)):
                        (shortname, extension) = os.path.splitext(f)
                        checkFileInterest(folder, f, extension)
                    else:
                        if(dig and folder + os.sep + f not in exclude):
                            scanFolder(folder + os.sep + f, dig, files)

           
           
           
            return recovered_paths

        recovered_paths = []
        error_paths = []
           
       


        for f in scanFolder(baseFolder, dig, files):
            srcfile = f[len(baseFolder)+1:]

            dstdir =  os.path.join(dstroot, os.path.dirname(srcfile))
            try:
                os.makedirs(dstdir)
            except OSError:
                pass
            try:  
                shutil.copy(baseFolder + os.sep + srcfile, dstdir)
                #size += os.path.getsize(f)
            except:
                pass
 
Last edited:
Theres a bug, it scans even folders that are not in models.txt file, so it basically scans all folder in chars , and then it for some reason leaves only wav files while removing everything else, it should not leave the wavs.
Heres how to trigger it - clone some folder of char, dont include it in models.txt, then run preparepak and take a look at the folder it created - it left the new folder and wavs in it.
I think it needs more strict checks.So if a folder is not mentioned in models txt, dont copy it over , well unless its mentioned in actual txt file, but the first check should be folders that are mentioned in models.
Code:
def scanFolder(folder, dig, files, models_folders):
    recovered_paths = []
    error_paths = []

    def checkFileInterest(folder, filename, extension):
        
        if folder in models_folders:
            files.append((folder, filename))
            recovered_paths.append(os.path.join(folder, filename))
        else:
            print(f"Folder '{folder}' is not mentioned in models.txt")

    for f in os.listdir(folder):
        if not f.startswith('.'):
            path = os.path.join(folder, f)
            if os.path.isfile(path):
                shortname, extension = os.path.splitext(f)
                checkFileInterest(folder, f, extension)
            elif dig and path not in exclude:
                rec_paths, err_paths = scanFolder(path, dig, files, models_folders)
                recovered_paths.extend(rec_paths)
                error_paths.extend(err_paths)

    return recovered_paths, error_paths


models_folders = set()  # stre folders mentioned in models


with open(os.path.join(dataPath, 'models.txt'), 'r') as models_file:
    for line in models_file:
        line = line.strip()
        if line.startswith('palette') or line.startswith('icon'):
            folder_path = line.split()[1] 
            folder_path = os.path.dirname(folder_path)  
            models_folders.add(folder_path)


recovered_paths, error_paths = scanFolder(baseFolder, dig, files, models_folders)
 
Last edited:
But they are not used by the script, that the thing, the wavs and folder are not used anywhere in mod.
If you do things in proper order, it will not remove them + it will bring "back" all the files that were ignored at first if it will find paths to them along the way.
I tried to write the gui to do similar thing today, failed hard flatfaced , i dont really have luxury of time to do it at the moment but ill defo would love to have a tool to cleanup all the mess i left over inside folders.
Id add extra options with ability to change paths and move all the leftover orphan wavs into sounds folder and change all paths to them so they still work.
 
Last edited:
But they are not used by the script, that the thing, the wavs and folder are not used anywhere in mod.
If you do things in proper order, it will not remove them + it will bring "back" all the files that were ignored at first if it will find paths to them along the way.
I tried to write the gui to do similar thing today, failed hard flatfaced , i dont really have luxury of time to do it at the moment but ill defo would love to have a tool to cleanup all the mess i left over inside folders.
Id add extra options with ability to change paths and move all the leftover orphan wavs into sounds folder and change all paths to them so they still work.
Yeah I see what you mean.
- The first pass scans for sprites, palettes, wav, ... that are referenced in characters models (txt)
- But the second pass scans for "wav" files everywhere in chars folder (and subfolders), so as to include "wav" that are not explicitly referenced (because they are used with scripts).

The second pass is indeed an issue if you have "fake character" folders or copies of characters folders because it will also look in these folders for "wav" files. I didn't have those in my game so it never happened.

I can add two options to fix that :
- an option to disable the second pass altogether
- an option to make second pass look for "wav" only in characters folders that are referenced in models.txt. But then it will be up to you to make sure you don't have wav somewhere that isn't included by this restriction.

I'll also add the option to edit which files the second pass look for. It's already in the code but you can't edit it in GUI.
 
Yeah I see what you mean.
- The first pass scans for sprites, palettes, wav, ... that are referenced in characters models (txt)
- But the second pass scans for "wav" files everywhere in chars folder (and subfolders), so as to include "wav" that are not explicitly referenced (because they are used with scripts).

The second pass is indeed an issue if you have "fake character" folders or copies of characters folders because it will also look in these folders for "wav" files. I didn't have those in my game so it never happened.

I can add two options to fix that :
- an option to disable the second pass altogether
- an option to make second pass look for "wav" only in characters folders that are referenced in models.txt. But then it will be up to you to make sure you don't have wav somewhere that isn't included by this restriction.

I'll also add the option to edit which files the second pass look for. It's already in the code but you can't edit it in GUI.

You can also load sprites from scripts. I do this a lot for HUDs and special effects. Not sure if you already account for this, if so feel free to ignore me. :)

DC
 
Yeah i have a mess everywhere, in all folders, bgs folders, scripts folders, i just keep the files even tho i dont use them i test them from time to time but id love to have a tool that wipes all unused stuff just before a release , so.. maybe a global list that points to every mention of path inside txt files that are in data folder would solve this.
And if the file is not on the list, scrap the file.
I think there needs to be precise workflow with multiple passess to find all the right files.
Yeah i do think about one button click to cleanup entire data folder, along with bgs,music, misc and all.
Folder with wav samples is a mess... and its tedious to check what file is not used.
Maybe a gui would be nicer for this so i can decide per every file what to do, remove, change path, move, clone , whatever.
But its a bigger task , someting i plan to do in the future, so at first the tool needs to know all the required files for openbor so it wont remove them.
 
Yeah i have a mess everywhere, in all folders, bgs folders, scripts folders, i just keep the files even tho i dont use them i test them from time to time but id love to have a tool that wipes all unused stuff just before a release , so.. maybe a global list that points to every mention of path inside txt files that are in data folder would solve this.
And if the file is not on the list, scrap the file.
I think there needs to be precise workflow with multiple passess to find all the right files.
Yeah i do think about one button click to cleanup entire data folder, along with bgs,music, misc and all.
Folder with wav samples is a mess... and its tedious to check what file is not used.
Maybe a gui would be nicer for this so i can decide per every file what to do, remove, change path, move, clone , whatever.
But its a bigger task , someting i plan to do in the future, so at first the tool needs to know all the required files for openbor so it wont remove them.

In the meantime, I'm uploading a new update for this prepare PAK tool, that let you customize some parameters of the second pass. It still will remain pretty simple, but for most people the customization will be more than enough.
 
Piccolo updated Chronocrash Modders Tools with a new update entry:

Changelog 0.6.12

Updated "Prepare PAK" tool so that you can now customize how the second pass work.

The tool has two passes :

- The first pass scans for sprites, palettes, wav, ... that are explicitly referenced in character models (txt). This pass is mandatory and not customizable
- The second pass scans for files with a specific format everywhere in chars folder (and subfolders), even if they are not explicitly referenced in character models. For example it can be used to include "wav" that...

Read the rest of this update entry...
 
You can also load sprites from scripts. I do this a lot for HUDs and special effects. Not sure if you already account for this, if so feel free to ignore me. :)

DC

The first pass of the tool account for sprites loaded with scripts if the scripts are in the character itself (will add an option for external ".c" files later) AND if their path is not build with variables (for example "data/chars/joe/idle" + X + ".png" will not be parsed).

The second pass of the tool will grab all sprites if you explicitly add the extension you want to look for (for example ".png").
 
  • Like
Reactions: ABK
error :

Traceback (most recent call last):

File "gui\pak.py", line 181, in process

FileNotFoundError: [Errno 2] No such file or directory: 'D:/Shrouds/data\\chars\\orman/shiz.txt'



and its true, this txt does not exist, shouldnt stop the code tho.
 
error :

Traceback (most recent call last):

File "gui\pak.py", line 181, in process

FileNotFoundError: [Errno 2] No such file or directory: 'D:/Shrouds/data\\chars\\orman/shiz.txt'



and its true, this txt does not exist, shouldnt stop the code tho.
Depends, is the non-existing file mentioned in models.txt or not ? If so it shouldn't stop the code indeed, but if it is not mentioned then it means there is an issue that needs to be fixed
 
yeah it is intentionally i put in some non existing shiz to test it out, it does not exist, i put in fake path into models.txt
 
Back
Top Bottom