Diese Funktion wird in ein Spiel eingebaut. Sie sucht dann auf einem fernen Server, ob es ein Update des Spiels gibt, läd das Update (im Hintergrund) in ein temp. Verzeichnis, beendet das Spiel und startet es neu.
Das Ganze besteht eigentlich aus zwei Programmen. Das Downloaden wird mit einer Funktion im Spiel (z.b. SPIEL.EXE) durchgeführt. Die Daten werden zunächst in einem temp.Verzeichnis zwischengespeichert. Am Ende startet SPIEL.EXE eine RESTART.EXE und beendet sich selbst. Diese RESTART.EXE kopiert nun die temp. Datei auf die SPIEL.EXE, startet SPIEL.EXE erneut und beendet sich selbst.
Hier ein Beispiel für MaxGui:
Erzeuge aus diesem Quellcode eine MYSPIEL.EXE. Damit es komplett funktioniert muss im gleichen Verzeichnis auch noch die RESTART.EXE vorhanden sein (siehe nächste CodeBox).
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] SuperStrict Import MaxGUI.Drivers Global Window:TGadget , UpdateButton:TGadget Local flags%=WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS|WINDOW_CENTER Window= CreateWindow("Leeres Test Window" , 0 , 0 , 600 , 400 , Null , Flags%) UpdateButton=CreateButton("Suche Update", 10,10,100,40,Window,BUTTON_PUSH)
Global Update:TUpdate = TUpdate.CreateMe(Window)
Update.SetDatei "http://www.midimaster.de" , "download/Setup_Ohr.exe" , "Info.txt" , "1.0.1"
CreateTimer 10 While WaitEvent() Local tmpGadget:TGadget Select EventID() Case EVENT_TIMERTICK Update.UpdateLauft Case EVENT_GADGETACTION Local tmpGadget:TGadget = TGadget(EventSource())
Select tmpGadget Case UpdateButton Update.NextStep -1 Default Update.Event tmpGadget End Select Case EVENT_WINDOWCLOSE End End Select Wend
Type TUpdate Const RESET%=-1 , BEGINN%=0 , SOLL_ICH%=1, NIX_DA%=2 , TRANSFER%=3 , NEUSTART%=4 , SPAETER%=5 , RESTART%=6 Const YES%=1 , NO%=0 , FINISH%=2 , ABBRUCH%=3 Global Stream:TStream , SaveStream:TStream
Global Parent:TGadget , ProgressWindow:TGadget , ProgBar:TGadget Global Label:TGadget , InfoZeile:TGadget , OkButton:Tgadget, AbbruchButton:Tgadget
Global AktMode% , URL$, Source$ , FinalDatei$ , Groesse% , InfoDatei$ , AlteVersion$ , NeueVersion$ , Running%
Function CreateMe:TUpdate(locParent:TGadget) Parent=locParent Local loc:TUpdate=New TUpdate Local flags%=WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS|WINDOW_CENTER ProgressWindow= CreateWindow(StripExt(StripDir(AppFile)) + " Update" , 0 , 0 , 300 , 200 , Parent , Flags%) label=CreateLabel("",30,70,250,25, ProgressWindow) InfoZeile=CreateLabel("",30,100,250,25, ProgressWindow) ProgBar = CreateProgBar(10,10,200,20,ProgressWindow) OkButton=CreateButton("Ok", 210,170,80,20,ProgressWindow,BUTTON_PUSH) AbbruchButton=CreateButton("Abbruch", 140,170,60,20,ProgressWindow,BUTTON_PUSH) HideGadget ProgressWindow Return loc End Function
Function SetDatei (EchtUrl$, locSource$ , VersionInfoDatei$ , Version$) Source=locSource FinalDatei = StripDir(Source) Groesse= HttpFileSize(EchtUrl + "/" + Source) If Instr(EchtUrl,"http://www.") URL = EchtUrl.Replace("http://www.", "http::") + "/" Else RuntimeError "no valid URL" EndIf InfoDatei=VersionInfoDatei AlteVersion=Version End Function Function Event (Gadget:TGadget) Select Gadget Case OKButton NextStep YES Case AbbruchButton NextStep NO End Select End Function
Function CheckVorhanden%() Local Stream:TStream , ok% , Text$ DisableGadget OkButton SetGadgetText Label,"Suche nach Update..." Stream = ReadStream(URL + InfoDatei) If Stream OK=1 If Ok=0 SetGadgetText InfoZeile,"Server nicht erreicht!" Return False Else SetGadgetText InfoZeile,"Prüfe Versionsnummer..." While Not Eof(Stream) Text= ReadLine(Stream) If Left(text,2)="<!" SetGadgetText InfoZeile , "Informations-Datei nicht gefunden!" CloseStream Stream Return False EndIf If Instr(Text, FinalDatei) Then Exit Wend CloseStream Stream If Instr(Text, FinalDatei) Print Text NeueVersion =Trim(Mid(Text,Instr(Text,"=")+1)) If NeueVersion="" SetGadgetText InfoZeile , "Informations-Zeile nicht gefunden!" Return False ElseIf NeueVersion=AlteVersion SetGadgetText InfoZeile,"kein aktuelleres Update vorhanden!" Return False EndIf Else SetGadgetText InfoZeile , "Informations-Zeile nicht gefunden!" Return False EndIf EndIf SetGadgetText InfoZeile,"Neue Version: " + NeueVersion Stream = ReadStream(Url + Source) If Stream Text= ReadLine(Stream) CloseStream stream If Left(text,2)="<!" SetGadgetText InfoZeile,"Download nicht gefunden!" Return False EndIf Else SetGadgetText InfoZeile,"Download nicht gefunden!" Return False EndIf EnableGadget OkButton Return OK End Function
Function NextStep(Wie%) If Wie=RESET AktMode=BEGINN ShowGadget ProgressWindow SetGadgetText Label,"" SetGadgetText OkButton ,"OK" ShowGadget OKButton UpdateProgBar progbar,0.0 EndIf Select AktMode Case BEGINN If CheckVorhanden()=False DisableGadget OkButton AktMode=NIX_DA Else SetGadgetText Label,"Ein Update steht bereit!" SetGadgetText OkButton,"Übertragen" AktMode=SOLL_ICH EndIf Case SOLL_ICH If Wie = NO Then HideGadget ProgressWindow Else AktMode=TRANSFER UpdateLauft RESET EndIf Case TRANSFER If Wie = NO Then Running=ABBRUCH EndIf Case NEUSTART If Wie =NO Then AktMode=SPAETER HideGadget ProgressWindow Else AktMODE=RESTART Neustarten EmitEvent CreateEvent:TEvent( EVENT_WINDOWCLOSE,Parent) EndIf Case NIX_DA HideGadget ProgressWindow End Select End Function
Function UpdateLauft(WasTun%=0) Global Z#, B# Select WasTun Case RESET Local TempDir$=getenv_("TEMP") +"/" Stream = ReadStream(Url + Source) SaveStream = WriteStream( TempDir + StripExt(FinalDatei) + ".Bin") DisableGadget OkButton SetGadgetText Label, "Daten werden übertragen " Running=YES Z=0 b=Groesse/256/95 Default If Running=YES While Eof(Stream)=0 z=z+1 CopyBytes Stream, SaveStream,256 If (Int(z) Mod 30)=0 UpdateProgBar progbar,z/b/100.0 Return EndIf Wend Running=FINISH ElseIf Running=FINISH CloseStream Stream CloseStream SaveStream Fake100 z/b/100.0 Running=NO AktMode= NEUSTART SetGadgetText Label,"Das Programm jetzt neu starten?" SetGadgetText OkButton,"Neu starten" EnableGadget OkButton EnableGadget AbbruchButton ElseIf Running=ABBRUCH CloseStream Stream CloseStream SaveStream Running=NO HideGadget ProgressWindow EndIf End Select End Function
Function Fake100(Value#) SetGadgetText Label, "Übertragung vollständig!" RedrawGadget label Repeat UpdateProgBar progbar,Value RedrawGadget progbar value:+0.01 Delay 100 Until value>1 Delay 500 End Function
Function NeuStarten() Local process:TProcess = CreateProcess("restart.exe -" + FinalDatei) If process Then TProcess.ProcessList.Remove process EndIf End Function
Function HttpFileSize:Int(url$) If Instr(url,"http://") url$ = url$.Replace("http://", "") Local slashPos% = url$.Find("/"), host$, file$ If slashPos <> -1 host$ = url$[..slashPos] file$ = url$[slashPos..] Else Return -1 EndIf Local stream:TStream=OpenStream("tcp::" + host$, 80) If Not stream Then Return -1 stream.WriteLine "HEAD " + file$ + " HTTP/1.0" stream.WriteLine "Host: " + host$ stream.WriteLine "" While Not Eof(stream) Local in$ = stream.ReadLine() If in$.Find("Content-Length:") <> -1 stream.Close() Return Int(in$[in$.Find(":") + 1..].Trim()) EndIf Wend stream.Close() EndIf Return -1 End Function End Type
Hinweis:
Die im Beispiel verwendeten Test-Angaben führen zum Download einer harmlosen 300k Datei SETUP_OHR.EXE von meinem Server. Damit könnt ihr den Download experimentieren. (SETUP_OHR.EXE ist ein Installationsprogramm für eines meiner Spiele. Wenn es am Ende erfolgreich startet, kann man es einfach abbrechen.) Die im Beispiel verwendetete INFO.TXT befindet sich auch permanent auf meinem Server und enthält Zeilen mit den Versioninformationen meiner Programme.
Jetzt die RESTART.EXE (muss so genannt werden)
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] SuperStrict
Framework BRL.Blitz Import Pub.FreeProcess Import BRL.Retro DrawTextEx " ", MIT_GRAPHICS
Global Datei$ , Source$, Dest$, y% Const MIT_GRAPHICS%=-1 , MIT_FLIP%=1
DrawTextEx "Number of arguments: "+AppArgs.length For Local arg:String = EachIn AppArgs DrawTextEx arg Next
If AppArgs.Length>1 Datei=Mid(AppArgs[1],2,-1) Dest=AppDir +"/" + Datei EndIf
Source= getenv_("TEMP") + "/" + StripExt(Datei) + ".Bin"
DrawTextEx "Source=" + source DrawTextEx "Dest= " + Dest, MIT_FLIP DrawTextEx "Copying..."
If FileType(Source)=1 CopyFile Source , Dest Else RuntimeError "error source file not found" End EndIf DrawTextEx "fertig" , MIT_FLIP
Local process:TProcess=CreateProcess(Dest) TProcess.ProcessList.Remove process
End
Function DrawTextEx(Text$, Flag%=0)
End Function
Um den Auto-Update in eigenen Programmen nutzen zu können, müssen nur Änderungen an einer Zeile in der MySpiel.Exe vorgenommen werden. Angenommen die Versionsnummer der aktuellen MySpiel.Exe ist 1.0.4, angenommen es soll später einmal die neue MySpiel.Exe 1.0.5 von dem Server www.myserver.de heruntergeladen werden können. Angenommen die Info-Datei heißt bei dir dort MyInFo.TxT. Dann ist aktuell folgende Zeile im Code anzupassen:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Update.SetDatei "http://www.myserver.de" , "MySpiel.Exe" , "MyInFo.TxT" , "1.0.4"
Wichtig ist, dass es dabei auf die Groß/Kleinschreibung ankommt!
Erscheint später einmal wirklich die 1.0.5 oder die 2.0.0, so muss auf dem Server eine Datei MyInFo.TxT vorhanden sein, die neben beliebig weiteren Zeilen vor allem diese Zeile enthalten muss:
Code: [AUSKLAPPEN] [EINKLAPPEN] MySpiel.Exe=2.0.0
Klickt der User draußen nun auf den Update-Knopf, wird die Information auf dem Server entdeckt, dass es ein Update gibt und der Update-Prozess startet.
Hier nun eine Silent-Version ohne MaxGui:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] SuperStrict Graphics 800,600
Global Update:TUpdate = TUpdate.CreateMe()
Update.SetDatei "http://www.midimaster.de" , "download/Setup_Ohr.exe" , "Info.txt" , "1.0.0"
Local FPS:TTimer=CreateTimer(10) Print "press <U> to check for Update"
Repeat If KeyHit(KEY_U) Then Update.FirstStep EndIf Update.UpdateLauft Flip WaitTimer FPS Until AppTerminate()
Type TUpdate Const RESET%=-1 , BEGINN%=0 , NIX_DA%=2 , TRANSFER%=3 , RESTART%=6 Const YES%=1 , NO%=0 , FINISH%=2 , ABBRUCH%=3 Global Stream:TStream , SaveStream:TStream
Global AktMode% , URL$, Source$ , FinalDatei$ , Groesse% , InfoDatei$ , AlteVersion$ , NeueVersion$ , Running%
Function CreateMe:TUpdate() Local loc:TUpdate=New TUpdate Return loc End Function
Function SetDatei (EchtUrl$, locSource$ , VersionInfoDatei$ , Version$) Source=locSource FinalDatei = StripDir(Source) Groesse= HttpFileSize(EchtUrl + "/" + Source) If Instr(EchtUrl,"http://www.") URL = EchtUrl.Replace("http://www.", "http::") + "/" Else RuntimeError "no valid URL" EndIf InfoDatei=VersionInfoDatei AlteVersion=Version End Function Function CheckVorhanden%() Local Stream:TStream , ok% , Text$ Print "Suche nach Informations-Datei" Stream = ReadStream(URL + InfoDatei) If Stream OK=1 If Ok=0 Print "Server nicht erreicht!" Return False Else Print "Prüfe Versionsnummer..." While Not Eof(Stream) Text= ReadLine(Stream) If Left(text,2)="<!" Print "Informations-Datei nicht gefunden!" CloseStream Stream Return False EndIf If Instr(Text, FinalDatei) Then Exit Wend CloseStream Stream If Instr(Text, FinalDatei) NeueVersion =Trim(Mid(Text,Instr(Text,"=")+1)) If NeueVersion="" Print "Informations-Zeile nicht gefunden!" Return False ElseIf NeueVersion=AlteVersion Print "kein aktuelleres Update vorhanden!" Return False EndIf Else Print "Informations-Zeile nicht gefunden!" Return False EndIf EndIf Print "Neue Version: " + NeueVersion Stream = ReadStream(Url + Source) If Stream Text= ReadLine(Stream) CloseStream stream If Left(text,2)="<!" Print "Download nicht gefunden!" Return False EndIf Else Print "Download nicht gefunden!" Return False EndIf Return OK End Function
Function FirstStep() Print "S T A R T U P D A T E P R O Z E S S" AktMode=BEGINN If CheckVorhanden()=False AktMode=NIX_DA Print "Abbruch, kein Update möglich" Else Print "Ein Update steht bereit!" AktMode=TRANSFER UpdateLauft RESET EndIf End Function
Function UpdateLauft%(WasTun%=0) Global Z#, B# Select WasTun Case RESET Local TempDir$=getenv_("TEMP") +"/" Stream = ReadStream(Url + Source) If Stream =Null Print "ERROR II" EndIf SaveStream = WriteStream( TempDir + StripExt(FinalDatei) + ".Bin") Print "Daten werden übertragen " Running=YES Z=0 b=Groesse/256/95 Default If Running=YES While Eof(Stream)=0 z=z+1 CopyBytes Stream, SaveStream,256 If (Int(z) Mod 30)=0 Print Int(z/b) + "%" Return 1 EndIf Wend Running=FINISH ElseIf Running=FINISH CloseStream Stream CloseStream SaveStream Fake100 z/b/100.0 Running=NO AktMODE=RESTART Neustarten End ElseIf Running=ABBRUCH CloseStream Stream CloseStream SaveStream Running=NO Return 0 EndIf End Select End Function
Function Fake100(Value#) Print "100%" Print "Übertragung vollständig!" End Function
Function NeuStarten() Local process:TProcess = CreateProcess("restart.exe -" + FinalDatei) If process Then TProcess.ProcessList.Remove process EndIf End Function
Function HttpFileSize:Int(url$) If Instr(url,"http://") url$ = url$.Replace("http://", "") Local slashPos% = url$.Find("/"), host$, file$ If slashPos <> -1 host$ = url$[..slashPos] file$ = url$[slashPos..] Else Return -1 EndIf Local stream:TStream=OpenStream("tcp::" + host$, 80) If Not stream Then Return -1 stream.WriteLine "HEAD " + file$ + " HTTP/1.0" stream.WriteLine "Host: " + host$ stream.WriteLine "" While Not Eof(stream) Local in$ = stream.ReadLine() If in$.Find("Content-Length:") <> -1 stream.Close() Return Int(in$[in$.Find(":") + 1..].Trim()) EndIf Wend stream.Close() EndIf Return -1 End Function
End Type
Die RESTART.EXE bleibt hierfür die gleiche. Die Anmerkungen (siehe oben) sind ebenfalls gleich.
Für Kommentare und Verbesserungsvorschläge wäre ich dankbar.
|