<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://g1r-mp.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Scripted_camera</id>
	<title>Scripted camera - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://g1r-mp.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Scripted_camera"/>
	<link rel="alternate" type="text/html" href="https://g1r-mp.com/wiki/index.php?title=Scripted_camera&amp;action=history"/>
	<updated>2026-09-19T06:21:39Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.0</generator>
	<entry>
		<id>https://g1r-mp.com/wiki/index.php?title=Scripted_camera&amp;diff=824&amp;oldid=prev</id>
		<title>QCherry: Update 0.1.3 camera world placement, streaming safety and far camera test</title>
		<link rel="alternate" type="text/html" href="https://g1r-mp.com/wiki/index.php?title=Scripted_camera&amp;diff=824&amp;oldid=prev"/>
		<updated>2026-09-09T00:07:56Z</updated>

		<summary type="html">&lt;p&gt;Update 0.1.3 camera world placement, streaming safety and far camera test&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw-interface=&quot;&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 00:07, 9 September 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l37&quot;&gt;Line 37:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 37:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Server-side &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; does not confirm the target client&#039;s camera is ready, accepts ownership, &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;satisfies the distance limit &lt;/del&gt;or displays the requested view. There are no server camera getters or server camera-acknowledgement events. Use client scripting for sequences that must wait for execution results. Do not mix client and server ownership within one sequence.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Server-side &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; does not confirm the target client&#039;s camera is ready, accepts ownership, &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;has finished world streaming &lt;/ins&gt;or displays the requested view. There are no server camera getters or server camera-acknowledgement events. Use client scripting for sequences that must wait for execution results. Do not mix client and server ownership within one sequence.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;== Units, poses and limits ==&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;== Units, poses and limits ==&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l46&quot;&gt;Line 46:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 46:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| Position || World-space metres; finite coordinates between -1,000,000 and 1,000,000&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| Position || World-space metres; finite coordinates between -1,000,000 and 1,000,000&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;|-&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;|-&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| Distance from player || &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Camera must remain within 100 m of &lt;/del&gt;the local character, &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;including during movement&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| Distance from player || &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;No distance limit relative to &lt;/ins&gt;the local character&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;; positions&lt;/ins&gt;, &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;paths and orbits may target distant locations in the current world, subject to the coordinate limits&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;|-&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;|-&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| Rotation || Pitch, yaw and roll in degrees; finite absolute values at most 360,000; shortest-angle interpolation&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| Rotation || Pitch, yaw and roll in degrees; finite absolute values at most 360,000; shortest-angle interpolation&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l71&quot;&gt;Line 71:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 71:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;orbitCamera(center, options)&amp;lt;/code&amp;gt; takes a fixed &amp;lt;code&amp;gt;{x,y,z}&amp;lt;/code&amp;gt; centre, not a player ID. Defaults are radius 5 m, height 2 m, startAngle 0 degrees, sweepAngle 360 degrees, loop false and easing smooth. Radius must be 0.1 to 50 m, height -50 to 50 m, startAngle within +/-360,000 degrees and sweepAngle within +/-3600 degrees. A negative sweep reverses direction. The current FOV is preserved.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;orbitCamera(center, options)&amp;lt;/code&amp;gt; takes a fixed &amp;lt;code&amp;gt;{x,y,z}&amp;lt;/code&amp;gt; centre, not a player ID. Defaults are radius 5 m, height 2 m, startAngle 0 degrees, sweepAngle 360 degrees, loop false and easing smooth. Radius must be 0.1 to 50 m, height -50 to 50 m, startAngle within +/-360,000 degrees and sweepAngle within +/-3600 degrees. A negative sweep reverses direction. The current FOV is preserved.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Client-side options must explicitly provide &amp;lt;code&amp;gt;durationMs&amp;lt;/code&amp;gt; from 100 to 600,000. On the server, the options table is required but a missing durationMs defaults to 10,000. The centre does not follow a moving player. The complete orbit must fit the &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;player&#039;s 100 m camera bound; the &lt;/del&gt;conservative check &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;includes centre &lt;/del&gt;distance &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;plus &lt;/del&gt;the &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;radius/height extent&lt;/del&gt;.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Client-side options must explicitly provide &amp;lt;code&amp;gt;durationMs&amp;lt;/code&amp;gt; from 100 to 600,000. On the server, the options table is required but a missing durationMs defaults to 10,000. The centre does not follow a moving player. The &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;centre and &lt;/ins&gt;complete orbit &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;extent &lt;/ins&gt;must fit the &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;finite coordinate range: &amp;lt;code&amp;gt;center.x +/- radius&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;center.y +/- radius&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;center.z + height&amp;lt;/code&amp;gt; must each remain between -1,000,000 and 1,000,000 metres. This &lt;/ins&gt;conservative check &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;applies even to a partial sweep; it is not a &lt;/ins&gt;distance &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;limit from &lt;/ins&gt;the &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;character&lt;/ins&gt;.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;== Acknowledgements and cached getters ==&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;== Acknowledgements and cached getters ==&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l129&quot;&gt;Line 129:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 129:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Resource stop/start failure automatically cleans up camera ownership; do not depend on a camera-reset callback while the resource is closing. Use the normal resource-stop lifecycle to cancel your own timers. For a still-running resource, [[onClientCameraReset]] reports forced native lifecycle cleanup or IPC invalidation. Native forced cleanup targets the camera owner; IPC disconnect also notifies affected query-only resources with cached state or pending requests. The cache, pending requests and ownership bookkeeping are cleared before the callback. On IPC disconnect, stateJson can be empty; this notification alone does not prove a newly restored view has rendered. Wait for world/spawn readiness before starting again. Old request IDs and connection generations must not be replayed.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Resource stop/start failure automatically cleans up camera ownership; do not depend on a camera-reset callback while the resource is closing. Use the normal resource-stop lifecycle to cancel your own timers. For a still-running resource, [[onClientCameraReset]] reports forced native lifecycle cleanup or IPC invalidation. Native forced cleanup targets the camera owner; IPC disconnect also notifies affected query-only resources with cached state or pending requests. The cache, pending requests and ownership bookkeeping are cleared before the callback. On IPC disconnect, stateJson can be empty; this notification alone does not prove a newly restored view has rendered. Wait for world/spawn readiness before starting again. Old request IDs and connection generations must not be replayed.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Camera movement does not change the server&#039;s area of interest: distant players/NPCs/monsters are still replicated relative to the character. This API is not long-range spectator support. The older experimental &amp;lt;code&amp;gt;setCameraTarget&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;resetCamera&amp;lt;/code&amp;gt; entry points are separate APIs, not aliases of these functions; remote-player target following is not implemented by this scripted-camera feature.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;== Distant views and world streaming ==&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Camera positions, paths and orbits are not restricted by distance from the local character. They address locations in the current world; they do not switch maps or make coordinates outside the game&#039;s actual terrain meaningful.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Unreal&#039;s standard local PlayerController streaming source follows its active &amp;lt;code&amp;gt;ViewTarget&amp;lt;/code&amp;gt;, which this API changes to the scripted camera.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Before taking that view, the native module adds its own &amp;lt;code&amp;gt;WorldPartitionStreamingSourceComponent&amp;lt;/code&amp;gt; to the validated local pawn. The engine follows the component owner&#039;s position, preserving a streaming source around the character without teleporting it or freezing input. It uses the world&#039;s default grid loading range without changing global streaming settings or existing sources. If this safeguard cannot be prepared, camera takeover is rejected with &amp;lt;code&amp;gt;camera-pawn-streaming-source-unavailable&amp;lt;/code&amp;gt;.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;The pawn&#039;s source remains active throughout a reset blend until the return is confirmed. Deferred cleanup or a foreign cutscene keeps it until a safe return to the pawn or pawn/world teardown. &amp;lt;code&amp;gt;stopCameraMovement&amp;lt;/code&amp;gt; and natural &amp;lt;code&amp;gt;completed&amp;lt;/code&amp;gt; do not release it because scripted camera ownership remains active. Keeping both areas loaded can increase memory and streaming costs and affect frame rate.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;World streaming is asynchronous: a large camera jump can initially show missing terrain, low-detail scenery or assets still loading. An &amp;lt;code&amp;gt;applied&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;completed&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; acknowledgement does not confirm streaming completion, and &amp;lt;code&amp;gt;ready&amp;lt;/code&amp;gt; describes camera/world context rather than readiness of every visible asset. A fresh pose read-back checks where the camera is, not whether the remote scenery has finished loading. Allow time for streaming and manually check the distant scene and the return to the character; camera commands do not provide an all-visible-assets-loaded event.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Camera movement does not change the server&#039;s area of interest: distant players/NPCs/monsters are still replicated relative to the character&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;. Streaming scenery around the camera does not request those remote multiplayer entities&lt;/ins&gt;. This API is not long-range &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;multiplayer &lt;/ins&gt;spectator support. The older experimental &amp;lt;code&amp;gt;setCameraTarget&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;resetCamera&amp;lt;/code&amp;gt; entry points are separate APIs, not aliases of these functions; remote-player target following is not implemented by this scripted-camera feature.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;== Example: a moving login background ==&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;== Example: a moving login background ==&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l207&quot;&gt;Line 207:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 219:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;== Manual test in the bundled GothicRP resource ==&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;== Manual test in the bundled GothicRP resource ==&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;After login and confirmed character spawn, run &amp;lt;code&amp;gt;/cameratest&amp;lt;/code&amp;gt; in a safe place. &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;It exercises &lt;/del&gt;position, rotation including roll, LookAt, FOV, cached getters, full poses, smooth and linear motion, paths/holds/loops, orbits, stop, movement replacement and reset. &amp;lt;code&amp;gt;/cameratest stop&amp;lt;/code&amp;gt; cancels the &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;sequence &lt;/del&gt;and requests a reset. Chat messages are in English.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;After login and confirmed character spawn, run &amp;lt;code&amp;gt;/cameratest&amp;lt;/code&amp;gt; in a safe place. &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Its original 19 stages remain local to the character and exercise &lt;/ins&gt;position, rotation including roll, LookAt, FOV, cached getters, full poses, smooth and linear motion, paths/holds/loops, orbits, stop, movement replacement and reset.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;The optional &amp;lt;code&amp;gt;/cameratest far&amp;lt;/code&amp;gt; runs a separate 14-stage sequence around a fixed scene approximately 300 m from the starting character position. It tests a distant position and LookAt, smooth movement, a three-point path, a full orbit, a reverse looping orbit, stop and return to the player camera. Five fresh state queries, issued at least 350 ms after the corresponding acknowledgement, verify that the camera is more than 200 m from the starting character position, is stopped where expected, and reaches the requested endpoints within 1 m. The final reset is acknowledged and followed by a fresh inactive/not-moving check. The far test reports an error on the old distance-limited client or when an acknowledgement arrives without the expected position change.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;/cameratest stop&amp;lt;/code&amp;gt; cancels &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;either sequence and requests a reset. A missing native acknowledgement fails &lt;/ins&gt;the &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;current step after 20 seconds &lt;/ins&gt;and requests a reset&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;. Restarting a test retires the previous run&#039;s timers and pending request; delayed results from that run do not advance the new sequence&lt;/ins&gt;. Chat messages are in English.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;This is a &lt;/del&gt;GothicRP resource &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;command&lt;/del&gt;, not &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;a &lt;/del&gt;built-in camera &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;API &lt;/del&gt;available in every gamemode. &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;It does &lt;/del&gt;not teleport the character or modify progression. &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;The sequence waits for native acknowledgements, but a &lt;/del&gt;success report &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;still requires &lt;/del&gt;a human &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;to judge visual &lt;/del&gt;movement and &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;the &lt;/del&gt;final return to the player camera.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;These are &lt;/ins&gt;GothicRP resource &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;commands&lt;/ins&gt;, not built-in camera &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;APIs &lt;/ins&gt;available in every gamemode. &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;They do &lt;/ins&gt;not teleport the character&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;, freeze input &lt;/ins&gt;or modify progression. &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;A &lt;/ins&gt;success report &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;confirms the tested commands/read-backs, not terrain loading or rendered image quality: &lt;/ins&gt;a human &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;must inspect the distant scenery, camera &lt;/ins&gt;movement and final return to the player camera.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Category:Lua API]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Category:Lua API]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Category:Lua Examples]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Category:Lua Examples]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>QCherry</name></author>
	</entry>
	<entry>
		<id>https://g1r-mp.com/wiki/index.php?title=Scripted_camera&amp;diff=810&amp;oldid=prev</id>
		<title>QCherry: Document scripted camera API and events available from G1R:MP 0.1.3</title>
		<link rel="alternate" type="text/html" href="https://g1r-mp.com/wiki/index.php?title=Scripted_camera&amp;diff=810&amp;oldid=prev"/>
		<updated>2026-09-08T23:51:05Z</updated>

		<summary type="html">&lt;p&gt;Document scripted camera API and events available from G1R:MP 0.1.3&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;__NOTOC__&lt;br /&gt;
= Scripted camera =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;background:#fff5f5; border:1px solid #d13b3b; border-left:5px solid #d13b3b; color:#111111; padding:0.85rem 1rem; margin:0.75rem 0 1rem;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;color:#111111; font-weight:bold; letter-spacing:0.04em;&amp;quot;&amp;gt;AVAILABLE FROM UPDATE 0.1.3&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;color:#111111; margin-top:0.25rem;&amp;quot;&amp;gt;The scripted-camera functions and client events described here are available in G1R:MP 0.1.3 and later.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use a scripted camera for a login background, character presentation, a fixed shot, a travelling shot or an orbit. It controls the local view without teleporting the character or possessing a spectator pawn. Camera control does not freeze player input, make the character invulnerable, or change server gameplay rules.&lt;br /&gt;
&lt;br /&gt;
== Function reference ==&lt;br /&gt;
&lt;br /&gt;
All functions support the documented lowerCamelCase name and an equivalent PascalCase name: for example, &amp;lt;code&amp;gt;setCameraPos&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;SetCameraPos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Purpose !! Functions !! Execution side&lt;br /&gt;
|-&lt;br /&gt;
| Position, rotation and view || [[setCameraPos]], [[setCameraRot]], [[setCameraLookAt]], [[setCameraFOV]], [[setCameraPose]] || Client and server&lt;br /&gt;
|-&lt;br /&gt;
| Movement || [[moveCameraTo]], [[playCameraPath]], [[orbitCamera]], [[stopCameraMovement]] || Client and server&lt;br /&gt;
|-&lt;br /&gt;
| Restore gameplay view || [[resetCameraPos]] || Client and server&lt;br /&gt;
|-&lt;br /&gt;
| Cached read-back || [[getCameraPos]], [[getCameraRot]], [[getCameraFOV]], [[getCameraState]] || Client only&lt;br /&gt;
|-&lt;br /&gt;
| Refresh cached state || [[requestCameraState]] || Client only&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Client mutators return a positive request ID, or &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; when validation or queuing fails. The ID is not an execution acknowledgement. Server mutators prepend &amp;lt;code&amp;gt;playerId&amp;lt;/code&amp;gt; and return a queued boolean instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- Client-side, current resource and local player:&lt;br /&gt;
local requestId = setCameraFOV(70)&lt;br /&gt;
&lt;br /&gt;
-- Server-side, a connected player:&lt;br /&gt;
local queued = setCameraFOV(playerId, 70)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Server-side &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; does not confirm the target client&amp;#039;s camera is ready, accepts ownership, satisfies the distance limit or displays the requested view. There are no server camera getters or server camera-acknowledgement events. Use client scripting for sequences that must wait for execution results. Do not mix client and server ownership within one sequence.&lt;br /&gt;
&lt;br /&gt;
== Units, poses and limits ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Value !! Contract&lt;br /&gt;
|-&lt;br /&gt;
| Position || World-space metres; finite coordinates between -1,000,000 and 1,000,000&lt;br /&gt;
|-&lt;br /&gt;
| Distance from player || Camera must remain within 100 m of the local character, including during movement&lt;br /&gt;
|-&lt;br /&gt;
| Rotation || Pitch, yaw and roll in degrees; finite absolute values at most 360,000; shortest-angle interpolation&lt;br /&gt;
|-&lt;br /&gt;
| FOV || 15 to 150 degrees inclusive&lt;br /&gt;
|-&lt;br /&gt;
| Timings || Whole milliseconds; general movement duration 0 to 600,000; reset blend 0 to 10,000&lt;br /&gt;
|-&lt;br /&gt;
| Easing || Case-sensitive &amp;lt;code&amp;gt;linear&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;smooth&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;in&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;out&amp;lt;/code&amp;gt;; default &amp;lt;code&amp;gt;smooth&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A complete pose has &amp;lt;code&amp;gt;x, y, z, pitch, yaw, roll, fov&amp;lt;/code&amp;gt;. Client-side &amp;lt;code&amp;gt;setCameraPose&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;moveCameraTo&amp;lt;/code&amp;gt; and the first path point can inherit missing fields from the current resource&amp;#039;s ready acknowledged cache. Without that cache, supply all seven fields. Later client path points inherit missing pose fields from the previous point.&lt;br /&gt;
&lt;br /&gt;
On the server, &amp;lt;code&amp;gt;setCameraPose&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;moveCameraTo&amp;lt;/code&amp;gt; and &amp;#039;&amp;#039;&amp;#039;every&amp;#039;&amp;#039;&amp;#039; path point independently require &amp;lt;code&amp;gt;x,y,z&amp;lt;/code&amp;gt;. Missing angles default to 0 and FOV to 90. There is no server-side pose inheritance.&lt;br /&gt;
&lt;br /&gt;
Position-only, rotation-only and FOV-only setters preserve the remaining current camera fields. Omitting &amp;lt;code&amp;gt;roll&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;setCameraRot&amp;lt;/code&amp;gt; sets roll to 0. &amp;lt;code&amp;gt;setCameraLookAt&amp;lt;/code&amp;gt; rotates towards a fixed world point, sets roll to 0, and fails if the target coincides with the camera position. It is not a persistent follow attachment.&lt;br /&gt;
&lt;br /&gt;
=== Paths ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;playCameraPath(points, options)&amp;lt;/code&amp;gt; accepts a dense 1-based array of 1 to 32 poses. Each point&amp;#039;s &amp;lt;code&amp;gt;durationMs&amp;lt;/code&amp;gt; defaults to 2000 and must be at least 1; &amp;lt;code&amp;gt;holdMs&amp;lt;/code&amp;gt; defaults to 0. The sum of all travel and hold times must not exceed 600,000 ms. Options are &amp;lt;code&amp;gt;loop=false&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;easing=&amp;quot;smooth&amp;quot;&amp;lt;/code&amp;gt; by default. A loop repeats the sequence until stopped, reset or interrupted; the 600,000 ms limit applies to one complete sequence, not the lifetime of a loop.&lt;br /&gt;
&lt;br /&gt;
=== Orbits ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;orbitCamera(center, options)&amp;lt;/code&amp;gt; takes a fixed &amp;lt;code&amp;gt;{x,y,z}&amp;lt;/code&amp;gt; centre, not a player ID. Defaults are radius 5 m, height 2 m, startAngle 0 degrees, sweepAngle 360 degrees, loop false and easing smooth. Radius must be 0.1 to 50 m, height -50 to 50 m, startAngle within +/-360,000 degrees and sweepAngle within +/-3600 degrees. A negative sweep reverses direction. The current FOV is preserved.&lt;br /&gt;
&lt;br /&gt;
Client-side options must explicitly provide &amp;lt;code&amp;gt;durationMs&amp;lt;/code&amp;gt; from 100 to 600,000. On the server, the options table is required but a missing durationMs defaults to 10,000. The centre does not follow a moving player. The complete orbit must fit the player&amp;#039;s 100 m camera bound; the conservative check includes centre distance plus the radius/height extent.&lt;br /&gt;
&lt;br /&gt;
== Acknowledgements and cached getters ==&lt;br /&gt;
&lt;br /&gt;
The built-in local event [[onClientCameraCommandResult]] is attached to &amp;lt;code&amp;gt;resourceRoot&amp;lt;/code&amp;gt;; no &amp;lt;code&amp;gt;addEvent&amp;lt;/code&amp;gt; call is needed. Its callback is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function(requestId, ok, phase, errorText, stateJson)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Command !! Successful phases&lt;br /&gt;
|-&lt;br /&gt;
| requestCameraState || &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Position/rotation/LookAt/FOV/pose setters; stopCameraMovement || &amp;lt;code&amp;gt;applied&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| moveCameraTo; non-looping playCameraPath/orbitCamera || &amp;lt;code&amp;gt;applied&amp;lt;/code&amp;gt;, then &amp;lt;code&amp;gt;completed&amp;lt;/code&amp;gt; using the same requestId&lt;br /&gt;
|-&lt;br /&gt;
| Looping path/orbit || &amp;lt;code&amp;gt;applied&amp;lt;/code&amp;gt;; no completed while looping&lt;br /&gt;
|-&lt;br /&gt;
| resetCameraPos || &amp;lt;code&amp;gt;reset&amp;lt;/code&amp;gt; after the restore transition&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Execution rejection reports &amp;lt;code&amp;gt;ok=false, phase=&amp;quot;error&amp;quot;&amp;lt;/code&amp;gt;. Replacing, stopping or resetting an active movement can report &amp;lt;code&amp;gt;ok=false, phase=&amp;quot;cancelled&amp;quot;&amp;lt;/code&amp;gt; for the earlier movement request. Interrupted reset requests can report an error. Match request IDs: a cancellation for an older movement is not a failure of the new command.&lt;br /&gt;
&lt;br /&gt;
A validated state snapshot is cached before the callback, including an available valid snapshot attached to a failed result. A query can be submitted before the local camera/world is ready if IPC is connected, and can successfully return &amp;lt;code&amp;gt;phase=&amp;quot;state&amp;quot;, ready=false&amp;lt;/code&amp;gt;; always check ready before using the pose or starting control. &amp;lt;code&amp;gt;getCameraPos&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;{x,y,z}&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;getCameraRot&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;{pitch,yaw,roll}&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;getCameraFOV&amp;lt;/code&amp;gt; returns a number. These return false when no ready snapshot exists. &amp;lt;code&amp;gt;getCameraState&amp;lt;/code&amp;gt; returns false with no cache, or a table which may have &amp;lt;code&amp;gt;ready=false&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The state table contains:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Fields !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| x, y, z; pitch, yaw, roll; fov || Last acknowledged engine camera pose, in metres/degrees&lt;br /&gt;
|-&lt;br /&gt;
| playerX, playerY, playerZ || Local character position in metres&lt;br /&gt;
|-&lt;br /&gt;
| ready || Whether valid local-world/camera context is available for the snapshot&lt;br /&gt;
|-&lt;br /&gt;
| active || Whether the scripted camera is active&lt;br /&gt;
|-&lt;br /&gt;
| moving || Whether a scripted movement is active&lt;br /&gt;
|-&lt;br /&gt;
| sampleTimeMs || Timestamp of the native sample; not a UTC wall-clock time&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The event&amp;#039;s JSON additionally includes &amp;lt;code&amp;gt;version=1&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;getCameraState()&amp;lt;/code&amp;gt; does not expose that version field. Failed results may have empty stateJson, so parse defensively.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Getters are not synchronous engine queries.&amp;#039;&amp;#039;&amp;#039; An applied acknowledgement confirms command handling; completed confirms the interpolation reached its end. Neither proves the new camera view has rendered. An immediate acknowledgement snapshot can still contain the previous frame&amp;#039;s pose. If you need post-change values, wait another frame or a short timer, call &amp;lt;code&amp;gt;requestCameraState&amp;lt;/code&amp;gt;, and handle its &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; result. Do not issue a new query unconditionally for every result, which would create a feedback loop.&lt;br /&gt;
&lt;br /&gt;
== Ownership, stopping and cleanup ==&lt;br /&gt;
&lt;br /&gt;
Only one resource/origin can own scripted camera control at a time. A client resource and a server resource with the same name are still different origins. Another resource&amp;#039;s mutating request is rejected while the owner is active. State queries do not take ownership and can be used by other client resources.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;stopCameraMovement&amp;lt;/code&amp;gt; leaves the camera in place and keeps ownership. A non-looping movement reaching completed also leaves the scripted camera active. Use &amp;lt;code&amp;gt;resetCameraPos&amp;lt;/code&amp;gt; to restore the player&amp;#039;s gameplay camera and release your ownership. Reset is owner-scoped; it does not steal another resource&amp;#039;s camera or forcefully replace a foreign cutscene.&lt;br /&gt;
&lt;br /&gt;
Resource stop/start failure automatically cleans up camera ownership; do not depend on a camera-reset callback while the resource is closing. Use the normal resource-stop lifecycle to cancel your own timers. For a still-running resource, [[onClientCameraReset]] reports forced native lifecycle cleanup or IPC invalidation. Native forced cleanup targets the camera owner; IPC disconnect also notifies affected query-only resources with cached state or pending requests. The cache, pending requests and ownership bookkeeping are cleared before the callback. On IPC disconnect, stateJson can be empty; this notification alone does not prove a newly restored view has rendered. Wait for world/spawn readiness before starting again. Old request IDs and connection generations must not be replayed.&lt;br /&gt;
&lt;br /&gt;
Camera movement does not change the server&amp;#039;s area of interest: distant players/NPCs/monsters are still replicated relative to the character. This API is not long-range spectator support. The older experimental &amp;lt;code&amp;gt;setCameraTarget&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;resetCamera&amp;lt;/code&amp;gt; entry points are separate APIs, not aliases of these functions; remote-player target following is not implemented by this scripted-camera feature.&lt;br /&gt;
&lt;br /&gt;
== Example: a moving login background ==&lt;br /&gt;
&lt;br /&gt;
This client-side example demonstrates the public APIs. Call &amp;lt;code&amp;gt;beginLoginCamera()&amp;lt;/code&amp;gt; from your UI flow only after the local game world/player camera is ready. Call &amp;lt;code&amp;gt;finishLoginCameraAfterSpawn()&amp;lt;/code&amp;gt; only after your resource has confirmed the actual character spawn has completed. Authentication success alone is not that confirmation. These two helper functions are defined by the example; they are not built-in events or engine functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot; line&amp;gt;&lt;br /&gt;
local showingLogin = false&lt;br /&gt;
local queryRequest, fovRequest, orbitRequest, resetRequest&lt;br /&gt;
local orbitCenter&lt;br /&gt;
&lt;br /&gt;
function beginLoginCamera()&lt;br /&gt;
    if showingLogin then return end&lt;br /&gt;
    showingLogin = true&lt;br /&gt;
    queryRequest = requestCameraState()&lt;br /&gt;
    if not queryRequest then showingLogin = false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function releaseLoginCamera()&lt;br /&gt;
    showingLogin = false&lt;br /&gt;
    queryRequest, fovRequest, orbitRequest = nil, nil, nil&lt;br /&gt;
    resetRequest = resetCameraPos(800)&lt;br /&gt;
    if not resetRequest then&lt;br /&gt;
        outputDebugString(&amp;quot;Login camera reset was not queued&amp;quot;, 2)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function finishLoginCameraAfterSpawn()&lt;br /&gt;
    releaseLoginCamera()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onClientCameraCommandResult&amp;quot;, resourceRoot,&lt;br /&gt;
    function(requestId, ok, phase, errorText)&lt;br /&gt;
        if requestId == resetRequest then&lt;br /&gt;
            if not ok or phase == &amp;quot;reset&amp;quot; then resetRequest = nil end&lt;br /&gt;
            if not ok then outputDebugString(&amp;quot;Camera reset: &amp;quot; .. tostring(errorText), 2) end&lt;br /&gt;
            return&lt;br /&gt;
        end&lt;br /&gt;
        if not showingLogin then return end&lt;br /&gt;
        if requestId ~= queryRequest and requestId ~= fovRequest&lt;br /&gt;
            and requestId ~= orbitRequest then return end&lt;br /&gt;
        if not ok then&lt;br /&gt;
            outputDebugString(&amp;quot;Login camera: &amp;quot; .. tostring(errorText), 2)&lt;br /&gt;
            releaseLoginCamera() -- Abort this presentation and release our view.&lt;br /&gt;
            return&lt;br /&gt;
        end&lt;br /&gt;
        if requestId == queryRequest and phase == &amp;quot;state&amp;quot; then&lt;br /&gt;
            queryRequest = nil&lt;br /&gt;
            local state = getCameraState()&lt;br /&gt;
            if not state or not state.ready then&lt;br /&gt;
                showingLogin = false&lt;br /&gt;
                return&lt;br /&gt;
            end&lt;br /&gt;
            orbitCenter = {x=state.playerX, y=state.playerY, z=state.playerZ + 1.2}&lt;br /&gt;
            fovRequest = setCameraFOV(70)&lt;br /&gt;
            if not fovRequest then releaseLoginCamera() end&lt;br /&gt;
        elseif requestId == fovRequest and phase == &amp;quot;applied&amp;quot; then&lt;br /&gt;
            fovRequest = nil&lt;br /&gt;
            orbitRequest = orbitCamera(orbitCenter,&lt;br /&gt;
                {radius=5, height=2, durationMs=30000, loop=true, easing=&amp;quot;linear&amp;quot;})&lt;br /&gt;
            if not orbitRequest then releaseLoginCamera() end&lt;br /&gt;
        elseif requestId == orbitRequest and phase == &amp;quot;applied&amp;quot; then&lt;br /&gt;
            outputDebugString(&amp;quot;Login camera orbit started&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
    end)&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onClientCameraReset&amp;quot;, resourceRoot, function(reason)&lt;br /&gt;
    showingLogin = false&lt;br /&gt;
    queryRequest, fovRequest, orbitRequest, resetRequest = nil, nil, nil, nil&lt;br /&gt;
    orbitCenter = nil&lt;br /&gt;
    outputDebugString(&amp;quot;Login camera invalidated: &amp;quot; .. tostring(reason))&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For production UI, also bound the time spent waiting for acknowledgements and cancel your own timers when the resource stops or the camera is invalidated. Do not retry indefinitely or reacquire the camera on every frame. Freeze/unfreeze gameplay input separately only if your resource&amp;#039;s login flow requires it; camera ownership itself does not manage input.&lt;br /&gt;
&lt;br /&gt;
== Manual test in the bundled GothicRP resource ==&lt;br /&gt;
&lt;br /&gt;
After login and confirmed character spawn, run &amp;lt;code&amp;gt;/cameratest&amp;lt;/code&amp;gt; in a safe place. It exercises position, rotation including roll, LookAt, FOV, cached getters, full poses, smooth and linear motion, paths/holds/loops, orbits, stop, movement replacement and reset. &amp;lt;code&amp;gt;/cameratest stop&amp;lt;/code&amp;gt; cancels the sequence and requests a reset. Chat messages are in English.&lt;br /&gt;
&lt;br /&gt;
This is a GothicRP resource command, not a built-in camera API available in every gamemode. It does not teleport the character or modify progression. The sequence waits for native acknowledgements, but a success report still requires a human to judge visual movement and the final return to the player camera.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua API]]&lt;br /&gt;
[[Category:Lua Examples]]&lt;/div&gt;</summary>
		<author><name>QCherry</name></author>
	</entry>
</feed>