/// <summary>Creates a mirrored copy of the prototype object (Animated objects)</summary>
 /// <param name="Prototype">The prototype</param>
 /// <returns>The mirrored copy</returns>
 private static UnifiedObject GetMirroredObject(UnifiedObject Prototype)
 {
     if (Prototype is ObjectManager.StaticObject)
     {
         ObjectManager.StaticObject s = (ObjectManager.StaticObject)Prototype;
         return(GetMirroredStaticObject(s));
     }
     if (Prototype is ObjectManager.AnimatedObjectCollection)
     {
         ObjectManager.AnimatedObjectCollection a      = (ObjectManager.AnimatedObjectCollection)Prototype;
         ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection
         {
             Objects = new ObjectManager.AnimatedObject[a.Objects.Length]
         };
         for (int i = 0; i < a.Objects.Length; i++)
         {
             Result.Objects[i] = a.Objects[i].Clone();
             for (int j = 0; j < a.Objects[i].States.Length; j++)
             {
                 Result.Objects[i].States[j].Object = GetMirroredStaticObject(a.Objects[i].States[j].Object);
             }
             Result.Objects[i].TranslateXDirection.X *= -1.0;
             Result.Objects[i].TranslateYDirection.X *= -1.0;
             Result.Objects[i].TranslateZDirection.X *= -1.0;
             Result.Objects[i].RotateXDirection.X    *= -1.0;
             Result.Objects[i].RotateYDirection.X    *= -1.0;
             Result.Objects[i].RotateZDirection.X    *= -1.0;
         }
         return(Result);
     }
     return(null);
 }
예제 #2
0
파일: Pole.cs 프로젝트: perhenrik90/OpenBVE
        internal void Create(PoleDictionary Poles, Vector3 WorldPosition, Transformation RailTransformation, Vector2 Direction, double planar, double updown, double StartingDistance, double EndingDistance)
        {
            double dz = StartingDistance / Interval;

            dz -= Math.Floor(dz + 0.5);
            if (dz >= -0.01 & dz <= 0.01)
            {
                if (Mode == 0)
                {
                    if (Location <= 0.0)
                    {
                        Poles[0][Type].CreateObject(WorldPosition, RailTransformation, Transformation.NullTransformation, StartingDistance, EndingDistance, StartingDistance);
                    }
                    else
                    {
                        UnifiedObject Pole = Poles[0][Type].Mirror();
                        Pole.CreateObject(WorldPosition, RailTransformation, Transformation.NullTransformation, StartingDistance, EndingDistance, StartingDistance);
                    }
                }
                else
                {
                    int     m  = Mode;
                    double  dx = -Location * 3.8;
                    double  wa = Math.Atan2(Direction.Y, Direction.X) - planar;
                    Vector3 w  = new Vector3(Math.Cos(wa), Math.Tan(updown), Math.Sin(wa));
                    w.Normalize();
                    double  sx   = Direction.Y;
                    double  sy   = 0.0;
                    double  sz   = -Direction.X;
                    Vector3 wpos = WorldPosition + new Vector3(sx * dx + w.X * dz, sy * dx + w.Y * dz, sz * dx + w.Z * dz);
                    int     type = Type;
                    Poles[m][type].CreateObject(wpos, RailTransformation, Transformation.NullTransformation, StartingDistance, EndingDistance, StartingDistance);
                }
            }
        }
예제 #3
0
    public static UnifiedObject InstantiateObject(Node parent, UnifiedObject templateObject, Vector3 position, Transform baseTransformation, Transform auxTransformation, bool accurateObjectDisposal, double startingDistance, double endingDistance, double blockLength, double trackPosition)
    {
        StaticObject instantiatedObject = (StaticObject)templateObject.Clone();

        MeshInstance instantiatedMesh = instantiatedObject.ObjectMeshInstance;

        Transform finalTrans = baseTransformation * auxTransformation;

        instantiatedMesh.GlobalTransform = new Transform(finalTrans.basis, Vector3.Zero);

        parent.AddChild(instantiatedMesh);

        instantiatedMesh.GlobalTranslate(position);

        return(instantiatedObject);

        // UnifiedObject retObject = null;
        // if (templateObject is StaticObject)
        // {
        //     retObject = new StaticObject();
        //     retObject.gameObject = instantiatedMesh;
        // }
        // else if (templateObject is AnimatedObjectCollection)
        // {
        // }

        // return retObject;
    }
예제 #4
0
파일: Host.cs 프로젝트: perhenrik90/OpenBVE
        public override bool LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject Object)
        {
            if (base.LoadObject(path, Encoding, out Object))
            {
                return(true);
            }

            if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path))
            {
                Encoding = TextEncoding.GetSystemEncodingFromFile(path, Encoding);

                for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++)
                {
                    if (Program.CurrentHost.Plugins[i].Object != null)
                    {
                        try {
                            if (Program.CurrentHost.Plugins[i].Object.CanLoadObject(path))
                            {
                                try
                                {
                                    UnifiedObject obj;
                                    if (Program.CurrentHost.Plugins[i].Object.LoadObject(path, Encoding, out obj))
                                    {
                                        obj.OptimizeObject(false, Interface.CurrentOptions.ObjectOptimizationBasicThreshold, Interface.CurrentOptions.ObjectOptimizationVertexCulling);
                                        Object = obj;

                                        StaticObject staticObject = Object as StaticObject;
                                        if (staticObject != null)
                                        {
                                            StaticObjectCache.Add(ValueTuple.Create(path, false), staticObject);
                                            return(true);
                                        }

                                        AnimatedObjectCollection aoc = Object as AnimatedObjectCollection;
                                        if (aoc != null)
                                        {
                                            AnimatedObjectCollectionCache.Add(path, aoc);
                                        }

                                        return(true);
                                    }
                                    Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadObject");
                                } catch (Exception ex) {
                                    Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadObject:" + ex.Message);
                                }
                            }
                        } catch (Exception ex) {
                            Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadObject:" + ex.Message);
                        }
                    }
                }
                Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading object " + path);
            }
            else
            {
                ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path);
            }
            Object = null;
            return(false);
        }
예제 #5
0
        public void LoadCarSections(UnifiedObject currentObject, bool visibleFromInterior)
        {
            int j = CarSections.Length;

            Array.Resize(ref CarSections, j + 1);
            CarSections[j] = new CarSection(TrainManagerBase.currentHost, ObjectType.Dynamic, visibleFromInterior, currentObject);
        }
예제 #6
0
파일: Car.Bogie.cs 프로젝트: hyusan/OpenBVE
            internal void LoadCarSections(UnifiedObject currentObject)
            {
                int j = CarSections.Length;

                Array.Resize(ref CarSections, j + 1);
                CarSections[j] = new CarSection();
                if (currentObject is ObjectManager.StaticObject)
                {
                    ObjectManager.StaticObject s = (ObjectManager.StaticObject)currentObject;
                    CarSections[j].Elements    = new ObjectManager.AnimatedObject[1];
                    CarSections[j].Elements[0] = new ObjectManager.AnimatedObject
                    {
                        States = new ObjectManager.AnimatedObjectState[1]
                    };
                    CarSections[j].Elements[0].States[0].Position = Vector3.Zero;
                    CarSections[j].Elements[0].States[0].Object   = s;
                    CarSections[j].Elements[0].CurrentState       = 0;
                    CarSections[j].Elements[0].ObjectIndex        = ObjectManager.CreateDynamicObject();
                }
                else if (currentObject is ObjectManager.AnimatedObjectCollection)
                {
                    ObjectManager.AnimatedObjectCollection a = (ObjectManager.AnimatedObjectCollection)currentObject;
                    CarSections[j].Elements = new ObjectManager.AnimatedObject[a.Objects.Length];
                    for (int h = 0; h < a.Objects.Length; h++)
                    {
                        CarSections[j].Elements[h]             = a.Objects[h].Clone();
                        CarSections[j].Elements[h].ObjectIndex = ObjectManager.CreateDynamicObject();
                    }
                }
            }
예제 #7
0
파일: Plugin.cs 프로젝트: s520/OpenBVE
 public override bool LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject unifiedObject)
 {
     if (currentObjParser == ObjParsers.Assimp)
     {
         try
         {
             unifiedObject = AssimpObjParser.ReadObject(path);
             return(true);
         }
         catch (Exception ex)
         {
             currentHost.AddMessage(MessageType.Error, false, "The new Obj parser raised the following exception: " + ex);
         }
     }
     try
     {
         unifiedObject = WavefrontObjParser.ReadObject(path, Encoding);
         return(true);
     }
     catch
     {
         unifiedObject = null;
         currentHost.AddMessage(MessageType.Error, false, "An unexpected error occured whilst attempting to load the following object: " + path);
     }
     return(false);
 }
예제 #8
0
 public override bool LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject unifiedObject)
 {
     try
     {
         if (currentXParser != XParsers.Original)
         {
             try
             {
                 if (currentXParser == XParsers.NewXParser)
                 {
                     unifiedObject = NewXParser.ReadObject(path, Encoding);
                     return(true);
                 }
                 unifiedObject = AssimpXParser.ReadObject(path);
                 return(true);
             }
             catch (Exception ex)
             {
                 currentHost.AddMessage(MessageType.Error, false, "The new X parser raised the following exception: " + ex);
                 unifiedObject = XObjectParser.ReadObject(path, Encoding);
                 return(true);
             }
         }
         unifiedObject = XObjectParser.ReadObject(path, Encoding);
         return(true);
     }
     catch
     {
         unifiedObject = null;
         currentHost.AddMessage(MessageType.Error, false, "An unexpected error occured whilst attempting to load the following object: " + path);
     }
     return(false);
 }
예제 #9
0
 internal void CreateObject(UnifiedObject Prototype, OpenBveApi.Math.Vector3 Position, Transformation BaseTransformation, Transformation AuxTransformation, bool AccurateObjectDisposal, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition)
 {
     if (Prototype != null)
     {
         CreateObject(Prototype, Position, BaseTransformation, AuxTransformation, -1, AccurateObjectDisposal, StartingDistance, EndingDistance, BlockLength, TrackPosition, 1.0, false);
     }
 }
예제 #10
0
            internal void LoadCarSections(UnifiedObject currentObject, bool visibleFromInterior)
            {
                int j = CarSections.Length;

                Array.Resize(ref CarSections, j + 1);
                CarSections[j] = new CarSection(Program.CurrentHost, ObjectType.Dynamic);
                CarSections[j].VisibleFromInterior = visibleFromInterior;
                if (currentObject is StaticObject)
                {
                    StaticObject s = (StaticObject)currentObject;
                    CarSections[j].Groups[0].Elements    = new AnimatedObject[1];
                    CarSections[j].Groups[0].Elements[0] = new AnimatedObject(Program.CurrentHost)
                    {
                        States       = new[] { new ObjectState(s) },
                        CurrentState = 0
                    };
                    Program.CurrentHost.CreateDynamicObject(ref CarSections[j].Groups[0].Elements[0].internalObject);
                }
                else if (currentObject is AnimatedObjectCollection)
                {
                    AnimatedObjectCollection a = (AnimatedObjectCollection)currentObject;
                    CarSections[j].Groups[0].Elements = new AnimatedObject[a.Objects.Length];
                    for (int h = 0; h < a.Objects.Length; h++)
                    {
                        CarSections[j].Groups[0].Elements[h] = a.Objects[h].Clone();
                        Program.CurrentHost.CreateDynamicObject(ref CarSections[j].Groups[0].Elements[h].internalObject);
                    }
                }
            }
예제 #11
0
 public override bool LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject Object)
 {
     if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path))
     {
         for (int i = 0; i < Plugins.LoadedPlugins.Length; i++)
         {
             if (Plugins.LoadedPlugins[i].Object != null)
             {
                 try {
                     if (Plugins.LoadedPlugins[i].Object.CanLoadObject(path))
                     {
                         try {
                             if (Plugins.LoadedPlugins[i].Object.LoadObject(path, Encoding, out Object))
                             {
                                 return(true);
                             }
                             Interface.AddMessage(MessageType.Error, false, "Plugin " + Plugins.LoadedPlugins[i].Title + " returned unsuccessfully at LoadObject");
                         } catch (Exception ex) {
                             Interface.AddMessage(MessageType.Error, false, "Plugin " + Plugins.LoadedPlugins[i].Title + " raised the following exception at LoadObject:" + ex.Message);
                         }
                     }
                 } catch (Exception ex) {
                     Interface.AddMessage(MessageType.Error, false, "Plugin " + Plugins.LoadedPlugins[i].Title + " raised the following exception at CanLoadObject:" + ex.Message);
                 }
             }
         }
         Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading object " + path);
     }
     else
     {
         ReportProblem(ProblemType.PathNotFound, path);
     }
     Object = null;
     return(false);
 }
예제 #12
0
            internal void LoadCarSections(UnifiedObject currentObject)
            {
                int j = CarSections.Length;

                Array.Resize(ref CarSections, j + 1);
                CarSections[j] = new CarSection
                {
                    Groups = new ElementsGroup[1]
                };
                CarSections[j].Groups[0] = new ElementsGroup();
                if (currentObject is StaticObject)
                {
                    StaticObject s = (StaticObject)currentObject;
                    CarSections[j].Groups[0].Elements    = new AnimatedObject[1];
                    CarSections[j].Groups[0].Elements[0] = new AnimatedObject(Program.CurrentHost)
                    {
                        States = new[] { new ObjectState() }
                    };
                    CarSections[j].Groups[0].Elements[0].States[0].Prototype = s;
                    CarSections[j].Groups[0].Elements[0].CurrentState        = 0;
                    Program.CurrentHost.CreateDynamicObject(ref CarSections[j].Groups[0].Elements[0].internalObject);
                }
                else if (currentObject is AnimatedObjectCollection)
                {
                    AnimatedObjectCollection a = (AnimatedObjectCollection)currentObject;
                    CarSections[j].Groups[0].Elements = new AnimatedObject[a.Objects.Length];
                    for (int h = 0; h < a.Objects.Length; h++)
                    {
                        CarSections[j].Groups[0].Elements[h] = a.Objects[h].Clone();
                        Program.CurrentHost.CreateDynamicObject(ref CarSections[j].Groups[0].Elements[h].internalObject);
                    }
                }
            }
예제 #13
0
        internal static void DragFile(object sender, FileDropEventArgs e)
        {
            int n = Files.Length;

            Array.Resize <string>(ref Files, n + 1);
            Files[n] = e.FileName;
            // reset
            ReducedMode      = false;
            LightingRelative = -1.0;
            Game.Reset();
            Textures.UnloadAllTextures();
            //Fonts.Initialize();
            Interface.ClearMessages();
            for (int i = 0; i < Files.Length; i++)
            {
#if !DEBUG
                try
                {
#endif
                if (String.Compare(System.IO.Path.GetFileName(Files[i]), "extensions.cfg", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    UnifiedObject[]    carObjects;
                    UnifiedObject[]    bogieObjects;
                    TrainManager.Train train;
                    ExtensionsCfgParser.ParseExtensionsConfig(Files[i], System.Text.Encoding.UTF8, out carObjects, out bogieObjects, out train, true);
                    double z = 0.0;
                    for (int j = 0; j < carObjects.Length; j++)
                    {
                        ObjectManager.CreateObject(carObjects[j], new Vector3(0.0, 0.0, z),
                                                   new Transformation(0.0, 0.0, 0.0), new Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0,
                                                   0.0);
                        if (j < train.Cars.Length - 1)
                        {
                            z -= (train.Cars[j].Length + train.Cars[j + 1].Length) / 2;
                        }
                    }
                }
                else
                {
                    UnifiedObject o = ObjectManager.LoadObject(Files[i], System.Text.Encoding.UTF8, false, false, false);
                    ObjectManager.CreateObject(o, Vector3.Zero,
                                               new Transformation(0.0, 0.0, 0.0), new Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0,
                                               0.0);
                }
#if !DEBUG
            }
            catch (Exception ex)
            {
                Interface.AddMessage(MessageType.Critical, false,
                                     "Unhandled error (" + ex.Message + ") encountered while processing the file " +
                                     Files[i] + ".");
            }
#endif
            }
            ObjectManager.InitializeVisibility();
            ObjectManager.FinishCreatingObjects();
            ObjectManager.UpdateVisibility(0.0, true);
            ObjectManager.UpdateAnimatedWorldObjects(0.01, true);
        }
예제 #14
0
        internal static int CreateStaticObject(UnifiedObject Prototype, Vector3 Position, Transformation BaseTransformation, Transformation AuxTransformation, bool AccurateObjectDisposal, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, double Brightness)
        {
            StaticObject obj = (StaticObject)Prototype;

            if (obj == null)
            {
                Interface.AddMessage(MessageType.Error, false, "Attempted to use an animated object where only static objects are allowed.");
                return(-1);
            }
            return(CreateStaticObject(obj, Position, BaseTransformation, AuxTransformation, AccurateObjectDisposal, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, BlockLength, TrackPosition, Brightness));
        }
예제 #15
0
 public static bool LoadObject(string path, Encoding encoding, out UnifiedObject obj)
 {
     foreach (var intf in interfaces)
     {
         if (intf.CanLoadObject(path) && intf.LoadObject(path, encoding, out obj))
         {
             return(true);
         }
     }
     obj = null;
     return(false);
 }
예제 #16
0
파일: Plugin.cs 프로젝트: xfleet/OpenBVE
 public override bool LoadObject(string path, Encoding Encoding, out UnifiedObject unifiedObject)
 {
     try
     {
         unifiedObject = ReadObject(path, Encoding);
         return(true);
     }
     catch
     {
         unifiedObject = null;
         return(false);
     }
 }
예제 #17
0
 public override bool LoadObject(string path, Encoding Encoding, out UnifiedObject unifiedObject)
 {
     try
     {
         unifiedObject = MsTsShapeParser.ReadObject(path);
     }
     catch
     {
         unifiedObject = null;
         return(false);
     }
     return(true);
 }
예제 #18
0
 internal void CreateObject(UnifiedObject Prototype, OpenBveApi.Math.Vector3 Position, Transformation BaseTransformation, Transformation AuxTransformation, int SectionIndex, bool AccurateObjectDisposal, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, double Brightness, bool DuplicateMaterials)
 {
     if (Prototype is StaticObject)
     {
         StaticObject s = (StaticObject)Prototype;
         CreateStaticObject(s, Position, BaseTransformation, AuxTransformation, AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, BlockLength, TrackPosition, Brightness);
     }
     else if (Prototype is AnimatedObjectCollection)
     {
         AnimatedObjectCollection a = (AnimatedObjectCollection)Prototype;
         a.CreateObject(Position, BaseTransformation, AuxTransformation, SectionIndex, AccurateObjectDisposal, StartingDistance, EndingDistance, BlockLength, TrackPosition, Brightness, DuplicateMaterials);
     }
 }
예제 #19
0
 public override bool LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject unifiedObject)
 {
     try
     {
         unifiedObject = ReadObject(path, Encoding);
         return(true);
     }
     catch
     {
         unifiedObject = null;
         currentHost.AddMessage(MessageType.Error, false, "An unexpected error occured whilst attempting to load the following object: " + path);
     }
     return(false);
 }
예제 #20
0
        internal int CreateStaticObject(UnifiedObject Prototype, Vector3 Position, Transformation BaseTransformation, Transformation AuxTransformation, bool AccurateObjectDisposal, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, double Brightness)
        {
            StaticObject obj = Prototype as StaticObject;

            if (obj == null)
            {
                Interface.AddMessage(MessageType.Error, false, "Attempted to use an animated object where only static objects are allowed.");
                return(-1);
            }
            if (obj.Mesh.Faces.Length == 0)
            {
                //Null object- Waste of time trying to calculate anything for these
                return(-1);
            }
            return(base.CreateStaticObject(obj, Position, BaseTransformation, AuxTransformation, AccurateObjectDisposal, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, BlockLength, TrackPosition, Brightness));
        }
예제 #21
0
 internal void CreateObject(UnifiedObject Prototype, Vector3 Position, Transformation BaseTransformation, Transformation AuxTransformation, int SectionIndex, bool AccurateObjectDisposal, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, double Brightness)
 {
     if (Prototype is StaticObject)
     {
         StaticObject s = (StaticObject)Prototype;
         if (s.Mesh.Faces.Length == 0)
         {
             return;
         }
         CreateStaticObject(s, Position, BaseTransformation, AuxTransformation, AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, BlockLength, TrackPosition, Brightness);
     }
     else if (Prototype is AnimatedObjectCollection)
     {
         AnimatedObjectCollection a = (AnimatedObjectCollection)Prototype;
         a.CreateObject(Position, BaseTransformation, AuxTransformation, SectionIndex, AccurateObjectDisposal, StartingDistance, EndingDistance, BlockLength, TrackPosition, Brightness, true);
     }
 }
예제 #22
0
        internal void Create(Vector3 wpos, Transformation RailTransformation, double StartingDistance, double EndingDistance, ObjectDictionary Beacon)
        {
            UnifiedObject obj = null;

            if (Beacon.ContainsKey(BeaconStructureIndex))
            {
                obj = Beacon[BeaconStructureIndex];
            }
            if (obj != null)
            {
                double dx = Position.X;
                double dy = Position.Y;
                double dz = TrackPosition - StartingDistance;
                wpos += dx * RailTransformation.X + dy * RailTransformation.Y + dz * RailTransformation.Z;
                double tpos = TrackPosition;
                obj.CreateObject(wpos, RailTransformation, new Transformation(Yaw, Pitch, Roll), StartingDistance, EndingDistance, tpos);
            }
        }
예제 #23
0
        internal void Create(Vector3 wpos, Transformation RailTransformation, double StartingDistance, double EndingDistance, double Brightness, ObjectDictionary Beacon)
        {
            UnifiedObject obj = null;

            if (BeaconStructureIndex == -2)
            {
                switch (Type)
                {
                case 0: obj = CompatibilityObjects.TransponderS; break;

                case 1: obj = CompatibilityObjects.TransponderSN; break;

                case 2: obj = CompatibilityObjects.TransponderFalseStart; break;

                case 3: obj = CompatibilityObjects.TransponderPOrigin; break;

                case 4: obj = CompatibilityObjects.TransponderPStop; break;
                }
            }
            else
            {
                int b = BeaconStructureIndex;
                if (b >= 0 & Beacon.ContainsKey(b))
                {
                    obj = Beacon[b];
                }
            }
            if (obj != null)
            {
                double dx = Position.X;
                double dy = Position.Y;
                double dz = TrackPosition - StartingDistance;
                wpos += dx * RailTransformation.X + dy * RailTransformation.Y + dz * RailTransformation.Z;
                double tpos = TrackPosition;
                if (BeaconStructureIndex == -2)
                {
                    obj.CreateObject(wpos, RailTransformation, new Transformation(Yaw, Pitch, Roll), -1, StartingDistance, EndingDistance, tpos, Brightness);
                }
                else
                {
                    obj.CreateObject(wpos, RailTransformation, new Transformation(Yaw, Pitch, Roll), StartingDistance, EndingDistance, tpos);
                }
            }
        }
예제 #24
0
파일: Hosts.cs 프로젝트: zbx1425/OpenBVE
        /// <summary>Loads an object</summary>
        /// <param name="Path">The absolute on-disk path to the object</param>
        /// <param name="Encoding">The detected text encoding</param>
        /// <param name="Object">The handle to the object</param>
        /// <returns>Whether loading the object was successful</returns>
        public virtual bool LoadObject(string Path, System.Text.Encoding Encoding, out UnifiedObject Object)
        {
            ValueTuple <string, bool> key = ValueTuple.Create(Path, false);

            if (StaticObjectCache.ContainsKey(key))
            {
                Object = StaticObjectCache[key].Clone();
                return(true);
            }

            if (AnimatedObjectCollectionCache.ContainsKey(Path))
            {
                Object = AnimatedObjectCollectionCache[Path].Clone();
                return(true);
            }

            Object = null;
            return(false);
        }
예제 #25
0
        public override bool LoadObject(string path, Encoding Encoding, out UnifiedObject unifiedObject)
        {
            try
            {
                if (path.ToLowerInvariant().EndsWith(".l3dobj", StringComparison.InvariantCultureIgnoreCase))
                {
                    unifiedObject = Ls3DObjectParser.ReadObject(path, Vector3.Zero);
                }
                else
                {
                    unifiedObject = Ls3DGrpParser.ReadObject(path, Encoding, Vector3.Zero);
                }
            }
            catch
            {
                unifiedObject = null;
                return(false);
            }

            return(true);
        }
예제 #26
0
    public void Create(PoleDictionary poles, Vector3 worldPos, Transform railTransform, Vector2 direction, float planar, float updown, float startingDistance, float endingDistance)
    {
        if (!Exists)
        {
            return;
        }

        float dz = startingDistance / Interval;

        dz -= Godot.Mathf.Floor(dz + 0.5f);
        if (dz >= -0.01 & dz <= 0.01)
        {
            if (Mode == 0)
            {
                if (Location <= 0.0)
                {
                    poles[0][Type].CreateObject(worldPos, railTransform, startingDistance, endingDistance, startingDistance);
                }
                else
                {
                    UnifiedObject Pole = poles[0][Type].Mirror();
                    Pole.CreateObject(worldPos, railTransform, startingDistance, endingDistance, startingDistance);
                }
            }
            else
            {
                int     m  = Mode;
                float   dx = -Location * 3.8f;
                float   wa = Godot.Mathf.Atan2(direction.y, direction.x) - planar;
                Vector3 w  = new Vector3(Godot.Mathf.Cos(wa), Godot.Mathf.Tan(updown), Godot.Mathf.Sin(wa));
                w = w.Normalized();
                float   sx   = direction.y;
                float   sy   = 0.0f;
                float   sz   = -direction.x;
                Vector3 wpos = worldPos + new Vector3(sx * dx + w.x * dz, sy * dx + w.y * dz, sz * dx + w.z * dz);
                int     type = Type;
                poles[m][type].CreateObject(wpos, railTransform, startingDistance, endingDistance, startingDistance);
            }
        }
    }
        internal static void LoadAutoGeneratedObjects(string CompatibilityFolder, out string LimitGraphicsPath)
        {
            string SignalPath = OpenBveApi.Path.CombineDirectory(CompatibilityFolder, "Signals");

            SignalPost = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(SignalPath, "signal_post.csv"), System.Text.Encoding.UTF8, false);
            string LimitPath = OpenBveApi.Path.CombineDirectory(CompatibilityFolder, "Limits");

            LimitGraphicsPath = OpenBveApi.Path.CombineDirectory(LimitPath, "Graphics");
            LimitPostStraight = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_straight.csv"), System.Text.Encoding.UTF8, false);
            LimitPostLeft     = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_left.csv"), System.Text.Encoding.UTF8, false);
            LimitPostRight    = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_right.csv"), System.Text.Encoding.UTF8, false);
            LimitPostInfinite = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_infinite.csv"), System.Text.Encoding.UTF8, false);
            LimitOneDigit     = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_1_digit.csv"), System.Text.Encoding.UTF8, false);
            LimitTwoDigits    = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_2_digits.csv"), System.Text.Encoding.UTF8, false);
            LimitThreeDigits  = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_3_digits.csv"), System.Text.Encoding.UTF8, false);
            StopPost          = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(CompatibilityFolder, "stop.csv"), System.Text.Encoding.UTF8, false);
            string TransponderPath = OpenBveApi.Path.CombineDirectory(CompatibilityFolder, "Transponders");

            TransponderS          = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(TransponderPath, "s.csv"), System.Text.Encoding.UTF8, false);
            TransponderSN         = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(TransponderPath, "sn.csv"), System.Text.Encoding.UTF8, false);
            TransponderFalseStart = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(TransponderPath, "falsestart.csv"), System.Text.Encoding.UTF8, false);
            TransponderPOrigin    = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(TransponderPath, "porigin.csv"), System.Text.Encoding.UTF8, false);
            TransponderPStop      = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(TransponderPath, "pstop.csv"), System.Text.Encoding.UTF8, false);
        }
예제 #28
0
        // create object
        internal static void CreateObject(UnifiedObject Prototype, World.Vector3D Position, World.Transformation BaseTransformation, World.Transformation AuxTransformation, bool AccurateObjectDisposal, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition)
        {
		if (Prototype != null)
		{
			CreateObject(Prototype, Position, BaseTransformation, AuxTransformation, -1, AccurateObjectDisposal, StartingDistance, EndingDistance, BlockLength, TrackPosition, 1.0, false);
		}
		else
		{
			int a = ObjectsUsed;
			if (a >= Objects.Length)
			{
				Array.Resize<StaticObject>(ref Objects, Objects.Length << 1);
			}
			ObjectsUsed++;
		}
        }
예제 #29
0
        /// <summary>Loads a Loksim3D GruppenObject</summary>
        /// <param name="FileName">The filename to load</param>
        /// <param name="Encoding">The text encoding of the containing file (Currently ignored, REMOVE??)</param>
        /// <param name="Rotation">A three-dimemsional vector describing the rotation to be applied</param>
        /// <returns>A new animated object collection, containing the GruppenObject's meshes etc.</returns>
        internal static ObjectManager.AnimatedObjectCollection ReadObject(string FileName, Encoding Encoding, Vector3 Rotation)
        {
            XmlDocument currentXML = new XmlDocument();

            ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection();
            Result.Objects = new ObjectManager.AnimatedObject[0];
            try
            {
                currentXML.Load(FileName);
            }
            catch (Exception ex)
            {
                //The XML is not strictly valid
                string[] Lines = File.ReadAllLines(FileName);
                using (var stringReader = new StringReader(Lines[0]))
                {
                    var settings = new XmlReaderSettings {
                        ConformanceLevel = ConformanceLevel.Fragment
                    };
                    using (var xmlReader = XmlReader.Create(stringReader, settings))
                    {
                        if (xmlReader.Read())
                        {
                            //Attempt to find the text encoding and re-read the file
                            var result = xmlReader.GetAttribute("encoding");
                            if (result != null)
                            {
                                var e = System.Text.Encoding.GetEncoding(result);
                                Lines = File.ReadAllLines(FileName, e);
                                //Turf out the old encoding, as our string array should now be UTF-8
                                Lines[0] = "<?xml version=\"1.0\"?>";
                            }
                        }
                    }
                }
                for (int i = 0; i < Lines.Length; i++)
                {
                    while (Lines[i].IndexOf("\"\"", StringComparison.InvariantCulture) != -1)
                    {
                        //Loksim parser tolerates multiple quotes, strict XML does not
                        Lines[i] = Lines[i].Replace("\"\"", "\"");
                    }
                    while (Lines[i].IndexOf("  ", StringComparison.InvariantCulture) != -1)
                    {
                        //Replace double-spaces with singles
                        Lines[i] = Lines[i].Replace("  ", " ");
                    }
                }
                bool tryLoad = false;
                try
                {
                    //Horrible hack: Write out our string array to a new memory stream, then load from this stream
                    //Why can't XmlDocument.Load() just take a string array......
                    using (var stream = new MemoryStream())
                    {
                        var sw = new StreamWriter(stream);
                        foreach (var line in Lines)
                        {
                            sw.Write(line);
                            sw.Flush();
                        }
                        sw.Flush();
                        stream.Position = 0;
                        currentXML.Load(stream);
                        tryLoad = true;
                    }
                }
                catch
                {
                    //Generic catch-all clause
                }
                if (!tryLoad)
                {
                    //Pass out the *original* XML error, not anything generated when we've tried to correct it
                    Interface.AddMessage(MessageType.Error, false, "Error parsing Loksim3D XML: " + ex.Message);
                    return(null);
                }
            }

            string BaseDir = System.IO.Path.GetDirectoryName(FileName);

            GruppenObject[] CurrentObjects = new GruppenObject[0];
            //Check for null
            if (currentXML.DocumentElement != null)
            {
                UnifiedObject[] obj           = new UnifiedObject[0];
                XmlNodeList     DocumentNodes = currentXML.DocumentElement.SelectNodes("/GRUPPENOBJECT");
                if (DocumentNodes != null)
                {
                    foreach (XmlNode outerNode in DocumentNodes)
                    {
                        if (outerNode.ChildNodes.OfType <XmlElement>().Any())
                        {
                            foreach (XmlNode node in outerNode.ChildNodes)
                            {
                                if (node.Name == "Object" && node.ChildNodes.OfType <XmlElement>().Any())
                                {
                                    foreach (XmlNode childNode in node.ChildNodes)
                                    {
                                        if (childNode.Name == "Props" && childNode.Attributes != null)
                                        {
                                            GruppenObject Object = new GruppenObject
                                            {
                                                Rotation = Rotation
                                            };
                                            foreach (XmlAttribute attribute in childNode.Attributes)
                                            {
                                                switch (attribute.Name)
                                                {
                                                case "Name":
                                                    string ObjectFile = OpenBveApi.Path.Loksim3D.CombineFile(BaseDir, attribute.Value, Program.FileSystem.LoksimPackageInstallationDirectory);
                                                    if (!File.Exists(ObjectFile))
                                                    {
                                                        Object.Name = null;
                                                        Interface.AddMessage(MessageType.Warning, true, "Ls3d Object file " + attribute.Value + " not found.");
                                                    }
                                                    else
                                                    {
                                                        Object.Name = ObjectFile;
                                                    }
                                                    break;

                                                case "Position":
                                                    string[] SplitPosition = attribute.Value.Split(';');
                                                    double.TryParse(SplitPosition[0], out Object.Position.X);
                                                    double.TryParse(SplitPosition[1], out Object.Position.Y);
                                                    double.TryParse(SplitPosition[2], out Object.Position.Z);
                                                    break;

                                                case "Rotation":
                                                    string[] SplitRotation = attribute.Value.Split(';');
                                                    Vector3  r;
                                                    double.TryParse(SplitRotation[0], out r.X);
                                                    double.TryParse(SplitRotation[1], out r.Y);
                                                    double.TryParse(SplitRotation[2], out r.Z);
                                                    Object.Rotation += r;
                                                    break;

                                                case "ShowOn":
                                                    //Defines when the object should be shown
                                                    Object.FunctionScript = FunctionScriptNotation.GetPostfixNotationFromInfixNotation(GetAnimatedFunction(attribute.Value, false));
                                                    break;

                                                case "HideOn":
                                                    //Defines when the object should be hidden
                                                    Object.FunctionScript = FunctionScriptNotation.GetPostfixNotationFromInfixNotation(GetAnimatedFunction(attribute.Value, true));
                                                    break;

                                                case "FixedDynamicVisibility":
                                                    if (attribute.Value.ToLowerInvariant() == "true")
                                                    {
                                                        Object.FixedDynamicVisibility = true;
                                                    }
                                                    else
                                                    {
                                                        Object.FixedDynamicVisibility = false;
                                                    }
                                                    break;

                                                case "DynamicVisibility":
                                                    if (Object.FixedDynamicVisibility)
                                                    {
                                                        Object.FunctionScript = FunctionScriptNotation.GetPostfixNotationFromInfixNotation(GetDynamicFunction(attribute.Value));
                                                    }
                                                    break;
                                                }
                                            }
                                            if (Object.Name != null)
                                            {
                                                Array.Resize <GruppenObject>(ref CurrentObjects, CurrentObjects.Length + 1);
                                                CurrentObjects[CurrentObjects.Length - 1] = Object;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    //We've loaded the XML references, now load the objects into memory

                    //Single mesh object, containing all static components of the LS3D object
                    //If we use multiples, the Z-sorting throws a wobbly
                    StaticObject staticObject = null;
                    for (int i = 0; i < CurrentObjects.Length; i++)
                    {
                        if (CurrentObjects[i] == null || string.IsNullOrEmpty(CurrentObjects[i].Name))
                        {
                            continue;
                        }
                        StaticObject Object = null;
                        ObjectManager.AnimatedObjectCollection AnimatedObject = null;
                        try
                        {
                            if (CurrentObjects[i].Name.ToLowerInvariant().EndsWith(".l3dgrp"))
                            {
                                AnimatedObject = ReadObject(CurrentObjects[i].Name, Encoding, CurrentObjects[i].Rotation);
                            }
                            else if (CurrentObjects[i].Name.ToLowerInvariant().EndsWith(".l3dobj"))
                            {
                                Object = (StaticObject)ObjectManager.LoadObject(CurrentObjects[i].Name, Encoding, false, false, false, CurrentObjects[i].Rotation);
                            }
                            else
                            {
                                throw new Exception("Format " + System.IO.Path.GetExtension(CurrentObjects[i].Name) + " is not currently supported by the Loksim3D object parser");
                            }
                        }
                        catch (Exception ex) {
                            Interface.AddMessage(MessageType.Error, false, ex.Message);
                        }
                        if (Object != null)
                        {
                            if (!string.IsNullOrEmpty(CurrentObjects[i].FunctionScript))
                            {
                                //If the function script is not empty, this is a new animated object bit
                                Array.Resize <UnifiedObject>(ref obj, obj.Length + 1);
                                obj[obj.Length - 1] = Object;
                                int aL = Result.Objects.Length;
                                Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, aL + 1);
                                ObjectManager.AnimatedObject a   = new ObjectManager.AnimatedObject();
                                AnimatedObjectState          aos = new AnimatedObjectState(Object, CurrentObjects[i].Position);
                                a.States           = new AnimatedObjectState[] { aos };
                                Result.Objects[aL] = a;
                                Result.Objects[aL].StateFunction = new FunctionScript(Program.CurrentHost, CurrentObjects[i].FunctionScript + " 1 == --", false);
                            }
                            else
                            {
                                //Otherwise, join to the main static mesh & update co-ords
                                for (int j = 0; j < Object.Mesh.Vertices.Length; j++)
                                {
                                    Object.Mesh.Vertices[j].Coordinates += CurrentObjects[i].Position;
                                }
                                staticObject.JoinObjects(Object);
                            }
                        }
                        else if (AnimatedObject != null)
                        {
                            int rl = Result.Objects.Length;
                            int l  = AnimatedObject.Objects.Length;
                            Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length + l);
                            for (int o = rl; o < rl + l; o++)
                            {
                                if (AnimatedObject.Objects[o - rl] != null)
                                {
                                    Result.Objects[o] = AnimatedObject.Objects[o - rl].Clone();
                                    for (int si = 0; si < Result.Objects[o].States.Length; si++)
                                    {
                                        Result.Objects[o].States[si].Position += CurrentObjects[i].Position;
                                    }
                                }
                                else
                                {
                                    Result.Objects[o]        = new ObjectManager.AnimatedObject();
                                    Result.Objects[o].States = new AnimatedObjectState[0];
                                }
                            }
                        }
                    }
                    if (staticObject != null)
                    {
                        Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length + 1);
                        ObjectManager.AnimatedObject a   = new ObjectManager.AnimatedObject();
                        AnimatedObjectState          aos = new AnimatedObjectState(staticObject, Vector3.Zero);
                        a.States = new AnimatedObjectState[] { aos };
                        Result.Objects[Result.Objects.Length - 1] = a;
                    }
                }
                return(Result);
            }
            //Didn't find an acceptable XML object
            //Probably will cause things to throw an absolute wobbly somewhere....
            return(null);
        }
예제 #30
0
        // process events
        internal static void KeyDown(object sender, KeyboardKeyEventArgs e)
        {
            switch (e.Key)
            {
            case Key.LShift:
            case Key.RShift:
                ShiftPressed = true;
                break;

            case Key.F5:
                // reset
                ReducedMode      = false;
                LightingRelative = -1.0;
                Game.Reset();
                Textures.UnloadAllTextures();
                //Fonts.Initialize();
                Interface.ClearMessages();
                for (int i = 0; i < Files.Length; i++)
                {
#if !DEBUG
                    try {
#endif
                    if (String.Compare(System.IO.Path.GetFileName(Files[i]), "extensions.cfg", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        UnifiedObject[]    carObjects;
                        UnifiedObject[]    bogieObjects;
                        double[]           axleLocations;
                        TrainManager.Train train;
                        ExtensionsCfgParser.ParseExtensionsConfig(Files[i], System.Text.Encoding.UTF8, out carObjects, out bogieObjects, out axleLocations, out train, true);
                        if (axleLocations.Length == 0)
                        {
                            axleLocations = new double[train.Cars.Length * 2];
                            for (int j = 0; j < train.Cars.Length; j++)
                            {
                                double ap = train.Cars.Length * 0.4;
                                axleLocations[j] = ap;
                                j++;
                                axleLocations[j] = -ap;
                            }
                        }
                        double z = 0.0;
                        for (int j = 0; j < carObjects.Length; j++)
                        {
                            ObjectManager.CreateObject(carObjects[j], new Vector3(0.0, 0.0, z),
                                                       new Transformation(0.0, 0.0, 0.0), new Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0,
                                                       0.0);
                            if (j < train.Cars.Length - 1)
                            {
                                z -= (train.Cars[j].Length + train.Cars[j + 1].Length) / 2;
                            }
                        }
                        z = 0.0;
                        for (int j = 0; j < bogieObjects.Length; j++)
                        {
                            ObjectManager.CreateObject(bogieObjects[j], new Vector3(0.0, 0.0, z + axleLocations[j]),
                                                       new Transformation(0.0, 0.0, 0.0), new Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0,
                                                       0.0);
                            j++;
                            ObjectManager.CreateObject(bogieObjects[j], new Vector3(0.0, 0.0, z - axleLocations[j]),
                                                       new Transformation(0.0, 0.0, 0.0), new Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0,
                                                       0.0);
                            if (j < train.Cars.Length - 1)
                            {
                                z -= (train.Cars[j].Length + train.Cars[j + 1].Length) / 2;
                            }
                        }
                    }
                    else
                    {
                        UnifiedObject o = ObjectManager.LoadObject(Files[i], System.Text.Encoding.UTF8, false, false, false);
                        ObjectManager.CreateObject(o, Vector3.Zero,
                                                   new Transformation(0.0, 0.0, 0.0), new Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0,
                                                   0.0);
                    }
#if !DEBUG
                }
                catch (Exception ex) {
                    Interface.AddMessage(MessageType.Critical, false, "Unhandled error (" + ex.Message + ") encountered while processing the file " + Files[i] + ".");
                }
#endif
                }
                ObjectManager.InitializeVisibility();
                ObjectManager.UpdateVisibility(0.0, true);
                ObjectManager.UpdateAnimatedWorldObjects(0.01, true);
                break;

            case Key.F7:
            {
                OpenFileDialog Dialog = new OpenFileDialog
                {
                    CheckFileExists = true,
                    Multiselect     = true,
                    Filter          = @"All supported object files|*.csv;*.b3d;*.x;*.animated;extensions.cfg;*.l3dobj;*.l3dgrp;*.obj;*.s|openBVE Objects|*.csv;*.b3d;*.x;*.animated;extensions.cfg|LokSim 3D Objects|*.l3dobj;*.l3dgrp|Wavefront Objects|*.obj|Microsoft Train Simulator Objects|*.s|All files|*"
                };
                if (Dialog.ShowDialog() == DialogResult.OK)
                {
                    Application.DoEvents();
                    string[] f = Dialog.FileNames;
                    int      n = Files.Length;
                    Array.Resize <string>(ref Files, n + f.Length);
                    for (int i = 0; i < f.Length; i++)
                    {
                        Files[n + i] = f[i];
                    }
                    // reset
                    ReducedMode      = false;
                    LightingRelative = -1.0;
                    Game.Reset();
                    Textures.UnloadAllTextures();
                    Interface.ClearMessages();
                    for (int i = 0; i < Files.Length; i++)
                    {
#if !DEBUG
                        try
                        {
#endif
                        if (String.Compare(System.IO.Path.GetFileName(Files[i]), "extensions.cfg", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            UnifiedObject[]    carObjects;
                            UnifiedObject[]    bogieObjects;
                            double[]           axleLocations;
                            TrainManager.Train train;
                            ExtensionsCfgParser.ParseExtensionsConfig(Files[i], System.Text.Encoding.UTF8, out carObjects, out bogieObjects, out axleLocations, out train, true);
                            if (axleLocations.Length == 0)
                            {
                                axleLocations = new double[train.Cars.Length * 2];
                                for (int j = 0; j < train.Cars.Length; j++)
                                {
                                    double ap = train.Cars.Length * 0.4;
                                    axleLocations[j] = ap;
                                    j++;
                                    axleLocations[j] = -ap;
                                }
                            }
                            double z = 0.0;
                            for (int j = 0; j < carObjects.Length; j++)
                            {
                                ObjectManager.CreateObject(carObjects[j], new Vector3(0.0, 0.0, z),
                                                           new Transformation(0.0, 0.0, 0.0), new Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0,
                                                           0.0);
                                if (j < train.Cars.Length - 1)
                                {
                                    z -= (train.Cars[j].Length + train.Cars[j + 1].Length) / 2;
                                }
                            }
                            z = 0.0;
                            for (int j = 0; j < bogieObjects.Length; j++)
                            {
                                ObjectManager.CreateObject(bogieObjects[j], new Vector3(0.0, 0.0, z + axleLocations[j]),
                                                           new Transformation(0.0, 0.0, 0.0), new Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0,
                                                           0.0);
                                j++;
                                ObjectManager.CreateObject(bogieObjects[j], new Vector3(0.0, 0.0, z - axleLocations[j]),
                                                           new Transformation(0.0, 0.0, 0.0), new Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0,
                                                           0.0);
                                if (j < train.Cars.Length - 1)
                                {
                                    z -= (train.Cars[j].Length + train.Cars[j + 1].Length) / 2;
                                }
                            }
                        }
                        else
                        {
                            UnifiedObject o = ObjectManager.LoadObject(Files[i], System.Text.Encoding.UTF8, false, false, false);
                            ObjectManager.CreateObject(o, Vector3.Zero,
                                                       new Transformation(0.0, 0.0, 0.0), new Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0,
                                                       0.0);
                        }
#if !DEBUG
                    }
                    catch (Exception ex)
                    {
                        Interface.AddMessage(MessageType.Critical, false,
                                             "Unhandled error (" + ex.Message + ") encountered while processing the file " +
                                             Files[i] + ".");
                    }
#endif
                    }
                    ObjectManager.InitializeVisibility();
                    ObjectManager.FinishCreatingObjects();
                    ObjectManager.UpdateVisibility(0.0, true);
                    ObjectManager.UpdateAnimatedWorldObjects(0.01, true);
                }
                else
                {
                    if (Program.CurrentlyRunOnMono)
                    {
                        //HACK: Dialog doesn't close properly when pressing the ESC key under Mono
                        //Avoid calling Application.DoEvents() unless absolutely necessary though!
                        Application.DoEvents();
                    }
                }
                Dialog.Dispose();
            }
            break;

            case Key.F9:
                if (Interface.MessageCount != 0)
                {
                    formMessages.ShowMessages();
                    Application.DoEvents();
                }
                break;

            case Key.Delete:
                ReducedMode      = false;
                LightingRelative = -1.0;
                Game.Reset();
                Textures.UnloadAllTextures();
                //Fonts.Initialize();
                Interface.ClearMessages();
                Files = new string[] { };
                break;

            case Key.Left:
                RotateX     = -1;
                ReducedMode = false;
                break;

            case Key.Right:
                RotateX     = 1;
                ReducedMode = false;
                break;

            case Key.Up:
                RotateY     = -1;
                ReducedMode = false;
                break;

            case Key.Down:
                RotateY     = 1;
                ReducedMode = false;
                break;

            case Key.A:
            case Key.Keypad4:
                MoveX       = -1;
                ReducedMode = false;
                break;

            case Key.D:
            case Key.Keypad6:
                MoveX       = 1;
                ReducedMode = false;
                break;

            case Key.Keypad8:
                MoveY       = 1;
                ReducedMode = false;
                break;

            case Key.Keypad2:
                MoveY       = -1;
                ReducedMode = false;
                break;

            case Key.W:
            case Key.Keypad9:
                MoveZ       = 1;
                ReducedMode = false;
                break;

            case Key.S:
            case Key.Keypad3:
                MoveZ       = -1;
                ReducedMode = false;
                break;

            case Key.Keypad5:
                ResetCamera();
                break;

            case Key.F:
            case Key.F1:
                Renderer.OptionWireframe = !Renderer.OptionWireframe;
                if (Renderer.OptionWireframe)
                {
                    GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
                }
                else
                {
                    GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
                }
                break;

            case Key.N:
            case Key.F2:
                Renderer.OptionNormals = !Renderer.OptionNormals;
                break;

            case Key.L:
            case Key.F3:
                LightingTarget = 1 - LightingTarget;
                ReducedMode    = false;
                break;

            case Key.I:
            case Key.F4:
                Renderer.OptionInterface = !Renderer.OptionInterface;
                ReducedMode = false;
                break;

            case Key.F8:
                formOptions.ShowOptions();
                Application.DoEvents();
                break;

            case Key.F10:
                formTrain.ShowTrainSettings();
                break;

            case Key.G:
            case Key.C:
                Renderer.OptionCoordinateSystem = !Renderer.OptionCoordinateSystem;
                ReducedMode = false;
                break;

            case Key.B:
                if (ShiftPressed)
                {
                    ColorDialog dialog = new ColorDialog();
                    dialog.FullOpen = true;
                    if (dialog.ShowDialog() == DialogResult.OK)
                    {
                        Renderer.BackgroundColor = -1;
                        Renderer.ApplyBackgroundColor(dialog.Color.R, dialog.Color.G, dialog.Color.B);
                    }
                }
                else
                {
                    Renderer.BackgroundColor++;
                    if (Renderer.BackgroundColor >= Renderer.MaxBackgroundColor)
                    {
                        Renderer.BackgroundColor = 0;
                    }
                    Renderer.ApplyBackgroundColor();
                }
                ReducedMode = false;
                break;
            }
        }
예제 #31
0
 // optimize object
 internal static void OptimizeObject(UnifiedObject Prototype, bool PreserveVertices)
 {
     if (Prototype is StaticObject) {
         StaticObject s = (StaticObject)Prototype;
         OptimizeObject(s, PreserveVertices);
     } else if (Prototype is AnimatedObjectCollection) {
         AnimatedObjectCollection a = (AnimatedObjectCollection)Prototype;
         for (int i = 0; i < a.Objects.Length; i++) {
             for (int j = 0; j < a.Objects[i].States.Length; j++) {
                 OptimizeObject(a.Objects[i].States[j].Object, PreserveVertices);
             }
         }
     }
 }
예제 #32
0
 internal static void CreateObject(UnifiedObject Prototype, Vector3 Position, World.Transformation BaseTransformation, World.Transformation AuxTransformation, int SectionIndex, bool AccurateObjectDisposal, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, double Brightness, bool DuplicateMaterials)
 {
     if (Prototype is StaticObject) {
         StaticObject s = (StaticObject)Prototype;
         CreateStaticObject(s, Position, BaseTransformation, AuxTransformation, AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, BlockLength, TrackPosition, Brightness, DuplicateMaterials);
     } else if (Prototype is AnimatedObjectCollection) {
         AnimatedObjectCollection a = (AnimatedObjectCollection)Prototype;
         CreateAnimatedWorldObjects(a.Objects, Position, BaseTransformation, AuxTransformation, SectionIndex, AccurateObjectDisposal, StartingDistance, EndingDistance, BlockLength, TrackPosition, Brightness, DuplicateMaterials);
     }
 }
예제 #33
0
 // create object
 internal static void CreateObject(UnifiedObject Prototype, Vector3 Position, World.Transformation BaseTransformation, World.Transformation AuxTransformation, bool AccurateObjectDisposal, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition)
 {
     CreateObject(Prototype, Position, BaseTransformation, AuxTransformation, -1, AccurateObjectDisposal, StartingDistance, EndingDistance, BlockLength, TrackPosition, 1.0, false);
 }
예제 #34
0
파일: Loading.cs 프로젝트: ian2009/OpenBVE
        private static void LoadEverythingThreaded()
        {
            Program.FileSystem.AppendToLogFile("Loading route file: " + CurrentRouteFile);
            Program.FileSystem.AppendToLogFile("INFO: Route file hash " + CsvRwRouteParser.GetChecksum(CurrentRouteFile));
            string RailwayFolder = GetRailwayFolder(CurrentRouteFile);
            string ObjectFolder  = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Object");
            string SoundFolder   = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Sound");

            Game.Reset(true, false);
            Game.MinimalisticSimulation = true;
            // screen
            Program.Renderer.Camera.CurrentMode = CameraViewMode.Interior;
            //First, check the format of the route file
            //RW routes were written for BVE1 / 2, and have a different command syntax
            bool IsRW = CsvRwRouteParser.isRWFile(CurrentRouteFile);

            Program.FileSystem.AppendToLogFile("Route file format is: " + (IsRW ? "RW" : "CSV"));
            CsvRwRouteParser.ParseRoute(CurrentRouteFile, IsRW, CurrentRouteEncoding, CurrentTrainFolder, ObjectFolder, SoundFolder, false);
            Thread createIllustrations = new Thread(Game.RouteInformation.LoadInformation)
            {
                IsBackground = true
            };

            createIllustrations.Start();
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            Program.CurrentRoute.Atmosphere.CalculateSeaLevelConstants();
            if (Program.CurrentRoute.BogusPreTrainInstructions.Length != 0)
            {
                double t = Program.CurrentRoute.BogusPreTrainInstructions[0].Time;
                double p = Program.CurrentRoute.BogusPreTrainInstructions[0].TrackPosition;
                for (int i = 1; i < Program.CurrentRoute.BogusPreTrainInstructions.Length; i++)
                {
                    if (Program.CurrentRoute.BogusPreTrainInstructions[i].Time > t)
                    {
                        t = Program.CurrentRoute.BogusPreTrainInstructions[i].Time;
                    }
                    else
                    {
                        t += 1.0;
                        Program.CurrentRoute.BogusPreTrainInstructions[i].Time = t;
                    }
                    if (Program.CurrentRoute.BogusPreTrainInstructions[i].TrackPosition > p)
                    {
                        p = Program.CurrentRoute.BogusPreTrainInstructions[i].TrackPosition;
                    }
                    else
                    {
                        p += 1.0;
                        Program.CurrentRoute.BogusPreTrainInstructions[i].TrackPosition = p;
                    }
                }
            }
            World.CameraTrackFollower = new TrackFollower(Program.CurrentHost)
            {
                Train = null, Car = null
            };
            if (Program.CurrentRoute.Stations.Length == 1)
            {
                //Log the fact that only a single station is present, as this is probably not right
                Program.FileSystem.AppendToLogFile("The processed route file only contains a single station.");
            }
            Program.FileSystem.AppendToLogFile("Route file loaded successfully.");
            RouteProgress = 1.0;
            // initialize trains
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            TrainManager.Trains = new TrainManager.Train[Game.PrecedingTrainTimeDeltas.Length + 1 + (Program.CurrentRoute.BogusPreTrainInstructions.Length != 0 ? 1 : 0)];
            for (int k = 0; k < TrainManager.Trains.Length; k++)
            {
                if (k == TrainManager.Trains.Length - 1 & Program.CurrentRoute.BogusPreTrainInstructions.Length != 0)
                {
                    TrainManager.Trains[k] = new TrainManager.Train(TrainState.Bogus);
                }
                else
                {
                    TrainManager.Trains[k] = new TrainManager.Train(TrainState.Pending);
                }
            }
            TrainManager.PlayerTrain = TrainManager.Trains[Game.PrecedingTrainTimeDeltas.Length];

            UnifiedObject[] CarObjects     = null;
            UnifiedObject[] BogieObjects   = null;
            UnifiedObject[] CouplerObjects = null;

            // load trains
            double TrainProgressMaximum = 0.7 + 0.3 * (double)TrainManager.Trains.Length;

            for (int k = 0; k < TrainManager.Trains.Length; k++)
            {
                //Sleep for 20ms to allow route loading locks to release
                Thread.Sleep(20);
                if (TrainManager.Trains[k].State == TrainState.Bogus)
                {
                    // bogus train
                    string TrainData = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility", "PreTrain"), "train.dat");
                    TrainDatParser.ParseTrainData(TrainData, System.Text.Encoding.UTF8, TrainManager.Trains[k]);
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainManager.Trains[k].InitializeCarSounds();
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainProgressCurrentWeight = 0.3 / TrainProgressMaximum;
                    TrainProgressCurrentSum   += TrainProgressCurrentWeight;
                }
                else
                {
                    TrainManager.Trains[k].TrainFolder = CurrentTrainFolder;
                    // real train
                    if (TrainManager.Trains[k].IsPlayerTrain)
                    {
                        Program.FileSystem.AppendToLogFile("Loading player train: " + TrainManager.Trains[k].TrainFolder);
                    }
                    else
                    {
                        Program.FileSystem.AppendToLogFile("Loading AI train: " + TrainManager.Trains[k].TrainFolder);
                    }
                    TrainProgressCurrentWeight = 0.1 / TrainProgressMaximum;
                    string TrainData = OpenBveApi.Path.CombineFile(TrainManager.Trains[k].TrainFolder, "train.dat");
                    TrainDatParser.ParseTrainData(TrainData, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainProgressCurrentWeight = 0.2 / TrainProgressMaximum;
                    SoundCfgParser.ParseSoundConfig(TrainManager.Trains[k].TrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    // door open/close speed
                    for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                    {
                        if (TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency <= 0.0)
                        {
                            if (TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer != null & TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer != null)
                            {
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer);
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer.Duration;
                                double b = TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer != null)
                            {
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = a > 0.0 ? 1.0 / a : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer != null)
                            {
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer);
                                double b = TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = b > 0.0 ? 1.0 / b : 0.8;
                            }
                            else
                            {
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = 0.8;
                            }
                        }
                        if (TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency <= 0.0)
                        {
                            if (TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer != null & TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer != null)
                            {
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer);
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer.Duration;
                                double b = TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer != null)
                            {
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = a > 0.0 ? 1.0 / a : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer != null)
                            {
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer);
                                double b = TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = b > 0.0 ? 1.0 / b : 0.8;
                            }
                            else
                            {
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = 0.8;
                            }
                        }
                        const double f = 0.015;
                        const double g = 2.75;
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch       = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                        TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch      = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency  /= TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch;
                        TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency /= TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch;

                        /*
                         * Remove the following two lines, then the pitch at which doors play
                         * takes their randomized opening and closing times into account.
                         * */
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch  = 1.0;
                        TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch = 1.0;
                    }
                }
                // add panel section
                if (TrainManager.Trains[k].IsPlayerTrain)
                {
                    TrainProgressCurrentWeight = 0.7 / TrainProgressMaximum;
                    TrainManager.ParsePanelConfig(TrainManager.Trains[k].TrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    Program.FileSystem.AppendToLogFile("Train panel loaded sucessfully.");
                }
                // add exterior section
                if (TrainManager.Trains[k].State != TrainState.Bogus)
                {
                    bool LoadObjects = false;
                    if (CarObjects == null)
                    {
                        CarObjects     = new UnifiedObject[TrainManager.Trains[k].Cars.Length];
                        BogieObjects   = new UnifiedObject[TrainManager.Trains[k].Cars.Length * 2];
                        CouplerObjects = new UnifiedObject[TrainManager.Trains[k].Cars.Length];
                        LoadObjects    = true;
                    }
                    string tXml = OpenBveApi.Path.CombineFile(TrainManager.Trains[k].TrainFolder, "train.xml");
                    if (System.IO.File.Exists(tXml))
                    {
                        TrainXmlParser.Parse(tXml, TrainManager.Trains[k], ref CarObjects, ref BogieObjects, ref CouplerObjects);
                    }
                    else
                    {
                        ExtensionsCfgParser.ParseExtensionsConfig(TrainManager.Trains[k].TrainFolder, CurrentTrainEncoding, ref CarObjects, ref BogieObjects, ref CouplerObjects, TrainManager.Trains[k], LoadObjects);
                    }
                    World.CameraCar = TrainManager.Trains[k].DriverCar;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    //Stores the current array index of the bogie object to add
                    //Required as there are two bogies per car, and we're using a simple linear array....
                    int currentBogieObject = 0;
                    for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                    {
                        if (CarObjects[i] == null)
                        {
                            // load default exterior object
                            string       file = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility"), "exterior.csv");
                            StaticObject so   = ObjectManager.LoadStaticObject(file, System.Text.Encoding.UTF8, false);
                            if (so == null)
                            {
                                CarObjects[i] = null;
                            }
                            else
                            {
                                double sx = TrainManager.Trains[k].Cars[i].Width;
                                double sy = TrainManager.Trains[k].Cars[i].Height;
                                double sz = TrainManager.Trains[k].Cars[i].Length;
                                so.ApplyScale(sx, sy, sz);
                                CarObjects[i] = so;
                            }
                        }
                        if (CarObjects[i] != null)
                        {
                            // add object
                            TrainManager.Trains[k].Cars[i].LoadCarSections(CarObjects[i]);
                        }

                        if (CouplerObjects[i] != null)
                        {
                            TrainManager.Trains[k].Cars[i].Coupler.LoadCarSections(CouplerObjects[i]);
                        }
                        //Load bogie objects
                        if (BogieObjects[currentBogieObject] != null)
                        {
                            TrainManager.Trains[k].Cars[i].FrontBogie.LoadCarSections(BogieObjects[currentBogieObject]);
                        }
                        currentBogieObject++;
                        if (BogieObjects[currentBogieObject] != null)
                        {
                            TrainManager.Trains[k].Cars[i].RearBogie.LoadCarSections(BogieObjects[currentBogieObject]);
                        }
                        currentBogieObject++;
                    }
                }
                // place cars
                TrainManager.Trains[k].PlaceCars(0.0);

                // configure ai / timetable
                if (TrainManager.Trains[k].IsPlayerTrain)
                {
                    TrainManager.Trains[k].TimetableDelta = 0.0;
                }
                else if (TrainManager.Trains[k].State != TrainState.Bogus)
                {
                    TrainManager.Trains[k].AI                  = new Game.SimpleHumanDriverAI(TrainManager.Trains[k]);
                    TrainManager.Trains[k].TimetableDelta      = Game.PrecedingTrainTimeDeltas[k];
                    TrainManager.Trains[k].Specs.DoorOpenMode  = TrainManager.DoorMode.Manual;
                    TrainManager.Trains[k].Specs.DoorCloseMode = TrainManager.DoorMode.Manual;
                }
            }

            /*
             * HACK: Store the TrainManager.Trains reference in the RouteManager also
             *		 Note that this may change when the TrainManager is separated from the lump
             *       Remember not to modify via this ref
             */
            // ReSharper disable once CoVariantArrayConversion
            Program.CurrentRoute.Trains = TrainManager.Trains;
            TrainProgress = 1.0;
            // finished created objects
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            Array.Resize(ref ObjectManager.AnimatedWorldObjects, ObjectManager.AnimatedWorldObjectsUsed);
            // update sections
            if (Program.CurrentRoute.Sections.Length > 0)
            {
                Program.CurrentRoute.UpdateAllSections();
            }
            // load plugin
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                if (TrainManager.Trains[i].State != TrainState.Bogus)
                {
                    if (TrainManager.Trains[i].IsPlayerTrain)
                    {
                        if (!TrainManager.Trains[i].LoadCustomPlugin(TrainManager.Trains[i].TrainFolder, CurrentTrainEncoding))
                        {
                            TrainManager.Trains[i].LoadDefaultPlugin(TrainManager.Trains[i].TrainFolder);
                        }
                    }
                    else
                    {
                        TrainManager.Trains[i].LoadDefaultPlugin(TrainManager.Trains[i].TrainFolder);
                    }
                }
            }
        }