예제 #1
0
        // This type must be kept in sync with the version in C.

        public ApiFunctions(ApiFunctionPointers p)
        {
            // Data
            XPLMFindDataRef     = Marshal.GetDelegateForFunctionPointer <XPLMFindDataRef>(p.XPLMFindDataRef);
            XPLMGetDataRefTypes = Marshal.GetDelegateForFunctionPointer <XPLMGetDataRefTypes>(p.XPLMGetDataRefTypes);
            XPLMGetDatai        = Marshal.GetDelegateForFunctionPointer <XPLMGetDatai>(p.XPLMGetDatai);
            XPLMSetDatai        = Marshal.GetDelegateForFunctionPointer <XPLMSetDatai>(p.XPLMSetDatai);
            XPLMGetDataf        = Marshal.GetDelegateForFunctionPointer <XPLMGetDataf>(p.XPLMGetDataf);
            XPLMSetDataf        = Marshal.GetDelegateForFunctionPointer <XPLMSetDataf>(p.XPLMSetDataf);
            XPLMGetDatad        = Marshal.GetDelegateForFunctionPointer <XPLMGetDatad>(p.XPLMGetDatad);
            XPLMSetDatad        = Marshal.GetDelegateForFunctionPointer <XPLMSetDatad>(p.XPLMSetDatad);
            XPLMGetDatavi       = Marshal.GetDelegateForFunctionPointer <XPLMGetDatavi>(p.XPLMGetDatavi);
            XPLMSetDatavi       = Marshal.GetDelegateForFunctionPointer <XPLMSetDatavi>(p.XPLMSetDatavi);
            XPLMGetDatavf       = Marshal.GetDelegateForFunctionPointer <XPLMGetDatavf>(p.XPLMGetDatavf);
            XPLMSetDatavf       = Marshal.GetDelegateForFunctionPointer <XPLMSetDatavf>(p.XPLMSetDatavf);
            XPLMGetDatab        = Marshal.GetDelegateForFunctionPointer <XPLMGetDatab>(p.XPLMGetDatab);
            XPLMSetDatab        = Marshal.GetDelegateForFunctionPointer <XPLMSetDatab>(p.XPLMSetDatab);

            // Commands
            XPLMFindCommand  = Marshal.GetDelegateForFunctionPointer <XPLMFindCommand>(p.XPLMFindCommand);
            XPLMCommandBegin = Marshal.GetDelegateForFunctionPointer <XPLMCommandBegin>(p.XPLMCommandBegin);
            XPLMCommandEnd   = Marshal.GetDelegateForFunctionPointer <XPLMCommandEnd>(p.XPLMCommandEnd);
            XPLMCommandOnce  = Marshal.GetDelegateForFunctionPointer <XPLMCommandOnce>(p.XPLMCommandOnce);

            // Processing
            XPLMGetElapsedTime                = Marshal.GetDelegateForFunctionPointer <XPLMGetElapsedTime>(p.XPLMGetElapsedTime);
            XPLMGetCycleNumber                = Marshal.GetDelegateForFunctionPointer <XPLMGetCycleNumber>(p.XPLMGetCycleNumber);
            XPLMRegisterFlightLoopCallback    = Marshal.GetDelegateForFunctionPointer <XPLMRegisterFlightLoopCallback>(p.XPLMRegisterFlightLoopCallback);
            XPLMUnregisterFlightLoopCallback  = Marshal.GetDelegateForFunctionPointer <XPLMUnregisterFlightLoopCallback>(p.XPLMUnregisterFlightLoopCallback);
            XPLMSetFlightLoopCallbackInterval = Marshal.GetDelegateForFunctionPointer <XPLMSetFlightLoopCallbackInterval>(p.XPLMSetFlightLoopCallbackInterval);
            XPLMCreateFlightLoop              = Marshal.GetDelegateForFunctionPointer <XPLMCreateFlightLoop>(p.XPLMCreateFlightLoop);
            XPLMDestroyFlightLoop             = Marshal.GetDelegateForFunctionPointer <XPLMDestroyFlightLoop>(p.XPLMDestroyFlightLoop);
            XPLMScheduleFlightLoop            = Marshal.GetDelegateForFunctionPointer <XPLMScheduleFlightLoop>(p.XPLMScheduleFlightLoop);
        }
예제 #2
0
        // This type must be kept in sync with the version in C.

        public ApiFunctions(ApiFunctionPointers p)
        {
            // Data
            XPLMFindDataRef            = Marshal.GetDelegateForFunctionPointer <XPLMFindDataRef>(p.XPLMFindDataRef);
            XPLMGetDataRefTypes        = Marshal.GetDelegateForFunctionPointer <XPLMGetDataRefTypes>(p.XPLMGetDataRefTypes);
            XPLMGetDatai               = Marshal.GetDelegateForFunctionPointer <XPLMGetDatai>(p.XPLMGetDatai);
            XPLMSetDatai               = Marshal.GetDelegateForFunctionPointer <XPLMSetDatai>(p.XPLMSetDatai);
            XPLMGetDataf               = Marshal.GetDelegateForFunctionPointer <XPLMGetDataf>(p.XPLMGetDataf);
            XPLMSetDataf               = Marshal.GetDelegateForFunctionPointer <XPLMSetDataf>(p.XPLMSetDataf);
            XPLMGetDatad               = Marshal.GetDelegateForFunctionPointer <XPLMGetDatad>(p.XPLMGetDatad);
            XPLMSetDatad               = Marshal.GetDelegateForFunctionPointer <XPLMSetDatad>(p.XPLMSetDatad);
            XPLMGetDatavi              = Marshal.GetDelegateForFunctionPointer <XPLMGetDatavi>(p.XPLMGetDatavi);
            XPLMSetDatavi              = Marshal.GetDelegateForFunctionPointer <XPLMSetDatavi>(p.XPLMSetDatavi);
            XPLMGetDatavf              = Marshal.GetDelegateForFunctionPointer <XPLMGetDatavf>(p.XPLMGetDatavf);
            XPLMSetDatavf              = Marshal.GetDelegateForFunctionPointer <XPLMSetDatavf>(p.XPLMSetDatavf);
            XPLMGetDatab               = Marshal.GetDelegateForFunctionPointer <XPLMGetDatab>(p.XPLMGetDatab);
            XPLMSetDatab               = Marshal.GetDelegateForFunctionPointer <XPLMSetDatab>(p.XPLMSetDatab);
            XPLMRegisterDataAccessor   = Marshal.GetDelegateForFunctionPointer <XPLMRegisterDataAccessor>(p.XPLMRegisterDataAccessor);
            XPLMUnregisterDataAccessor = Marshal.GetDelegateForFunctionPointer <XPLMUnregisterDataAccessor>(p.XPLMUnregisterDataAccessor);

            // Commands
            XPLMFindCommand  = Marshal.GetDelegateForFunctionPointer <XPLMFindCommand>(p.XPLMFindCommand);
            XPLMCommandBegin = Marshal.GetDelegateForFunctionPointer <XPLMCommandBegin>(p.XPLMCommandBegin);
            XPLMCommandEnd   = Marshal.GetDelegateForFunctionPointer <XPLMCommandEnd>(p.XPLMCommandEnd);
            XPLMCommandOnce  = Marshal.GetDelegateForFunctionPointer <XPLMCommandOnce>(p.XPLMCommandOnce);

            // Processing
            XPLMGetElapsedTime                = Marshal.GetDelegateForFunctionPointer <XPLMGetElapsedTime>(p.XPLMGetElapsedTime);
            XPLMGetCycleNumber                = Marshal.GetDelegateForFunctionPointer <XPLMGetCycleNumber>(p.XPLMGetCycleNumber);
            XPLMRegisterFlightLoopCallback    = Marshal.GetDelegateForFunctionPointer <XPLMRegisterFlightLoopCallback>(p.XPLMRegisterFlightLoopCallback);
            XPLMUnregisterFlightLoopCallback  = Marshal.GetDelegateForFunctionPointer <XPLMUnregisterFlightLoopCallback>(p.XPLMUnregisterFlightLoopCallback);
            XPLMSetFlightLoopCallbackInterval = Marshal.GetDelegateForFunctionPointer <XPLMSetFlightLoopCallbackInterval>(p.XPLMSetFlightLoopCallbackInterval);
            XPLMCreateFlightLoop              = Marshal.GetDelegateForFunctionPointer <XPLMCreateFlightLoop>(p.XPLMCreateFlightLoop);
            XPLMDestroyFlightLoop             = Marshal.GetDelegateForFunctionPointer <XPLMDestroyFlightLoop>(p.XPLMDestroyFlightLoop);
            XPLMScheduleFlightLoop            = Marshal.GetDelegateForFunctionPointer <XPLMScheduleFlightLoop>(p.XPLMScheduleFlightLoop);

            // Display
            XPLMRegisterDrawCallback   = Marshal.GetDelegateForFunctionPointer <XPLMRegisterDrawCallback>(p.XPLMRegisterDrawCallback);
            XPLMUnregisterDrawCallback = Marshal.GetDelegateForFunctionPointer <XPLMUnregisterDrawCallback>(p.XPLMUnregisterDrawCallback);

            // Scenery
            XPLMCreateProbe     = Marshal.GetDelegateForFunctionPointer <XPLMCreateProbe>(p.XPLMCreateProbe);
            XPLMDestroyProbe    = Marshal.GetDelegateForFunctionPointer <XPLMDestroyProbe>(p.XPLMDestroyProbe);
            XPLMProbeTerrainXYZ = Marshal.GetDelegateForFunctionPointer <XPLMProbeTerrainXYZ>(p.XPLMProbeTerrainXYZ);
            XPLMLoadObject      = Marshal.GetDelegateForFunctionPointer <XPLMLoadObject>(p.XPLMLoadObject);
            XPLMLoadObjectAsync = Marshal.GetDelegateForFunctionPointer <XPLMLoadObjectAsync>(p.XPLMLoadObjectAsync);
            XPLMDrawObjects     = Marshal.GetDelegateForFunctionPointer <XPLMDrawObjects>(p.XPLMDrawObjects);
            XPLMUnloadObject    = Marshal.GetDelegateForFunctionPointer <XPLMUnloadObject>(p.XPLMUnloadObject);
            XPLMLookupObjects   = Marshal.GetDelegateForFunctionPointer <XPLMLookupObjects>(p.XPLMLookupObjects);

            // Graphics
            XPLMWorldToLocal = Marshal.GetDelegateForFunctionPointer <XPLMWorldToLocal>(p.XPLMWorldToLocal);
            XPLMLocalToWorld = Marshal.GetDelegateForFunctionPointer <XPLMLocalToWorld>(p.XPLMLocalToWorld);

            // InstanceDrawing
            XPLMCreateInstance      = Marshal.GetDelegateForFunctionPointer <XPLMCreateInstance>(p.XPLMCreateInstance);
            XPLMDestroyInstance     = Marshal.GetDelegateForFunctionPointer <XPLMDestroyInstance>(p.XPLMDestroyInstance);
            XPLMInstanceSetPosition = Marshal.GetDelegateForFunctionPointer <XPLMInstanceSetPosition>(p.XPLMInstanceSetPosition);
        }
예제 #3
0
        internal static bool StartInternal(ref StartParams startParams, ref ApiFunctionPointers apiFunctionPointers, string rootDir)
        {
            if (!File.Exists(m_configFilePath))
            {
                m_log.Log($"XPNet CLR: Will not load plugin because config file does not exist: (Path = {m_configFilePath}).");
                return(false);
            }

            m_config = GetConfig(m_configFilePath);
            if (m_config == null)
            {
                m_log.Log($"XPNet CLR: Will not load plugin because config file was unusable: (Path = {m_configFilePath}).");
                return(false);
            }

            m_configReloadToken         = m_config.GetReloadToken();
            m_configReloadTokenDisposer = m_configReloadToken.RegisterChangeCallback(o =>
            {
                m_log.Log($"XPNet CLR: Config file change detected: (Path = {m_configFilePath}).");

                m_log.Log($"XPNet CLR: Will reconfigure logging.");
                m_api.Log = m_log = ReconfigureLogging(forceLogging: false);

                m_log.Log($"XPNet CLR: Will tell plugin that config changed.");
                m_api.RaiseConfigChanged();
            }, state: null);

            // Make a local copy of the given set of API function pointers.
            ApiFunctions = new ApiFunctions(apiFunctionPointers);

            m_api = new XPlaneApi(m_log, m_config);

            m_plugin = LoadPlugin(rootDir);
            if (m_plugin == null)
            {
                m_log.Log("XPNet CLR: Failed to find a plugin to load.  Will tell X-Plane we failed to start.");
                return(false);
            }

            var typeInfo = m_plugin.GetType().GetTypeInfo();
            var xpattr   = typeInfo.GetCustomAttribute <XPlanePluginAttribute>();

            unsafe
            {
                fixed(byte *pc = startParams.Name)
                Interop.CopyCString(pc, 256, xpattr.Name);

                fixed(byte *pc = startParams.Signature)
                Interop.CopyCString(pc, 256, xpattr.Signature);

                fixed(byte *pc = startParams.Description)
                Interop.CopyCString(pc, 256, xpattr.Description);
            }

            return(true);
        }
예제 #4
0
        public static bool Start(ref StartParams startParams, ref ApiFunctionPointers apiFunctionPointers)
        {
            // MAINT: This is the initial entry point that gets called from C++ when the plugin system is
            // initialized.
            //
            // * Do not call anything from _this_ method that requires any other DLLs, other than those
            //   that come with the framework itself.  (Put such calls into StartInternal instead).
            //
            // * Do not introduce anything in a static constructor of this class that requires any
            //   other DLLs, other than those that come with the framework itself.
            //
            // Violating either of those rules makes debugging "missing dependency" problems much more
            // difficult.  When the framework finds a missing dependency, it throws an exception.  If that
            // happens at a place where we cannot catch it in C#, then it will make it back to C++-land
            // as a hard crash.  (It is actually an NT exception and could be handled with __try/__except,
            // but that wouldn't work on other macOS or Linux, and we wouldn't be able to log any information
            // about the exception, so that's a non-optimal solution).
            //
            // The reason you can't call methods that are loaded from other DLLs here, but can in StartInternal,
            // is to do with how the JIT compiler works.  If it encounters a method it can't compile because
            // of a missing DLL, it will fail to compile _that_ method with an exception.  If one of the core
            // dependencies (like Microsoft.Configuration.*) is missing, we want that failure to occur while
            // compiling StartInternal, which we call from here.  That way, we can catch it with our try/catch
            // here, and report a good error message.  If _this_ method were to fail to JIT-compile, there are
            // no other .NET methods higher in the stack to catch and properly report the error, and the result
            // looks to the user like a hard crash.
            //
            // Logically, this method should be very small, just a try/catch wrapper around StartInternal.
            // However,
            //
            // 1. Logging is safe, because we specifically make sure that it doesn't require any external
            //    dependencies.  (That is one of the reasons that we aren't using something like log4net).
            // 2. Setting up logging (but nothing else!) at this level lets us pass back to the host environment
            //    a useful message about exactly which DLL is missing, because in practice the host environment
            //    is our C++ X-Plane plugin DLL, which passes a log handle, so it can catch what we log.
            //    Without that, we might as well just be telling the user "¯\_(ツ)_/¯ sucks to be you..."
            //
            // NOTE: There's not much we can do right now about unhandled exceptions on other threads.
            // Plugin writers will have to be conscientious about taking care of that themselves.  When/if
            // .NET Core adds an equivalent to AppDomain.UnhandledException, we could give it a try.
            //

            try
            {
                var thisAssemblyPath = typeof(PluginBridge).GetTypeInfo().Assembly.Location;
                var rootDir          = Path.GetDirectoryName(thisAssemblyPath);

                m_configFilePath = Path.Combine(rootDir, "xpnetcfg.json");
                m_logFilePath    = Path.Combine(rootDir, "xpnet.log");

                // We always start out with logging enabled.  We may reconfigure it off once config loads.
                m_log = InitLogging(ref startParams);

                m_log.Log("XPNet CLR: Start");

                return(StartInternal(ref startParams, ref apiFunctionPointers, rootDir));
            }
            catch (Exception exc)
            {
                // File.WriteAllText(@"D:\Games\X-Plane\X-Plane 11 Beta\Resources\plugins\XPNetDev\64\Emergency.txt", "Error: " + exc);
                m_log?.Log(exc);
                return(false);
            }
        }
예제 #5
0
        public static bool Start(ref StartParams startParams, ref ApiFunctionPointers apiFunctionPointers)
        {
            try
            {
                var thisAssemblyPath = typeof(PluginBridge).GetTypeInfo().Assembly.Location;
                var rootDir          = Path.GetDirectoryName(thisAssemblyPath);

                m_configFilePath = Path.Combine(rootDir, "xpnetcfg.json");
                m_logFilePath    = Path.Combine(rootDir, "xpnet.log");

                // We always start out with logging enabled.  We may reconfigure it off once config loads.
                m_log = InitLogging(ref startParams);

                m_log.Log("XPNet CLR: Start");

                if (!File.Exists(m_configFilePath))
                {
                    m_log.Log($"XPNet CLR: Will not load plugin because config file does not exist: (Path = {m_configFilePath}).");
                    return(false);
                }

                m_config = GetConfig(m_configFilePath);
                if (m_config == null)
                {
                    m_log.Log($"XPNet CLR: Will not load plugin because config file was unusable: (Path = {m_configFilePath}).");
                    return(false);
                }

                m_configReloadToken         = m_config.GetReloadToken();
                m_configReloadTokenDisposer = m_configReloadToken.RegisterChangeCallback(o =>
                {
                    m_log.Log($"XPNet CLR: Config file change detected: (Path = {m_configFilePath}).");

                    m_log.Log($"XPNet CLR: Will reconfigure logging.");
                    m_api.Log = m_log = ReconfigureLogging(forceLogging: false);

                    m_log.Log($"XPNet CLR: Will tell plugin that config changed.");
                    m_api.RaiseConfigChanged();
                }, state: null);

                // Make a local copy of the given set of API function pointers.
                ApiFunctions = new ApiFunctions(apiFunctionPointers);

                m_api = new XPlaneApi(m_log, m_config);

                m_plugin = LoadPlugin(rootDir);
                if (m_plugin == null)
                {
                    m_log.Log("XPNet CLR: Failed to find a plugin to load.  Will tell X-Plane we failed to start.");
                    return(false);
                }

                var typeInfo = m_plugin.GetType().GetTypeInfo();
                var xpattr   = typeInfo.GetCustomAttribute <XPlanePluginAttribute>();

                unsafe
                {
                    fixed(byte *pc = startParams.Name)
                    Interop.CopyCString(pc, 256, xpattr.Name);

                    fixed(byte *pc = startParams.Signature)
                    Interop.CopyCString(pc, 256, xpattr.Signature);

                    fixed(byte *pc = startParams.Description)
                    Interop.CopyCString(pc, 256, xpattr.Description);
                }

                return(true);
            }
            catch (Exception exc)
            {
                // File.WriteAllText(@"D:\Games\X-Plane\X-Plane 11 Beta\Resources\plugins\XPNetDev\64\Emergency.txt", "Error: " + exc);
                m_log?.Log(exc);
                return(false);
            }
        }