Teil 3: Einfache Änderungen an Spieldateien
-------------------------------------------------------------------------------------------------------------------------------------
Um Spieldateien zu verändern werden diese nicht wie in den vorgängern ersetzt sondern wir verwenden stattdessen XML-Diff Dateien gemäß RFC5261 - kling erst einmal kompliziert ist aber prinzipiell eine simple sache.
Betrachten wir noch einmal die MK4-Engine aus dem vorigen Teil:
\assets\props\SurfaceElements\Macros\engine_player_bal_mk4_macro.xml
Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<!--Exported by: Michael (192.168.3.144) at 14.05.2014_13-46-22-->
<macros>
<macro name="engine_player_bal_mk4_macro" class="engine">
<component ref="props_enginesystems_player_bal_mk1" />
<properties>
<identification name="{20108,301}" description="{20108,302}" />
<acceleration forward="90" reverse="135" strafe="180" pitch="250" yaw="250" roll="180" />
<angular />
<speed forward="270" reverse="-90" strafe="135" pitch="85" yaw="85" roll="90" />
<typeinfo mk="4" type="1" />
<hull min="250" max="1000" hittable="0" />
<efficiency>
<threshold threshold="1" value="1" />
<threshold threshold="0.5" value="0.9" />
<threshold threshold="0.25" value="0.8" />
</efficiency>
<sounds>
<ambient ref="eng_player_ambient" />
</sounds>
</properties>
<connections>
<connection ref="enginebooster">
<macro ref="enginebooster_player_01_macro" connection="engine" />
</connection>
</connections>
</macro>
</macros>
Wir wollen, dass diese schneller werden,
also dass das Spiel nicht das oben sieht sondern das hier
Dafür erstellenen wir in unserer Beispielerweiterung eine Datei mit demselben Pfad und Namen wie die Datei oben, aber statt da eine Kopie des obigen rein zu schreiben kommt das hier rein:
Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<diff>
<replace sel='/macros/macro/properties/speed'>
<speed forward="500" reverse="-150" strafe="250" pitch="85" yaw="85" roll="90" />
</replace>
</diff>
zur erklärung:
<diff>-root-Node: damit dem Spiel klar ist, dass dies keine Merge-Date oder neue Datei ist (dazu später mehr) sondern dass diese Datei Änderungen an bestehen Dateien vornehmen soll.
<replace>-Node: damit wird gesagt, dass ein teil der ursprungsdatei ersetzt werden soll (es gibt noch add und delete, die behandeln wir später in diesem Teil).
sel=-Attribut: Dies wählt aus, welcher teil erssetzt werden soll. Nodes werden wie Ordner ausgewählt (mit / als Trenner)
Hier noch einmal in Farbiger Hervorhebung, welcher Teil was auswählt: /macros/macro/properties/speed - im prinzip funktioniert das ganze wie eine Ordnerstruktur, es sind aber auch mehrere gleichnamige Ordner/Nodes im selben Ordner/Node erlaubt, die sich dann durch Attribute und/oder beinhaltete Nodes unterscheiden (oder auch durch die Reihenfolge in der Datei).
Inhalt des <replace>-Nodes: das, was anstatt des Ausgewählten Inhaltes eingefügt werden soll, in diesem fall werden die Leistungsdaten so ersetzt, dass das Triebwerk jetzt vorwärts 500 macht, rückwärts 150 und Seitwärts 250, statt der vorigen 270/90/135.
Natürlich sind auch andere Selektionen denkbar, hier ein paar weitere Beispiele, die jeweils eine ander Option der Auswahlsyntax aufzeigen:
-> Direktes Auswählen/ersetzen eines Attributes, ohne die anderen zu ändern (Beispiel: die Vorwärtsbeschleunigung halbieren)
Code: Select all
<diff>
<replace sel='/macros/macro/properties/acceleration/@forward'>45</replace>
</diff>
wobei der Sel-Attribut nacheinander diese Nodes und zum schluss ein Attribut auswählt:
/macros/macro/properties/acceleration/@forward. der trick hierbei ist das @, wie @ttribut
-> einen Node direkt auswählen, ohne den kompletten Pfad einzugeben (Beispiel: vervielfachen der Hüllenwerte/Hitpoints x10 ):
Code: Select all
<diff>
<replace sel='//hull'>
<hull min="2500" max="10000" hittable="0" />
</replace>
</diff>
in diesem fall wählt //hull den hull-Knoten direkt aus, ohne den kompletten Pfad zu beschreiben. der trick dabei ist das doppelte //. Das vereinfacht zwar sehr viele dinge, aber man muss bedenken dass die XPath-Pfade immer eindeutig sein müssen. für das genannte Beispiel würde //threshold zum beispiel nicht funktionieren, weil es diesen Knoten mehrmals gibt, aber auch hier ist eindeutigkeit möglich:
-> einen Node basierend auf den Werten seiner Attribute auswählen (Beispiel: Effizienz der Triebwerke auf 50% herabsetzen wenn diese nur noch 25% Hülle haben; mehrere Beispiele wie man das hin bekommt; effekt ist bei allen exakt derselbe)
1. Vollständigen Pfad beschreiben und bei den threshold-Nodes diese durch das value-Attribut auseinanderhalten:
Code: Select all
<diff>
<replace sel='/macros/macro/properties/efficiency/threshold[@value="0.8"]'>
<threshold threshold="0.25 value="0.5" />
</replace>
</diff>
Hier wird über die angaben in den [] ein bestimmter Node von mehreren in frage kommenden ausgewählt. Mögliche Merkmale sind ein auseinanderhalten über die Werte von Attributen (wie dieses Beispiel hier), oder auch der wievielte Node in der Datei dies ist (in diesem fall wäre das [3] ), wobei ich ausser in ausnahmefällen davon abrate, dies zu nutzen weil damit keine eindutigkeit über mehrere Versionen und mit mehreren Mods garantiert ist.
2. Direktes addresieren des Nodes und Attributes, der ersetzt werden soll:
Code: Select all
<diff>
<replace sel='//threshold[@value="0.8"]/@value'>0.5</replace>
</diff>
beachtet hierbei das doppelte @value, zuerst zum auswählen/unterscheiden des Nodes, dann die wahl des Attributes selber.
3. Addresieren des Nodes nach einem anderen Wert als der, der ersetzt werden soll:
Code: Select all
<diff>
<replace sel='//treshold[@threshold="0.25"]/@value'>0.5</replace>
</diff>
wie man sieht müssen die Attribute zum wählen des Nodes und zum Addresieren, welches Attribut ersetzt werden soll nicht dieselben sein - und in den vielen fällen wird dies auch nötig sein, da die zu ändernden Werte von mehreren Nodes dieselben sind und andere Attribute der einzige Unterschied.
4. Auswahl nach Attributen allein:
Code: Select all
<diff>
<replace sel='//*[@threshold="0.25"]/@value'>0.5</replace>
</diff>
wie man hier sieht ist die angabe eines Node-namens unnötig (kann durch den platzhalter * ersetzt werden), ich würde diesen aber zwecks verständlichkeit trotzdem immer mit angeben.
***** wird später fortgesetzt / ergänzt - kann gerade nicht auswendig weiter machen *****
Zudem kann man nicht nur Werte verändern sondern diese auch hinzufügen oder löschen. Modifizieren wir einfach hierfür mal das Reparaturdock, was man auf Schiffen und Stationen findet (Triebwerke sind zwar schön kurz, aber entsprechend kann man da nicht viel mehr machen)
Die relevanten Daten für Objekte im Spiel sind immer in mehreren Dateien, davon 2 xmls: macro und component;
-> die component beschreibt dabei ein einzelnes Bauteil, also wo lichter sind, an welchen stellen man etwas anbauen kann, wie diie einzelnen Teile des Objektes selber liegen etc.
-> das macro ist ein Bauplan der beschreibt welches Bauteil wo am Objekt angebaut wurde - hierbei können auch andere macros/baupläne referenziert werden, ohne einzeln zu beschreiben was daran verbaut ist (so sind z.B. die Targon-Tracer/Waffenplatformen an alle Stationen montiert) oder auch einzelne components direkt verbaut werden ohne über ein (benanntes) macro zu gehen
so viel zur Einführung, dann fangen wir einmal damit an die Skunk vom Rep-dock/der Landeplatform zu entfernen und daraus ne Aussichtsplatform zu machen.
Öffnet dafür zur Referenz gleich mal die
assets\interiors\rooms\macros\interiors_rooms_dockingbay_repairdock_macro.xml
(aufgrund der Länge dieser Datei werde ich sie nicht vollständig hier rein kopieren sondern nur ddie relevanten Abschnitte)
Hier befinden sich 3 Teile, welche die Skunk auf der Platform darstellen:
-> die Skunk selber
-> die Ausgangstür (seperat, da animiert)
-> der Schalter für die Tür (dito)
hier die diesbezüglichen Ausschnitte aus dem macro:
Code: Select all
…
<connections>
<connection ref="ConnectionFor_interiors_rooms_ar_albionskunk">
<macro>
<component ref="interiors_rooms_ar_albionskunk" connection="space" />
</macro>
</connection>
……
<connection ref="ConnectionFor_interiors_rooms_swa_button_01">
<macro>
<component ref="interiors_rooms_swa_button_01" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_swa_skunk_exit">
<macro>
<component ref="interiors_rooms_swa_skunk_exit" connection="space" />
</macro>
</connection>
</connections>
……
Um diese zu entfernen legen wir nun eine Neue Datei in unserer Extension an und dort kommt folgendes rein:
Code: Select all
<diff>
<remove sel=’//connection[@ref="ConnectionFor_interiors_rooms_ar_albionskunk"]' />
<remove sel='//connnection[@ref="ConnectionFor_interiors_rooms_swa_button_01"]' />
<remove sel='//connection[macro/component/@ref="interiors_rooms_swa_skunk_exit"] />
</diff>
wie zu sehen ist kann man auch mehrere Patchaktionen in einem diff-file zusammen fasssen. ***** Braucht bestätigung ***** Ausserdem sticht sicher der extrem lange XPath beim letzten remove ins Auge - ich habe diesen extra ein wenig koplizierter als nötig gemacht um zu zeigen, wie man einen Node basierend auf den Werten der child-Nodes Addresieren kann - die [] werden hierfür an der stelle des Pfades geöffnet, den man Addresieren will und darin wird dann der weitere Pfad zum eindeutigen identifier beschrieben (alternativ kann man hier auch einen Pfad rein schreiben der einmalig ist) ***** /Braucht Bestätigung ****
Als nächstes werde ich den Add-Node erklären, indem wir einen Plüsch-Jeb auf den Holoprojektor setzen. Anschliessend machen wir zudem eine richtige Aussichtsplatform aus dem Landepad, indem die Hütte im Boden versenkt wird, sämtliche Kisten entfernt werden und vielleicht noch ein paar Blickfänge platzieren, wie nen Aquarium oder so. Ausserdem noch die NPC umpositionieren, sodass sie zur neuen Einrichtung passen - aber nicht mehr heute.
Personal note: Die Component des Landepads noch hierher kopieren...
--------------------------------------------------------------------------------
nur zur persönlichen Referenz:
\assets\props\SurfaceElements\Macros
Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<!--Exported by: Michael (192.168.3.144) at 14.05.2014_13-46-22-->
<macros>
<macro name="engine_player_bal_mk4_macro" class="engine">
<component ref="props_enginesystems_player_bal_mk1" />
<properties>
<identification name="{20108,301}" description="{20108,302}" />
<acceleration forward="90" reverse="135" strafe="180" pitch="250" yaw="250" roll="180" />
<angular />
<speed forward="270" reverse="-90" strafe="135" pitch="85" yaw="85" roll="90" />
<typeinfo mk="4" type="1" />
<hull min="250" max="1000" hittable="0" />
<efficiency>
<threshold threshold="1" value="1" />
<threshold threshold="0.5" value="0.9" />
<threshold threshold="0.25" value="0.8" />
</efficiency>
<sounds>
<ambient ref="eng_player_ambient" />
</sounds>
</properties>
<connections>
<connection ref="enginebooster">
<macro ref="enginebooster_player_01_macro" connection="engine" />
</connection>
</connections>
</macro>
</macros>
\assets\interiors\rooms\macros
Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<!--Exported by: Owen (192.168.3.121) at 02.06.2014_14-56-30-->
<macros>
<macro name="interiors_rooms_dockingbay_repairdock_macro" class="dockingbay">
<component ref="interiors_rooms_dockingbay_repairdock" />
<properties>
<identification unique="0" />
<dock detail="1" />
<sounds>
<ambient ref="amb_int_repairdock_01" />
</sounds>
<wall opaque="0" />
</properties>
<connections>
<connection ref="ConnectionFor_interiors_rooms_ar_albionskunk">
<macro>
<component ref="interiors_rooms_ar_albionskunk" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_baseplate_01">
<macro>
<component ref="interiors_rooms_ar_baseplate_01" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_boxes">
<macro>
<component ref="interiors_rooms_ar_boxes" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_boxes1">
<macro>
<component ref="interiors_rooms_ar_boxes" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_boxes2">
<macro>
<component ref="interiors_rooms_ar_boxes" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_boxes3">
<macro>
<component ref="interiors_rooms_ar_boxes" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_boxes4">
<macro>
<component ref="interiors_rooms_ar_boxes" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_boxes5">
<macro>
<component ref="interiors_rooms_ar_boxes" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_boxes6">
<macro>
<component ref="interiors_rooms_ar_boxes" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_boxes7">
<macro>
<component ref="interiors_rooms_ar_boxes" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_boxes8">
<macro>
<component ref="interiors_rooms_ar_boxes" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_boxes9">
<macro>
<component ref="interiors_rooms_ar_boxes" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_container_xl">
<macro>
<component ref="interiors_rooms_ar_container_xl" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_container_xl1">
<macro>
<component ref="interiors_rooms_ar_container_xl" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_container_xl2">
<macro>
<component ref="interiors_rooms_ar_container_xl" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_container_xl3">
<macro>
<component ref="interiors_rooms_ar_container_xl" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_container_xl4">
<macro>
<component ref="interiors_rooms_ar_container_xl" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_elephant">
<macro>
<component ref="interiors_rooms_ar_elephant" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_elephant1">
<macro>
<component ref="interiors_rooms_ar_elephant" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_light_gen">
<macro>
<component ref="interiors_rooms_ar_light_gen" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_light_gen1">
<macro>
<component ref="interiors_rooms_ar_light_gen" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_light_gen2">
<macro>
<component ref="interiors_rooms_ar_light_gen" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_smallbox">
<macro>
<component ref="interiors_rooms_ar_smallbox" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_smallbox1">
<macro>
<component ref="interiors_rooms_ar_smallbox" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_smallbox2">
<macro>
<component ref="interiors_rooms_ar_smallbox" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_smallbox3">
<macro>
<component ref="interiors_rooms_ar_smallbox" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_smallbox4">
<macro>
<component ref="interiors_rooms_ar_smallbox" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_smallbox5">
<macro>
<component ref="interiors_rooms_ar_smallbox" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_smallbox6">
<macro>
<component ref="interiors_rooms_ar_smallbox" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_ar_smallbox7">
<macro>
<component ref="interiors_rooms_ar_smallbox" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_holodisplay">
<macro>
<component ref="interiors_rooms_holodisplay" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_swa_button_01">
<macro>
<component ref="interiors_rooms_swa_button_01" connection="space" />
</macro>
</connection>
<connection ref="ConnectionFor_interiors_rooms_swa_skunk_exit">
<macro>
<component ref="interiors_rooms_swa_skunk_exit" connection="space" />
</macro>
</connection>
</connections>
</macro>
</macros>