File Directory [Solved]

Jimmy

New member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
569
I feel stupid for asking but I've been trying to find example how to load and save json files that sits beside the app file itself on the desktop on Windows and MacOS, how do you do that? Is there a path defined for this?

I don't want to refer to the absolute desktop path but I want to access files wherever the app itself happens to be on macOS/Windows, is that possible?
 

dawlane

Well-known member
CX Code Contributor
Joined
Jun 21, 2017
Messages
795
Simple: Look in the trans source code. You'll find your answer there.
Clue, check out the os mdule.
 

Jimmy

New member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
569
Thanks, okay so I was reading up and found this nugget :

# Function AppPath:String()
Returns the file system path of the currently running application.

# Function RealPath:String(path:String)
Returns the real, or 'absolute', file system path corresponding to the given path.

Parameters:
path - a file system path.


I quickly threw this together :

code_language.cerberus:
Local path:String = AppPath() ' import os
Local path2:String =  RealPath("")
Print path
Print path2

The first one did work but it gives you something like this

. . . .. /Desktop/gamefix/test.buildv2020-11-15/glfw3/xcode/build/Release/CerberusGame.app/Contents/MacOS/CerberusGame

The app-level is CerberusGame.app, everything after that is "inside" the executable icon.
How can I chop it off at .app? Is it just a matter of string manipulation?
 
Last edited:

Jimmy

New member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
569
Okay so I failed to read the json file so I went for something simpler and load image but I can't even do that the app just closes down.

Here's a simple current example :

code_language.cerberus:
Import mojo2
Import os

Function Main()
    New MyApp
End

Class MyApp Extends App

    Field canvas:Canvas   
    Field readonlyimage:Image       
    Field paint2:Canvas
    Field paint3:Canvas
    Field image2:Image   
    Field image3:Image
    Field size:Int=32
    Field wx:Int, wy:Int
    Field tilemap:Int[512*512]
    Field path:String
    Field path2:String
    
    Method OnCreate()
        
        For Local y :=0 To 511
            For Local x := 0 To 511
                tilemap[x + y * 512] = Int(Rnd(127))
            Next
        Next





' -------------------------------------------------------------------------------------------------
        path = AppPath()
        path2 =  RealPath("")
        ' Print path
        ' Print path2
        
        ' Example of path
        ' . . .. /Desktop/gamefix/test.buildv2020-11-15/glfw3/xcode/build/Release/CerberusGame.app/Contents/MacOS/CerberusGame
        
        path=path+"/"+"betatestsprites.png" ' Get path where application is
        readonlyimage = Image.Load(path,0,0,0) '  Try load beta-sprites placed inside the application at correct spot inside the app.
' -------------------------------------------------------------------------------------------------




        
        ' readonlyimage = Image.Load("512x512sprites2.png",0,0,0)
        
        image3 = New Image(readonlyimage.Width,readonlyimage.Height,,,0)
        image2 = New Image(256,256,0,0,0)
        paint2 = New Canvas(image2)
        paint3 = New Canvas(image3)   
        canvas = New Canvas
        SetSwapInterval 1
        SetUpdateRate 0   
    End

     Method OnRender()
    
        Local w=DeviceWidth, h=DeviceHeight       
        canvas.SetViewport 0,0,w,h ; canvas.SetScissor 0,0,w,h ; canvas.SetProjection2d 0,w,0,h ; canvas.Clear 0,0,0
          paint3.SetViewport 0,0,w,h ; paint3.SetScissor 0,0,w,h ; paint3.SetProjection2d 0,w,0,h
          paint3.Clear ;    paint3.DrawImage readonlyimage,0,0 ; paint3.Flush
        paint2.SetViewport 0,0,w,h ; paint2.SetScissor 0,0,w,h ; paint2.SetProjection2d 0,w,0,h ; paint2.Clear 0,0,0
        paint2.DrawImage readonlyimage,0,0
        paint2.DrawImage image3,256,256
        paint2.Flush

        Local scrx := wx Mod size, scry:=wy Mod size
        Local mapx := wx / size, mapy:=wy / size   
        Local cnty := -scry
        For Local y := mapy To mapy+((h/size)+1)
            Local cntx := -scrx
            For Local x:=mapx To mapx+((w/size)+1)
                Local char:= tilemap[x + y * 512] ; Local tilex := char & 15 ; Local tiley := char Shr 4
                canvas.DrawRect cntx,cnty,size,size,image2,tilex Shl 5,tiley Shl 5,32,32
                cntx=cntx+size
            Next
            cnty = cnty + size
        Next   
        
        canvas.DrawText path,-450,100
        wx = wx + 1       
        canvas.Flush
    End
 
End
 

Jimmy

New member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
569
I can however get the path correctly, I construct the path correctly, so far so good.

Maybe the the load command needs some extra time or something to load when the file is so far away?
 

Jimmy

New member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
569
Okay but even with the path being correct I can't seem to be able to use it with LoadImage yet.

Will solve this later and post the solution when I find it.
I need to check this more tonight.


code_language.cerberus:
Function Main()
    Local tcc:=New TransCC
    #If CONFIG="debug"
        SetEnv "CERBERUS_DIR",RealPath( ExtractDir( AppPath )+"/../../../../" )
        SetEnv "CXS_FILE",GetEnv( "CERBERUS_DIR" )+TEST_PATH+"/"+TEST_FILE+"/"+TEST_FILE+".cxs"
     
        Local str:String, args$[]=[ GetEnv( "CERBERUS_DIR" )+"/bin/transcc_"+HostOS(),
                                    "-target="+TEST_TARGET,
                                    "-config="+TEST_CONFIG,
                                    TEST_BUILD,
                                    GetEnv( "CXS_FILE" ) ]
        For Local i:=Eachin args
            str+=i+" "
        Next
        DebugLog "~nRunning in debug mode:~n"+str
        tcc.Run args
    #Else
        SetEnv "CERBERUS_DIR",RealPath( ExtractDir( AppPath )+"/.." )
        tcc.Run AppArgs
    #Endif
End
 

Jimmy

New member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
569
haha I found the problem I think
. . .. /Desktop/gamefix/test.buildv2020-11-15/glfw3/xcode/build/Release/CerberusGame.app/Contents/MacOS/CerberusGame

the name of the app itself is included in the path!

I have to take away CerberusGame for the "internal" (manually placed by the animator inside the Mac app file) for the file to work
. . .. /Desktop/gamefix/test.buildv2020-11-15/glfw3/xcode/build/Release/CerberusGame.app/Contents/MacOS/

And to have an external file that lays beside the actual app will be simple deleteon of a few more characters so it becomes this
(in other workds I should not save filename.app)
. . .. /Desktop/gamefix/test.buildv2020-11-15/glfw3/xcode/build/Release/
 

Jimmy

New member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
569
So as I see it the simplest way is simply to import os and use AppPath() and manipulate that string it gives you
so you save only up to .. ."Release/". Everything after that should be deleted.

And that will be the path of your executable on macOS!

With Windows my guess without trying is that is iit too gives you the name that includes the app (but .exe instead of .app) and it it does not go "inside" the exe, it probably stops there, so you have less to take away.

But the recipe becomes the same :
Use AppPath() to get the full path and save everything of that string until you reach .... ....Release/" and the snip the rest.

and this will get you the path of your executable on any desktop probably.
 

Jimmy

New member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
569
But if you move the file, there's no Release..

Fuck okay I need to go back to the drawing board.
 

Jimmy

New member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
569
I can do the ugly way, if I don't change the name of the app I can hardcode this :
Take away from string from the right side "CerberusGame.app/Contents/MacOS/CerberusGame"

And that would work on macOS alone.
 

dawlane

Well-known member
CX Code Contributor
Joined
Jun 21, 2017
Messages
795
Try this.
code_language.cerberus:
Strict

Import os

Function Main:Int()
    Local appRoot:="", contentsRoot:="", resourceRoot:="", jsonFile:="", exeRoot:=RealPath( ExtractDir( AppPath() ) ) ' Extracting the directory removes the last part. In other words the executable name.

    Print""

    #If HOST="macos"
        appRoot = RealPath( exeRoot+"/../../" )    ' MacOS go back two directories. Should set you to the bundle root directory aka .app
        contentsRoot = RealPath( exeRoot+"/../" )    ' MacOS go back one directory. Should set you to the Contents directory
        resourceRoot = contentsRoot+"/Resource"    ' From the Contents directory, construct the path to the files
        jsonFile = resourceRoot+"/myJson.json"       ' If the json file was located in the resource directory. Else if the json was with the executable, then use exeRoot instead of resourceRoot.
        Print contentsRoot+"~n the Contents direcory~n"
    #Else
        jsonFile = exeRoot+"/myJson.json"
    #End

    Print "The executable directory~n"+exeRoot+"~n"
    Print "The path to the json file~n"+jsonFile

    Return 0
End
 
Last edited:

Jimmy

New member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
569
Thanks so much!

I will try to understand this tonight, is it possible to see the console PRINTs when you execute
actual desktop binarys or do you need create a window with Drawtext?
 

Jimmy

New member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
569
Thanks Dawnlane and Mike, got it working now perfectly
 

Jimmy

New member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
569
Here's a working example that saves a file just beside the game executable on macOS.
:D
Am really happy having this working as it will truly make the development so much faster!

MacOS version
Screenshot.png


code_language.cerberus:
Strict
Import mojo2
Import brl.filestream
Import os

Function Main:Int()
    New Game()
    Return 0
End

Class Game Extends App

    Field canvas:Canvas
 
    Method OnCreate:Int()
        canvas=New Canvas
        canvas.Clear
        
        ' Create data
        Local numbers:Int[] = [10,20,30,40,50,60,70,80,90,100]

        ' Find directory
        Local exeRoot := RealPath(ExtractDir(AppPath()))
        Local besideapp := RealPath(exeRoot+"/../../../")

        ' Save data
        Local dump := New FileStream(besideapp+"/"+"numbers.dat","w")
        For Local i:Int = EachIn numbers
            dump.WriteString(i+ ",") ' as (8-bit) strings, totally 31 bytes.
            ' dump.WriteInt(i) ' as (32-bit) integers, totally 40 bytes.
        Next
        dump.Close
        
        Return 0
    End
    
    Method OnRender:Int()
        ' DebugStop
        Return 0
    End 

End
 
Last edited:
Top Bottom