├── .gitignore
├── Assets
└── SplashExample
│ └── textures
│ ├── InitialSplash.dds
│ ├── InitialSplash.dds.cryasset
│ ├── InitialSplash.tif
│ ├── Splash.dds
│ ├── Splash.dds.cryasset
│ └── Splash.tif
├── Code
├── CMakeLists.txt
├── Plugin.cpp
├── Plugin.h
├── SplashExample.cpp
├── SplashExample.h
├── SplashExample.vcxproj.user.in
├── StdAfx.cpp
├── StdAfx.h
└── cvars.h
├── Docs
├── CONCEPT.txt
├── INSTALL.txt
└── MIGRATION_NOTES.txt
├── LICENSE.txt
├── SplashExamplePlugin.cryproject
├── SplashExamplePlugin_GameSDK.cryproject
├── SplashExamplePlugin_GameZero.cryproject
└── readme.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build specific files, we only want source code tracked
2 | *.lib
3 | *.pdb
4 | /Solutions/*
5 | /Release/*
6 | /Backup/*
7 | *.sln
8 | *.lnk
9 | *.ilk
10 | *.exp
--------------------------------------------------------------------------------
/Assets/SplashExample/textures/InitialSplash.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uniflare/SplashExample/b4d5a59b8e3c730e14698bde0681695b01e0ae4d/Assets/SplashExample/textures/InitialSplash.dds
--------------------------------------------------------------------------------
/Assets/SplashExample/textures/InitialSplash.dds.cryasset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 512
7 | 300
8 | 1
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Assets/SplashExample/textures/InitialSplash.tif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uniflare/SplashExample/b4d5a59b8e3c730e14698bde0681695b01e0ae4d/Assets/SplashExample/textures/InitialSplash.tif
--------------------------------------------------------------------------------
/Assets/SplashExample/textures/Splash.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uniflare/SplashExample/b4d5a59b8e3c730e14698bde0681695b01e0ae4d/Assets/SplashExample/textures/Splash.dds
--------------------------------------------------------------------------------
/Assets/SplashExample/textures/Splash.dds.cryasset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 2560
7 | 1440
8 | 1
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Assets/SplashExample/textures/Splash.tif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uniflare/SplashExample/b4d5a59b8e3c730e14698bde0681695b01e0ae4d/Assets/SplashExample/textures/Splash.tif
--------------------------------------------------------------------------------
/Code/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 3.6.2)
2 | set(CRYENGINE_DIR "C:/Program Files (x86)/Crytek/CRYENGINE Launcher/Crytek/CRYENGINE_5.4")
3 | set(TOOLS_CMAKE_DIR "${CRYENGINE_DIR}/Tools/CMake")
4 |
5 | set(PROJECT_BUILD 1)
6 | set(PROJECT_DIR "C:/dev/git/sf/SplashExample")
7 |
8 | include("${TOOLS_CMAKE_DIR}/CommonOptions.cmake")
9 |
10 | add_subdirectory("${CRYENGINE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/CRYENGINE")
11 |
12 | include("${TOOLS_CMAKE_DIR}/Configure.cmake")
13 | start_sources()
14 |
15 | sources_platform(ALL)
16 | add_sources("Code_uber.cpp"
17 | PROJECTS SplashExamplePlugin
18 | SOURCE_GROUP "Root"
19 | "Plugin.cpp"
20 | "SplashExample.cpp"
21 | "StdAfx.cpp"
22 | "cvars.h"
23 | "Plugin.h"
24 | "SplashExample.h"
25 | "StdAfx.h"
26 | )
27 |
28 | end_sources()
29 |
30 | CryEngineModule(SplashExamplePlugin PCH "StdAfx.cpp" SOLUTION_FOLDER "Project")
31 |
32 | target_include_directories(${THIS_PROJECT}
33 | PRIVATE
34 | "${CRYENGINE_DIR}/Code/CryEngine/CryCommon"
35 | "${CRYENGINE_DIR}/Code/CryEngine/CryAction"
36 | "${CRYENGINE_DIR}/Code/CryEngine/CrySchematyc/Core/Interface"
37 | "${CRYENGINE_DIR}/Code/CryPlugins/CryDefaultEntities/Module"
38 | )
39 |
40 | # Set StartUp project in Visual Studio
41 |
42 | add_library(GameLauncher STATIC "${CRYENGINE_DIR}/Code/CryEngine/CryCommon/CryCore/Platform/platform.h")
43 | set_target_properties(GameLauncher PROPERTIES LINKER_LANGUAGE CXX)
44 | if (WIN32)
45 | set_visual_studio_debugger_command(GameLauncher "${CRYENGINE_DIR}/bin/win_x64/GameLauncher.exe" "-project \"C:/dev/git/sf/SplashExample/SplashExamplePlugin.cryproject\"")
46 | endif()
47 |
48 | add_library(Sandbox STATIC "${CRYENGINE_DIR}/Code/CryEngine/CryCommon/CryCore/Platform/platform.h")
49 | set_target_properties(Sandbox PROPERTIES LINKER_LANGUAGE CXX)
50 | if (WIN32)
51 | set_visual_studio_debugger_command(Sandbox "${CRYENGINE_DIR}/bin/win_x64/Sandbox.exe" "-project \"C:/dev/git/sf/SplashExample/SplashExamplePlugin.cryproject\"")
52 | endif()
53 |
54 | add_library(GameServer STATIC "${CRYENGINE_DIR}/Code/CryEngine/CryCommon/CryCore/Platform/platform.h")
55 | set_target_properties(GameServer PROPERTIES LINKER_LANGUAGE CXX)
56 | if (WIN32)
57 | set_visual_studio_debugger_command(GameServer "${CRYENGINE_DIR}/bin/win_x64/Game_Server.exe" "-project \"C:/dev/git/sf/SplashExample/SplashExamplePlugin.cryproject\"")
58 | endif()
59 |
60 | set_solution_startup_target(GameLauncher)
61 |
62 | if (WIN32)
63 | set_visual_studio_debugger_command( ${THIS_PROJECT} "${CRYENGINE_DIR}/bin/win_x64/GameLauncher.exe" "-project \"C:/dev/git/sf/SplashExample/SplashExamplePlugin.cryproject\"" )
64 | endif()
65 |
66 | #BEGIN-CUSTOM
67 | set (USE_TEST_PLATFORM_PROJECT "FALSE")
68 |
69 | set (TestPlatformRoot "C:/dev/git/sf/BLANKGAME/")
70 | set (TestPlatformPath "${TestPlatformRoot}bin/win_x64/")
71 | set (TestPlatformProject "${TestPlatformRoot}Game.cryproject")
72 |
73 | # Default to this project, if no test platform project is used
74 | if (NOT USE_TEST_PLATFORM_PROJECT)
75 | set (TestPlatformProject "${PROJECT_FILE}")
76 | endif()
77 |
78 | if(USE_TEST_PLATFORM_PROJECT)
79 | add_custom_command(TARGET ${THIS_PROJECT} POST_BUILD
80 | COMMAND "${CMAKE_COMMAND}" -E copy
81 | "$"
82 | "${TestPlatformPath}/$"
83 | COMMENT "Copying to test platform directory")
84 | endif(USE_TEST_PLATFORM_PROJECT)
85 | #END-CUSTOM
--------------------------------------------------------------------------------
/Code/Plugin.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017, uniflare, see LICENSE.txt for details
2 |
3 | #include "StdAfx.h"
4 |
5 | // Included only once per DLL module.
6 | #include
7 |
8 | #include "Plugin.h"
9 |
10 | ///////////////////////////////////////////////////////////////////////////
11 | //! Module constructor
12 | CPlugin_SplashExample::CPlugin_SplashExample()
13 | : m_sCVars()
14 | , m_pSplashExample(nullptr)
15 | {
16 | // Skip if we are in the editor
17 | if (gEnv->IsEditor())
18 | {
19 | CRY_LOG_ALWAYS("Editor mode detected. Skipping splash example.");
20 | return;
21 | }
22 | else if (gEnv->IsDedicated())
23 | {
24 | CRY_LOG_ALWAYS("Dedicated mode detected. Skipping splash example.");
25 | return;
26 | }
27 |
28 | m_pSplashExample = CryAlignedNew();
29 | }
30 |
31 | ///////////////////////////////////////////////////////////////////////////
32 | //! Module destructor
33 | CPlugin_SplashExample::~CPlugin_SplashExample()
34 | {
35 | SAFE_DELETE(m_pSplashExample);
36 | // ~m_sCVars(); (stack)
37 | }
38 |
39 | ///////////////////////////////////////////////////////////////////////////
40 | //! ICryPlugin override
41 | bool CPlugin_SplashExample::Initialize(SSystemGlobalEnvironment& env, const SSystemInitParams& initParams)
42 | {
43 | if (m_pSplashExample)
44 | return m_pSplashExample->Initialize(env, initParams);
45 | return true;
46 | }
47 |
48 | CRYREGISTER_SINGLETON_CLASS(CPlugin_SplashExample)
--------------------------------------------------------------------------------
/Code/Plugin.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017, uniflare, see LICENSE.txt for details
2 |
3 | #pragma once
4 | #include "CVars.h"
5 | #include "SplashExample.h"
6 |
7 | #include
8 | #include
9 |
10 | class CSplashExample;
11 | class CPlugin_SplashExample
12 | : ICryPlugin
13 | {
14 | // Console variables provided by this object
15 | CVars m_sCVars;
16 |
17 | // reference to splash example implementation
18 | CSplashExample * m_pSplashExample;
19 | public:
20 | CRYINTERFACE_SIMPLE(ICryPlugin)
21 | CRYGENERATE_SINGLETONCLASS_GUID(CPlugin_SplashExample, "Plugin_SplashExample", "{ 53706C61 - 7368 - 2045 - 7861 - 6D706C650000 }"_cry_guid)
22 |
23 | // ICryPlugin
24 | virtual const char* GetName() const override { return "Splash Example Plugin"; }
25 | virtual const char* GetCategory() const override { return "Game"; }
26 | virtual bool Initialize(SSystemGlobalEnvironment& env, const SSystemInitParams& initParams) override;
27 | virtual void OnPluginUpdate(EPluginUpdateType updateType) override {}
28 | // ~ICryPlugin
29 |
30 | CPlugin_SplashExample();
31 | virtual ~CPlugin_SplashExample();
32 | };
--------------------------------------------------------------------------------
/Code/SplashExample.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017, uniflare, see LICENSE.txt for details
2 |
3 | #include "StdAfx.h"
4 |
5 | #include "SplashExample.h"
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 |
15 | ///////////////////////////////////////////////////////////////////////////
16 | //! Default Constructor
17 | CSplashExample::CSplashExample() :
18 | m_sCVars()
19 | , m_bInitialized(false)
20 | , m_bSystemListenerRegistered(false)
21 | , m_bProfileListenerRegistered(false)
22 | , m_bLoadedProfileAttributes(false)
23 | , m_bIgnoreNextProfileSave(false)
24 | , m_pSplashTexture(nullptr)
25 | , m_pInitialSplashTexture(nullptr)
26 | , m_pProfileManager(nullptr)
27 | , m_pCurrentProfile(nullptr)
28 | , m_pDefaultProfile(nullptr)
29 | {
30 | }
31 |
32 | ///////////////////////////////////////////////////////////////////////////
33 | //! Destructor
34 | CSplashExample::~CSplashExample()
35 | {
36 | SafeReleaseSplashTextures();
37 | UnregisterProfileListener(this);
38 | UnregisterSystemListener(this);
39 | }
40 |
41 | ///////////////////////////////////////////////////////////////////////////
42 | //! Called from ICryPlugin interface
43 | bool CSplashExample::Initialize(SSystemGlobalEnvironment & env, const SSystemInitParams & initParams)
44 | {
45 | m_sCVars.Init();
46 |
47 | // Try to initialize splash example
48 | TryInitialize();
49 |
50 | return true;
51 | }
52 |
53 | ///////////////////////////////////////////////////////////////////////////
54 | //! Releases textures if possible, ensures nulled pointers.
55 | void CSplashExample::SafeReleaseSplashTextures()
56 | {
57 | // Release our textures (-1 ref count)
58 | if (m_pInitialSplashTexture)
59 | m_pInitialSplashTexture->Release();
60 |
61 | if (m_pSplashTexture)
62 | m_pSplashTexture->Release();
63 |
64 | m_pSplashTexture = m_pInitialSplashTexture = nullptr;
65 | }
66 |
67 | ///////////////////////////////////////////////////////////////////////////
68 | //! If plugin construction is ever moved upwards in system init, this will still be compatible.
69 | //! Also useful if any system/required components failed to init yet for any reason.
70 | void CSplashExample::TryInitialize()
71 | {
72 | CRY_LOG_CALL("CSplashExample::TryConstruct()");
73 |
74 | // Try to register our system listener, if we havn't managed to before now for some reason.
75 | RegisterSystemListener(this);
76 |
77 | // Only init once (Listener is required to function properly)
78 | if (!m_bInitialized && m_bSystemListenerRegistered)
79 | {
80 | ICryPak * pCryPak = gEnv->pCryPak;
81 | IConsole * pConsole = gEnv->pConsole;
82 | IRenderer * pRenderer = gEnv->pRenderer;
83 | ITimer * pTimer = gEnv->pTimer;
84 |
85 | // Only construct if the system is in a state we can use
86 | if (!pConsole)
87 | {
88 | CRY_LOG_DEBUG("pConsole has not initialized yet. Skipping construction.");
89 | return;
90 | }
91 |
92 | if(!pTimer)
93 | {
94 | CRY_LOG_DEBUG("pTimer has not initialized yet. Skipping construction.");
95 | return;
96 | }
97 |
98 | if (!pCryPak)
99 | {
100 | CRY_LOG_DEBUG("pCryPak has not initialized yet. Skipping construction.");
101 | return;
102 | }
103 |
104 | if (!pRenderer)
105 | {
106 | CRY_LOG_DEBUG("pRenderer has not initialized yet. Skipping construction.");
107 | return;
108 | }
109 |
110 | // Attempt to load our intial splash texture from CVar
111 | if (!m_pInitialSplashTexture && m_sCVars.m_iInitialSplashEnable > 0)
112 | {
113 | string InitialSplashTexturePath = m_sCVars.m_pInitialSplashTexturePath->GetString();
114 |
115 | if (pCryPak->IsFileExist(InitialSplashTexturePath))
116 | {
117 | m_pInitialSplashTexture = pRenderer->EF_LoadTexture(InitialSplashTexturePath, FT_DONT_STREAM | FT_NOMIPS);
118 | if (!m_pInitialSplashTexture)
119 | CRY_LOG_ERROR("Unable to load initial splash texture. Path '%s'", InitialSplashTexturePath);
120 | }
121 | else
122 | CRY_LOG_ERROR("Initial splash texture not found. Path: '%s'", InitialSplashTexturePath);
123 | }
124 |
125 | // Attempt to load our main splash texture from CVar
126 | if (!m_pSplashTexture && m_sCVars.m_iMainSplashEnable > 0)
127 | {
128 | string SplashTexturePath = m_sCVars.m_pSplashTexturePath->GetString();
129 | if (pCryPak->IsFileExist(SplashTexturePath))
130 | {
131 | m_pSplashTexture = pRenderer->EF_LoadTexture(SplashTexturePath, FT_DONT_STREAM | FT_NOMIPS);
132 | if (!m_pSplashTexture)
133 | {
134 | CRY_LOG_ERROR("Unable to load initial splash texture. Path '%s'", SplashTexturePath);
135 | }
136 | else
137 | {
138 | m_pSplashTexture->SetHighQualityFiltering(true);
139 | }
140 | }
141 | else
142 | CRY_LOG_ERROR("Splash texture not found. Path: '%s'", SplashTexturePath);
143 | }
144 |
145 | if (m_pSplashTexture)
146 | {
147 | pConsole->GetCVar("sys_rendersplashscreen")->Set(0); // Disable built-in splash screen routine
148 | }
149 |
150 | m_bInitialized = true;
151 | CRY_LOG_DEBUG("Constructed splash example.");
152 | }
153 | }
154 |
155 | ///////////////////////////////////////////////////////////////////////////
156 | //! Handles the initial splash display.
157 | void CSplashExample::DisplayInitialSplash(bool stallThread)
158 | {
159 | CRY_LOG_CALL("CSplashExample::DisplayInitialSplash()");
160 |
161 | if (m_pInitialSplashTexture)
162 | {
163 | // Set viewport to our initial splash texture size if not already.
164 | gEnv->pConsole->GetCVar("r_width")->Set(m_pInitialSplashTexture->GetWidth());
165 | gEnv->pConsole->GetCVar("r_height")->Set(m_pInitialSplashTexture->GetHeight());
166 | gEnv->pConsole->GetCVar("r_fullscreen")->Set(0); // Force window mode (Note this may bring us our of fullscreen if not disabled in cfg).
167 | gEnv->pConsole->GetCVar("r_fullscreenwindow")->Set(1); // Remove window border (Note same problem if not enabled in cfg).
168 |
169 | gEnv->pConsole->GetCVar("sys_rendersplashscreen")->Set(0); // Disable built-in splash screen routine
170 |
171 | // force window update
172 | gEnv->pRenderer->FlushRTCommands(true, false, false);
173 |
174 | if (!stallThread)
175 | {
176 | if (m_pInitialSplashTexture)
177 | {
178 | // Hide cursor immediately
179 | gEnv->pSystem->GetIHardwareMouse()->Hide(true);
180 |
181 | // Push a single frame with our texture to renderer
182 | gEnv->pRenderer->BeginFrame();
183 | Draw2DImage(m_pInitialSplashTexture, true);
184 | gEnv->pRenderer->EndFrame();
185 | }
186 | }
187 | else
188 | {
189 | CRY_LOG_DEBUG("Stalling thread for initial splash");
190 | if (!DrawAndStall(gEnv->pTimer->GetAsyncCurTime(), m_sCVars.m_fInitialSplashPlaybackTime, m_pInitialSplashTexture, true))
191 | return;
192 | }
193 | }
194 | }
195 |
196 | ///////////////////////////////////////////////////////////////////////////
197 | //! Handles the main splash display.
198 | void CSplashExample::DisplayMainSplash(const bool stallThread)
199 | {
200 | CRY_LOG_CALL("CSplashExample::DisplayMainSplash()");
201 |
202 | const SWindowProperties sWindowProperties = GetWindowProperties();
203 |
204 | // Propagate changes
205 | static bool bSetCVars = false;
206 | if (!bSetCVars)
207 | {
208 | gEnv->pConsole->GetCVar("r_fullscreen")->Set(sWindowProperties.sWindowMode.bFullscreen);
209 | CRY_LOG_DEBUG("Set Fullscreen CVar to profile setting ('%s')", CryStringUtils::toString(sWindowProperties.sWindowMode.bFullscreen));
210 | gEnv->pConsole->GetCVar("r_fullscreenwindow")->Set(sWindowProperties.sWindowMode.bHideWindowBorder);
211 | CRY_LOG_DEBUG("Set FullscreenWindow CVar to profile setting ('%s')", CryStringUtils::toString(sWindowProperties.sWindowMode.bHideWindowBorder));
212 | SetScreenResolution(sWindowProperties.sScreenResolution);
213 | CRY_LOG_DEBUG("Got splash resolution from profile setting ('%s')", sWindowProperties.sScreenResolution.sResolution);
214 | bSetCVars = true;
215 | }
216 |
217 | // This will update the window using any changed cvars
218 | gEnv->pRenderer->FlushRTCommands(false, true, true);
219 |
220 | if (m_pSplashTexture)
221 | {
222 | // Hide cursor
223 | gEnv->pSystem->GetIHardwareMouse()->Hide(true);
224 |
225 | if (!stallThread)
226 | {
227 | gEnv->pRenderer->BeginFrame();
228 | Draw2DImage(m_pSplashTexture);
229 | gEnv->pRenderer->EndFrame();
230 | }
231 | else
232 | {
233 | // Set the start time for render, note this is not an accurate stamp
234 | // for when the image is actually rendered to the screen so we can
235 | // apply an additional offset here.
236 | float StartTime = gEnv->pTimer->GetAsyncCurTime() + m_sCVars.m_fStartTimeOffset;
237 |
238 | // Get the minimum playback time
239 | float LengthTime = m_sCVars.m_fSplashPlaybackTime;
240 |
241 | CRY_LOG_DEBUG("Stalling thread for splash, (start=%s,Length=%s)", CryStringUtils::toString(StartTime), CryStringUtils::toString(LengthTime));
242 |
243 | // Stall the engine if we havn't shown our splash for enough time!
244 | DrawAndStall(StartTime, LengthTime, m_pSplashTexture, false);
245 |
246 | // After Stall...
247 |
248 | // Show cursor
249 | gEnv->pSystem->GetIHardwareMouse()->Hide(false);
250 |
251 | // Make sure we dont use this tex again!
252 | if (m_pSplashTexture) m_pSplashTexture->Release();
253 | m_pSplashTexture = nullptr;
254 |
255 | CRY_LOG_DEBUG("Finished main splash screen draw cycle.");
256 | }
257 | }
258 | }
259 |
260 | ///////////////////////////////////////////////////////////////////////////
261 | //! Draws the supplied texture in stretched mode to the main viewport
262 | void CSplashExample::Draw2DImage(const ITexture * pTex, bool bUseTextureSize) const
263 | {
264 | if (pTex)
265 | {
266 | int RenderWidth = gEnv->pRenderer->GetOverlayWidth();
267 | int RenderHeight = gEnv->pRenderer->GetOverlayHeight();
268 | int TextureWidth = pTex->GetWidth();
269 | int TextureHeight = pTex->GetHeight();
270 |
271 | float PosX = 0;
272 | float PosY = 0;
273 |
274 | if (TextureWidth > 0 && TextureHeight > 0 && RenderWidth > 0 && RenderHeight > 0)
275 | {
276 | if (bUseTextureSize)
277 | {
278 | // Get Center offsets from window size
279 | if (TextureWidth < RenderWidth)
280 | PosX = (float)(int)((RenderWidth - TextureWidth) / 2); // raw cast to int to floor, then float to suppress warnings
281 | if (TextureHeight < RenderHeight)
282 | PosY = (float)(int)((RenderHeight - TextureHeight) / 2); // raw cast to int to floor, then float to suppress warnings
283 |
284 | // Don't exceed renderable dimensions
285 | RenderWidth = min(TextureWidth, RenderWidth);
286 | RenderHeight = min(TextureHeight, RenderHeight);
287 | }
288 |
289 | //gEnv->pRenderer->SetViewport(0, 0, RenderWidth, RenderHeight);
290 |
291 | // Force fullscreen render
292 | /*
293 | float fScaledW = RenderWidth / (float(RenderWidth) / 800.0f);
294 | float fScaledH = RenderHeight / (float(RenderHeight) / 600.0f);
295 | */
296 | float fScaledW = 800.f;
297 | float fScaledH = 600.f;
298 |
299 | // make sure it's rendered in full screen mode when triple buffering is enabled as well
300 | for (size_t n = 0; n < 3; n++)
301 | {
302 | // gEnv->pRenderer->SetCullMode(R_CULL_NONE);
303 | gEnv->pRenderer->SetState(GS_NODEPTHTEST);
304 | // gEnv->pRenderer->Draw2dImageStretchMode(true);
305 | // gEnv->pRenderer->Draw2dImage(PosX, PosY, fScaledW, fScaledH, pTex->GetTextureID(), 0.0f, 1.0f, 1.0f, 0.0f);
306 | gEnv->pRenderer->Draw2dImage(0, 0, 800, 600, pTex->GetTextureID(), 0.0f, 1.0f, 1.0f, 0.0f);
307 | // gEnv->pRenderer->Draw2dImageStretchMode(false);
308 | }
309 | }
310 | }
311 | }
312 |
313 | ///////////////////////////////////////////////////////////////////////////
314 | //! Stalls the current executing thread. Draws stretched texture. Returns false if app requested exit through PumpWindowMessage()
315 | //! float StartTime Time from getasynccurtime() start of render
316 | //! float LengthTime Time in seconds, duration of playback
317 | //! ITexture * pTex Texture to draw
318 | //! bool bUseTextureSize Use the size of the texture to set the viewport size
319 | //! bool bUpdateInput Each loop/frame, update input system
320 | //! bool bUpdateMouse Each loop/frame, update hardware mouse system
321 | //! bool bDrawConsole Each loop/frame, update console draw state
322 | //! bool bPumpWinMsg Each loop/frame, handle any pumped window messages
323 | bool CSplashExample::DrawAndStall(float StartTime, float LengthTime, ITexture * pTex, bool bUseTextureSize, bool bUpdateInput, bool bUpdateMouse, bool bDrawConsole, bool bPumpWinMsg)
324 | {
325 | CRY_LOG_CALL("CSplashExample::DrawAndStall()");
326 |
327 | if (pTex)
328 | {
329 | CSimpleThreadBackOff backoff;
330 | while (gEnv->pTimer->GetAsyncCurTime() - LengthTime <= StartTime) {
331 |
332 | // Make sure we don't stall on app exit
333 | if (IsShuttingDown())
334 | break;
335 |
336 | // Keep hiding cursor (needed for some reason)
337 | if (!gEnv->pConsole->GetStatus())
338 | gEnv->pSystem->GetIHardwareMouse()->Hide(true);
339 | else
340 | gEnv->pSystem->GetIHardwareMouse()->Hide(false);
341 |
342 | // Make sure windows doesn't think our application has crashed
343 | if (bPumpWinMsg) if (gEnv->pSystem->PumpWindowMessage(true) == -1) return false;
344 |
345 | // Update input events so we don't get any windows cursors during our splash
346 | if (bUpdateInput) gEnv->pInput->Update(true);
347 | if (bUpdateMouse) gEnv->pSystem->GetIHardwareMouse()->Update();
348 |
349 | // Render the splash image
350 | gEnv->pRenderer->BeginFrame();
351 | Draw2DImage(pTex, bUseTextureSize); // Our overlay texture (can have alpha which is why we need background color)
352 | if (bDrawConsole) gEnv->pConsole->Draw(); // Allow drawing of console while we stall
353 | gEnv->pRenderer->EndFrame();
354 |
355 | // Give the system some breathing space
356 | backoff.backoff();
357 | continue;
358 | };
359 | }
360 | return true;
361 | }
362 |
363 | ///////////////////////////////////////////////////////////////////////////
364 | //! Gets the user-defined, or default-defined window properties from PlayerProfiles.
365 | const CSplashExample::SWindowProperties CSplashExample::GetWindowProperties()
366 | {
367 | CRY_LOG_CALL("CSplashExample::GetWindowProperties()");
368 |
369 | if (m_pDefaultProfile == nullptr)
370 | {
371 | static bool warned = false;
372 | if (!warned)
373 | {
374 | warned = true;
375 | CRY_LOG_WARNING("Could not get default profile! Using native resolution.");
376 |
377 | return SWindowProperties(
378 | GetScreenResolution(-1),
379 | #if !defined(_RELEASE)
380 | SWindowMode(0, 0)
381 | #else
382 | SWindowMode(1, 0)
383 | #endif
384 | );
385 | }
386 | }
387 |
388 | // Revert to defaults from lib/config
389 | auto pProfile = (m_pCurrentProfile) ? m_pCurrentProfile : m_pDefaultProfile;
390 |
391 | // Get profile attributes or use predefined defaults
392 | int paResolution;
393 | bool paFullscreen;
394 | bool paFullscreenWindow;
395 |
396 | TFlowInputData buf;
397 |
398 | buf.SetValueWithConversion(WINDOW_DEFAULT_RESOLUTION_IDX);
399 | pProfile->GetAttribute("Resolution", buf, true);
400 | buf.GetValueWithConversion(paResolution);
401 |
402 | buf.SetValueWithConversion(WINDOW_DEFAULT_FULLSCREEN);
403 | pProfile->GetAttribute("Fullscreen", buf, true);
404 | buf.GetValueWithConversion(paFullscreen);
405 |
406 | buf.SetValueWithConversion(WINDOW_DEFAULT_HIDE_BORDER);
407 | pProfile->GetAttribute("FullscreenWindow", buf, true);
408 | buf.GetValueWithConversion(paFullscreenWindow);
409 |
410 | return SWindowProperties(
411 | GetScreenResolution(paResolution),
412 | SWindowMode(paFullscreen, paFullscreenWindow)
413 | );
414 | }
415 |
416 | //////////////////////////////////////////////////////////////////////////
417 | //! Gets the requested screen resolution from GetScreenResolutions()
418 | const CSplashExample::SScreenResolution CSplashExample::GetScreenResolution(const int idx)
419 | {
420 | CRY_LOG_CALL("CSplashExample::GetScreenResolution()");
421 |
422 | static auto ScreenResolutions = CSplashExample::GetScreenResolutions();
423 |
424 | // Didn't get any resolution data for some reason
425 | if (ScreenResolutions.size() <= 0)
426 | {
427 | CRY_LOG_ERROR("Could not get available screen resolutions for display.");
428 | return SScreenResolution();
429 | }
430 |
431 | // If we don't have a resolution this high, get the highest available
432 | if (idx >= ScreenResolutions.size() || idx < 0)
433 | {
434 | CRY_LOG_ALWAYS("idx is not supported, defaulting to highest available. ('%s')", ScreenResolutions[ScreenResolutions.size() - 1].sResolution);
435 | return ScreenResolutions[ScreenResolutions.size() - 1];
436 | }
437 |
438 | return ScreenResolutions[idx];
439 | }
440 |
441 | //////////////////////////////////////////////////////////////////////////
442 | //! Generates a list of supported screen resolutions
443 | //! From GameSDK Sample
444 | const std::vector CSplashExample::GetScreenResolutions()
445 | {
446 | CRY_LOG_CALL("CSplashExample::GetScreenResolutions()");
447 |
448 | static std::vector ScreenResolutions;
449 |
450 | #if CRY_PLATFORM_DESKTOP
451 |
452 | if (ScreenResolutions.size() > 0)
453 | return ScreenResolutions;
454 |
455 | CryFixedStringT<16> format;
456 |
457 | SDispFormat *formats = NULL;
458 | int numFormats = gEnv->pRenderer->EnumDisplayFormats(NULL);
459 | if (numFormats)
460 | {
461 | formats = new SDispFormat[numFormats];
462 | gEnv->pRenderer->EnumDisplayFormats(formats);
463 | }
464 |
465 | for (int i = 0; i < numFormats; ++i)
466 | {
467 | bool bAlreadyExists = false;
468 |
469 | for (auto &res : ScreenResolutions)
470 | if (res.iWidth == formats[i].m_Width && res.iHeight == formats[i].m_Height)
471 | bAlreadyExists = true;
472 |
473 | if (bAlreadyExists || formats[i].m_Width < 800)
474 | continue;
475 |
476 | format.Format("%i X %i", formats[i].m_Width, formats[i].m_Height);
477 |
478 | ScreenResolutions.emplace_back(formats[i].m_Width, formats[i].m_Height, formats[i].m_BPP, format.c_str());
479 | }
480 |
481 | if (formats)
482 | delete[] formats;
483 |
484 | #endif
485 |
486 | return ScreenResolutions;
487 | }
488 |
489 | ///////////////////////////////////////////////////////////////////////////
490 | //! Sets the r_width and r_height CVars if they are set properly in sResolution
491 | void CSplashExample::SetScreenResolution(const SScreenResolution &res) const
492 | {
493 | CRY_LOG_CALL("CSplashExample::SetScreenResolution()");
494 |
495 | if (res.iWidth > 0 && res.iHeight > 0)
496 | {
497 | CRY_LOG_DEBUG("Setting resolution to '%s'", res.sResolution);
498 |
499 | gEnv->pConsole->GetCVar("r_width")->Set(res.iWidth);
500 | gEnv->pConsole->GetCVar("r_height")->Set(res.iHeight);
501 | }
502 | else
503 | {
504 | CRY_LOG_ERROR("Invalid resolution params supplied to SetScreenResolution(). (iWidth=%s,iHeight=%s)", res.iWidth, res.iHeight);
505 | }
506 | }
507 |
508 | ///////////////////////////////////////////////////////////////////////////
509 | //! Gets the Player Profile Manager interface
510 | IPlayerProfileManager * CSplashExample::GetIPlayerProfileManager()
511 | {
512 | CRY_LOG_CALL("CSplashExample::GetIPlayerProfileManager()");
513 |
514 | assert(gEnv->pGameFramework != nullptr);
515 |
516 | // Make sure we have what we need
517 | if (!gEnv->pGameFramework)
518 | return nullptr;
519 |
520 | return gEnv->pGameFramework->GetIPlayerProfileManager();
521 | }
522 |
523 | //////////////////////////////////////////////////////////////////////////
524 | //! Gets the default player profile
525 | IPlayerProfile * CSplashExample::GetDefaultPlayerProfile(IPlayerProfileManager * pProfileManager)
526 | {
527 | CRY_LOG_CALL("CSplashExample::GetDefaultPlayerProfile()");
528 |
529 | if (!pProfileManager) return nullptr;
530 |
531 | IPlayerProfile * pDefaultProfile = pProfileManager->GetDefaultProfile();
532 |
533 | // Get the current user profile (or default if none)
534 | return (pProfileManager) ? pProfileManager->GetDefaultProfile() : nullptr;
535 | }
536 |
537 | //////////////////////////////////////////////////////////////////////////
538 | //! Gets the currently used player profile
539 | IPlayerProfile * CSplashExample::GetCurrentPlayerProfile(IPlayerProfileManager * pProfileManager)
540 | {
541 | CRY_LOG_CALL("CSplashExample::GetCurrentPlayerProfile()");
542 |
543 | // Get the current user profile (or default if none)
544 | return (pProfileManager) ? pProfileManager->GetCurrentProfile(pProfileManager->GetCurrentUser()) : nullptr;
545 | }
546 |
547 | ///////////////////////////////////////////////////////////////////////////
548 | //! Sets the splash flag attribute & manually saves the profile
549 | bool CSplashExample::TryLoadProfileAttributes()
550 | {
551 | CRY_LOG_CALL("CSplashExample::TryLoadProfileAttributes()");
552 |
553 | // Attempt to get profile manager if we havn't already
554 | m_pProfileManager = (!m_pProfileManager)? GetIPlayerProfileManager() : m_pProfileManager;
555 | if (m_pProfileManager != nullptr)
556 | {
557 | // Register the profile listener
558 | RegisterProfileListener(this);
559 |
560 | // Attempt to get the default profile if we havn't already
561 | m_pDefaultProfile = (!m_pDefaultProfile) ? GetDefaultPlayerProfile() : m_pDefaultProfile;
562 | if (m_pDefaultProfile != nullptr)
563 | {
564 | // Attempt to get the current profile if we havn't already
565 | m_pCurrentProfile = (!m_pCurrentProfile)? GetCurrentPlayerProfile() : m_pCurrentProfile;
566 | if (m_pCurrentProfile != nullptr)
567 | {
568 | // Use the SplashFlag in the player profile to check if this is the very first game launch
569 | bool bSplashFlag = true;
570 | if (!m_pCurrentProfile->GetAttribute("SplashFlag_FirstRun", bSplashFlag, false))
571 | {
572 | int res = 0;
573 | // If profile attribute Resolution is <= 0 (or not set).
574 | if (!m_pCurrentProfile->GetAttribute("Resolution", res, false) || res <= 0)
575 | {
576 | // First launch of game, copy defaults (libs/config) to the current profile.
577 | if (!CopyProfileAttributes(/* To */ m_pCurrentProfile, /* From */ m_pDefaultProfile))
578 | {
579 | CRY_LOG_ERROR("Could not copy default profile attributes to '%s'.).", m_pCurrentProfile->GetName());
580 | }
581 | }
582 | else
583 | {
584 | // If the resolution is set higher than the bare minimum supported then
585 | // assume this profile was created outside the scope of this plugin.
586 | //
587 | // Add the splashflag to this profile to prevent overwriting the window preoperties later.
588 | if (!SaveSplashFlagToProfile())
589 | {
590 | CRY_LOG_ERROR("Could not save splash flag to profile '%s'.", m_pCurrentProfile->GetName());
591 | }
592 | }
593 | }
594 |
595 | m_bLoadedProfileAttributes = true;
596 | }
597 | else
598 | {
599 | // Could not get current profile, use defaults
600 | return false;
601 | }
602 | }
603 | else
604 | {
605 | // Could not get default profile
606 |
607 |
608 | return false;
609 | }
610 | }
611 | else
612 | {
613 | // Could not get profile manager
614 | return false;
615 | }
616 | return true;
617 | }
618 |
619 | ///////////////////////////////////////////////////////////////////////////
620 | //! Copies profile attributes from one profile to the other
621 | bool CSplashExample::CopyProfileAttributes(IPlayerProfile * pTo, IPlayerProfile * pFrom)
622 | {
623 | CRY_LOG_CALL("CSplashExample::CopyProfileAttributes()");
624 |
625 | assert(pTo != nullptr);
626 | assert(pFrom != nullptr);
627 |
628 | if (pTo == pFrom)
629 | return true;
630 |
631 | if (pTo->IsDefault())
632 | return false;
633 |
634 | auto pAttrEnumerator = pFrom->CreateAttributeEnumerator();
635 | IAttributeEnumerator::SAttributeDescription desc;
636 | TFlowInputData value;
637 | bool ok = true;
638 | while (pAttrEnumerator->Next(desc))
639 | {
640 | pFrom->GetAttribute(desc.name, value);
641 | if (!pTo->SetAttribute(desc.name, value))
642 | {
643 | CRY_LOG_ERROR("Could not set default attribute to current profile.");
644 | ok = false;
645 | }
646 | }
647 | return ok;
648 | }
649 |
650 | ///////////////////////////////////////////////////////////////////////////
651 | //! Sets the splash flag attribute on the current profile
652 | bool CSplashExample::SetProfileAttribute(const char * attributeName, const TFlowInputData attributeValue)
653 | {
654 | CRY_LOG_CALL("CSplashExample::SetProfileAttribute()");
655 | return m_pCurrentProfile->SetAttribute(attributeName, attributeValue);
656 | }
657 | template
658 | bool CSplashExample::SetProfileAttribute(const char * attributeName, const T& attributeValue)
659 | {
660 | CRY_LOG_CALL("CSplashExample::SetProfileAttribute()");
661 | return m_pCurrentProfile->SetAttribute(attributeName, attributeValue);
662 | }
663 |
664 | ///////////////////////////////////////////////////////////////////////////
665 | //! Sets the splash flag attribute & manually saves the profile
666 | bool CSplashExample::SaveSplashFlagToProfile()
667 | {
668 | CRY_LOG_CALL("CSplashExample::SaveSplashFlagToProfile()");
669 |
670 | if (!SetProfileAttribute("SplashFlag_FirstRun", 0))
671 | return false;
672 |
673 | EPOResult res;
674 | if (!SavePlayerProfile(res, EProfileReasons::ePR_Options))
675 | return false;
676 |
677 | return true;
678 | }
679 |
680 | ///////////////////////////////////////////////////////////////////////////
681 | //! Manually saves the current profile
682 | bool CSplashExample::SavePlayerProfile(EPOResult &result, EProfileReasons reason)
683 | {
684 | CRY_LOG_CALL("CSplashExample::SavePlayerProfile()");
685 |
686 | assert(m_pProfileManager != nullptr);
687 | assert(m_pCurrentProfile != nullptr);
688 |
689 | m_bIgnoreNextProfileSave = true;
690 |
691 | if (m_pProfileManager->SaveProfile(m_pCurrentProfile->GetName(), result, reason))
692 | {
693 | return true;
694 | }
695 | else
696 | {
697 | m_bIgnoreNextProfileSave = false;
698 | return false;
699 | }
700 | }
701 |
702 | ///////////////////////////////////////////////////////////////////////////
703 | //! Registers the player profile listener if not registered
704 | bool CSplashExample::RegisterProfileListener(IPlayerProfileListener * pListener)
705 | {
706 | CRY_LOG_CALL("CSplashExample::RegisterProfileListener()");
707 | assert(pListener);
708 |
709 | if (!m_bProfileListenerRegistered)
710 | {
711 | auto pMan = GetIPlayerProfileManager();
712 | if (pMan)
713 | {
714 | pMan->AddListener(pListener, false);
715 | m_bProfileListenerRegistered = true;
716 | CRY_LOG_DEBUG("Registered Profile Manager Listener.");
717 | }
718 | else
719 | {
720 | CRY_LOG_DEBUG("Profile Manager not available, could not register listener.");
721 | }
722 | }
723 |
724 | return m_bProfileListenerRegistered;
725 | }
726 |
727 | ///////////////////////////////////////////////////////////////////////////
728 | //! De-Registers the player profile listener
729 | bool CSplashExample::UnregisterProfileListener(IPlayerProfileListener * pListener)
730 | {
731 | CRY_LOG_CALL("CSplashExample::UnregisterProfileListener()");
732 | assert(pListener);
733 |
734 | if (m_bProfileListenerRegistered)
735 | {
736 | auto pMan = GetIPlayerProfileManager();
737 | if (pMan)
738 | {
739 | pMan->RemoveListener(pListener);
740 | m_bProfileListenerRegistered = false;
741 | CRY_LOG_DEBUG("Unregistered Profile Manager Listener.");
742 | }
743 | else
744 | {
745 | CRY_LOG_ERROR("Profile manager destructed before removing listener.");
746 | }
747 | }
748 |
749 | return !m_bProfileListenerRegistered;
750 | }
751 |
752 | ///////////////////////////////////////////////////////////////////////////
753 | //! Registers the system event listener if not registered
754 | bool CSplashExample::RegisterSystemListener(ISystemEventListener * pListener)
755 | {
756 | CRY_LOG_CALL("CSplashExample::RegisterSystemListener()");
757 | assert(pListener);
758 |
759 | if (!m_bSystemListenerRegistered)
760 | {
761 | if (gEnv->pSystem)
762 | {
763 | auto pDispatcher = gEnv->pSystem->GetISystemEventDispatcher();
764 | if (pDispatcher)
765 | {
766 | #ifdef CRYGENERATE_SINGLETONCLASS_GUID
767 | pDispatcher->RegisterListener(pListener, "SplashExampleSystem");
768 | #else
769 | pDispatcher->RegisterListener(pListener);
770 | #endif
771 | m_bSystemListenerRegistered = true;
772 | CRY_LOG_DEBUG("Registered System Event Listener.");
773 | }
774 | else
775 | {
776 | CRY_LOG_DEBUG("System Event Dispatcher not available, could not register listener.");
777 | }
778 | }
779 | else
780 | {
781 | CRY_LOG_DEBUG("Profile Manager not available, could not register listener.");
782 | }
783 | }
784 |
785 | return m_bSystemListenerRegistered;
786 | }
787 |
788 | ///////////////////////////////////////////////////////////////////////////
789 | //! De-Registers the system event listener
790 | bool CSplashExample::UnregisterSystemListener(ISystemEventListener * pListener)
791 | {
792 | CRY_LOG_CALL("CSplashExample::UnregisterSystemListener()");
793 | assert(pListener);
794 |
795 | if (m_bSystemListenerRegistered)
796 | {
797 | if (gEnv->pSystem)
798 | {
799 | auto pDispatcher = gEnv->pSystem->GetISystemEventDispatcher();
800 | if (pDispatcher)
801 | {
802 | pDispatcher->RemoveListener(pListener);
803 | m_bSystemListenerRegistered = false;
804 | CRY_LOG_DEBUG("Unregistered System Event Listener.");
805 | }
806 | else
807 | {
808 | CRY_LOG_ERROR("System Event Dispatcher destructed before removing listener.");
809 | }
810 | }
811 | else
812 | {
813 | CRY_LOG_ERROR("System destructed before removing listener.");
814 | }
815 | }
816 |
817 | return !m_bSystemListenerRegistered;
818 | }
819 |
820 | ///////////////////////////////////////////////////////////////////////////
821 | //! Listener:
822 | void CSplashExample::SaveToProfile(IPlayerProfile* pProfile, bool online, unsigned int /*EProfileReasons*/ reason)
823 | {
824 | CRY_LOG_CALL("CSplashExample::SaveToProfile()");
825 |
826 | if (m_bIgnoreNextProfileSave)
827 | {
828 | m_bIgnoreNextProfileSave = false;
829 | return;
830 | }
831 |
832 | // Todo: Make sure we have required profile attributes?
833 | return;
834 | }
835 |
836 | ///////////////////////////////////////////////////////////////////////////
837 | //! Listener: Ensures loaded profiles have the splash flag.
838 | void CSplashExample::LoadFromProfile(IPlayerProfile* pProfile, bool online, unsigned int /*EProfileReasons*/ reason)
839 | {
840 | CRY_LOG_CALL("CSplashExample::LoadFromProfile()");
841 |
842 | if (!pProfile->IsDefault())
843 | {
844 | if (m_pCurrentProfile == nullptr)
845 | m_pCurrentProfile = pProfile;
846 | else if (m_pCurrentProfile != pProfile)
847 | SaveSplashFlagToProfile();
848 | }
849 | }
850 |
851 | ///////////////////////////////////////////////////////////////////////////
852 | //! Listener: All splash operations are dispatched from this method
853 | void CSplashExample::OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam)
854 | {
855 |
856 | CRY_LOG_CALL("Debug OnSystemEvent. event = %s", SYSEVENT_CODE_TO_TEXT(event));
857 |
858 | // Unlink listeners if we notice a shutdown (CE Registry Destruction Bug)
859 | if (IsShuttingDown()) return;
860 |
861 | // Construct at the earliest opportunity
862 | // * This is a safe-guard if the plugins object construction
863 | // * is moved before other systems have initialized.
864 | // * (Currently in 5.3.0, Construction, Initialization, and
865 | // * ESYSTEM_EVENT_PRE_RENDERER_INIT are called at the same
866 | // * time in CSystem::Init)
867 |
868 | switch (event)
869 | {
870 | // First stage, override startscreen, hide cursor and draw our gui splash (splash_a)
871 | case ESYSTEM_EVENT_PRE_RENDERER_INIT:
872 | {
873 | if (!m_bInitialized) return; // Only respond to events if we are ready to
874 |
875 | // Initial splash
876 | DisplayInitialSplash();
877 |
878 | break;
879 | }
880 |
881 | // Second stage, stall with our initial splash for the specified time
882 | case ESYSTEM_EVENT_GAME_POST_INIT:
883 | {
884 | // Stall if needed
885 | DisplayInitialSplash(true);
886 |
887 | break;
888 | }
889 |
890 | // Third stage, Render main splash image, and delay further loading for the specified time.
891 | case ESYSTEM_EVENT_GAME_POST_INIT_DONE:
892 | {
893 | // Load profile attributes or defaults
894 | if (!m_bLoadedProfileAttributes)
895 | TryLoadProfileAttributes();
896 |
897 | // Stall if needed
898 | DisplayMainSplash(true);
899 | }
900 | }
901 | }
902 |
903 | bool CSplashExample::IsShuttingDown()
904 | {
905 | if (gEnv->pSystem->IsQuitting())
906 | {
907 | // cleanup immmediately
908 | UnregisterProfileListener(this);
909 | UnregisterSystemListener(this);
910 | return true;
911 | }
912 | return false;
913 | }
--------------------------------------------------------------------------------
/Code/SplashExample.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017, uniflare, see LICENSE.txt for details
2 |
3 | #pragma once
4 | #include "cvars.h"
5 |
6 | #include
7 | #include
8 |
9 | #ifdef _DEBUG
10 | #define POR_RESULT_CODE_TO_TEXT(EResult) \
11 | (EResult == IPlayerProfileManager::EProfileOperationResult::ePOR_Success)? "ePOR_Success" : \
12 | (EResult == IPlayerProfileManager::EProfileOperationResult::ePOR_NotInitialized)? "ePOR_NotInitialized" : \
13 | (EResult == IPlayerProfileManager::EProfileOperationResult::ePOR_NameInUse)? "ePOR_NameInUse" : \
14 | (EResult == IPlayerProfileManager::EProfileOperationResult::ePOR_UserNotLoggedIn)? "ePOR_UserNotLoggedIn" : \
15 | (EResult == IPlayerProfileManager::EProfileOperationResult::ePOR_NoSuchProfile)? "ePOR_NoSuchProfile" : \
16 | (EResult == IPlayerProfileManager::EProfileOperationResult::ePOR_ProfileInUse)? "ePOR_ProfileInUse" : \
17 | (EResult == IPlayerProfileManager::EProfileOperationResult::ePOR_NoActiveProfile)? "ePOR_NoActiveProfile" : \
18 | (EResult == IPlayerProfileManager::EProfileOperationResult::ePOR_DefaultProfile)? "ePOR_DefaultProfile" : \
19 | (EResult == IPlayerProfileManager::EProfileOperationResult::ePOR_LoadingProfile)? "ePOR_LoadingProfile" : "ePOR_Unknown"
20 |
21 | #define SYSEVENT_CODE_TO_TEXT(EEvent) \
22 | EEvent == ESYSTEM_EVENT_CHANGE_FOCUS? "ESYSTEM_EVENT_CHANGE_FOCUS" : \
23 | EEvent == ESYSTEM_EVENT_MOVE? "ESYSTEM_EVENT_MOVE" : \
24 | EEvent == ESYSTEM_EVENT_RESIZE? "ESYSTEM_EVENT_RESIZE" : \
25 | EEvent == ESYSTEM_EVENT_ACTIVATE? "ESYSTEM_EVENT_ACTIVATE" : \
26 | EEvent == ESYSTEM_EVENT_POS_CHANGED? "ESYSTEM_EVENT_POS_CHANGED" : \
27 | EEvent == ESYSTEM_EVENT_STYLE_CHANGED? "ESYSTEM_EVENT_STYLE_CHANGED" : \
28 | EEvent == ESYSTEM_EVENT_LEVEL_LOAD_START_PRELOADINGSCREEN? "ESYSTEM_EVENT_LEVEL_LOAD_START_PRELOADINGSCREEN" : \
29 | EEvent == ESYSTEM_EVENT_LEVEL_LOAD_RESUME_GAME? "ESYSTEM_EVENT_LEVEL_LOAD_RESUME_GAME" : \
30 | EEvent == ESYSTEM_EVENT_LEVEL_LOAD_START? "ESYSTEM_EVENT_LEVEL_LOAD_START" : \
31 | EEvent == ESYSTEM_EVENT_LEVEL_LOAD_PREPARE? "ESYSTEM_EVENT_LEVEL_LOAD_PREPARE" : \
32 | EEvent == ESYSTEM_EVENT_LEVEL_LOAD_START_LOADINGSCREEN? "ESYSTEM_EVENT_LEVEL_LOAD_START_LOADINGSCREEN" : \
33 | EEvent == ESYSTEM_EVENT_LEVEL_LOAD_LOADINGSCREEN_ACTIVE? "ESYSTEM_EVENT_LEVEL_LOAD_LOADINGSCREEN_ACTIVE" : \
34 | EEvent == ESYSTEM_EVENT_LEVEL_LOAD_START? "ESYSTEM_EVENT_LEVEL_LOAD_START" : \
35 | EEvent == ESYSTEM_EVENT_LEVEL_LOAD_END? "ESYSTEM_EVENT_LEVEL_LOAD_END" : \
36 | EEvent == ESYSTEM_EVENT_LEVEL_LOAD_ERROR? "ESYSTEM_EVENT_LEVEL_LOAD_ERROR" : \
37 | EEvent == ESYSTEM_EVENT_LEVEL_NOT_READY? "ESYSTEM_EVENT_LEVEL_NOT_READY" : \
38 | EEvent == ESYSTEM_EVENT_LEVEL_PRECACHE_START? "ESYSTEM_EVENT_LEVEL_PRECACHE_START" : \
39 | EEvent == ESYSTEM_EVENT_LEVEL_PRECACHE_FIRST_FRAME? "ESYSTEM_EVENT_LEVEL_PRECACHE_FIRST_FRAME" : \
40 | EEvent == ESYSTEM_EVENT_LEVEL_GAMEPLAY_START? "ESYSTEM_EVENT_LEVEL_GAMEPLAY_START" : \
41 | EEvent == ESYSTEM_EVENT_LEVEL_UNLOAD? "ESYSTEM_EVENT_LEVEL_UNLOAD" : \
42 | EEvent == ESYSTEM_EVENT_LEVEL_POST_UNLOAD? "ESYSTEM_EVENT_LEVEL_POST_UNLOAD" : \
43 | EEvent == ESYSTEM_EVENT_GAME_POST_INIT? "ESYSTEM_EVENT_GAME_POST_INIT" : \
44 | EEvent == ESYSTEM_EVENT_GAME_POST_INIT_DONE? "ESYSTEM_EVENT_GAME_POST_INIT_DONE" : \
45 | EEvent == ESYSTEM_EVENT_FULL_SHUTDOWN? "ESYSTEM_EVENT_FULL_SHUTDOWN" : \
46 | EEvent == ESYSTEM_EVENT_FAST_SHUTDOWN? "ESYSTEM_EVENT_FAST_SHUTDOWN" : \
47 | EEvent == ESYSTEM_EVENT_LANGUAGE_CHANGE? "ESYSTEM_EVENT_LANGUAGE_CHANGE" : \
48 | EEvent == ESYSTEM_EVENT_TOGGLE_FULLSCREEN? "ESYSTEM_EVENT_TOGGLE_FULLSCREEN" : \
49 | EEvent == ESYSTEM_EVENT_SHARE_SHADER_COMBINATIONS? "ESYSTEM_EVENT_SHARE_SHADER_COMBINATIONS" : \
50 | EEvent == ESYSTEM_EVENT_3D_POST_RENDERING_START? "ESYSTEM_EVENT_3D_POST_RENDERING_START" : \
51 | EEvent == ESYSTEM_EVENT_3D_POST_RENDERING_END? "ESYSTEM_EVENT_3D_POST_RENDERING_END" : \
52 | EEvent == ESYSTEM_EVENT_LEVEL_PRECACHE_END? "ESYSTEM_EVENT_LEVEL_PRECACHE_END" : \
53 | EEvent == ESYSTEM_EVENT_GAME_MODE_SWITCH_START? "ESYSTEM_EVENT_GAME_MODE_SWITCH_START" : \
54 | EEvent == ESYSTEM_EVENT_GAME_MODE_SWITCH_END? "ESYSTEM_EVENT_GAME_MODE_SWITCH_END" : \
55 | EEvent == ESYSTEM_EVENT_VIDEO? "ESYSTEM_EVENT_VIDEO" : \
56 | EEvent == ESYSTEM_EVENT_GAME_PAUSED? "ESYSTEM_EVENT_GAME_PAUSED" : \
57 | EEvent == ESYSTEM_EVENT_GAME_RESUMED? "ESYSTEM_EVENT_GAME_RESUMED" : \
58 | EEvent == ESYSTEM_EVENT_TIME_OF_DAY_SET? "ESYSTEM_EVENT_TIME_OF_DAY_SET" : \
59 | EEvent == ESYSTEM_EVENT_EDITOR_ON_INIT? "ESYSTEM_EVENT_EDITOR_ON_INIT" : \
60 | EEvent == ESYSTEM_EVENT_FRONTEND_INITIALISED? "ESYSTEM_EVENT_FRONTEND_INITIALISED" : \
61 | EEvent == ESYSTEM_EVENT_EDITOR_GAME_MODE_CHANGED? "ESYSTEM_EVENT_EDITOR_GAME_MODE_CHANGED" : \
62 | EEvent == ESYSTEM_EVENT_EDITOR_SIMULATION_MODE_CHANGED? "ESYSTEM_EVENT_EDITOR_SIMULATION_MODE_CHANGED" : \
63 | EEvent == ESYSTEM_EVENT_ENVIRONMENT_SETTINGS_CHANGED? "ESYSTEM_EVENT_ENVIRONMENT_SETTINGS_CHANGED" : \
64 | EEvent == ESYSTEM_EVENT_FRONTEND_RELOADED? "ESYSTEM_EVENT_FRONTEND_RELOADED" : \
65 | EEvent == ESYSTEM_EVENT_SW_FORCE_LOAD_START? "ESYSTEM_EVENT_SW_FORCE_LOAD_START" : \
66 | EEvent == ESYSTEM_EVENT_SW_FORCE_LOAD_END? "ESYSTEM_EVENT_SW_FORCE_LOAD_END" : \
67 | EEvent == ESYSTEM_EVENT_SW_SHIFT_WORLD? "ESYSTEM_EVENT_SW_SHIFT_WORLD" : \
68 | EEvent == ESYSTEM_EVENT_CHANGE_FOCUS? "ESYSTEM_EVENT_CHANGE_FOCUS" : \
69 | EEvent == ESYSTEM_EVENT_STREAMING_INSTALL_ERROR? "ESYSTEM_EVENT_STREAMING_INSTALL_ERROR" : \
70 | EEvent == ESYSTEM_EVENT_ONLINE_SERVICES_INITIALISED? "ESYSTEM_EVENT_ONLINE_SERVICES_INITIALISED" : \
71 | EEvent == ESYSTEM_EVENT_AUDIO_IMPLEMENTATION_LOADED? "ESYSTEM_EVENT_AUDIO_IMPLEMENTATION_LOADED" : \
72 | EEvent == ESYSTEM_EVENT_URI? "ESYSTEM_EVENT_URI" : \
73 | EEvent == ESYSTEM_EVENT_USER? "ESYSTEM_EVENT_USER" : \
74 | EEvent == ESYSTEM_EVENT_BEAM_PLAYER_TO_CAMERA_POS? "ESYSTEM_EVENT_BEAM_PLAYER_TO_CAMERA_POS" : \
75 | EEvent == ESYSTEM_EVENT_CRYSYSTEM_INIT_DONE? "ESYSTEM_EVENT_CRYSYSTEM_INIT_DONE" : \
76 | EEvent == ESYSTEM_EVENT_PRE_RENDERER_INIT? "ESYSTEM_EVENT_PRE_RENDERER_INIT" : \
77 | EEvent == ESYSTEM_EVENT_GAMEWINDOW_ACTIVATE? "ESYSTEM_EVENT_GAMEWINDOW_ACTIVATE" : \
78 | EEvent == ESYSTEM_EVENT_REGISTER_FLOWNODES? "ESYSTEM_EVENT_REGISTER_FLOWNODES" : \
79 | EEvent == ESYSTEM_EVENT_CRYSYSTEM_INIT_DONE? "ESYSTEM_EVENT_CRYSYSTEM_INIT_DONE" : \
80 | EEvent == ESYSTEM_EVENT_GAME_FRAMEWORK_INIT_DONE? "ESYSTEM_EVENT_GAME_FRAMEWORK_INIT_DONE" : "UNKNOWN"
81 | #else
82 | #define POR_RESULT_CODE_TO_TEXT(...) ""
83 | #define SYSEVENT_CODE_TO_TEXT(...) ""
84 | #endif // _DEBUG
85 |
86 | // This is due to the default gamesdk not using default profile attributes from configs.
87 | // -1 will tell GetScreenResolution(idx) to give us the native screen res
88 | #define WINDOW_DEFAULT_RESOLUTION_IDX -1
89 | #define WINDOW_DEFAULT_FULLSCREEN 1
90 | #define WINDOW_DEFAULT_HIDE_BORDER 0
91 |
92 | typedef IPlayerProfileManager::EProfileOperationResult EPOResult;
93 |
94 | // CSplashExample implements ISystemEventListener
95 | //
96 | //! Handles main functionality of plugin Splash Example
97 | class CSplashExample
98 | : public ISystemEventListener,
99 | public IPlayerProfileListener
100 | {
101 |
102 | private:
103 |
104 | //! Struct to hold screen resolution details
105 | struct SScreenResolution
106 | {
107 | // Copied from GameSDK - For using profile saved resolution
108 | int iWidth;
109 | int iHeight;
110 | int nDepthPerPixel;
111 | string sResolution;
112 |
113 | SScreenResolution(unsigned int _iWidth, unsigned int _iHeight, unsigned int _nDepthPerPixel, const char* _sResolution) :
114 | iWidth(_iWidth)
115 | , iHeight(_iHeight)
116 | , nDepthPerPixel(_nDepthPerPixel)
117 | , sResolution(_sResolution)
118 | {}
119 |
120 | SScreenResolution() :
121 | iWidth(-1)
122 | , iHeight(-1)
123 | , nDepthPerPixel(-1)
124 | , sResolution("")
125 | {}
126 | };
127 |
128 | struct SWindowMode
129 | {
130 | bool bFullscreen;
131 | bool bHideWindowBorder;
132 |
133 | SWindowMode(const bool &fullscreen, const bool &hideWindowBorder)
134 | {
135 | bFullscreen = fullscreen;
136 | bHideWindowBorder = hideWindowBorder;
137 | }
138 |
139 | SWindowMode() :
140 | bFullscreen(1),
141 | bHideWindowBorder(1)
142 | {}
143 | };
144 |
145 | struct SWindowProperties
146 | {
147 | SScreenResolution sScreenResolution;
148 | SWindowMode sWindowMode;
149 |
150 | SWindowProperties(const SScreenResolution &screenResolution, const SWindowMode &windowMode) :
151 | sScreenResolution(screenResolution),
152 | sWindowMode(windowMode)
153 | {}
154 |
155 | SWindowProperties() :
156 | sScreenResolution(),
157 | sWindowMode()
158 | {}
159 | };
160 |
161 | // Console variables provided by this object
162 | CVars m_sCVars;
163 |
164 | //! Textures
165 | ITexture * m_pInitialSplashTexture;
166 | ITexture * m_pSplashTexture;
167 |
168 | //! Simple flag to make sure we don't initialize more than once
169 | bool m_bInitialized;
170 |
171 | //! Simple flags to make sure we don't register/unregister our listeners too many times etc
172 | bool m_bSystemListenerRegistered;
173 | bool m_bProfileListenerRegistered;
174 | bool m_bLoadedProfileAttributes;
175 | bool m_bIgnoreNextProfileSave;
176 |
177 | //! Local refs
178 | IPlayerProfileManager * m_pProfileManager;
179 | IPlayerProfile * m_pCurrentProfile;
180 | IPlayerProfile * m_pDefaultProfile;
181 |
182 | private:
183 |
184 | //! Handles init of Splash Example. (Can only init once)
185 | void TryInitialize();
186 |
187 | //! Draws the supplied texture in stretched mode to the main viewport
188 | void Draw2DImage(const ITexture * tex, bool bUseTextureSize = false) const;
189 |
190 | //! Wrapper to stall the current thread for LengthTime whilst drawing pTex
191 | bool DrawAndStall(float StartTime, float LengthTime, ITexture * pTex, bool bUseTextureSize = false, bool bUpdateInput = true, bool bUpdateMouse = true, bool bDrawConsole = true, bool bPumpWinMsg = true);
192 |
193 | //! Gets the currently in-use player profile
194 | IPlayerProfile * GetCurrentPlayerProfile(IPlayerProfileManager * pProfileManager = GetIPlayerProfileManager());
195 |
196 | //! Gets the default player profile
197 | IPlayerProfile * GetDefaultPlayerProfile(IPlayerProfileManager * pProfileManager = GetIPlayerProfileManager());
198 |
199 |
200 | //! Gets the requested screen resolution from GetScreenResolutions()
201 | static const SScreenResolution GetScreenResolution(const int idx);
202 |
203 | //! Generates a list of supported screen resolutions
204 | static const std::vector GetScreenResolutions();
205 |
206 | const SWindowProperties GetWindowProperties();
207 |
208 | //! Sets the r_width and r_height CVars if they are set properly in sResolution
209 | void SetScreenResolution(const SScreenResolution &sResolution) const;
210 |
211 | //! Self explanatory
212 | void SafeReleaseSplashTextures();
213 |
214 | //! Handles the display of the initial splash window
215 | void DisplayInitialSplash(bool stallThread = false);
216 |
217 | //! Handles the display of the main splash window
218 | void DisplayMainSplash(const bool stallThread = false);
219 |
220 | bool TryLoadProfileAttributes();
221 |
222 | bool CopyProfileAttributes(IPlayerProfile * pTo, IPlayerProfile * pFrom);
223 |
224 | static IPlayerProfileManager * GetIPlayerProfileManager();
225 | bool SaveSplashFlagToProfile();
226 | bool SetProfileAttribute(const char * attributeName, const TFlowInputData attributeValue);
227 | template
228 | bool SetProfileAttribute(const char * attributeName, const T& attributeValue);
229 | bool SavePlayerProfile(EPOResult &result, EProfileReasons reason = EProfileReasons::ePR_Options);
230 |
231 | bool RegisterSystemListener(ISystemEventListener * pListener);
232 | bool UnregisterSystemListener(ISystemEventListener * pListener);
233 | // ISystemEventListener
234 | virtual void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam) override;
235 | // ~ISystemEventListener
236 |
237 | bool RegisterProfileListener(IPlayerProfileListener * pListener);
238 | bool UnregisterProfileListener(IPlayerProfileListener * pListener);
239 | // IPlayerProfileListener
240 | virtual void SaveToProfile(IPlayerProfile* pProfile, bool online, unsigned int /*EProfileReasons*/ reason) override;
241 | virtual void LoadFromProfile(IPlayerProfile* pProfile, bool online, unsigned int /*EProfileReasons*/ reason) override;
242 | // ~IPlayerProfileListener
243 |
244 | bool IsShuttingDown();
245 |
246 | public:
247 |
248 | CSplashExample();
249 | ~CSplashExample();
250 |
251 | // ICryPlugin
252 | bool Initialize(SSystemGlobalEnvironment& env, const SSystemInitParams& initParams);
253 | // ~ICryPlugin
254 | };
--------------------------------------------------------------------------------
/Code/SplashExample.vcxproj.user.in:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | @CryEngine_DIR@\bin\win_x64\GameLauncher.exe
5 | -project "${TestPlatformProject}"
6 | WindowsLocalDebugger
7 |
8 |
--------------------------------------------------------------------------------
/Code/StdAfx.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017, uniflare, see LICENSE.txt for details
2 |
3 | #include "StdAfx.h"
--------------------------------------------------------------------------------
/Code/StdAfx.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017, uniflare, see LICENSE.txt for details
2 |
3 | #pragma once
4 |
5 | #include
6 | #define eCryModule eCryM_EnginePlugin
7 | #define GAME_API DLL_EXPORT
8 |
9 | // Custom logging defines for readability
10 | #define CRY_LOG_ALWAYS(...) CryLogAlways("[SplashExamplePlugin] " ##__VA_ARGS__)
11 | #define CRY_LOG_ERROR(...) CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_ERROR, "[SplashExamplePlugin] " ##__VA_ARGS__)
12 | #define CRY_LOG_WARNING(...) CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "[SplashExamplePlugin] " ##__VA_ARGS__)
13 | #define CRY_LOG_DEBUG(...) CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_COMMENT, "[SplashExamplePlugin] " ##__VA_ARGS__)
14 | #ifdef _DEBUG
15 | #define CRY_LOG_CALL(...) CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_COMMENT, "[SplashExamplePlugin] " ##__VA_ARGS__)
16 | #else
17 | #define CRY_LOG_CALL(...) 0
18 | #endif
19 |
20 | #include
--------------------------------------------------------------------------------
/Code/cvars.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017, uniflare, see LICENSE.txt for details
2 | #pragma once
3 |
4 | #include
5 | #include
6 |
7 | struct CVars
8 | {
9 | bool m_bHasRegistered;
10 |
11 | int m_iSplashEnable;
12 | int m_iMainSplashEnable;
13 | int m_iInitialSplashEnable;
14 |
15 | float m_fSplashPlaybackTime;
16 | float m_fInitialSplashPlaybackTime;
17 | float m_fStartTimeOffset;
18 |
19 | ICVar * m_pSplashTexturePath;
20 | ICVar * m_pInitialSplashTexturePath;
21 |
22 | // Register console variables
23 | CVars() :
24 | m_bHasRegistered(false)
25 | , m_iSplashEnable(false)
26 | , m_iInitialSplashEnable(false)
27 | , m_iMainSplashEnable(false)
28 | , m_fSplashPlaybackTime(0.f)
29 | , m_fInitialSplashPlaybackTime(0.f)
30 | , m_fStartTimeOffset(0.f)
31 | , m_pSplashTexturePath(nullptr)
32 | , m_pInitialSplashTexturePath(nullptr)
33 |
34 | {
35 | CRY_LOG_CALL("CVars::CVars()");
36 | }
37 |
38 | // Unregister console variables
39 | ~CVars()
40 | {
41 | CRY_LOG_CALL("CVars::~CVars()");
42 | assert(gEnv->pConsole);
43 | if (!gEnv->pConsole) return;
44 |
45 | gEnv->pConsole->UnregisterVariable("splash_texture_initial");
46 | gEnv->pConsole->UnregisterVariable("splash_texture");
47 | gEnv->pConsole->UnregisterVariable("splash_startTimeOffset");
48 | gEnv->pConsole->UnregisterVariable("splash_minimumPlaybackTime");
49 | gEnv->pConsole->UnregisterVariable("splash_minimumPlaybackTime_initial");
50 | gEnv->pConsole->UnregisterVariable("splash_show_initial");
51 | gEnv->pConsole->UnregisterVariable("splash_show");
52 | gEnv->pConsole->UnregisterVariable("splash_plugin_enable");
53 |
54 | CRY_LOG_DEBUG("Unregistered CVars.");
55 | }
56 |
57 | bool Init()
58 | {
59 | assert(gEnv->pConsole);
60 | if (!gEnv->pConsole) return false;
61 |
62 | REGISTER_CVAR2("splash_plugin_enable", &m_iSplashEnable, 1, VF_CHEAT, "Whether to enable the splash plugin (0=no)");
63 | REGISTER_CVAR2("splash_show", &m_iMainSplashEnable, 1, VF_CHEAT, "Whether to enable the main (second) splash image (0=no)");
64 | REGISTER_CVAR2("splash_show_initial", &m_iInitialSplashEnable, 1, VF_CHEAT, "Whether to enable the intial (smaller) splash screen (0=no)");
65 | REGISTER_CVAR2("splash_minimumPlaybackTime_initial", &m_fInitialSplashPlaybackTime, 3.f, VF_CHEAT, "Initial Splash - Minimum playback time in seconds (float min 0.f)");
66 | REGISTER_CVAR2("splash_minimumPlaybackTime", &m_fSplashPlaybackTime, 3.f, VF_CHEAT, "Main Splash - Minimum playback time in seconds (float min 0.f)");
67 | REGISTER_CVAR2("splash_startTimeOffset", &m_fStartTimeOffset, 0.0f, VF_CHEAT, "Offset to make splash_minimumPlaybackTime more accurate (float)");
68 | m_pSplashTexturePath = REGISTER_STRING("splash_texture", "splashexample/textures/Splash.dds", VF_CHEAT, "Sets the splash overlay texture to load");
69 | m_pInitialSplashTexturePath = REGISTER_STRING("splash_texture_initial", "splashexample/textures/InitialSplash.dds", VF_CHEAT, "Sets the initial splash overlay texture to load (before we go fullscreen)");
70 |
71 | CRY_LOG_DEBUG("Registered CVars.");
72 | return true;
73 | }
74 | };
--------------------------------------------------------------------------------
/Docs/CONCEPT.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017, uniflare, see LICENSE.txt for details
2 | Splash Example Plugin
3 |
4 | This file explains the idea or 'concept' of the Splash Example Plugin,
5 | as well as an overview of the internal implementation details.
6 |
7 | # Boring stuff
8 | The reason this plugin came about is mainly as an exercise to myself, it gave
9 | me a problem to solve, that seemed basic but functional.
10 |
11 | This project was fun to make and although this project is technically not
12 | vetted for production release it was taken into consideration.
13 |
14 | # Initial concept
15 | The idea was to use the CryCommon exposed 2d rendering routines to display
16 | a fullwindow* image upon starting the engine for a configurable amount of time,
17 | whilst remaining as compatible as is reasonable and/or possible.
18 |
19 | # Evolution
20 | Concept was expanded to include a borderless windowed image to display
21 | a (old-school) splash picture preceeding a (expected) larger or fullscreen window.
22 |
23 | # Implementation
24 |
25 | # Restrictions:
26 | - Only works in game mode (not editor/dedicated server)
27 | - Resolution CVARS must be set correctly to avoid switching window properties.
28 | (Due to the fact plugins/projects are loaded/initialized after the renderer module)
29 | - Only compatible with engine-compatible Windows platform
30 | - Uses the player profile attributes system to store data for GameSDK compatibility**
31 | - Untested with multi-display single-desktop span configurations. Probably will not work in these cases.
32 | - Initial splash is limited to a minimum size of 512x300, the minimum resolution used by the engine.
33 | - Cannot specify custom dll binary output path for release builds - building from source.
34 |
35 | # Initialization
36 | Uses system events to try to determine the earliest point in engine init to init required data
37 | for the splash example plugin. Essentially this is to make it compatible with future changes
38 | of the initialization ordering between plugins and the engine itself. (For ex, if the plugin
39 | system if moved before renderer in the initialization of the engine).
40 |
41 | # Internals
42 | Uses the `gEnv->pRenderer->Draw2dImage(...)` internally to draw bitmaps to the screen.
43 | Textures are loaded using `pRenderer->EF_LoadTexture(...)`
44 | Delay/Stall is handled via simple blocking `while(...)` loop with `gEnv->pTimer->GetAsyncCurTime()`, cpu time
45 | is minimized by making use of `CSimpleThreadBackOff` struct provided by the engine interfaces.
46 | During stall, window events and other interupt message (input) routines are explicitly signaled inside
47 | the stalling routine to allow (if wanted) console access and prevent erroneous 'Not Responding'
48 | messages from windows.
49 | Textures are released immediately after display so the render thread can discard the data at the most
50 | appropriate time.
51 | Uses `gEnv->pRenderer->EnumDisplayFormats(NULL)` to get the compatible display formats for the current primary device.
52 | Hooks into Player Profile updates to ensure switching between profiles will not cause undesired effects if the
53 | profile loaded/saved does not include the splash flag as this could override user-set rendering properties.
54 | Attempts to catch shutdown signals via system events to unregister routines that could cause issues during shutdown.
55 | Makes use of some custom CVARS for easier configuration of the splash routines.
56 |
57 | # CVARS
58 | Due to the initial splash screen not able to initialize before the renderer module, the r_width and r_height cvars
59 | ideally should match the size of your initial splash image (if using).
60 | Some CVARS are marked 'VF_CHEAT' to restrict modification in pure-client release builds to prevent end-users from
61 | supplying or overriding the textures used.
62 |
63 | # Compatibility
64 | Emphasis on compatiblity is prevelant and is always a concern for bloat. For this reason, only the current major engine version
65 | will receive updates and new features. The minimum compatibility criteria includes compatiblity with all projects designed
66 | for the current engine version targeted by the plugin. This should encompass GameZero/GameSDK and official template projects.
67 | Testing is done for GameZero/GameSDK and the C++ FPS template project - subject to project availability in the targeted
68 | engine version.
69 |
70 | # Special Notes
71 | * fullwindow by my meaning corresponds to the viewable, or renderable portion of the current active viewport or window.
72 | ** Caveats for this integration is:
73 | 1. Cannot use a player profile attribute named `SplashFlag_FirstRun`. This attribute is used internally.
74 | 2. If the splash flag is not set, and the default profile resolution is desired to be lowest possible setting,
75 | the resolution will be assumed to be wrong, and will override with the native resolution of the monitor.
76 | 3. Assumes CVARS like `r_width`/`r_fullscreen` etc to be used for the splash itself, whereas the attributes similarly
77 | named in the player profile (default or otherwise) to be the actual desired window rendering properties. This
78 | applies to all projects that use this plugin, not just the GameSDK.
--------------------------------------------------------------------------------
/Docs/INSTALL.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017, uniflare, see LICENSE.txt for details
2 | Splash Example Plugin
3 |
4 | # Compatiblity
5 | GameZero
6 | GameSDK
7 | Project templates
8 |
9 | # Pre-requisites
10 | CRYENGINE version 5.4.x
11 |
12 | 1. Compatible and working CRYENGINE installation either,
13 | by the official CRYENGINE Launcher, or
14 | by building your own custom engine from source*
15 |
16 | 2. If using a project, that the project is working, and
17 | both the Splash Example project and your own project
18 | uses the same CRYENGINE installation
19 |
20 | 3. If building from source, the requirements match with
21 | the target engine version requirements, eg;
22 | Visual Studio 2015 + Win SDK 10586.
23 |
24 | # Testing with GameZero or GameSDK
25 | 1. Copy the 'GameZero/GameSDK' asset folder to the splash example project root
26 |
27 | 2. Confirm the folder you copied is named correctly either, GameZero or GameSDK respectively.
28 |
29 | 3. From the supplied 'Assets' directory, copy the 'SplashExample' folder to the GameSDK/GameZero assets folder you copied.
30 | eg, for GameZero, you should now have a folder structure like so;
31 | |----SplashExample
32 | |----gamezero
33 | |----levels
34 | |----SplashExample
35 | |----game.cfg
36 | |----gamedata.cryasset.pak
37 | |----...
38 |
39 | 3b. (GameSDK Only)
40 | For 5.4, you will need to copy the GameSDK dll from the sample project to the matcvhing engine folder, eg
41 | C:\Program Files (x86)\Crytek\CRYENGINE Launcher\Crytek\gamesdk_5.4\GameSDK\bin\win_x64\CryGameSDK.dll
42 | to
43 | C:\Program Files (x86)\Crytek\CRYENGINE Launcher\Crytek\CRYENGINE_5.4\bin\win_x64\CryGameSDK.dll
44 |
45 | 4. (Right-Click) Launch Game using one of the provided cryproject files
46 | 'SplashExamplePlugin_GameZero', or 'SplashExamplePlugin_GameSDK'
47 |
48 | Note: By default these projects are set to use the official engine
49 | supplied by the 'CRYENGINE Launcher' application.
50 |
51 | # Installation/Integration into your project
52 |
53 | # Using pre-built binary for windows (x64 only)
54 | 1. CE 5.4 removes the cryplugin.csv file and takes CVARS in the respective cryproject file,
55 | be sure to copy necessary cvar entries (look to the supplied cryproject files for reference).
56 |
57 | 2. This package contains custom texture assets that must be bundled with your desired
58 | project assets, a simple 'drag & drop' from `Assets/SplashExamplePlugin` to
59 | to your `Project/Assets/SplashExamplePlugin` will suffice.
60 |
61 | 3. Make sure the binary (SplashExamplePlugin.dll) is bundled with your own project binary,
62 | this should reside in `Project/bin/win_x64` directory next to any 'Game' dll.
63 |
64 | # Building Splash Example from source
65 | 1. Please take a look at the supplied `Code/cmakelists.txt` file for variables that
66 | reference "TestPlatform". This is a feature tested with visual studio that allows
67 | the output binary to be directly copied to a target project binary folder. Default
68 | is disabled as the path will most certainly be innaccurate.
69 |
70 | 2. If using a testplatform, the assets will still need to be copied to your projects assets.**
71 |
72 | 3. As with other projects, simply use the 'SplashExamplePlugin.cryproject' file to generate
73 | the solution, and modify/build using Visual Studio.
74 |
75 | * Of course, due to the nature of custom engine builds, support cannot be given
76 | for custom built and modified engine installations. You take responsibility
77 | to maintain compatiblity with your modifications and the plugin provided.
78 |
79 | ** This feature is experimental and may or may not be included with future iterations.
80 |
81 | # WARNING
82 | It is not reccommended to use the "Switch engine version" feature of the cryproject context menu
83 | for moving from or to different engine versions. Rather, only use this feature to swtich between
84 | locally registered engines of the same version, ie, 'Official 5.4.x' and 'Custom Built-From-Source 5.4.x'.
--------------------------------------------------------------------------------
/Docs/MIGRATION_NOTES.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017, uniflare, see LICENSE.txt for details
2 | Splash Example Plugin
3 |
4 | Since 1.3.0 for 5.3, migration to 5.4 resulted in a new limitation for building from source -
5 | you cannot specify a custom output directory for release builds in the projects cmakelists file.
6 | Yet, inherited the more robust and compatible cmake system from 5.4. Minor tweaks to code base.
7 |
8 | # Usage differences
9 | 1. CVARS are now put into the respective cryproject files. (No more .cfg editing).
10 | 2. Necessary data from cryplugin.csv moved into respective cryproject files., csv deleted.
11 | 3. Renamed DLL name.
12 |
13 | # Technical changes
14 | *Some things may be missed, check github commits for more detailed information.
15 |
16 | No significant technical differences.
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | BSD 2-Clause License
2 |
3 | Copyright (c) 2017 uniflare
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/SplashExamplePlugin.cryproject:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "type": "CRYENGINE Project",
4 | "info": { "name": "Splash Example Plugin" },
5 | "content": {
6 | "assets": [ "Assets" ],
7 | "code": [ "Code" ]
8 | },
9 | "require": {
10 | "engine": "engine-5.4",
11 | "plugins": [
12 | { "type": "EPluginType::Native", "path": "bin/win_x64/SplashExamplePlugin" }
13 | ]
14 | },
15 | "console_variables": [
16 | { "name": "splash_show", "value": "1" },
17 | { "name": "splash_minimumPlaybackTime", "value": "3.0" },
18 | { "name": "splash_show_initial", "value": "1" },
19 | { "name": "splash_minimumPlaybackTime_initial", "value": "3.0" },
20 | { "name": "splash_texture", "value": "SplashExample/textures/Splash.dds" },
21 | { "name": "splash_texture_initial", "value": "SplashExample/textures/InitialSplash.dds" },
22 | { "name": "r_width", "value": "512" },
23 | { "name": "r_height", "value": "300" },
24 | { "name": "r_fullscreenwindow", "value": "1" },
25 | { "name": "r_fullscreen", "value": "0" }
26 | ]
27 | }
--------------------------------------------------------------------------------
/SplashExamplePlugin_GameSDK.cryproject:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "type": "CRYENGINE Project",
4 | "info": { "name": "Splash Example on GameSDK" },
5 | "content": {
6 | "assets": [ "gamesdk" ],
7 | "code": [ "" ],
8 | "libs": [
9 | {
10 | "name": "CRYENGINE",
11 | "shared": { "any": "CryGameSDK", "win_x64": "", "win_x86": "" }
12 | }
13 | ]
14 | },
15 | "require": {
16 | "engine": "engine-5.4",
17 | "plugins": [
18 | { "type": "EPluginType::Native", "path": "CryDefaultEntities" },
19 | { "type": "EPluginType::Native", "path": "CrySensorSystem" },
20 | { "type": "EPluginType::Native", "path": "CryPerceptionSystem" },
21 | { "type": "EPluginType::Native", "path": "bin/win_x64/SplashExamplePlugin" }
22 | ]
23 | },
24 | "console_variables": [
25 | { "name": "splash_show", "value": "1" },
26 | { "name": "splash_minimumPlaybackTime", "value": "3.0" },
27 | { "name": "splash_show_initial", "value": "1" },
28 | { "name": "splash_minimumPlaybackTime_initial", "value": "3.0" },
29 | { "name": "splash_texture", "value": "SplashExample/textures/Splash.dds" },
30 | { "name": "splash_texture_initial", "value": "SplashExample/textures/InitialSplash.dds" },
31 | { "name": "r_width", "value": "512" },
32 | { "name": "r_height", "value": "300" },
33 | { "name": "r_fullscreenwindow", "value": "1" },
34 | { "name": "r_fullscreen", "value": "0" }
35 | ]
36 | }
--------------------------------------------------------------------------------
/SplashExamplePlugin_GameZero.cryproject:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "type": "CRYENGINE Project",
4 | "info": { "name": "Splash Example on GameZero" },
5 | "content": {
6 | "assets": [ "gamezero" ],
7 | "code": [ "" ],
8 | "libs": [
9 | {
10 | "name": "CRYENGINE",
11 | "shared": { "any": "CryGameZero", "win_x64": "", "win_x86": "" }
12 | }
13 | ]
14 | },
15 | "require": {
16 | "engine": "engine-5.4",
17 | "plugins": [
18 | { "type": "EPluginType::Native", "path": "CryDefaultEntities" },
19 | { "type": "EPluginType::Native", "path": "CrySensorSystem" },
20 | { "type": "EPluginType::Native", "path": "CryPerceptionSystem" },
21 | { "type": "EPluginType::Native", "path": "bin/win_x64/SplashExamplePlugin" }
22 | ]
23 | },
24 | "console_variables": [
25 | { "name": "splash_show", "value": "1" },
26 | { "name": "splash_minimumPlaybackTime", "value": "3.0" },
27 | { "name": "splash_show_initial", "value": "1" },
28 | { "name": "splash_minimumPlaybackTime_initial", "value": "3.0" },
29 | { "name": "splash_texture", "value": "SplashExample/textures/Splash.dds" },
30 | { "name": "splash_texture_initial", "value": "SplashExample/textures/InitialSplash.dds" },
31 | { "name": "r_width", "value": "512" },
32 | { "name": "r_height", "value": "300" },
33 | { "name": "r_fullscreenwindow", "value": "1" },
34 | { "name": "r_fullscreen", "value": "0" }
35 | ]
36 | }
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017, uniflare, see LICENSE.txt for details
2 | # Splash Screen Example Plugin
3 | #
4 | Splash Example Plugin is a simple, light-weight splash screen rendering plugin with several features such as;
5 | - Drop and play!*
6 | - Compatible with engine templates and GameZero/GameSDK Sample project**
7 | - Renders an 'Initial' Splash texture in windowed mode immediately (first)***
8 | - Renders a 'Main' Splash texture in windowed or fullscreen mode
9 | - Several CVars to control the plugin without building from source
10 | - CVar `splash_plugin_enable` (def 1) Enable/Disable splash plugin
11 | - CVar `splash_show` (def 1) Controls showing the main (second) splash image
12 | - CVar `splash_minimumPlaybackTime` (def 3.0) 'Main' splash display time in seconds
13 | - CVar `splash_texture` (def 'SplashExample/Textures/Splash.dds') Main splash texture
14 | - CVar `splash_show_initial` (def 1) Enable/Disable the intial splash image
15 | - CVar `splash_minimumPlaybackTime_initial` (def 3.0) 'Initial' splash display time in seconds
16 | - CVar `splash_texture_initial` (def 'SplashExample/Textures/InitialSplash.dds') Pre splash texture
17 | - CVar `splash_startTimeOffset` (def 0.0) Allows for more accurate splash length in some cases
18 | - Extra documentation for learning/understanding the example plugin' concept
19 | - Verbosely commented source code (available on github)
20 | - Automatically overrides original splash screen routine (if any)
21 |
22 | * Installation can vary between projects, be sure to read the INSTALL.txt document in the 'Docs/' folder.
23 | ** Assumes that the example plugin package is compatible with the target engine.
24 | *** Make sure you set the correct r_width/r_height cvar values! This plugin assumes you are using the player
25 | profiles feature of CRYENGINE to store/set your game resolution! These cvars should be the same width
26 | and height of your initial splash image!
27 |
28 | ### Quick Start
29 | If you want to see it in action immediately, right-click and select 'Launch Game' on any cryproject file*
30 |
31 | * Assumes compatible engines have been installed via the CRYENGINE Launcher,
32 | also assumes the necessary assets folder exists in the projects root and contains the splash
33 | example textures.
34 |
35 | Note for 5.4: CryGameSDK does not seem to be lnicluded with the downloaded engine via the CRYENGINE Launcher.
36 | For this reason, an extra step is required to test the CryGameSDK; Simply copy CryGameSDK.dll from
37 | the GameSDK (5.4) bin folder to the launcher engine bin folder, by default, this means;
38 | C:\Program Files (x86)\Crytek\CRYENGINE Launcher\Crytek\gamesdk_5.4\GameSDK\bin\win_x64\CryGameSDK.dll
39 | to
40 | C:\Program Files (x86)\Crytek\CRYENGINE Launcher\Crytek\CRYENGINE_5.4\bin\win_x64\CryGameSDK.dll
41 |
42 | ### Integration with a project
43 | Integration consists of a several requierd steps to combine the splash plugin with an external project. For
44 | more information consult the INSTALL.txt document in the 'Docs/' folder supplied with this package.
45 |
46 | ### Building the plugin using Visual Studio
47 | Building is not necessary to use the plugin, however it is very easy to do so.
48 | Consult the INSTALL.txt document in the 'Docs/' folder supplied with this package.
49 |
50 | ### More information
51 | For help or more information please visit the associated thread on the forums below.
52 | CRYENGINE ® Forum Thread: https://forum.cryengine.com/viewtopic.php?f=55&t=4201
53 | CRYENGINE ® (Archived) Forum Thread: https://www.cryengine.com/community_archive/viewtopic.php?f=314&t=135972
54 | GitHub ® Repository: https://github.com/uniflare/SplashExample
--------------------------------------------------------------------------------