mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2026-02-10 00:06:03 +00:00
Add mis parser
This commit is contained in:
parent
4f9a0066f0
commit
bfae8b91d8
5 changed files with 384 additions and 9 deletions
|
|
@ -1,5 +1,7 @@
|
|||
package;
|
||||
|
||||
import mis.MisParser;
|
||||
import sys.io.File;
|
||||
import shapes.EndPad;
|
||||
import shapes.LandMine;
|
||||
import shapes.StartPad;
|
||||
|
|
@ -57,6 +59,10 @@ class Main extends hxd.App {
|
|||
tform.setPosition(new Vector(0, 0, 0));
|
||||
db.setTransform(tform);
|
||||
|
||||
var ltr = File.getContent("data/missions/beginner/finale.mis");
|
||||
var mfp = new MisParser(ltr);
|
||||
var mis = mfp.parse();
|
||||
|
||||
// var pi = new PathedInterior();
|
||||
// DifBuilder.loadDif("data/interiors/addon/smallplatform.dif", loader, pi);
|
||||
// var pim = pi.getTransform();
|
||||
|
|
|
|||
17
src/Util.hx
17
src/Util.hx
|
|
@ -139,4 +139,21 @@ class Util {
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static function indexIsInStringLiteral(str:String, index:Int, strLiteralToken = '"') {
|
||||
var inString = false;
|
||||
for (i in 0...str.length) {
|
||||
var c = str.charAt(i);
|
||||
if (inString) {
|
||||
if (i == index)
|
||||
return true;
|
||||
if (c == strLiteralToken && str.charAt(i - 1) != '\\')
|
||||
inString = false;
|
||||
continue;
|
||||
}
|
||||
if (c == strLiteralToken)
|
||||
inString = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,15 @@
|
|||
package mis;
|
||||
|
||||
class MisFile {}
|
||||
import mis.MissionElement.MissionElementSimGroup;
|
||||
|
||||
@:publicFields
|
||||
class MisFile {
|
||||
var root:MissionElementSimGroup;
|
||||
|
||||
/** The custom marble attributes overrides specified in the file. */
|
||||
var marbleAttributes:Map<String, String>;
|
||||
|
||||
var activatedPackages:Array<String>;
|
||||
|
||||
public function new() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,22 @@
|
|||
package mis;
|
||||
|
||||
import haxe.Exception;
|
||||
import mis.MissionElement.MissionElementPathedInterior;
|
||||
import mis.MissionElement.MissionElementPath;
|
||||
import mis.MissionElement.MissionElementSimGroup;
|
||||
import mis.MissionElement.MissionElementBase;
|
||||
import mis.MissionElement.MissionElementParticleEmitterNode;
|
||||
import mis.MissionElement.MissionElementTSStatic;
|
||||
import mis.MissionElement.MissionElementMessageVector;
|
||||
import mis.MissionElement.MissionElementAudioProfile;
|
||||
import mis.MissionElement.MissionElementTrigger;
|
||||
import mis.MissionElement.MissionElementMarker;
|
||||
import mis.MissionElement.MissionElementItem;
|
||||
import mis.MissionElement.MissionElementStaticShape;
|
||||
import mis.MissionElement.MissionElementInteriorInstance;
|
||||
import mis.MissionElement.MissionElementSun;
|
||||
import mis.MissionElement.MissionElementSky;
|
||||
import mis.MissionElement.MissionElementMissionArea;
|
||||
import mis.MissionElement.MissionElementType;
|
||||
import mis.MissionElement.MissionElementScriptObject;
|
||||
import src.Util;
|
||||
|
|
@ -23,7 +40,174 @@ class MisParser {
|
|||
this.text = text;
|
||||
}
|
||||
|
||||
public function parse() {}
|
||||
public function parse() {
|
||||
var objectWriteBeginIndex = this.text.indexOf("//--- OBJECT WRITE BEGIN ---");
|
||||
var objectWriteEndIndex = this.text.lastIndexOf("//--- OBJECT WRITE END ---");
|
||||
|
||||
var outsideText = this.text.substring(0, objectWriteBeginIndex) + this.text.substring(objectWriteEndIndex);
|
||||
|
||||
// Find all specified variables
|
||||
this.variables = ["$usermods" => '""']; // Just make $usermods point to nothing
|
||||
|
||||
var startText = outsideText;
|
||||
|
||||
while (assignmentRegEx.match(startText)) {
|
||||
if (!this.variables.exists(assignmentRegEx.matched(1)))
|
||||
this.variables.set(assignmentRegEx.matched(1), assignmentRegEx.matched(2));
|
||||
startText = assignmentRegEx.matchedRight();
|
||||
}
|
||||
|
||||
var marbleAttributes = new Map();
|
||||
|
||||
startText = outsideText;
|
||||
|
||||
while (marbleAttributesRegEx.match(startText)) {
|
||||
marbleAttributes.set(marbleAttributesRegEx.matched(1), this.resolveExpression(marbleAttributesRegEx.matched(2)));
|
||||
startText = marbleAttributesRegEx.matchedRight();
|
||||
}
|
||||
|
||||
var activatedPackages = [];
|
||||
startText = outsideText;
|
||||
|
||||
while (activatePackageRegEx.match(startText)) {
|
||||
activatedPackages.push(this.resolveExpression(activatePackageRegEx.matched(1)));
|
||||
startText = marbleAttributesRegEx.matchedRight();
|
||||
}
|
||||
|
||||
if (objectWriteBeginIndex != -1 && objectWriteEndIndex != -1) {
|
||||
this.text = this.text.substring(objectWriteBeginIndex, objectWriteEndIndex);
|
||||
}
|
||||
|
||||
var currentIndex = 0;
|
||||
while (true) {
|
||||
// blockCommentRegEx.lastIndex = currentIndex;
|
||||
// lineCommentRegEx.lastIndex = currentIndex;
|
||||
|
||||
var blockMatch = blockCommentRegEx.matchSub(this.text, currentIndex);
|
||||
var lineMatch = lineCommentRegEx.matchSub(this.text, currentIndex);
|
||||
|
||||
// The detected "comment" might be inside a string literal, in which case we ignore it 'cause it ain't no comment.
|
||||
if (blockMatch && Util.indexIsInStringLiteral(this.text, blockCommentRegEx.matchedPos().pos))
|
||||
blockMatch = false;
|
||||
if (lineMatch && Util.indexIsInStringLiteral(this.text, lineCommentRegEx.matchedPos().pos))
|
||||
lineMatch = false;
|
||||
|
||||
if (!blockMatch && !lineMatch)
|
||||
break;
|
||||
else if (!lineMatch || (blockMatch && lineMatch && blockCommentRegEx.matchedPos().pos < lineCommentRegEx.matchedPos().pos)) {
|
||||
this.text = this.text.substring(0, blockCommentRegEx.matchedPos().pos)
|
||||
+ this.text.substring(blockCommentRegEx.matchedPos().pos + blockCommentRegEx.matchedPos().len);
|
||||
currentIndex += blockCommentRegEx.matchedPos().pos;
|
||||
} else {
|
||||
this.text = this.text.substring(0, lineCommentRegEx.matchedPos().pos)
|
||||
+ this.text.substring(lineCommentRegEx.matchedPos().pos + lineCommentRegEx.matchedPos().len);
|
||||
currentIndex += lineCommentRegEx.matchedPos().pos;
|
||||
}
|
||||
}
|
||||
|
||||
var elements = [];
|
||||
while (this.hasNextElement()) {
|
||||
var element = this.readElement();
|
||||
if (element == null)
|
||||
continue;
|
||||
elements.push(element);
|
||||
}
|
||||
|
||||
if (elements.length != 1) {
|
||||
// We expect there to be only one outer element; the MissionGroup SimGroup.
|
||||
trace(elements);
|
||||
throw new Exception("Mission file doesn't have exactly 1 outer element!");
|
||||
}
|
||||
|
||||
var mf = new MisFile();
|
||||
mf.root = cast elements[0];
|
||||
mf.marbleAttributes = marbleAttributes;
|
||||
mf.activatedPackages = activatedPackages;
|
||||
return mf;
|
||||
}
|
||||
|
||||
function readElement() {
|
||||
// Get information about the head
|
||||
// elementHeadRegEx.lastIndex = this.index;
|
||||
var head = elementHeadRegEx.match(this.text.substring(this.index));
|
||||
this.index += elementHeadRegEx.matchedPos().pos + elementHeadRegEx.matchedPos().len;
|
||||
var type = elementHeadRegEx.matched(1);
|
||||
var name = elementHeadRegEx.matched(2);
|
||||
var element:MissionElementBase = null;
|
||||
switch (type) {
|
||||
case "SimGroup":
|
||||
element = this.readSimGroup(name);
|
||||
case "ScriptObject":
|
||||
element = this.readScriptObject(name);
|
||||
case "MissionArea":
|
||||
element = this.readMissionArea(name);
|
||||
case "Sky":
|
||||
element = this.readSky(name);
|
||||
case "Sun":
|
||||
element = this.readSun(name);
|
||||
case "InteriorInstance":
|
||||
element = this.readInteriorInstance(name);
|
||||
case "StaticShape":
|
||||
element = this.readStaticShape(name);
|
||||
case "Item":
|
||||
element = this.readItem(name);
|
||||
case "Path":
|
||||
element = this.readPath(name);
|
||||
case "Marker":
|
||||
element = this.readMarker(name);
|
||||
case "PathedInterior":
|
||||
element = this.readPathedInterior(name);
|
||||
case "Trigger":
|
||||
element = this.readTrigger(name);
|
||||
case "AudioProfile":
|
||||
element = this.readAudioProfile(name);
|
||||
case "MessageVector":
|
||||
element = this.readMessageVector(name);
|
||||
case "TSStatic":
|
||||
element = this.readTSStatic(name);
|
||||
case "ParticleEmitterNode":
|
||||
element = this.readParticleEmitterNode(name);
|
||||
default:
|
||||
trace("Unknown element type! " + type);
|
||||
// Still advance the index
|
||||
var endingBraceIndex = Util.indexOfIgnoreStringLiterals(this.text, '};', this.index);
|
||||
if (endingBraceIndex == -1)
|
||||
endingBraceIndex = this.text.length;
|
||||
this.index = endingBraceIndex + 2;
|
||||
}
|
||||
if (element != null)
|
||||
element._id = this.currentElementId++;
|
||||
return element;
|
||||
}
|
||||
|
||||
function hasNextElement() {
|
||||
if (!elementHeadRegEx.match(this.text.substring(this.index)))
|
||||
return false;
|
||||
if (Util.indexOfIgnoreStringLiterals(this.text.substring(this.index, this.index + elementHeadRegEx.matchedPos().pos), '}') != -1)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function readSimGroup(name:String) {
|
||||
var elements = [];
|
||||
// Read in all elements
|
||||
while (this.hasNextElement()) {
|
||||
var element = this.readElement();
|
||||
if (element == null)
|
||||
continue;
|
||||
elements.push(element);
|
||||
}
|
||||
var endingBraceIndex = Util.indexOfIgnoreStringLiterals(this.text, '};', this.index);
|
||||
if (endingBraceIndex == -1)
|
||||
endingBraceIndex = this.text.length;
|
||||
this.index = endingBraceIndex + 2;
|
||||
|
||||
var sg = new MissionElementSimGroup();
|
||||
sg._name = name;
|
||||
sg._type = MissionElementType.SimGroup;
|
||||
sg.elements = elements;
|
||||
return sg;
|
||||
}
|
||||
|
||||
function readValues() {
|
||||
// Values are either strings or string arrays.
|
||||
|
|
@ -65,21 +249,175 @@ class MisParser {
|
|||
return obj;
|
||||
}
|
||||
|
||||
function readScriptObject(name:String) {
|
||||
var obj = new MissionElementScriptObject();
|
||||
obj._type = MissionElementType.ScriptObject;
|
||||
obj._name = name;
|
||||
function copyFields(obj:Dynamic) {
|
||||
var values = this.readValues();
|
||||
var objfields = Type.getInstanceFields(Type.getClass(obj));
|
||||
|
||||
for (key => value in values) {
|
||||
if (value.length > 1) {
|
||||
for (i in 0...value.length) {
|
||||
Reflect.setField(obj, '${key}${i}', value[i]);
|
||||
var fname = '${key}${i}';
|
||||
if (objfields.contains(fname))
|
||||
Reflect.setField(obj, fname, value[i]);
|
||||
}
|
||||
} else {
|
||||
Reflect.setField(obj, key, value[0]);
|
||||
if (key == "static")
|
||||
key = "isStatic";
|
||||
if (objfields.contains(key))
|
||||
Reflect.setField(obj, key, value[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function readScriptObject(name:String) {
|
||||
var obj = new MissionElementScriptObject();
|
||||
obj._type = MissionElementType.ScriptObject;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readMissionArea(name:String) {
|
||||
var obj = new MissionElementMissionArea();
|
||||
obj._type = MissionElementType.MissionArea;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readSky(name:String) {
|
||||
var obj = new MissionElementSky();
|
||||
obj._type = MissionElementType.Sky;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readSun(name:String) {
|
||||
var obj = new MissionElementSun();
|
||||
obj._type = MissionElementType.Sun;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readInteriorInstance(name:String) {
|
||||
var obj = new MissionElementInteriorInstance();
|
||||
obj._type = MissionElementType.InteriorInstance;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readStaticShape(name:String) {
|
||||
var obj = new MissionElementStaticShape();
|
||||
obj._type = MissionElementType.StaticShape;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readItem(name:String) {
|
||||
var obj = new MissionElementItem();
|
||||
obj._type = MissionElementType.Item;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readPath(name:String) {
|
||||
var sg:MissionElementSimGroup = cast this.readSimGroup(name);
|
||||
var obj = new MissionElementPath();
|
||||
obj._type = MissionElementType.Path;
|
||||
obj._name = name;
|
||||
obj.markers = sg.elements.map(x -> cast x);
|
||||
obj.markers.sort((a, b) -> cast MisParser.parseNumber(a.seqnum) - MisParser.parseNumber(b.seqnum));
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readMarker(name:String) {
|
||||
var obj = new MissionElementMarker();
|
||||
obj._type = MissionElementType.Marker;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readPathedInterior(name:String) {
|
||||
var obj = new MissionElementPathedInterior();
|
||||
obj._type = MissionElementType.PathedInterior;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readTrigger(name:String) {
|
||||
var obj = new MissionElementTrigger();
|
||||
obj._type = MissionElementType.Trigger;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readAudioProfile(name:String) {
|
||||
var obj = new MissionElementAudioProfile();
|
||||
obj._type = MissionElementType.AudioProfile;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readMessageVector(name:String) {
|
||||
var obj = new MissionElementMessageVector();
|
||||
obj._type = MissionElementType.MessageVector;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readTSStatic(name:String) {
|
||||
var obj = new MissionElementTSStatic();
|
||||
obj._type = MissionElementType.TSStatic;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function readParticleEmitterNode(name:String) {
|
||||
var obj = new MissionElementParticleEmitterNode();
|
||||
obj._type = MissionElementType.ParticleEmitterNode;
|
||||
obj._name = name;
|
||||
|
||||
copyFields(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,9 @@ class MissionElementSky extends MissionElementBase {
|
|||
var position:String;
|
||||
var rotation:String;
|
||||
var scale:String;
|
||||
var cloudheightper:Array<String>;
|
||||
var cloudheightper0:String;
|
||||
var cloudheightper1:String;
|
||||
var cloudheightper2:String;
|
||||
var cloudspeed1:String;
|
||||
var cloudspeed2:String;
|
||||
var cloudspeed3:String;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue