mirror of
https://github.com/Ratstail91/Mementos.git
synced 2025-11-29 10:34:27 +11:00
Committed everything
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ink.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all ink runtime content.
|
||||
/// </summary>
|
||||
public /* TODO: abstract */ class Object
|
||||
{
|
||||
/// <summary>
|
||||
/// Runtime.Objects can be included in the main Story as a hierarchy.
|
||||
/// Usually parents are Container objects. (TODO: Always?)
|
||||
/// </summary>
|
||||
/// <value>The parent.</value>
|
||||
public Runtime.Object parent { get; set; }
|
||||
|
||||
public Runtime.DebugMetadata debugMetadata {
|
||||
get {
|
||||
if (_debugMetadata == null) {
|
||||
if (parent) {
|
||||
return parent.debugMetadata;
|
||||
}
|
||||
}
|
||||
|
||||
return _debugMetadata;
|
||||
}
|
||||
|
||||
set {
|
||||
_debugMetadata = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Runtime.DebugMetadata ownDebugMetadata {
|
||||
get {
|
||||
return _debugMetadata;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Come up with some clever solution for not having
|
||||
// to have debug metadata on the object itself, perhaps
|
||||
// for serialisation purposes at least.
|
||||
DebugMetadata _debugMetadata;
|
||||
|
||||
public int? DebugLineNumberOfPath(Path path)
|
||||
{
|
||||
if (path == null)
|
||||
return null;
|
||||
|
||||
// Try to get a line number from debug metadata
|
||||
var root = this.rootContentContainer;
|
||||
if (root) {
|
||||
Runtime.Object targetContent = root.ContentAtPath (path).obj;
|
||||
if (targetContent) {
|
||||
var dm = targetContent.debugMetadata;
|
||||
if (dm != null) {
|
||||
return dm.startLineNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Path path
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_path == null) {
|
||||
|
||||
if (parent == null) {
|
||||
_path = new Path ();
|
||||
} else {
|
||||
// Maintain a Stack so that the order of the components
|
||||
// is reversed when they're added to the Path.
|
||||
// We're iterating up the hierarchy from the leaves/children to the root.
|
||||
var comps = new Stack<Path.Component> ();
|
||||
|
||||
var child = this;
|
||||
Container container = child.parent as Container;
|
||||
|
||||
while (container) {
|
||||
|
||||
var namedChild = child as INamedContent;
|
||||
if (namedChild != null && namedChild.hasValidName) {
|
||||
comps.Push (new Path.Component (namedChild.name));
|
||||
} else {
|
||||
comps.Push (new Path.Component (container.content.IndexOf(child)));
|
||||
}
|
||||
|
||||
child = container;
|
||||
container = container.parent as Container;
|
||||
}
|
||||
|
||||
_path = new Path (comps);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return _path;
|
||||
}
|
||||
}
|
||||
Path _path;
|
||||
|
||||
public SearchResult ResolvePath(Path path)
|
||||
{
|
||||
if (path.isRelative) {
|
||||
|
||||
Container nearestContainer = this as Container;
|
||||
if (!nearestContainer) {
|
||||
Debug.Assert (this.parent != null, "Can't resolve relative path because we don't have a parent");
|
||||
nearestContainer = this.parent as Container;
|
||||
Debug.Assert (nearestContainer != null, "Expected parent to be a container");
|
||||
Debug.Assert (path.GetComponent(0).isParent);
|
||||
path = path.tail;
|
||||
}
|
||||
|
||||
return nearestContainer.ContentAtPath (path);
|
||||
} else {
|
||||
return this.rootContentContainer.ContentAtPath (path);
|
||||
}
|
||||
}
|
||||
|
||||
public Path ConvertPathToRelative(Path globalPath)
|
||||
{
|
||||
// 1. Find last shared ancestor
|
||||
// 2. Drill up using ".." style (actually represented as "^")
|
||||
// 3. Re-build downward chain from common ancestor
|
||||
|
||||
var ownPath = this.path;
|
||||
|
||||
int minPathLength = Math.Min (globalPath.length, ownPath.length);
|
||||
int lastSharedPathCompIndex = -1;
|
||||
|
||||
for (int i = 0; i < minPathLength; ++i) {
|
||||
var ownComp = ownPath.GetComponent(i);
|
||||
var otherComp = globalPath.GetComponent(i);
|
||||
|
||||
if (ownComp.Equals (otherComp)) {
|
||||
lastSharedPathCompIndex = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No shared path components, so just use global path
|
||||
if (lastSharedPathCompIndex == -1)
|
||||
return globalPath;
|
||||
|
||||
int numUpwardsMoves = (ownPath.length-1) - lastSharedPathCompIndex;
|
||||
|
||||
var newPathComps = new List<Path.Component> ();
|
||||
|
||||
for(int up=0; up<numUpwardsMoves; ++up)
|
||||
newPathComps.Add (Path.Component.ToParent ());
|
||||
|
||||
for (int down = lastSharedPathCompIndex + 1; down < globalPath.length; ++down)
|
||||
newPathComps.Add (globalPath.GetComponent(down));
|
||||
|
||||
var relativePath = new Path (newPathComps, relative:true);
|
||||
return relativePath;
|
||||
}
|
||||
|
||||
// Find most compact representation for a path, whether relative or global
|
||||
public string CompactPathString(Path otherPath)
|
||||
{
|
||||
string globalPathStr = null;
|
||||
string relativePathStr = null;
|
||||
if (otherPath.isRelative) {
|
||||
relativePathStr = otherPath.componentsString;
|
||||
globalPathStr = this.path.PathByAppendingPath(otherPath).componentsString;
|
||||
} else {
|
||||
var relativePath = ConvertPathToRelative (otherPath);
|
||||
relativePathStr = relativePath.componentsString;
|
||||
globalPathStr = otherPath.componentsString;
|
||||
}
|
||||
|
||||
if (relativePathStr.Length < globalPathStr.Length)
|
||||
return relativePathStr;
|
||||
else
|
||||
return globalPathStr;
|
||||
}
|
||||
|
||||
public Container rootContentContainer
|
||||
{
|
||||
get
|
||||
{
|
||||
Runtime.Object ancestor = this;
|
||||
while (ancestor.parent) {
|
||||
ancestor = ancestor.parent;
|
||||
}
|
||||
return ancestor as Container;
|
||||
}
|
||||
}
|
||||
|
||||
public Object ()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual Object Copy()
|
||||
{
|
||||
throw new System.NotImplementedException (GetType ().Name + " doesn't support copying");
|
||||
}
|
||||
|
||||
public void SetChild<T>(ref T obj, T value) where T : Runtime.Object
|
||||
{
|
||||
if (obj)
|
||||
obj.parent = null;
|
||||
|
||||
obj = value;
|
||||
|
||||
if( obj )
|
||||
obj.parent = this;
|
||||
}
|
||||
|
||||
/// Allow implicit conversion to bool so you don't have to do:
|
||||
/// if( myObj != null ) ...
|
||||
public static implicit operator bool (Object obj)
|
||||
{
|
||||
var isNull = object.ReferenceEquals (obj, null);
|
||||
return !isNull;
|
||||
}
|
||||
|
||||
/// Required for implicit bool comparison
|
||||
public static bool operator ==(Object a, Object b)
|
||||
{
|
||||
return object.ReferenceEquals (a, b);
|
||||
}
|
||||
|
||||
/// Required for implicit bool comparison
|
||||
public static bool operator !=(Object a, Object b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/// Required for implicit bool comparison
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
return object.ReferenceEquals (obj, this);
|
||||
}
|
||||
|
||||
/// Required for implicit bool comparison
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return base.GetHashCode ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user