com.wallstop-studios.unity-helpers
Version:
Treasure chest of Unity developer tools
226 lines • 94.2 kB
HTML
<!doctype html><html lang=en class=no-js> <head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=description content="Production-ready Unity utilities: 10-15x faster PRNGs, O(log n) spatial queries, zero-allocation pooling, Odin-level inspector tooling, and data-driven effects."><meta name=author content="Wallstop Studios"><link href=https://wallstop.github.io/unity-helpers/features/logging/unity-main-thread-dispatcher/ rel=canonical><link href=../logging-extensions/ rel=prev><link href=../../editor-tools/editor-tools-guide/ rel=next><link rel=icon href=../../../assets/images/favicon.png><meta name=generator content="mkdocs-1.6.1, mkdocs-material-9.7.3"><title>Main Thread Dispatcher - Unity Helpers</title><link rel=stylesheet href=../../../assets/stylesheets/main.484c7ddc.min.css><link rel=stylesheet href=../../../assets/stylesheets/palette.ab4e12ef.min.css><style>:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20448%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M64%20480c-35.3%200-64-28.7-64-64V96c0-35.3%2028.7-64%2064-64h320c35.3%200%2064%2028.7%2064%2064v213.5c0%2017-6.7%2033.3-18.7%2045.3L322.7%20461.3c-12%2012-28.3%2018.7-45.3%2018.7zm325.5-176H296c-13.3%200-24%2010.7-24%2024v93.5z%22/%3E%3C/svg%3E');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20448%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M384%20512H96c-53%200-96-43-96-96V96C0%2043%2043%200%2096%200h304c26.5%200%2048%2021.5%2048%2048v288c0%2020.9-13.4%2038.7-32%2045.3V448c17.7%200%2032%2014.3%2032%2032s-14.3%2032-32%2032zM96%20384c-17.7%200-32%2014.3-32%2032s14.3%2032%2032%2032h256v-64zm32-232c0%2013.3%2010.7%2024%2024%2024h176c13.3%200%2024-10.7%2024-24s-10.7-24-24-24H152c-13.3%200-24%2010.7-24%2024m24%2072c-13.3%200-24%2010.7-24%2024s10.7%2024%2024%2024h176c13.3%200%2024-10.7%2024-24s-10.7-24-24-24z%22/%3E%3C/svg%3E');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20512%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M256%20512a256%20256%200%201%200%200-512%20256%20256%200%201%200%200%20512m-32-352a32%2032%200%201%201%2064%200%2032%2032%200%201%201-64%200m-8%2064h48c13.3%200%2024%2010.7%2024%2024v88h8c13.3%200%2024%2010.7%2024%2024s-10.7%2024-24%2024h-80c-13.3%200-24-10.7-24-24s10.7-24%2024-24h24v-64h-24c-13.3%200-24-10.7-24-24s10.7-24%2024-24%22/%3E%3C/svg%3E');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20384%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M292.9%20384c7.3-22.3%2021.9-42.5%2038.4-59.9C364%20289.7%20384%20243.2%20384%20192%20384%2086%20298%200%20192%200S0%2086%200%20192c0%2051.2%2020%2097.7%2052.7%20132.1%2016.5%2017.4%2031.2%2037.6%2038.4%2059.9h201.7zm-4.9%2048H96v16c0%2044.2%2035.8%2080%2080%2080h32c44.2%200%2080-35.8%2080-80zM184%20112c-39.8%200-72%2032.2-72%2072%200%2013.3-10.7%2024-24%2024s-24-10.7-24-24c0-66.3%2053.7-120%20120-120%2013.3%200%2024%2010.7%2024%2024s-10.7%2024-24%2024%22/%3E%3C/svg%3E');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20448%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M434.8%2070.1c14.3%2010.4%2017.5%2030.4%207.1%2044.7l-256%20352c-5.5%207.6-14%2012.3-23.4%2013.1s-18.5-2.7-25.1-9.3l-128-128c-12.5-12.5-12.5-32.8%200-45.3s32.8-12.5%2045.3%200l101.5%20101.5%20234-321.7c10.4-14.3%2030.4-17.5%2044.7-7.1z%22/%3E%3C/svg%3E');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20512%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M256%20512a256%20256%200%201%200%200-512%20256%20256%200%201%200%200%20512m0-336c-17.7%200-32%2014.3-32%2032%200%2013.3-10.7%2024-24%2024s-24-10.7-24-24c0-44.2%2035.8-80%2080-80s80%2035.8%2080%2080c0%2047.2-36%2067.2-56%2074.5v3.8c0%2013.3-10.7%2024-24%2024s-24-10.7-24-24v-8.1c0-20.5%2014.8-35.2%2030.1-40.2%206.4-2.1%2013.2-5.5%2018.2-10.3%204.3-4.2%207.7-10%207.7-19.6%200-17.7-14.3-32-32-32zm-32%20192a32%2032%200%201%201%2064%200%2032%2032%200%201%201-64%200%22/%3E%3C/svg%3E');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20512%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M256%200c14.7%200%2028.2%208.1%2035.2%2021l216%20400c6.7%2012.4%206.4%2027.4-.8%2039.5S486.1%20480%20472%20480H40c-14.1%200-27.2-7.4-34.4-19.5s-7.5-27.1-.8-39.5l216-400c7-12.9%2020.5-21%2035.2-21m0%20352a32%2032%200%201%200%200%2064%2032%2032%200%201%200%200-64m0-192c-18.2%200-32.7%2015.5-31.4%2033.7l7.4%20104c.9%2012.5%2011.4%2022.3%2023.9%2022.3%2012.6%200%2023-9.7%2023.9-22.3l7.4-104c1.3-18.2-13.1-33.7-31.4-33.7z%22/%3E%3C/svg%3E');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20384%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M55.1%2073.4c-12.5-12.5-32.8-12.5-45.3%200s-12.5%2032.8%200%2045.3L147.2%20256%209.9%20393.4c-12.5%2012.5-12.5%2032.8%200%2045.3s32.8%2012.5%2045.3%200l137.3-137.4%20137.4%20137.3c12.5%2012.5%2032.8%2012.5%2045.3%200s12.5-32.8%200-45.3L237.8%20256l137.3-137.4c12.5-12.5%2012.5-32.8%200-45.3s-32.8-12.5-45.3%200L192.5%20210.7z%22/%3E%3C/svg%3E');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20512%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M416%20427.4c58.5-44%2096-111.6%2096-187.4C512%20107.5%20397.4%200%20256%200S0%20107.5%200%20240c0%2075.8%2037.5%20143.4%2096%20187.4V464c0%2026.5%2021.5%2048%2048%2048h32v-40c0-13.3%2010.7-24%2024-24s24%2010.7%2024%2024v40h64v-40c0-13.3%2010.7-24%2024-24s24%2010.7%2024%2024v40h32c26.5%200%2048-21.5%2048-48zM96%20256a64%2064%200%201%201%20128%200%2064%2064%200%201%201-128%200m256-64a64%2064%200%201%201%200%20128%2064%2064%200%201%201%200-128%22/%3E%3C/svg%3E');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20576%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M192%2096c0-53%2043-96%2096-96s96%2043%2096%2096v3.6c0%2015.7-12.7%2028.4-28.4%2028.4H220.5c-15.7%200-28.4-12.7-28.4-28.4V96zm345.6%2012.8c10.6%2014.1%207.7%2034.2-6.4%2044.8l-97.8%2073.3c5.3%208.9%209.3%2018.7%2011.8%2029.1H544c17.7%200%2032%2014.3%2032%2032s-14.3%2032-32%2032h-96v32c0%202.6-.1%205.3-.2%207.9l83.4%2062.5c14.1%2010.6%2017%2030.7%206.4%2044.8s-30.7%2017-44.8%206.4l-63.1-47.3c-23.2%2044.2-66.5%2076.2-117.7%2083.9V280c0-13.3-10.7-24-24-24s-24%2010.7-24%2024v230.2c-51.2-7.7-94.5-39.7-117.7-83.9l-63.1%2047.3c-14.1%2010.6-34.2%207.7-44.8-6.4s-7.7-34.2%206.4-44.8l83.4-62.5c-.1-2.6-.2-5.2-.2-7.9v-32H32c-17.7%200-32-14.3-32-32s14.3-32%2032-32h98.8c2.5-10.4%206.5-20.2%2011.8-29.1l-97.8-73.3c-14.1-10.6-17-30.7-6.4-44.8s30.7-17%2044.8-6.4L192%20184c12.3-5.1%2025.8-8%2040-8h112c14.2%200%2027.7%202.8%2040%208l108.8-81.6c14.1-10.6%2034.2-7.7%2044.8%206.4%22/%3E%3C/svg%3E');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20448%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M288%200H128c-17.7%200-32%2014.3-32%2032s14.3%2032%2032%2032v151.5L7.5%20426.3C2.6%20435%200%20444.7%200%20454.7%200%20486.4%2025.6%20512%2057.3%20512h333.4c31.6%200%2057.3-25.6%2057.3-57.3%200-10-2.6-19.8-7.5-28.4L320%20215.5V64c17.7%200%2032-14.3%2032-32S337.7%200%20320%200zm-96%20215.5V64h64v151.5c0%2011.1%202.9%2022.1%208.4%2031.8L306%20320H142l41.6-72.7c5.5-9.7%208.4-20.6%208.4-31.8%22/%3E%3C/svg%3E');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20448%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%207.1.0%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202025%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M0%20216C0%20149.7%2053.7%2096%20120%2096h8c17.7%200%2032%2014.3%2032%2032s-14.3%2032-32%2032h-8c-30.9%200-56%2025.1-56%2056v8h64c35.3%200%2064%2028.7%2064%2064v64c0%2035.3-28.7%2064-64%2064H64c-35.3%200-64-28.7-64-64zm256%200c0-66.3%2053.7-120%20120-120h8c17.7%200%2032%2014.3%2032%2032s-14.3%2032-32%2032h-8c-30.9%200-56%2025.1-56%2056v8h64c35.3%200%2064%2028.7%2064%2064v64c0%2035.3-28.7%2064-64%2064h-64c-35.3%200-64-28.7-64-64z%22/%3E%3C/svg%3E');}</style><link rel=preconnect href=https://fonts.gstatic.com crossorigin><link rel=stylesheet href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback"><style>:root{--md-text-font:"Inter";--md-code-font:"JetBrains Mono"}</style><link rel=stylesheet href=../../../css/timeago.css><link rel=stylesheet href=../../../stylesheets/custom.css><script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script></head> <body dir=ltr data-md-color-scheme=slate data-md-color-primary=teal data-md-color-accent=deep-orange> <input class=md-toggle data-md-toggle=drawer type=checkbox id=__drawer autocomplete=off> <input class=md-toggle data-md-toggle=search type=checkbox id=__search autocomplete=off> <label class=md-overlay for=__drawer></label> <div data-md-component=skip> <a href=#unity-main-thread-dispatcher-guard class=md-skip> Skip to content </a> </div> <div data-md-component=announce> </div> <header class="md-header md-header--shadow md-header--lifted" data-md-component=header> <nav class="md-header__inner md-grid" aria-label=Header> <a href=../../.. title="Unity Helpers" class="md-header__button md-logo" aria-label="Unity Helpers" data-md-component=logo> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg> </a> <label class="md-header__button md-icon" for=__drawer> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg> </label> <div class=md-header__title data-md-component=header-title> <div class=md-header__ellipsis> <div class=md-header__topic> <span class=md-ellipsis> Unity Helpers </span> </div> <div class=md-header__topic data-md-component=header-topic> <span class=md-ellipsis> Main Thread Dispatcher </span> </div> </div> </div> <form class=md-header__option data-md-component=palette> <input class=md-option data-md-color-media data-md-color-scheme=slate data-md-color-primary=teal data-md-color-accent=deep-orange aria-label="Switch to light mode" type=radio name=__palette id=__palette_0> <label class="md-header__button md-icon" title="Switch to light mode" for=__palette_1 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="m17.75 4.09-2.53 1.94.91 3.06-2.63-1.81-2.63 1.81.91-3.06-2.53-1.94L12.44 4l1.06-3 1.06 3zm3.5 6.91-1.64 1.25.59 1.98-1.7-1.17-1.7 1.17.59-1.98L15.75 11l2.06-.05L18.5 9l.69 1.95zm-2.28 4.95c.83-.08 1.72 1.1 1.19 1.85-.32.45-.66.87-1.08 1.27C15.17 23 8.84 23 4.94 19.07c-3.91-3.9-3.91-10.24 0-14.14.4-.4.82-.76 1.27-1.08.75-.53 1.93.36 1.85 1.19-.27 2.86.69 5.83 2.89 8.02a9.96 9.96 0 0 0 8.02 2.89m-1.64 2.02a12.08 12.08 0 0 1-7.8-3.47c-2.17-2.19-3.33-5-3.49-7.82-2.81 3.14-2.7 7.96.31 10.98 3.02 3.01 7.84 3.12 10.98.31"/></svg> </label> <input class=md-option data-md-color-media data-md-color-scheme=default data-md-color-primary=teal data-md-color-accent=deep-orange aria-label="Switch to dark mode" type=radio name=__palette id=__palette_1> <label class="md-header__button md-icon" title="Switch to dark mode" for=__palette_0 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0-7 2.39 3.42C13.65 5.15 12.84 5 12 5s-1.65.15-2.39.42zM3.34 7l4.16-.35A7.2 7.2 0 0 0 5.94 8.5c-.44.74-.69 1.5-.83 2.29zm.02 10 1.76-3.77a7.131 7.131 0 0 0 2.38 4.14zM20.65 7l-1.77 3.79a7.02 7.02 0 0 0-2.38-4.15zm-.01 10-4.14.36c.59-.51 1.12-1.14 1.54-1.86.42-.73.69-1.5.83-2.29zM12 22l-2.41-3.44c.74.27 1.55.44 2.41.44.82 0 1.63-.17 2.37-.44z"/></svg> </label> </form> <script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script> <label class="md-header__button md-icon" for=__search> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg> </label> <div class=md-search data-md-component=search role=dialog> <label class=md-search__overlay for=__search></label> <div class=md-search__inner role=search> <form class=md-search__form name=search> <input type=text class=md-search__input name=query aria-label=Search placeholder=Search autocapitalize=off autocorrect=off autocomplete=off spellcheck=false data-md-component=search-query required> <label class="md-search__icon md-icon" for=__search> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg> </label> <nav class=md-search__options aria-label=Search> <a href=javascript:void(0) class="md-search__icon md-icon" title=Share aria-label=Share data-clipboard data-clipboard-text data-md-component=search-share tabindex=-1> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg> </a> <button type=reset class="md-search__icon md-icon" title=Clear aria-label=Clear tabindex=-1> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg> </button> </nav> <div class=md-search__suggest data-md-component=search-suggest></div> </form> <div class=md-search__output> <div class=md-search__scrollwrap tabindex=0 data-md-scrollfix> <div class=md-search-result data-md-component=search-result> <div class=md-search-result__meta> Initializing search </div> <ol class=md-search-result__list role=presentation></ol> </div> </div> </div> </div> </div> <div class=md-header__source> <a href=https://github.com/wallstop/unity-helpers title="Go to repository" class=md-source data-md-component=source> <div class="md-source__icon md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 512 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </div> <div class=md-source__repository> wallstop/unity-helpers </div> </a> </div> </nav> <nav class=md-tabs aria-label=Tabs data-md-component=tabs> <div class=md-grid> <ul class=md-tabs__list> <li class=md-tabs__item> <a href=../../.. class=md-tabs__link> Home </a> </li> <li class=md-tabs__item> <a href=../../../overview/getting-started/ class=md-tabs__link> Getting Started </a> </li> <li class="md-tabs__item md-tabs__item--active"> <a href=../../inspector/inspector-overview/ class=md-tabs__link> Features </a> </li> <li class=md-tabs__item> <a href=../../../performance/random-performance/ class=md-tabs__link> Performance </a> </li> <li class=md-tabs__item> <a href=../../../guides/odin-migration-guide/ class=md-tabs__link> Guides </a> </li> <li class=md-tabs__item> <a href=../../../project/contributing/ class=md-tabs__link> Contributing </a> </li> <li class=md-tabs__item> <a href=../../../project/license/ class=md-tabs__link> Project </a> </li> </ul> </div> </nav> </header> <div class=md-container data-md-component=container> <main class=md-main data-md-component=main> <div class="md-main__inner md-grid"> <div class="md-sidebar md-sidebar--primary" data-md-component=sidebar data-md-type=navigation> <div class=md-sidebar__scrollwrap> <div class=md-sidebar__inner> <nav class="md-nav md-nav--primary md-nav--lifted md-nav--integrated" aria-label=Navigation data-md-level=0> <label class=md-nav__title for=__drawer> <a href=../../.. title="Unity Helpers" class="md-nav__button md-logo" aria-label="Unity Helpers" data-md-component=logo> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg> </a> Unity Helpers </label> <div class=md-nav__source> <a href=https://github.com/wallstop/unity-helpers title="Go to repository" class=md-source data-md-component=source> <div class="md-source__icon md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 512 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </div> <div class=md-source__repository> wallstop/unity-helpers </div> </a> </div> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../.. class=md-nav__link> <span class=md-ellipsis> Home </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_2> <div class="md-nav__link md-nav__container"> <a href=../../../overview/ class="md-nav__link "> <span class=md-ellipsis> Getting Started </span> </a> <label class="md-nav__link " for=__nav_2 id=__nav_2_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_2_label aria-expanded=false> <label class=md-nav__title for=__nav_2> <span class="md-nav__icon md-icon"></span> Getting Started </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../overview/getting-started/ class=md-nav__link> <span class=md-ellipsis> Quick Start </span> </a> </li> <li class=md-nav__item> <a href=../../../overview/glossary/ class=md-nav__link> <span class=md-ellipsis> Glossary </span> </a> </li> <li class=md-nav__item> <a href=../../../overview/roadmap/ class=md-nav__link> <span class=md-ellipsis> Roadmap </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_3 checked> <label class=md-nav__link for=__nav_3 id=__nav_3_label tabindex> <span class=md-ellipsis> Features </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_3_label aria-expanded=true> <label class=md-nav__title for=__nav_3> <span class="md-nav__icon md-icon"></span> Features </label> <ul class=md-nav__list data-md-scrollfix> <li class="md-nav__item md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_3_1> <label class=md-nav__link for=__nav_3_1 id=__nav_3_1_label tabindex> <span class=md-ellipsis> Inspector </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_3_1_label aria-expanded=false> <label class=md-nav__title for=__nav_3_1> <span class="md-nav__icon md-icon"></span> Inspector </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../inspector/inspector-overview/ class=md-nav__link> <span class=md-ellipsis> Overview </span> </a> </li> <li class=md-nav__item> <a href=../../inspector/inspector-button/ class=md-nav__link> <span class=md-ellipsis> Buttons </span> </a> </li> <li class=md-nav__item> <a href=../../inspector/inspector-grouping-attributes/ class=md-nav__link> <span class=md-ellipsis> Grouping Attributes </span> </a> </li> <li class=md-nav__item> <a href=../../inspector/inspector-selection-attributes/ class=md-nav__link> <span class=md-ellipsis> Selection Attributes </span> </a> </li> <li class=md-nav__item> <a href=../../inspector/inspector-conditional-display/ class=md-nav__link> <span class=md-ellipsis> Conditional Display </span> </a> </li> <li class=md-nav__item> <a href=../../inspector/inspector-validation-attributes/ class=md-nav__link> <span class=md-ellipsis> Validation Attributes </span> </a> </li> <li class=md-nav__item> <a href=../../inspector/inspector-inline-editor/ class=md-nav__link> <span class=md-ellipsis> Inline Editor </span> </a> </li> <li class=md-nav__item> <a href=../../inspector/inspector-settings/ class=md-nav__link> <span class=md-ellipsis> Inspector Settings </span> </a> </li> <li class=md-nav__item> <a href=../../inspector/utility-components/ class=md-nav__link> <span class=md-ellipsis> Utility Components </span> </a> </li> <li class=md-nav__item> <a href=../../inspector/visual-components/ class=md-nav__link> <span class=md-ellipsis> Visual Components </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_3_2> <label class=md-nav__link for=__nav_3_2 id=__nav_3_2_label tabindex> <span class=md-ellipsis> Relational Components </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_3_2_label aria-expanded=false> <label class=md-nav__title for=__nav_3_2> <span class="md-nav__icon md-icon"></span> Relational Components </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../relational-components/relational-components/ class=md-nav__link> <span class=md-ellipsis> Overview </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_3_3> <label class=md-nav__link for=__nav_3_3 id=__nav_3_3_label tabindex> <span class=md-ellipsis> Spatial Data Structures </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_3_3_label aria-expanded=false> <label class=md-nav__title for=__nav_3_3> <span class="md-nav__icon md-icon"></span> Spatial Data Structures </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../spatial/spatial-trees-2d-guide/ class=md-nav__link> <span class=md-ellipsis> 2D Spatial Trees </span> </a> </li> <li class=md-nav__item> <a href=../../spatial/spatial-trees-3d-guide/ class=md-nav__link> <span class=md-ellipsis> 3D Spatial Trees </span> </a> </li> <li class=md-nav__item> <a href=../../spatial/hulls/ class=md-nav__link> <span class=md-ellipsis> Hull Algorithms </span> </a> </li> <li class=md-nav__item> <a href=../../spatial/spatial-tree-semantics/ class=md-nav__link> <span class=md-ellipsis> Spatial Tree Semantics </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_3_4> <label class=md-nav__link for=__nav_3_4 id=__nav_3_4_label tabindex> <span class=md-ellipsis> Effects System </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_3_4_label aria-expanded=false> <label class=md-nav__title for=__nav_3_4> <span class="md-nav__icon md-icon"></span> Effects System </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../effects/effects-system/ class=md-nav__link> <span class=md-ellipsis> Overview </span> </a> </li> <li class=md-nav__item> <a href=../../effects/effects-system-tutorial/ class=md-nav__link> <span class=md-ellipsis> Tutorial </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_3_5> <label class=md-nav__link for=__nav_3_5 id=__nav_3_5_label tabindex> <span class=md-ellipsis> Serialization </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_3_5_label aria-expanded=false> <label class=md-nav__title for=__nav_3_5> <span class="md-nav__icon md-icon"></span> Serialization </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../serialization/serialization/ class=md-nav__link> <span class=md-ellipsis> Overview </span> </a> </li> <li class=md-nav__item> <a href=../../serialization/serialization-types/ class=md-nav__link> <span class=md-ellipsis> Serializable Types </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_3_6> <label class=md-nav__link for=__nav_3_6 id=__nav_3_6_label tabindex> <span class=md-ellipsis> Utilities </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_3_6_label aria-expanded=false> <label class=md-nav__title for=__nav_3_6> <span class="md-nav__icon md-icon"></span> Utilities </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../utilities/math-and-extensions/ class=md-nav__link> <span class=md-ellipsis> Math & Extensions </span> </a> </li> <li class=md-nav__item> <a href=../../utilities/data-structures/ class=md-nav__link> <span class=md-ellipsis> Data Structures </span> </a> </li> <li class=md-nav__item> <a href=../../utilities/random-generators/ class=md-nav__link> <span class=md-ellipsis> Random Generators </span> </a> </li> <li class=md-nav__item> <a href=../../utilities/singletons/ class=md-nav__link> <span class=md-ellipsis> Singletons </span> </a> </li> <li class=md-nav__item> <a href=../../utilities/reflection-helpers/ class=md-nav__link> <span class=md-ellipsis> Reflection Helpers </span> </a> </li> <li class=md-nav__item> <a href=../../utilities/helper-utilities/ class=md-nav__link> <span class=md-ellipsis> Helper Utilities </span> </a> </li> <li class=md-nav__item> <a href=../../utilities/pooling-guide/ class=md-nav__link> <span class=md-ellipsis> Pooling Guide </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_3_7 checked> <label class=md-nav__link for=__nav_3_7 id=__nav_3_7_label tabindex> <span class=md-ellipsis> Logging </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_3_7_label aria-expanded=true> <label class=md-nav__title for=__nav_3_7> <span class="md-nav__icon md-icon"></span> Logging </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../logging-extensions/ class=md-nav__link> <span class=md-ellipsis> Logging Extensions </span> </a> </li> <li class="md-nav__item md-nav__item--active"> <input class="md-nav__toggle md-toggle" type=checkbox id=__toc> <label class="md-nav__link md-nav__link--active" for=__toc> <span class=md-ellipsis> Main Thread Dispatcher </span> <span class="md-nav__icon md-icon"></span> </label> <a href=./ class="md-nav__link md-nav__link--active"> <span class=md-ellipsis> Main Thread Dispatcher </span> </a> <nav class="md-nav md-nav--secondary" aria-label="Table of contents"> <label class=md-nav__title for=__toc> <span class="md-nav__icon md-icon"></span> Table of contents </label> <ul class=md-nav__list data-md-component=toc data-md-scrollfix> <li class=md-nav__item> <a href=#overview class=md-nav__link> <span class=md-ellipsis> Overview </span> </a> </li> <li class=md-nav__item> <a href=#unitymainthreaddispatcher class=md-nav__link> <span class=md-ellipsis> UnityMainThreadDispatcher </span> </a> <nav class=md-nav aria-label=UnityMainThreadDispatcher> <ul class=md-nav__list> <li class=md-nav__item> <a href=#basic-usage class=md-nav__link> <span class=md-ellipsis> Basic Usage </span> </a> </li> <li class=md-nav__item> <a href=#api class=md-nav__link> <span class=md-ellipsis> API </span> </a> </li> <li class=md-nav__item> <a href=#use-cases class=md-nav__link> <span class=md-ellipsis> Use Cases </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#unitymainthreadguard class=md-nav__link> <span class=md-ellipsis> UnityMainThreadGuard </span> </a> <nav class=md-nav aria-label=UnityMainThreadGuard> <ul class=md-nav__list> <li class=md-nav__item> <a href=#basic-usage_1 class=md-nav__link> <span class=md-ellipsis> Basic Usage </span> </a> </li> <li class=md-nav__item> <a href=#why-it-exists class=md-nav__link> <span class=md-ellipsis> Why It Exists </span> </a> </li> <li class=md-nav__item> <a href=#api_1 class=md-nav__link> <span class=md-ellipsis> API </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#default-bootstrapping-flow class=md-nav__link> <span class=md-ellipsis> Default Bootstrapping Flow </span> </a> </li> <li class=md-nav__item> <a href=#opting-inout-of-auto-creation class=md-nav__link> <span class=md-ellipsis> Opting In/Out of Auto-Creation </span> </a> <nav class=md-nav aria-label="Opting In/Out of Auto-Creation"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#autocreationscope-scoped-toggles class=md-nav__link> <span class=md-ellipsis> AutoCreationScope (scoped toggles) </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#test-bootstrap-workflow class=md-nav__link> <span class=md-ellipsis> Test Bootstrap Workflow </span> </a> <nav class=md-nav aria-label="Test Bootstrap Workflow"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#runtime-playmode-testsruntimetestutilsunitymainthreaddispatchertestbootstrapcs class=md-nav__link> <span class=md-ellipsis> Runtime / PlayMode (Tests/Runtime/TestUtils/UnityMainThreadDispatcherTestBootstrap.cs) </span> </a> </li> <li class=md-nav__item> <a href=#editor-editmode-testseditortestutilsunitymainthreaddispatchereditortestbootstrapcs class=md-nav__link> <span class=md-ellipsis> Editor / EditMode (Tests/Editor/TestUtils/UnityMainThreadDispatcherEditorTestBootstrap.cs) </span> </a> </li> <li class=md-nav__item> <a href=#re-enabling-per-test class=md-nav__link> <span class=md-ellipsis> Re-enabling per Test </span> </a> </li> </ul> </nav> </li> </ul> </nav> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_3_8> <label class=md-nav__link for=__nav_3_8 id=__nav_3_8_label tabindex> <span class=md-ellipsis> Editor Tools </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_3_8_label aria-expanded=false> <label class=md-nav__title for=__nav_3_8> <span class="md-nav__icon md-icon"></span> Editor Tools </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../editor-tools/editor-tools-guide/ class=md-nav__link> <span class=md-ellipsis> Tools Guide </span> </a> </li> <li class=md-nav__item> <a href=../../editor-tools/unity-method-analyzer/ class=md-nav__link> <span class=md-ellipsis> Unity Method Analyzer </span> </a> </li> <li class=md-nav__item> <a href=../../editor-tools/asset-change-detection/ class=md-nav__link> <span class=md-ellipsis> Asset Change Detection </span> </a> </li> <li class=md-nav__item> <a href=../../editor-tools/failed-tests-exporter/ class=md-nav__link> <span class=md-ellipsis> Failed Tests Exporter </span> </a> </li> </ul> </nav> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_4> <label class=md-nav__link for=__nav_4 id=__nav_4_label tabindex=0> <span class=md-ellipsis> Performance </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_4_label aria-expanded=false> <label class=md-nav__title for=__nav_4> <span class="md-nav__icon md-icon"></span> Performance </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../performance/random-performance/ class=md-nav__link> <span class=md-ellipsis> Random Generators </span> </a> </li> <li class=md-nav__item> <a href=../../../performance/spatial-tree-2d-performance/ class=md-nav__link> <span class=md-ellipsis> Spatial Trees 2D </span> </a> </li> <li class=md-nav__item> <a href=../../../performance/spatial-tree-3d-performance/ class=md-nav__link> <span class=md-ellipsis> Spatial Trees 3D </span> </a> </li> <li class=md-nav__item> <a href=../../../performance/relational-components-performance/ class=md-nav__link> <span class=md-ellipsis> Relational Components </span> </a> </li> <li class=md-nav__item> <a href=../../../performance/reflection-performance/ class=md-nav__link> <span class=md-ellipsis> Reflection Helpers </span> </a> </li> <li class=md-nav__item> <a href=../../../performance/ilist-sorting-performance/ class=md-nav__link> <span class=md-ellipsis> IList Sorting </span> </a> </li> <li class=md-nav__item> <a href=../../../performance/baseline-tests-performance/ class=md-nav__link> <span class=md-ellipsis> Baseline Tests </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_5> <label class=md-nav__link for=__nav_5 id=__nav_5_label tabindex=0> <span class=md-ellipsis> Guides </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_5_label aria-expanded=false> <label class=md-nav__title for=__nav_5> <span class="md-nav__icon md-icon"></span> Guides </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../guides/odin-migration-guide/ class=md-nav__link> <span class=md-ellipsis> Odin Migration </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_6> <label class=md-nav__link for=__nav_6 id=__nav_6_label tabindex=0> <span class=md-ellipsis> Contributing </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_6_label aria-expanded=false> <label class=md-nav__title for=__nav_6> <span class="md-nav__icon md-icon"></span> Contributing </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../project/contributing/ class=md-nav__link> <span class=md-ellipsis> Overview </span> </a> </li> <li class=md-nav__item> <a href=../../../contributing/testing-patterns/ class=md-nav__link> <span class=md-ellipsis> Testing Patterns </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_7> <label class=md-nav__link for=__nav_7 id=__nav_7_label tabindex=0> <span class=md-ellipsis> Project </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_7_label aria-expanded=false> <label class=md-nav__title for=__nav_7> <span class="md-nav__icon md-icon"></span> Project </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../project/license/ class=md-nav__link> <span class=md-ellipsis> License </span> </a> </li> <li class=md-nav__item> <a href=../../../project/third-party-notices/ class=md-nav__link> <span class=md-ellipsis> Third-Party Notices </span> </a> </li> <li class=md-nav__item> <a href=../../../project/llms-txt/ class=md-nav__link> <span class=md-ellipsis> LLMs.txt </span> </a> </li> </ul> </nav> </li> </ul> </nav> </div> </div> </div> <div class=md-content data-md-component=content> <nav class=md-path aria-label=Navigation> <ol class=md-path__list> <li class=md-path__item> <a href=../../.. class=md-path__link> <span class=md-ellipsis> Home </span> </a> </li> <li class=md-path__item> <a href=../../inspector/inspector-overview/ class=md-path__link> <span class=md-ellipsis> Features </span> </a> </li> <li class=md-path__item> <a href=../logging-extensions/ class=md-path__link> <span class=md-ellipsis> Logging </span> </a> </li> </ol> </nav> <article class="md-content__inner md-typeset"> <a href=https://github.com/wallstop/unity-helpers/edit/main/docs/features/logging/unity-main-thread-dispatcher.md title="Edit this page" class="md-content__button md-icon" rel=edit> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75z"/></svg> </a> <a href=https://github.com/wallstop/unity-helpers/raw/main/docs/features/logging/unity-main-thread-dispatcher.md title="View source of this page" class="md-content__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0 8a5 5 0 0 1-5-5 5 5 0 0 1 5-5 5 5 0 0 1 5 5 5 5 0 0 1-5 5m0-12.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5"/></svg> </a> <h1 id=unity-main-thread-dispatcher-guard>Unity Main Thread Dispatcher & Guard<a class=headerlink href=#unity-main-thread-dispatcher-guard title="Permanent link">¶</a></h1> <p><code>UnityMainThreadDispatcher</code> and <code>UnityMainThreadGuard</code> provide thread-safe access to Unity's main thread from background workers, ensuring callbacks execute correctly and preventing common threading errors.</p> <h2 id=overview>Overview<a class=headerlink href=#overview title="Permanent link">¶</a></h2> <table> <thead> <tr> <th>Component</th> <th>Purpose</th> <th>Usage Pattern</th> </tr> </thead> <tbody> <tr> <td><code>UnityMainThreadDispatcher</code></td> <td><strong>Dispatch</strong> work to the main thread</td> <td><code>dispatcher.RunOnMainThread(() => ...)</code></td> </tr> <tr> <td><code>UnityMainThreadGuard</code></td> <td><strong>Assert</strong> code is on the main thread</td> <td><code>UnityMainThreadGuard.EnsureMainThread()</code></td> </tr> </tbody> </table> <h2 id=unitymainthreaddispatcher>UnityMainThreadDispatcher<a class=headerlink href=#unitymainthreaddispatcher title="Permanent link">¶</a></h2> <p>The <code>UnityMainThreadDispatcher</code> is the package-wide bridge for marshaling callbacks from worker threads back onto Unity's main thread. The dispatcher is implemented as a <code>RuntimeSingleton<UnityMainThreadDispatcher></code>, is marked <code>[ExecuteAlways]</code>, and runs both in Edit Mode and Play Mode so background logging, importers, and build scripts can all enqueue work safely.</p> <h3 id=basic-usage>Basic Usage<a class=headerlink href=#basic-usage title="Permanent link">¶</a></h3> <div class="language-csharp highlight"><table class=highlighttable><tr><th colspan=2 class=filename><span class=filename>C#</span></th></tr><tr><td class=linenos><div class=linenodiv><pre><span></span><span class=normal><a href=#__codelineno-0-1> 1</a></span>
<span class=normal><a href=#__codelineno-0-2> 2</a></span>
<span class=normal><a href=#__codelineno-0-3> 3</a></span>
<span class=normal><a href=#__codelineno-0-4> 4</a></span>
<span class=normal><a href=#__codelineno-0-5> 5</a></span>
<span class=normal><a href=#__codelineno-0-6> 6</a></span>
<span class=normal><a href=#__codelineno-0-7> 7</a></span>
<span class=normal><a href=#__codelineno-0-8> 8</a></span>
<span class=normal><a href=#__codelineno-0-9> 9</a></span>
<span class=normal><a href=#__codelineno-0-10>10</a></span>
<span class=normal><a href=#__codelineno-0-11>11</a></span>
<span class=normal><a href=#__codelineno-0-12>12</a></span>
<span class=normal><a href=#__codelineno-0-13>13</a></span>
<span class=normal><a href=#__codelineno-0-14>14</a></span>
<span class=normal><a href=#__codelineno-0-15>15</a></span>
<span class=normal><a href=#__codelineno-0-16>16</a></span></pre></div></td><td class=code><div><pre><span></span><code><span id=__span-0-1><a id=__codelineno-0-1 name=__codelineno-0-1></a><span class=k>using</span><span class=w> </span><span class=nn>UnityEngine</span><span class=p>;</span>
</span><span id=__span-0-2><a id=__codelineno-0-2 name=__codelineno-0-2></a><span class=k>using</span><span class=w> </span><span class=nn>WallstopStudios.UnityHelpers.Core.Helper</span><span class=p>;</span>
</span><span id=__span-0-3><a id=__codelineno-0-3 name=__codelineno-0-3></a>
</span><span id=__span-0-4><a id=__codelineno-0-4 name=__codelineno-0-4></a><span class=k>public</span><span class=w> </span><span class=k>class</span><span class=w> </span><span class=nc>BackgroundProcessor</span>
</span><span id=__span-0-5><a id=__codelineno-0-5 name=__codelineno-0-5></a><span class=p>{</span>
</span><span id=__span-0-6><a id=__codelineno-0-6 name=__codelineno-0-6></a><span class=w> </span><span class=k>public</span><span class=w> </span><span class=k>void</span><span class=w> </span><span class=nf>ProcessOnWorkerThread</span><span class=p>()</span>
</span><span id=__span-0-7><a id=__codelineno-0-7 name=__codelineno-0-7></a><span class=w> </span><span class=p>{</span>
</span><span id=__span-0-8><a id=__codelineno-0-8 name=__codelineno-0-8></a><span class=w> </span><span class=c1>// Queue work from any thread to execute on Unity's main thread</span>
</span><span id=__span-0-9><a id=__codelineno-0-9 name=__codelineno-0-9></a><span class=w> </span><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>Instance</span><span class=p>.</span><span class=n>RunOnMainThread</span><span class=p>(()</span><span class=w> </span><span class=o>=></span>
</span><span id=__span-0-10><a id=__codelineno-0-10 name=__codelineno-0-10></a><span class=w> </span><span class=p>{</span>
</span><span id=__span-0-11><a id=__codelineno-0-11 name=__codelineno-0-11></a><span class=w> </span><span class=c1>// This code executes on the main thread during the next Update</span>
</span><span id=__span-0-12><a id=__codelineno-0-12 name=__codelineno-0-12></a><span class=w> </span><span class=n>Debug</span><span class=p>.</span><span class=n>Log</span><span class=p>(</span><span class=s>"Safe to call Unity APIs here"</span><span class=p>);</span>
</span><span id=__span-0-13><a id=__codelineno-0-13 name=__codelineno-0-13></a><span class=w> </span><span class=n>Object</span><span class=p>.</span><span class=n>FindObjectOfType</span><span class=o><</span><span class=n>Player</span><span class=o>></span><span class=p>().</span><span class=n>UpdateState</span><span class=p>();</span>
</span><span id=__span-0-14><a id=__codelineno-0-14 name=__codelineno-0-14></a><span class=w> </span><span class=p>});</span>
</span><span id=__span-0-15><a id=__codelineno-0-15 name=__codelineno-0-15></a><span class=w> </span><span class=p>}</span>
</span><span id=__span-0-16><a id=__codelineno-0-16 name=__codelineno-0-16></a><span class=p>}</span>
</span></code></pre></div></td></tr></table></div> <h3 id=api>API<a class=headerlink href=#api title="Permanent link">¶</a></h3> <div class="language-csharp highlight"><table class=highlighttable><tr><th colspan=2 class=filename><span class=filename>C#</span></th></tr><tr><td class=linenos><div class=linenodiv><pre><span></span><span class=normal><a href=#__codelineno-1-1> 1</a></span>
<span class=normal><a href=#__codelineno-1-2> 2</a></span>
<span class=normal><a href=#__codelineno-1-3> 3</a></span>
<span class=normal><a href=#__codelineno-1-4> 4</a></span>
<span class=normal><a href=#__codelineno-1-5> 5</a></span>
<span class=normal><a href=#__codelineno-1-6> 6</a></span>
<span class=normal><a href=#__codelineno-1-7> 7</a></span>
<span class=normal><a href=#__codelineno-1-8> 8</a></span>
<span class=normal><a href=#__codelineno-1-9> 9</a></span>
<span class=normal><a href=#__codelineno-1-10>10</a></span>
<span class=normal><a href=#__codelineno-1-11>11</a></span></pre></div></td><td class=code><div><pre><span></span><code><span id=__span-1-1><a id=__codelineno-1-1 name=__codelineno-1-1></a><span class=c1>// Queue action to run on main thread (logs warning if queue is full)</span>
</span><span id=__span-1-2><a id=__codelineno-1-2 name=__codelineno-1-2></a><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>Instance</span><span class=p>.</span><span class=n>RunOnMainThread</span><span class=p>(</span><span class=n>Action</span><span class=w> </span><span class=n>action</span><span class=p>);</span>
</span><span id=__span-1-3><a id=__codelineno-1-3 name=__codelineno-1-3></a>
</span><span id=__span-1-4><a id=__codelineno-1-4 name=__codelineno-1-4></a><span class=c1>// Queue action silently (returns false if queue is full, no warning)</span>
</span><span id=__span-1-5><a id=__codelineno-1-5 name=__codelineno-1-5></a><span class=kt>bool</span><span class=w> </span><span class=n>queued</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>Instance</span><span class=p>.</span><span class=n>TryRunOnMainThread</span><span class=p>(</span><span class=n>Action</span><span class=w> </span><span class=n>action</span><span class=p>);</span>
</span><span id=__span-1-6><a id=__codelineno-1-6 name=__codelineno-1-6></a>
</span><span id=__span-1-7><a id=__codelineno-1-7 name=__codelineno-1-7></a><span class=c1>// Check current queue depth</span>
</span><span id=__span-1-8><a id=__codelineno-1-8 name=__codelineno-1-8></a><span class=kt>int</span><span class=w> </span><span class=n>pending</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>Instance</span><span class=p>.</span><span class=n>PendingActionCount</span><span class=p>;</span>
</span><span id=__span-1-9><a id=__codelineno-1-9 name=__codelineno-1-9></a>
</span><span id=__span-1-10><a id=__codelineno-1-10 name=__codelineno-1-10></a><span class=c1>// Configure queue limit (0 = unlimited)</span>
</span><span id=__span-1-11><a id=__codelineno-1-11 name=__codelineno-1-11></a><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>Instance</span><span class=p>.</span><span class=n>PendingActionLimit</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=mi>4096</span><span class=p>;</span>
</span></code></pre></div></td></tr></table></div> <h3 id=use-cases>Use Cases<a class=headerlink href=#use-cases title="Permanent link">¶</a></h3> <div class="language-csharp highlight"><table class=highlighttable><tr><th colspan=2 class=filename><span class=filename>C#</span></th></tr><tr><td class=linenos><div class=linenodiv><pre><span></span><span class=normal><a href=#__codelineno-2-1> 1</a></span>
<span class=normal><a href=#__codelineno-2-2> 2</a></span>
<span class=normal><a href=#__codelineno-2-3> 3</a></span>
<span class=normal><a href=#__codelineno-2-4> 4</a></span>
<span class=normal><a href=#__codelineno-2-5> 5</a></span>
<span class=normal><a href=#__codelineno-2-6> 6</a></span>
<span class=normal><a href=#__codelineno-2-7> 7</a></span>
<span class=normal><a href=#__codelineno-2-8> 8</a></span>
<span class=normal><a href=#__codelineno-2-9> 9</a></span>
<span class=normal><a href=#__codelineno-2-10>10</a></span>
<span class=normal><a href=#__codelineno-2-11>11</a></span>
<span class=normal><a href=#__codelineno-2-12>12</a></span>
<span class=normal><a href=#__codelineno-2-13>13</a></span>
<span class=normal><a href=#__codelineno-2-14>14</a></span>
<span class=normal><a href=#__codelineno-2-15>15</a></span>
<span class=normal><a href=#__codelineno-2-16>16</a></span>
<span class=normal><a href=#__codelineno-2-17>17</a></span>
<span class=normal><a href=#__codelineno-2-18>18</a></span>
<span class=normal><a href=#__codelineno-2-19>19</a></span>
<span class=normal><a href=#__codelineno-2-20>20</a></span>
<span class=normal><a href=#__codelineno-2-21>21</a></span>
<span class=normal><a href=#__codelineno-2-22>22</a></span>
<span class=normal><a href=#__codelineno-2-23>23</a></span>
<span class=normal><a href=#__codelineno-2-24>24</a></span>
<span class=normal><a href=#__codelineno-2-25>25</a></span>
<span class=normal><a href=#__codelineno-2-26>26</a></span>
<span class=normal><a href=#__codelineno-2-27>27</a></span>
<span class=normal><a href=#__codelineno-2-28>28</a></span>
<span class=normal><a href=#__codelineno-2-29>29</a></span>
<span class=normal><a href=#__codelineno-2-30>30</a></span>
<span class=normal><a href=#__codelineno-2-31>31</a></span>
<span class=normal><a href=#__codelineno-2-32>32</a></span>
<span class=normal><a href=#__codelineno-2-33>33</a></span>
<span class=normal><a href=#__codelineno-2-34>34</a></span>
<span class=normal><a href=#__codelineno-2-35>35</a></span></pre></div></td><td class=code><div><pre><span></span><code><span id=__span-2-1><a id=__codelineno-2-1 name=__codelineno-2-1></a><span class=c1>// Async/await with Unity API access</span>
</span><span id=__span-2-2><a id=__codelineno-2-2 name=__codelineno-2-2></a><span class=k>public</span><span class=w> </span><span class=k>async</span><span class=w> </span><span class=n>Task</span><span class=o><</span><span class=n>GameObject</span><span class=o>></span><span class=w> </span><span class=n>LoadAssetAsync</span><span class=p>(</span><span class=kt>string</span><span class=w> </span><span class=n>path</span><span class=p>)</span>
</span><span id=__span-2-3><a id=__codelineno-2-3 name=__codelineno-2-3></a><span class=p>{</span>
</span><span id=__span-2-4><a id=__codelineno-2-4 name=__codelineno-2-4></a><span class=w> </span><span class=n>GameObject</span><span class=w> </span><span class=n>asset</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=k>await</span><span class=w> </span><span class=n>LoadFromDiskAsync</span><span class=p>(</span><span class=n>path</span><span class=p>);</span>
</span><span id=__span-2-5><a id=__codelineno-2-5 name=__codelineno-2-5></a>
</span><span id=__span-2-6><a id=__codelineno-2-6 name=__codelineno-2-6></a><span class=w> </span><span class=c1>// Marshal instantiation to main thread</span>
</span><span id=__span-2-7><a id=__codelineno-2-7 name=__codelineno-2-7></a><span class=w> </span><span class=n>TaskCompletionSource</span><span class=o><</span><span class=n>GameObject</span><span class=o>></span><span class=w> </span><span class=n>tcs</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=k>new</span><span class=p>();</span>
</span><span id=__span-2-8><a id=__codelineno-2-8 name=__codelineno-2-8></a><span class=w> </span><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>Instance</span><span class=p>.</span><span class=n>RunOnMainThread</span><span class=p>(()</span><span class=w> </span><span class=o>=></span>
</span><span id=__span-2-9><a id=__codelineno-2-9 name=__codelineno-2-9></a><span class=w> </span><span class=p>{</span>
</span><span id=__span-2-10><a id=__codelineno-2-10 name=__codelineno-2-10></a><span class=w> </span><span class=n>tcs</span><span class=p>.</span><span class=n>SetResult</span><span class=p>(</span><span class=n>Object</span><span class=p>.</span><span class=n>Instantiate</span><span class=p>(</span><span class=n>asset</span><span class=p>));</span>
</span><span id=__span-2-11><a id=__codelineno-2-11 name=__codelineno-2-11></a><span class=w> </span><span class=p>});</span>
</span><span id=__span-2-12><a id=__codelineno-2-12 name=__codelineno-2-12></a>
</span><span id=__span-2-13><a id=__codelineno-2-13 name=__codelineno-2-13></a><span class=w> </span><span class=k>return</span><span class=w> </span><span class=k>await</span><span class=w> </span><span class=n>tcs</span><span class=p>.</span><span class=n>Task</span><span class=p>;</span>
</span><span id=__span-2-14><a id=__codelineno-2-14 name=__codelineno-2-14></a><span class=p>}</span>
</span><span id=__span-2-15><a id=__codelineno-2-15 name=__codelineno-2-15></a>
</span><span id=__span-2-16><a id=__codelineno-2-16 name=__codelineno-2-16></a><span class=c1>// Thread Pool work</span>
</span><span id=__span-2-17><a id=__codelineno-2-17 name=__codelineno-2-17></a><span class=n>ThreadPool</span><span class=p>.</span><span class=n>QueueUserWorkItem</span><span class=p>(</span><span class=n>_</span><span class=w> </span><span class=o>=></span>
</span><span id=__span-2-18><a id=__codelineno-2-18 name=__codelineno-2-18></a><span class=p>{</span>
</span><span id=__span-2-19><a id=__codelineno-2-19 name=__codelineno-2-19></a><span class=w> </span><span class=n>ComputedData</span><span class=w> </span><span class=n>data</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>ProcessHeavyComputation</span><span class=p>();</span>
</span><span id=__span-2-20><a id=__codelineno-2-20 name=__codelineno-2-20></a>
</span><span id=__span-2-21><a id=__codelineno-2-21 name=__codelineno-2-21></a><span class=w> </span><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>Instance</span><span class=p>.</span><span class=n>RunOnMainThread</span><span class=p>(()</span><span class=w> </span><span class=o>=></span>
</span><span id=__span-2-22><a id=__codelineno-2-22 name=__codelineno-2-22></a><span class=w> </span><span class=p>{</span>
</span><span id=__span-2-23><a id=__codelineno-2-23 name=__codelineno-2-23></a><span class=w> </span><span class=n>ApplyToScene</span><span class=p>(</span><span class=n>data</span><span class=p>);</span><span class=w> </span><span class=c1>// Safe Unity API calls</span>
</span><span id=__span-2-24><a id=__codelineno-2-24 name=__codelineno-2-24></a><span class=w> </span><span class=p>});</span>
</span><span id=__span-2-25><a id=__codelineno-2-25 name=__codelineno-2-25></a><span class=p>});</span>
</span><span id=__span-2-26><a id=__codelineno-2-26 name=__codelineno-2-26></a>
</span><span id=__span-2-27><a id=__codelineno-2-27 name=__codelineno-2-27></a><span class=c1>// Task continuation</span>
</span><span id=__span-2-28><a id=__codelineno-2-28 name=__codelineno-2-28></a><span class=n>Task</span><span class=p>.</span><span class=n>Run</span><span class=p>(()</span><span class=w> </span><span class=o>=></span><span class=w> </span><span class=n>ComputeData</span><span class=p>())</span>
</span><span id=__span-2-29><a id=__codelineno-2-29 name=__codelineno-2-29></a><span class=w> </span><span class=p>.</span><span class=n>ContinueWith</span><span class=p>(</span><span class=n>task</span><span class=w> </span><span class=o>=></span>
</span><span id=__span-2-30><a id=__codelineno-2-30 name=__codelineno-2-30></a><span class=w> </span><span class=p>{</span>
</span><span id=__span-2-31><a id=__codelineno-2-31 name=__codelineno-2-31></a><span class=w> </span><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>Instance</span><span class=p>.</span><span class=n>RunOnMainThread</span><span class=p>(()</span><span class=w> </span><span class=o>=></span>
</span><span id=__span-2-32><a id=__codelineno-2-32 name=__codelineno-2-32></a><span class=w> </span><span class=p>{</span>
</span><span id=__span-2-33><a id=__codelineno-2-33 name=__codelineno-2-33></a><span class=w> </span><span class=n>DisplayResults</span><span class=p>(</span><span class=n>task</span><span class=p>.</span><span class=n>Result</span><span class=p>);</span>
</span><span id=__span-2-34><a id=__codelineno-2-34 name=__codelineno-2-34></a><span class=w> </span><span class=p>});</span>
</span><span id=__span-2-35><a id=__codelineno-2-35 name=__codelineno-2-35></a><span class=w> </span><span class=p>});</span>
</span></code></pre></div></td></tr></table></div> <h2 id=unitymainthreadguard>UnityMainThreadGuard<a class=headerlink href=#unitymainthreadguard title="Permanent link">¶</a></h2> <p>The <code>UnityMainThreadGuard</code> is a <strong>guard/assertion</strong> that throws an exception if called from a background thread. Use it to protect Unity API access points that must never be called off-thread.</p> <blockquote> <p>⚠️ <strong>Important:</strong> <code>EnsureMainThread()</code> does NOT dispatch work to the main thread. It throws <code>InvalidOperationException</code> if called from a background thread. To dispatch work, use <code>UnityMainThreadDispatcher.Instance.RunOnMainThread()</code>.</p> <p>📦 <strong>Internal API:</strong> <code>UnityMainThreadGuard</code> is an <code>internal</code> class, accessible only within the Unity Helpers assembly or via <code>[InternalsVisibleTo]</code>. For most use cases, prefer using <code>UnityMainThreadDispatcher</code> directly which is <code>public</code>.</p> </blockquote> <h3 id=basic-usage_1>Basic Usage<a class=headerlink href=#basic-usage_1 title="Permanent link">¶</a></h3> <div class="language-csharp highlight"><table class=highlighttable><tr><th colspan=2 class=filename><span class=filename>C#</span></th></tr><tr><td class=linenos><div class=linenodiv><pre><span></span><span class=normal><a href=#__codelineno-3-1> 1</a></span>
<span class=normal><a href=#__codelineno-3-2> 2</a></span>
<span class=normal><a href=#__codelineno-3-3> 3</a></span>
<span class=normal><a href=#__codelineno-3-4> 4</a></span>
<span class=normal><a href=#__codelineno-3-5> 5</a></span>
<span class=normal><a href=#__codelineno-3-6> 6</a></span>
<span class=normal><a href=#__codelineno-3-7> 7</a></span>
<span class=normal><a href=#__codelineno-3-8> 8</a></span>
<span class=normal><a href=#__codelineno-3-9> 9</a></span>
<span class=normal><a href=#__codelineno-3-10>10</a></span>
<span class=normal><a href=#__codelineno-3-11>11</a></span>
<span class=normal><a href=#__codelineno-3-12>12</a></span>
<span class=normal><a href=#__codelineno-3-13>13</a></span>
<span class=normal><a href=#__codelineno-3-14>14</a></span>
<span class=normal><a href=#__codelineno-3-15>15</a></span>
<span class=normal><a href=#__codelineno-3-16>16</a></span>
<span class=normal><a href=#__codelineno-3-17>17</a></span>
<span class=normal><a href=#__codelineno-3-18>18</a></span>
<span class=normal><a href=#__codelineno-3-19>19</a></span>
<span class=normal><a href=#__codelineno-3-20>20</a></span>
<span class=normal><a href=#__codelineno-3-21>21</a></span>
<span class=normal><a href=#__codelineno-3-22>22</a></span>
<span class=normal><a href=#__codelineno-3-23>23</a></span></pre></div></td><td class=code><div><pre><span></span><code><span id=__span-3-1><a id=__codelineno-3-1 name=__codelineno-3-1></a><span class=k>using</span><span class=w> </span><span class=nn>WallstopStudios.UnityHelpers.Core.Helper</span><span class=p>;</span>
</span><span id=__span-3-2><a id=__codelineno-3-2 name=__codelineno-3-2></a>
</span><span id=__span-3-3><a id=__codelineno-3-3 name=__codelineno-3-3></a><span class=k>public</span><span class=w> </span><span class=k>class</span><span class=w> </span><span class=nc>PlayerManager</span>
</span><span id=__span-3-4><a id=__codelineno-3-4 name=__codelineno-3-4></a><span class=p>{</span>
</span><span id=__span-3-5><a id=__codelineno-3-5 name=__codelineno-3-5></a><span class=w> </span><span class=k>private</span><span class=w> </span><span class=n>Player</span><span class=w> </span><span class=n>_cachedPlayer</span><span class=p>;</span>
</span><span id=__span-3-6><a id=__codelineno-3-6 name=__codelineno-3-6></a>
</span><span id=__span-3-7><a id=__codelineno-3-7 name=__codelineno-3-7></a><span class=w> </span><span class=k>public</span><span class=w> </span><span class=n>Player</span><span class=w> </span><span class=n>Instance</span>
</span><span id=__span-3-8><a id=__codelineno-3-8 name=__codelineno-3-8></a><span class=w> </span><span class=p>{</span>
</span><span id=__span-3-9><a id=__codelineno-3-9 name=__codelineno-3-9></a><span class=w> </span><span class=k>get</span>
</span><span id=__span-3-10><a id=__codelineno-3-10 name=__codelineno-3-10></a><span class=w> </span><span class=p>{</span>
</span><span id=__span-3-11><a id=__codelineno-3-11 name=__codelineno-3-11></a><span class=w> </span><span class=c1>// Throws if accessed from background thread</span>
</span><span id=__span-3-12><a id=__codelineno-3-12 name=__codelineno-3-12></a><span class=w> </span><span class=n>UnityMainThreadGuard</span><span class=p>.</span><span class=n>EnsureMainThread</span><span class=p>();</span>
</span><span id=__span-3-13><a id=__codelineno-3-13 name=__codelineno-3-13></a><span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>_cachedPlayer</span><span class=p>;</span>
</span><span id=__span-3-14><a id=__codelineno-3-14 name=__codelineno-3-14></a><span class=w> </span><span class=p>}</span>
</span><span id=__span-3-15><a id=__codelineno-3-15 name=__codelineno-3-15></a><span class=w> </span><span class=p>}</span>
</span><span id=__span-3-16><a id=__codelineno-3-16 name=__codelineno-3-16></a>
</span><span id=__span-3-17><a id=__codelineno-3-17 name=__codelineno-3-17></a><span class=w> </span><span class=k>public</span><span class=w> </span><span class=k>void</span><span class=w> </span><span class=nf>RefreshUI</span><span class=p>()</span>
</span><span id=__span-3-18><a id=__codelineno-3-18 name=__codelineno-3-18></a><span class=w> </span><span class=p>{</span>
</span><span id=__span-3-19><a id=__codelineno-3-19 name=__codelineno-3-19></a><span class=w> </span><span class=c1>// Optional context string for better error messages</span>
</span><span id=__span-3-20><a id=__codelineno-3-20 name=__codelineno-3-20></a><span class=w> </span><span class=n>UnityMainThreadGuard</span><span class=p>.</span><span class=n>EnsureMainThread</span><span class=p>(</span><span class=s>"Refreshing player UI"</span><span class=p>);</span>
</span><span id=__span-3-21><a id=__codelineno-3-21 name=__codelineno-3-21></a><span class=w> </span><span class=c1>// Safe to interact with Unity objects here</span>
</span><span id=__span-3-22><a id=__codelineno-3-22 name=__codelineno-3-22></a><span class=w> </span><span class=p>}</span>
</span><span id=__span-3-23><a id=__codelineno-3-23 name=__codelineno-3-23></a><span class=p>}</span>
</span></code></pre></div></td></tr></table></div> <h3 id=why-it-exists>Why It Exists<a class=headerlink href=#why-it-exists title="Permanent link">¶</a></h3> <p><strong>Problem:</strong> Unity APIs must be called from the main thread, but bugs can allow background thread access that causes silent corruption or crashes.</p> <p><strong>Solution:</strong> <code>UnityMainThreadGuard.EnsureMainThread()</code> fails fast with a clear error message, catching threading bugs during development.</p> <h3 id=api_1>API<a class=headerlink href=#api_1 title="Permanent link">¶</a></h3> <div class="language-csharp highlight"><table class=highlighttable><tr><th colspan=2 class=filename><span class=filename>C#</span></th></tr><tr><td class=linenos><div class=linenodiv><pre><span></span><span class=normal><a href=#__codelineno-4-1>1</a></span>
<span class=normal><a href=#__codelineno-4-2>2</a></span>
<span class=normal><a href=#__codelineno-4-3>3</a></span>
<span class=normal><a href=#__codelineno-4-4>4</a></span>
<span class=normal><a href=#__codelineno-4-5>5</a></span>
<span class=normal><a href=#__codelineno-4-6>6</a></span></pre></div></td><td class=code><div><pre><span></span><code><span id=__span-4-1><a id=__codelineno-4-1 name=__codelineno-4-1></a><span class=c1>// Throws InvalidOperationException if not on main thread</span>
</span><span id=__span-4-2><a id=__codelineno-4-2 name=__codelineno-4-2></a><span class=n>UnityMainThreadGuard</span><span class=p>.</span><span class=n>EnsureMainThread</span><span class=p>();</span>
</span><span id=__span-4-3><a id=__codelineno-4-3 name=__codelineno-4-3></a><span class=n>UnityMainThreadGuard</span><span class=p>.</span><span class=n>EnsureMainThread</span><span class=p>(</span><span class=s>"optional context"</span><span class=p>);</span>
</span><span id=__span-4-4><a id=__codelineno-4-4 name=__codelineno-4-4></a>
</span><span id=__span-4-5><a id=__codelineno-4-5 name=__codelineno-4-5></a><span class=c1>// Check without throwing (internal API)</span>
</span><span id=__span-4-6><a id=__codelineno-4-6 name=__codelineno-4-6></a><span class=kt>bool</span><span class=w> </span><span class=n>isMainThread</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>UnityMainThreadGuard</span><span class=p>.</span><span class=n>IsMainThread</span><span class=p>;</span>
</span></code></pre></div></td></tr></table></div> <h2 id=default-bootstrapping-flow>Default Bootstrapping Flow<a class=headerlink href=#default-bootstrapping-flow title="Permanent link">¶</a></h2> <ul> <li>A <code>[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]</code> (<code>EnsureDispatcherBootstrap</code>) spins up the dispatcher before user assemblies receive their own <code>RuntimeInitializeOnLoadMethod</code> callbacks. This guarantees that worker threads can enqueue diagnostics as soon as your game loads.</li> <li>Inside the editor, <code>[InitializeOnLoadMethod]</code> (<code>EnsureDispatcherBootstrapInEditor</code>) mirrors the same behavior for Edit Mode tools. The bootstrap politely skips when play mode is already running, so it does not duplicate the instance scene-side.</li> <li>Both entry points run through <code>UnityMainThreadGuard.EnsureMainThread(...)</code> before touching Unity APIs, so the dispatcher is always created on the real main thread even when background code tries to force instantiation.</li> </ul> <p>With no configuration, the dispatcher therefore always exists, enforces the queue bound exposed via <code>PendingActionLimit</code>, and is hidden from the hierarchy during Edit Mode by <code>HideFlags.HideInHierarchy | HideFlags.HideInInspector | HideFlags.NotEditable</code>.</p> <h2 id=opting-inout-of-auto-creation>Opting In/Out of Auto-Creation<a class=headerlink href=#opting-inout-of-auto-creation title="Permanent link">¶</a></h2> <p>Occasionally (especially in tests) you want to control exactly when the dispatcher is created so that scenes unload cleanly and Unity does not warn about hidden objects surviving domain reloads. Use the internal switch:</p> <div class="language-csharp highlight"><table class=highlighttable><tr><th colspan=2 class=filename><span class=filename>C#</span></th></tr><tr><td class=linenos><div class=linenodiv><pre><span></span><span class=normal><a href=#__codelineno-5-1>1</a></span>
<span class=normal><a href=#__codelineno-5-2>2</a></span>
<span class=normal><a href=#__codelineno-5-3>3</a></span></pre></div></td><td class=code><div><pre><span></span><code><span id=__span-5-1><a id=__codelineno-5-1 name=__codelineno-5-1></a><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>SetAutoCreationEnabled</span><span class=p>(</span><span class=k>false</span><span class=p>);</span>
</span><span id=__span-5-2><a id=__codelineno-5-2 name=__codelineno-5-2></a><span class=c1>// ... destroy any dispatcher instance if you want a completely clean slate ...</span>
</span><span id=__span-5-3><a id=__codelineno-5-3 name=__codelineno-5-3></a><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>SetAutoCreationEnabled</span><span class=p>(</span><span class=k>true</span><span class=p>);</span>
</span></code></pre></div></td></tr></table></div> <ul> <li>The toggle is global to the current domain; disabling it prevents the runtime/editor bootstrap hooks from creating fresh GameObjects.</li> <li>When you re-enable auto-creation the very next call to <code>UnityMainThreadDispatcher.Instance</code> will recreate the singleton on the main thread (and Play Mode bootstrap will recreate it on the following domain reload).</li> <li>Always destroy the existing dispatcher GameObject (<code>UnityMainThreadDispatcher.DestroyExistingDispatcher</code> or the test helper) before turning the feature back on so that stale instances are removed from <code>Resources.FindObjectsOfTypeAll</code>.</li> </ul> <h3 id=autocreationscope-scoped-toggles>AutoCreationScope (scoped toggles)<a class=headerlink href=#autocreationscope-scoped-toggles title="Permanent link">¶</a></h3> <p><code>UnityMainThreadDispatcher.AutoCreationScope</code> wraps the toggle/cleanup pattern above in an <code>IDisposable</code> so you cannot forget to restore the previous state:</p> <div class="language-csharp highlight"><table class=highlighttable><tr><th colspan=2 class=filename><span class=filename>C#</span></th></tr><tr><td class=linenos><div class=linenodiv><pre><span></span><span class=normal><a href=#__codelineno-6-1>1</a></span>
<span class=normal><a href=#__codelineno-6-2>2</a></span>
<span class=normal><a href=#__codelineno-6-3>3</a></span>
<span class=normal><a href=#__codelineno-6-4>4</a></span>
<span class=normal><a href=#__codelineno-6-5>5</a></span>
<span class=normal><a href=#__codelineno-6-6>6</a></span>
<span class=normal><a href=#__codelineno-6-7>7</a></span>
<span class=normal><a href=#__codelineno-6-8>8</a></span></pre></div></td><td class=code><div><pre><span></span><code><span id=__span-6-1><a id=__codelineno-6-1 name=__codelineno-6-1></a><span class=k>using</span><span class=w> </span><span class=nn>UnityMainThreadDispatcher.AutoCreationScope</span><span class=w> </span><span class=n>scope</span><span class=w> </span><span class=o>=</span>
</span><span id=__span-6-2><a id=__codelineno-6-2 name=__codelineno-6-2></a><span class=w> </span><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>AutoCreationScope</span><span class=p>.</span><span class=n>Disabled</span><span class=p>(</span>
</span><span id=__span-6-3><a id=__codelineno-6-3 name=__codelineno-6-3></a><span class=w> </span><span class=n>destroyExistingInstanceOnEnter</span><span class=p>:</span><span class=w> </span><span class=k>true</span><span class=p>,</span>
</span><span id=__span-6-4><a id=__codelineno-6-4 name=__codelineno-6-4></a><span class=w> </span><span class=n>destroyInstancesOnDispose</span><span class=p>:</span><span class=w> </span><span class=k>true</span><span class=p>,</span>
</span><span id=__span-6-5><a id=__codelineno-6-5 name=__codelineno-6-5></a><span class=w> </span><span class=n>destroyImmediate</span><span class=p>:</span><span class=w> </span><span class=k>true</span><span class=w> </span><span class=c1>// prefer true in tests, false in runtime code</span>
</span><span id=__span-6-6><a id=__codelineno-6-6 name=__codelineno-6-6></a><span class=w> </span><span class=p>);</span>
</span><span id=__span-6-7><a id=__codelineno-6-7 name=__codelineno-6-7></a>
</span><span id=__span-6-8><a id=__codelineno-6-8 name=__codelineno-6-8></a><span class=c1>// Auto-creation is disabled inside the scope; manually enable or create instances as needed.</span>
</span></code></pre></div></td></tr></table></div> <ul> <li>On enter, the scope captures the previous <code>AutoCreationEnabled</code> value, switches to the desired state, and optionally destroys any existing dispatcher instances.</li> <li>On dispose, the scope restores the original toggle and (when requested) destroys any dispatcher that may have been created during the scoped work, ensuring follow-up tests inherit a clean slate.</li> </ul> <h2 id=test-bootstrap-workflow>Test Bootstrap Workflow<a class=headerlink href=#test-bootstrap-workflow title="Permanent link">¶</a></h2> <p>Two dedicated bootstraps live under <code>Tests/*/TestUtils</code> and keep dispatcher lifetimes predictable during automated suites:</p> <h3 id=runtime-playmode-testsruntimetestutilsunitymainthreaddispatchertestbootstrapcs>Runtime / PlayMode (<code>Tests/Runtime/TestUtils/UnityMainThreadDispatcherTestBootstrap.cs</code>)<a class=headerlink href=#runtime-playmode-testsruntimetestutilsunitymainthreaddispatchertestbootstrapcs title="Permanent link">¶</a></h3> <div class="language-csharp highlight"><table class=highlighttable><tr><th colspan=2 class=filename><span class=filename>C#</span></th></tr><tr><td class=linenos><div class=linenodiv><pre><span></span><span class=normal><a href=#__codelineno-7-1>1</a></span>
<span class=normal><a href=#__codelineno-7-2>2</a></span>
<span class=normal><a href=#__codelineno-7-3>3</a></span>
<span class=normal><a href=#__codelineno-7-4>4</a></span>
<span class=normal><a href=#__codelineno-7-5>5</a></span>
<span class=normal><a href=#__codelineno-7-6>6</a></span></pre></div></td><td class=code><div><pre><span></span><code><span id=__span-7-1><a id=__codelineno-7-1 name=__codelineno-7-1></a><span class=na>[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]</span>
</span><span id=__span-7-2><a id=__codelineno-7-2 name=__codelineno-7-2></a><span class=k>private</span><span class=w> </span><span class=k>static</span><span class=w> </span><span class=k>void</span><span class=w> </span><span class=nf>DisableAutoCreation</span><span class=p>()</span>
</span><span id=__span-7-3><a id=__codelineno-7-3 name=__codelineno-7-3></a><span class=p>{</span>
</span><span id=__span-7-4><a id=__codelineno-7-4 name=__codelineno-7-4></a><span class=w> </span><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>SetAutoCreationEnabled</span><span class=p>(</span><span class=k>false</span><span class=p>);</span>
</span><span id=__span-7-5><a id=__codelineno-7-5 name=__codelineno-7-5></a><span class=w> </span><span class=n>UnityMainThreadDispatcherTestHelper</span><span class=p>.</span><span class=n>DestroyDispatcherIfExists</span><span class=p>(</span><span class=n>immediate</span><span class=p>:</span><span class=w> </span><span class=k>true</span><span class=p>);</span>
</span><span id=__span-7-6><a id=__codelineno-7-6 name=__codelineno-7-6></a><span class=p>}</span>
</span></code></pre></div></td></tr></table></div> <ul> <li>Runs before every play-mode domain reload.</li> <li>Forces any hidden dispatcher left over from a prior scene to be <code>DestroyImmediate</code>'d so play-mode tests can opt into dispatcher usage explicitly.</li> <li>Guarantees a clean slate for suites that create and destroy scenes repeatedly (see <code>CommonTestBase.BaseSetUp</code>).</li> </ul> <h3 id=editor-editmode-testseditortestutilsunitymainthreaddispatchereditortestbootstrapcs>Editor / EditMode (<code>Tests/Editor/TestUtils/UnityMainThreadDispatcherEditorTestBootstrap.cs</code>)<a class=headerlink href=#editor-editmode-testseditortestutilsunitymainthreaddispatchereditortestbootstrapcs title="Permanent link">¶</a></h3> <div class="language-csharp highlight"><table class=highlighttable><tr><th colspan=2 class=filename><span class=filename>C#</span></th></tr><tr><td class=linenos><div class=linenodiv><pre><span></span><span class=normal><a href=#__codelineno-8-1>1</a></span>
<span class=normal><a href=#__codelineno-8-2>2</a></span>
<span class=normal><a href=#__codelineno-8-3>3</a></span>
<span class=normal><a href=#__codelineno-8-4>4</a></span>
<span class=normal><a href=#__codelineno-8-5>5</a></span>
<span class=normal><a href=#__codelineno-8-6>6</a></span>
<span class=normal><a href=#__codelineno-8-7>7</a></span>
<span class=normal><a href=#__codelineno-8-8>8</a></span>
<span class=normal><a href=#__codelineno-8-9>9</a></span></pre></div></td><td class=code><div><pre><span></span><code><span id=__span-8-1><a id=__codelineno-8-1 name=__codelineno-8-1></a><span class=na>[InitializeOnLoad]</span>
</span><span id=__span-8-2><a id=__codelineno-8-2 name=__codelineno-8-2></a><span class=k>internal</span><span class=w> </span><span class=k>static</span><span class=w> </span><span class=k>class</span><span class=w> </span><span class=nc>UnityMainThreadDispatcherEditorTestBootstrap</span>
</span><span id=__span-8-3><a id=__codelineno-8-3 name=__codelineno-8-3></a><span class=p>{</span>
</span><span id=__span-8-4><a id=__codelineno-8-4 name=__codelineno-8-4></a><span class=w> </span><span class=k>static</span><span class=w> </span><span class=nf>UnityMainThreadDispatcherEditorTestBootstrap</span><span class=p>()</span>
</span><span id=__span-8-5><a id=__codelineno-8-5 name=__codelineno-8-5></a><span class=w> </span><span class=p>{</span>
</span><span id=__span-8-6><a id=__codelineno-8-6 name=__codelineno-8-6></a><span class=w> </span><span class=n>UnityMainThreadDispatcher</span><span class=p>.</span><span class=n>SetAutoCreationEnabled</span><span class=p>(</span><span class=k>false</span><span class=p>);</span>
</span><span id=__span-8-7><a id=__codelineno-8-7 name=__codelineno-8-7></a><span class=w> </span><span class=c1>// DestroyImmediate the hidden dispatcher object, if any.</span>
</span><span id=__span-8-8><a id=__codelineno-8-8 name=__codelineno-8-8></a><span class=w> </span><span class=p>}</span>
</span><span id=__span-8-9><a id=__codelineno-8-9 name=__codelineno-8-9></a><span class=p>}</span>
</span></code></pre></div></td></tr></table></div> <ul> <li>Executes once per editor domain reload (before EditMode tests run).</li> <li>Ensures the hidden dispatcher object is removed from the hierarchy so Unity's test runner does not flag leaked objects between assemblies.</li> </ul> <p><a id=testing-patterns></a></p> <h3 id=re-enabling-per-test>Re-enabling per Test<a class=headerlink href=#re-enabling-per-test title="Permanent link">¶</a></h3> <p>The runtime and editor <code>CommonTestBase</code> fixtures demonstrate the intended per-test lifecycle via <code>UnityMainThreadDispatcher.AutoCreationScope</code>:</p> <ol> <li>At <code>[SetUp]</code> it grabs <code>UnityMainThreadDispatcher.CreateTestScope(destroyImmediate: true)</code> which internally disables auto-creation, destroys stragglers, and then re-enables auto-creation so the test can access <code>Instance</code> normally.</li> <li>Production code can create/destroy the dispatcher freely; the scope tracks everything automatically.</li> <li>During every teardown stage it disposes the scope, restoring the previous auto-creation flag and destroying any dispatcher created while the test runs — no manual try/finally blocks required.</li> </ol> <p>Downstream packages can copy the exact pattern:</p> <ol> <li>Add a <code>[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]</code> that disables auto-creation and destroys lingering instances.</li> <li>Add an <code>[InitializeOnLoad]</code> editor bootstrap that mirrors the same behavior for Edit Mode.</li> <li>When a single test needs to temporarily disable the dispatcher, wrap the custom logic in <code>using var scope = UnityMainThreadDispatcher.AutoCreationScope.Disabled(...)</code> so cleanup always runs.</li> </ol> <p>Following this workflow keeps Unity from warning about hidden GameObjects during test teardown, prevents worker threads from instantiating the dispatcher off-thread, and documents exactly when auto-creation is in effect for your package.</p> <aside class=md-source-file> <span class=md-source-file__fact> <span class=md-icon title="Last update"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1zM12.5 7v5.2l4 2.4-1 1L11 13V7zM11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-timeago" title="January 26, 2026 05:34:01 UTC"><span class=timeago datetime=2026-01-26T05:34:01+00:00 locale=en></span></span><span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-iso_date" title="January 26, 2026 05:34:01 UTC">2026-01-26</span> </span> <span class=md-source-file__fact> <span class=md-icon title=Created> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M14.47 15.08 11 13V7h1.5v5.25l3.08 1.83c-.41.28-.79.62-1.11 1m-1.39 4.84c-.36.05-.71.08-1.08.08-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8c0 .37-.03.72-.08 1.08.69.1 1.33.32 1.92.64.1-.56.16-1.13.16-1.72 0-5.5-4.5-10-10-10S2 6.5 2 12s4.47 10 10 10c.59 0 1.16-.06 1.72-.16-.32-.59-.54-1.23-.64-1.92M18 15v3h-3v2h3v3h2v-3h3v-2h-3v-3z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-timeago" title="December 25, 2025 20:02:30 UTC"><span class=timeago datetime=2025-12-25T20:02:30+00:00 locale=en></span></span><span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-iso_date" title="December 25, 2025 20:02:30 UTC">2025-12-25</span> </span> </aside> </article> </div> <script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script> <script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script> </div> <button type=button class="md-top md-icon" data-md-component=top hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg> Back to top </button> </main> <footer class=md-footer> <nav class="md-footer__inner md-grid" aria-label=Footer> <a href=../logging-extensions/ class="md-footer__link md-footer__link--prev" aria-label="Previous: Logging Extensions"> <div class="md-footer__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg> </div> <div class=md-footer__title> <span class=md-footer__direction> Previous </span> <div class=md-ellipsis> Logging Extensions </div> </div> </a> <a href=../../editor-tools/editor-tools-guide/ class="md-footer__link md-footer__link--next" aria-label="Next: Tools Guide"> <div class=md-footer__title> <span class=md-footer__direction> Next </span> <div class=md-ellipsis> Tools Guide </div> </div> <div class="md-footer__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg> </div> </a> </nav> <div class="md-footer-meta md-typeset"> <div class="md-footer-meta__inner md-grid"> <div class=md-copyright> <div class=md-copyright__highlight> Copyright © 2024-2026 Wallstop Studios - MIT License </div> </div> <div class=md-social> <a href=https://github.com/wallstop/unity-helpers target=_blank rel=noopener title="Unity Helpers on GitHub" class=md-social__link> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 512 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </a> </div> </div> </div> </footer> </div> <div class=md-dialog data-md-component=dialog> <div class="md-dialog__inner md-typeset"></div> </div> <div class=md-progress data-md-component=progress role=progressbar></div> <script id=__config type=application/json>{"annotate": null, "base": "../../..", "features": ["navigation.instant", "navigation.instant.prefetch", "navigation.instant.progress", "navigation.tracking", "navigation.tabs", "navigation.tabs.sticky", "navigation.sections", "navigation.expand", "navigation.path", "navigation.indexes", "navigation.top", "navigation.footer", "toc.follow", "toc.integrate", "search.suggest", "search.highlight", "search.share", "header.autohide", "content.code.copy", "content.code.annotate", "content.tabs.link", "content.tooltips", "content.action.edit", "content.action.view"], "search": "../../../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script> <script src=../../../assets/javascripts/bundle.79ae519e.min.js></script> <script src=../../../js/timeago.min.js></script> <script src=../../../js/timeago_mkdocs_material.js></script> <script src=https://unpkg.com/mermaid@10/dist/mermaid.min.js></script> </body> </html>