OPF-Workshop 2005 - Projekt: PyOPFAddOnManager

Du hast eine Idee für ein Projekt?
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Zum vorgestellten OPF-Workshop ( http://www.python-forum.de/viewtopic.php?t=3100 ) würde ich gern ein AddOnManager auf den Workshop programmieren.

Ein Crossposting im mapfact-Forum findet sich hier: http://mapfact.gamigo.de/forum/viewtopic.php?p=55684

Hier eine grobe Darstellunge der Problematik:

AddOn's für das Spiel OPF sind *.pbo Dateien. In diesen Dateien sind alle Informationen (wie 3D-Modelle, Texturen, Skripts) gepeichert. Neben einigen Basis-pbo-Dateien, die das Grundsystem darstellen, gibt es jede Menge AddOn's aus dem Internet.
Bei den AddOn's aus dem Internet steht i.d.R. in irgendeinem readme drin, welche anderen AddOns dieses benötigt und der User muss dafür sorgen das diese AddOns auch vorhanden sind.
Folglich tummeln sich bei den meisten Spielern zig pbo-Dateien ;)

Das Spiel lädt alle pbo's die im Verzeichnis .\addons\ liegen. Somit werden, auch pbo-Daten geladen, die evtl. für das gestartete Spiel gar nicht gebraucht werden. Dieses soll vom AddOnManager geregelt werden.

Das kann recht einfach gelöst werden, denn wenn man eine *.pbo-Datei mit einer anderen Endung versieht, werden sie vom Spiel nicht mehr geladen.

Also muss man nur quasi eine kleine Datenbank haben, in der festgehalten wird, welche AddOn's gebraucht werden. Im einfachsten Fall muss der User sich das in einer Text-Datei selber zusammenschreiben.

Neben den AddOn's existieren aber auch Mods. Bei diesen ist das Problem recht ähnlich und kann evtl. auch vom AddOnManager verwaltet werden.
Die Mods haben ein eigenes Verzeichnis und darin gibt es ein eigenes addons-Verzeichnis mit den pbo-Dateien

gestartet wird ein Mod, wenn man der Spiel-EXE-Datei mit den Parameter "-mod:" startet, also z.B. so:

Code: Alles auswählen

opf.exe -mod: finmod
----

Es gibt zwei Arten, den AddOnManager zu benutzen. Entweder wählt der User vor dem Spiel...
...eine bestimmte Mission aus
...ein bestimmtes AddOn

Außerdem soll es natürlich auch Möglich sein, alle PBO's oder nur die Basis PBO's zu aktivieren.

----

Das ganze soll als eigenständiges Programm laufen, also wird py2exe eingesetzt.

Die Interaktion mit dem User erfolgt im einfachsten Fall über eine Web-Oberfläche, besser aber mit GTK2. Eine Weboberfläche wäre nur eine Notlösung, weil ich mich damit, im Gegensatz zu GTK, gut auskenne.
Somit kann ich für die GUI hilfe gebrauchen...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Wenn du GTK Fragen hast, kannst du gerne in der GTK Forum posten, oder auch eines meiner GTK Programme sezieren ;) Ich kann aber nicht garantieren dass ich eine Lösung finde..
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich bräuchte mal eure Hilfe... Ich sitze jetzt hier im Workshop und versuche die Fahne für Python hoch zu halten ;)

Ich möchte gern eine DLL benutzen, hab es mit Python allerdings noch nie gemacht... Ich denke das Stichwort ist cTypes, oder?

Die DLL dient zum Auspacken von PBO Dateien: DePboDLL.rar von http://andrew.nf/ofp/tools/

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:Ich möchte gern eine DLL benutzen, hab es mit Python allerdings noch nie gemacht... Ich denke das Stichwort ist cTypes, oder?
Ja, ich denke da kommst du am ehesten mit ctypes hin, hier hast du mal zwei Beispiele.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ja danke, das hilft mir schonmal weiter.

Ich hab in einer Datei eine Liste der "Exports" gefunden:

Code: Alles auswählen

DePboClose
DePboOpen
DePboStrError
DePboFindEntry
DePboFileCount
DePboFirstEntry
DePboNextEntry
DePboGetEntryName
DePboGetNumberOfEntries
DePboGetData
Ich gehe mal von aus, das die Exports Funktionen sind, die ich aufrufen kann:

Code: Alles auswählen

import ctypes

DePbo = ctypes.cdll.LoadLibrary("DePbo.dll")

pbofile = "Vzpoura.Eden.pbo"
print DePbo.DePboOpen( pbofile )
Ich hab die Funktion DePboOpen einfach mit einen Dateinamen aufgerufen. Allerdings erhalte ich einen Fehler:

Code: Alles auswählen

Traceback (most recent call last):
  File "DePbo.py", line 9, in ?
    print DePbo.DePboOpen( pbofile )
ValueError: Procedure called with not enough arguments (4 bytes missing) or wrong calling convention

In einer anderen Datei habe ich eine Beschreibung für VISUAL BASIC entdeckt:

Code: Alles auswählen

Attribute VB_Name = "pboDefs"
'''' VISUAL BASIC TO PBODLL.DLL API
''''''''''''''''''''''''''''''''''''
' author mikero@norfolk.nf
' simply include this module in your visual basic code

Public Declare Function DePboOpen Lib "DePbo" (ByVal fname As String) As Long
'  returns 0 on success
Public Declare Sub DePboClose Lib "DePbo" ()
Public Declare Function DePboStrError Lib "DePbo" () As String
'   returns reason for fail
Public Declare Function DePboFileCount Lib "DePbo" () As Long
Public Declare Function DePboGetNumberOfEntries Lib "DePbo" () As Long
' synonymous.

Public Declare Function DePboFindEntry Lib "DePbo" (ByVal fname As String) As Long
' find an entry by name eg "mission.sqm" (case insensitive)
' note that mission.sqm and missions/mission.sqm are not the same
' returns 0 if no fname exists in header
' otherwise returns a handle to be used for other calls
Public Declare Function DePboFirstEntry Lib "DePbo" () As Long
Public Declare Function DePboNextEntry Lib "DePbo" (ByVal Entry As Long) As Long
' also return entry handles
' iterate thru list
Public Declare Function DePboGetEntryName Lib "DePbo" (ByVal Entry As Long) As String
' find the file name for this entry eg "misions/description.ext"
Public Declare Function DePboGetData Lib "DePbo" (ByVal Entry As Long, status As Long) As String
' pass the read data back to vb
'  returns length of file, including 0 negative vals are errors

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Guck vielleicht mal im ctypes-Tutorial unter Simple data types, du könntest versuchen, den String in ein char-Datentyp zu wandeln.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Jau, so geht's anscheinend:

Code: Alles auswählen

import ctypes

DePbo = ctypes.windll.LoadLibrary("DePbo.dll")

pbofile = ctypes.c_char_p( "Vzpoura.Eden.pbo" )
print DePbo.DePboOpen( pbofile ) # returns 0 on success

FileCount = DePbo.DePboFileCount()
print "FileCount:",FileCount

NumberOfEntries = DePbo.DePboGetNumberOfEntries()
print "NumberOfEntries:",NumberOfEntries
Mal sehen, wie es weiter geht...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Bin weiter gekommen, allerdings hänge ich nun bei dem eigentlichen lesen der Daten:

Code: Alles auswählen

import ctypes

DePbo = ctypes.windll.LoadLibrary("DePbo.dll")

filename = "Vzpoura.Eden.pbo"
ErrCode = DePbo.DePboOpen( ctypes.c_char_p(filename) )
if ErrCode != 0:
    print "Error file open!"

FileCount = DePbo.DePboFileCount()
print "FileCount:",FileCount

NumberOfEntries = DePbo.DePboGetNumberOfEntries()
print "NumberOfEntries:",NumberOfEntries

mission_sqm_handle = DePbo.DePboFindEntry( ctypes.c_char_p( "mission.sqm" ) )
print "mission_sqm_handle :",mission_sqm_handle
if mission_sqm_handle == 0:
    print "No 'mission.sqm' found!"

print DePbo.DePboGetData( mission_sqm_handle, mission_sqm_handle )
Ich bekomme einen üblen Windows Systemfehler :( Ungefähr: '''Der Vorgang "read" konnte nicht auf dem Speicher durchgeführt werden.'''

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hier ist mal ein Auszug, wie es in VB gehen soll:

Code: Alles auswählen

' opens the pbo and reads contents of mission.sqm into textbox
' returns true only if data present

Private Function ReadMissionSqm(MissionName) As Long
Dim EntryHandle As Long

 ReadMissionSqm = DePboFindEntry(MissionName) ' use as an entry handle
 If ReadMissionSqm = 0 Then Exit Function
 MissionText = DePboGetData(ReadMissionSqm, ReadMissionSqm) ' use it as handle pass back as status
 If (ReadMissionSqm < 0) Then Exit Function
 ReadMissionSqm = 1
End Function
Irgendwie finde ich es sehr merkwürdig, warum ReadMissionSqm zweimal übergeben werden soll... Eine andere Version später in den Sourcen scheint mir schon gescheiter:

Code: Alles auswählen

Private Function ListFiles(AllowRead As Boolean) As Boolean
Dim EntryHandle As Long
Dim EntryName As String
Dim status As Long
 
 ListFiles = False
 EntryHandle = DePboFirstEntry()
 While EntryHandle
  EntryName = DePboGetEntryName(EntryHandle)
  If EntryName = "" Then
   ErrMessage "entry has no file name"
   Exit Function
  End If
  lstFiles.AddItem EntryName
  If AllowRead Then
   MissionText = DePboGetData(EntryHandle, status) '  back as status
   If (status < 0) Then
    ErrMessage EntryName & " data error " & DePboStrError()
    Exit Function
   End If
  End If
  EntryHandle = DePboNextEntry(EntryHandle)
 Wend
 ListFiles = True
End Function

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Komme leider nicht weiter:
FileCount: 5
NumberOfEntries: 5
EntryHandle : 11018288
EntryName: 2387188
Traceback (most recent call last):
File "DePbo.py", line 57, in ?
print DePbo.DePboGetData( ctypes.c_long(EntryName), ctypes.c_long(0) )
WindowsError: exception: access violation reading 0x0005025E
>Exit code: -1073741819

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Gibt nun eine Live Webcam vom Workshop:

http://www.mapfact.gamigo.de/Material/N ... ebcam.html

Ich bin der Typ mit dem roten T-Shirt ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

jens hat geschrieben:Komme leider nicht weiter:
FileCount: 5
NumberOfEntries: 5
EntryHandle : 11018288
EntryName: 2387188
Traceback (most recent call last):
File "DePbo.py", line 57, in ?
print DePbo.DePboGetData( ctypes.c_long(EntryName), ctypes.c_long(0) )
WindowsError: exception: access violation reading 0x0005025E
>Exit code: -1073741819
In dem VB Quelltext, den Du davor geposted hast, wird `DePboGetData()` mit `EntryHandle` aufgerufen und nicht mit `EntryName`. Liegt's vielleicht daran?
Antworten