Warning: include_once(/var/www/html/pmwiki-2.2.86/cookbook/soap4pmwiki/soap4pmwiki.php): failed to open stream: No such file or directory in /var/www/html/fields/dbp13/local/config.php on line 4

Warning: include_once(): Failed opening '/var/www/html/pmwiki-2.2.86/cookbook/soap4pmwiki/soap4pmwiki.php' for inclusion (include_path='.:/opt/php/lib/php') in /var/www/html/fields/dbp13/local/config.php on line 4

Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/fields/dbp13/local/config.php:4) in /var/www/html/pmwiki-2.2.86/pmwiki.php on line 1250
Datenbankpraktikum SS 2013 - MMOG - Schiffe Und Missionen Schiffsbau

Schiffsbau

von Isaak Mitschke

Vorwort

Eine Schiffswerft ist ein Gebäude, dass jeder Spieler auf seinem Planeten bauen und erweitern (hochleveln) kann. Einige Schiffe können sofort in der ersten Schiffswerft gebaut werden, andere wiederum benötigen eine bessere Schiffswerft (z.B. Level 3) und andere Vorraussetzungen. Um diese für den Bau eines Schiffs zu realisieren gibt es die Tabelle „buildingtypes_ships“ welche jeweils das Schiff und die dazugehörigen Voraussetzungen enthält. Außerdem sind unsere Spielregeln so definiert, dass jeder Spieler immer nur ein Schiff gleichzeitig pro Planet bauen kann.

Für das Bauen von Schiffen gibt es zwei Views. Eine auf der man Schiffe baut und eine auf der man sehen kann welche Schiffe gerade wo gebaut werden und auf welchen Planeten man überhaupt bauen kann.

Soll ein Schiff gebaut werden, wird der Auftrag an den Resque-Scheduler übergeben. Dieser ruft dann sobald die Bauzeit erreicht ist die Methode zum hinzufügen eines Schiffes in eine Flotte auf. Da der Benutzer zu jeder Zeit die Möglichkeit haben soll, einzelne Bauaufträge abzubrechen und zu sehen, wann welche Schiffe fertig sind, haben wir ein Model erstellt in dem wir all diese Daten (Schiffstyp, Planet, Abschlusszeit) speichern.

Ausschnitt des ERM (SchipBuildingQueue)

Views

Bau von Schiffen

Hier werden alle Schiffe angezeigt, die auf dem ausgewählten Planeten gebaut werden können. Da alle wichtigen Informationen zu einem Schiff nicht in eine Zeile passen, wurde noch ein Info-Button hinzugefügt der Mittels „popover“ die restlichen Informationen anzeigt. Nun kann man auswählen, wie viele von welchen Schiffen gebaut werden sollen. Mittels Javascript wird live berechnet ob man genügend Rohstoffe hat.Falls nicht, wird der Submit-Button ausgeblendet und es wird angezeigt, welche Rohstoffe fehlen.

View: Build Ships

Übersicht

In der Übersichtsview werden alle aktuellen Bauaufträge sowie deren Dauer bis zur Fertigstellung angezeigt. Außerdem besteht die Möglichkeit, einzelne Aufträge abzubrechen. Das Abbrechen erfolgt durch einen Ajax-Request. Auf der Übersichtsseite wird dann der entsprechende Eintrag aus der Tabelle (mittels Javascript und Jquery) entfernt, die Zeiten werden neuberechnet usw.

View: Starport Übersicht

Controller

Starport

Der „Starport-Controller“ hat drei Actions:

  • Index: Stellt Daten für die Übersichtsseite bereit.
  • Show: Schnittstelle für die View zum Bauen von Schiffen
  • Build: Verarbeitet die Parameter (POST), welche die Anzahl der zu Bauenden Schiffe entahalten und leitet den Bau dieser ein.

Ship building queue

Der ShipBuildingQueue Controller hat neben den normalen Actions (durch Scaffolding automatisch entstanden) auch noch die Action „destroy_queue“ mit welcher ein Element aus der Datenbank und aus der Resque entfernt wird. Die generierte destroy-Action haben wir nicht überschrieben, da es sich zum debuggen als sinnvoll erwiesen hat, Objekte wohl aus der Datenbank zu entfernen, nicht aber aus der Resque.

Models

ShipBuildingQueue

Sowohl der Starport- als auch der ShipBuildingQueue-Controller arbeiten mit dem ShipBuildingQueue-Model.

In diesem Model gibt es unter anderem Methoden zum Einfügen in die Queue (sowohl Datenbank als auch Resque), Löschen und updaten.

Schiffe in die Queue einfügen: Die Insert-Methode bekommt als Parameter eine Hash von Schiffen übergeben deren Datenwert der Anzahl der einzufügenden Schiffe entspricht. Zuerst werden die benötigten Ressourcen berechnet und vom Planeten abgezogen. Dafür wird die Methode Planet.take([Rohstof], [Menge]) verwendet, welche die Planeten-Gruppe zur Verfügung gestellt hat. Diese liefert die Zahl der Tatsächlich abgezogenen Rohstoffe zurück. Sollte der Rückgabewert kleiner als die angegebene Menge sein, mangelt es dem Planeten an diesem Rohstoff. Wenn also der Planet genug Rohstoffe hat, wird über jeden Schlüssel des Schiff-Hash dessen Wert nicht null ist iteriert und das Schiff entsprechend häufig in die Datenbank eingefügt. In jedem Durchlauf des Iterators wird auch die Zeit berechnet, in der das Schiff fertiggestellt sein wird (die Zeit des letzten Objekts in der Queue, dessen Planet gleich dem des einzufügenden Objekts ist, plus die Bauzeit).

Schiffe aus der Queue entfernen: Da wir dem User auch die Möglichkeit geben wollten, Bauaufträge abzubrechen z.B. falls er sich verklickt hat oder die Rohstoffe schon für etwas anderes benötigt werden, mussten wir noch eine entsprechende Funktion implementieren. Da die Bauaufträge, die nach dem zu löschenden Bauauftrag aus dem Resque- Scheduler gelöscht werden mussten (wir haben die absolute Zeit zum Ausführen eines Deleyed- Jobs angegeben) war es nötig, diese auch danach wieder neu zu berechnen und einzufügen. Anfangs haben wir dieses Problem wie folgt gelöst:

def self.update_time(time, planet, end_time)
	queue=self.where("planet_id=? AND end_time>?", planet, time)
	queue.each do |q|
		q.end_time-=end_time
		Resque.remove_delayed(AddShip, q.ship_id, q.planet_id, q.qid )
		Fleet.add_ship_in(q.end_time, q.ship, q.planet, q.qid)
		q.save
	end
end

Wir haben jedes Objekt aus der Queue, dessen Zeit größer der Zeit des zu löschenden Objekts ist, gändert und dessen Auftrag aus dem Resque-Scheduler gelöscht und einen neuen mit geänderten Datum eingefügt. Das Ändern von mehr als 30 Einträgen dauerte jedoch sehr lange. Wir haben uns deswegen dafür entschieden, erst alle Einträge aus dem Resque-Scheduler zu löschen, neue Jobs einzufügen und dann mittels „update_all“ ein SQL UPDATE durchzuführen mit dem alle Einträge geändert werden.

def self.update_time(time, planet, end_time)
	queue=self.where("planet_id=? AND end_time>?", planet, time).includes(:ship,:planet).to_a
	queue.each do |q|
		q.end_time-=end_time
		Resque.remove_delayed(AddShip, q.ship_id, q.planet_id, q.qid )
		Fleet.add_ship_in(q.end_time, q.ship, q.planet, q.qid)
 
	end
	plid=planet.id
	ShipBuildingQueue.update_all("end_time= end_time - #{end_time}","planet_id=#{plid} AND end_time>#{time}")
end

Dies führte dazu, dass jetzt ca 100 Einträge geändert werden können, ohne dass es zu langen Ladezeiten kommt. Außerdem wird der Lösch- Vorgang im Hintergrunf mittels Ajax aufgerufen, sodass die Zeile in der Tabelle gleich gelöscht wird und der User nichts davon mitbekommt.


Page last modified on August 24, 2013, at 01:07 AM