mirror of
https://github.com/originalnicodr/CinematicUnityExplorer.git
synced 2026-10-10 04:53:15 +08:00
Add support for multiple IGCS addons (#132)
* feat: fill camera data to igcs connector. * Add camera locked data * feat: support all possible dof implementations * Remove misterious constants
This commit is contained in:
@@ -2,13 +2,30 @@
|
||||
#include <Windows.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <Psapi.h>
|
||||
|
||||
#define EXPOSE __declspec(dllexport)
|
||||
|
||||
// Since we're using C, we're a bit limited on how we define enums,
|
||||
// so for the screenshot session, we have to do this.
|
||||
|
||||
#ifdef _M_IX86
|
||||
typedef uint8_t SessionStatus;
|
||||
#else
|
||||
typedef int SessionStatus;
|
||||
#endif
|
||||
|
||||
#define SESSION_STATUS_OK ((SessionStatus)0)
|
||||
#define SESSION_STATUS_CAMERA_NOT_ENABLED ((SessionStatus)1)
|
||||
#define SESSION_STATUS_CAMERA_PATH_PLAYING ((SessionStatus)2)
|
||||
#define SESSION_STATUS_ALREADY_SESSION_ACTIVE ((SessionStatus)3)
|
||||
#define SESSION_STATUS_CAMERA_FEAT_NOT_AVAILABLE ((SessionStatus)4)
|
||||
#define SESSION_STATUS_UNKNOWN_ERROR ((SessionStatus)5)
|
||||
|
||||
// The function that will be the one called from the C# side, that will update the corresponding values.
|
||||
typedef void (*MoveCameraCallback)(float, float, float, int);
|
||||
|
||||
typedef void (*SessionCallback)(void);
|
||||
typedef int (*SessionCallback)(void);
|
||||
|
||||
typedef uint8_t* (*GetCameraDataFunc)(void);
|
||||
|
||||
@@ -16,15 +33,19 @@ MoveCameraCallback GlobalCallback = NULL;
|
||||
SessionCallback GlobalStartSession = NULL;
|
||||
SessionCallback GlobalEndSession = NULL;
|
||||
|
||||
EXPOSE uint8_t* U_IGCS_CameraData[10];
|
||||
|
||||
// There are things that only needs to be run once.
|
||||
static int first_initialization = 1;
|
||||
|
||||
EXPOSE int __cdecl IGCS_StartScreenshotSession(uint8_t _ignore) {
|
||||
|
||||
|
||||
EXPOSE SessionStatus __cdecl IGCS_StartScreenshotSession(uint8_t _ignore) {
|
||||
if (GlobalStartSession) {
|
||||
GlobalStartSession();
|
||||
printf("Called StartSession\n");
|
||||
return (SessionStatus)GlobalStartSession();
|
||||
}
|
||||
return 0;
|
||||
return SESSION_STATUS_CAMERA_FEAT_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
EXPOSE void __cdecl IGCS_EndScreenshotSession() {
|
||||
@@ -32,6 +53,34 @@ EXPOSE void __cdecl IGCS_EndScreenshotSession() {
|
||||
printf("Called EndSession\n");
|
||||
}
|
||||
|
||||
int connect_all_tools() {
|
||||
HMODULE mods[1024];
|
||||
DWORD cbNeeded;
|
||||
HANDLE proc = GetCurrentProcess();
|
||||
int cameraSize = 0;
|
||||
|
||||
if (!EnumProcessModules(proc, mods, sizeof(mods), &cbNeeded)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
|
||||
FARPROC connect_camera_tools = GetProcAddress(mods[i], "connectFromCameraTools");
|
||||
GetCameraDataFunc getCameraData = (GetCameraDataFunc)GetProcAddress(mods[i], "getDataFromCameraToolsBuffer");
|
||||
|
||||
if (connect_camera_tools == NULL) continue;
|
||||
|
||||
char module_name[512];
|
||||
GetModuleFileNameA(mods[i], module_name, sizeof(module_name));
|
||||
|
||||
printf("Connected to %s tool\n", module_name);
|
||||
connect_camera_tools();
|
||||
U_IGCS_CameraData[cameraSize] = getCameraData();
|
||||
cameraSize++;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPOSE uint8_t* __cdecl U_IGCS_Initialize(MoveCameraCallback cb, SessionCallback start_cb, SessionCallback end_cb) {
|
||||
AllocConsole();
|
||||
printf("Initializing callback\n");
|
||||
@@ -39,37 +88,18 @@ EXPOSE uint8_t* __cdecl U_IGCS_Initialize(MoveCameraCallback cb, SessionCallback
|
||||
GlobalStartSession = start_cb;
|
||||
GlobalEndSession = end_cb;
|
||||
|
||||
// Load IGCS
|
||||
#ifdef _M_IX86
|
||||
HMODULE igcs = LoadLibraryA("IgcsConnector.addon32");
|
||||
#else
|
||||
HMODULE igcs = LoadLibraryA("IgcsConnector.addon64");
|
||||
#endif
|
||||
|
||||
if (!igcs) {
|
||||
MessageBoxA(
|
||||
NULL,
|
||||
"IgcsConnector.addon64 was not found, make sure it is in the same directory as the executable.",
|
||||
"Unable to find IgcsConnector",
|
||||
MB_OK | MB_ICONERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FARPROC cameraToolsFunction = GetProcAddress(igcs, "connectFromCameraTools");
|
||||
GetCameraDataFunc getCameraData = (GetCameraDataFunc)GetProcAddress(igcs, "getDataFromCameraToolsBuffer");
|
||||
|
||||
if (first_initialization) {
|
||||
cameraToolsFunction();
|
||||
|
||||
if (connect_all_tools()) {
|
||||
printf("Error connecting cameras\n");
|
||||
return 0;
|
||||
}
|
||||
first_initialization = 0;
|
||||
}
|
||||
|
||||
// TODO: move this where it belongs. Maybe at some point we should actually fill in the data.
|
||||
uint8_t* cameraData = getCameraData();
|
||||
cameraData[0] = 0;
|
||||
|
||||
printf("Camera connected!\n");
|
||||
|
||||
return cameraData;
|
||||
return &U_IGCS_CameraData[0];
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,52 @@ namespace CinematicUnityExplorer.Cinematic
|
||||
// StepCommand is basically the offset of step_left and step_up, what IGCS sends to move the camera.
|
||||
using StepCommand = Mono.CSharp.Tuple<float, float>;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct Vec3
|
||||
{
|
||||
public float x, y, z;
|
||||
|
||||
public void FromVector3(Vector3 v)
|
||||
{
|
||||
this.x = v.x; this.y = v.y; this.z = v.z;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct Vec4
|
||||
{
|
||||
public float x, y, z, w;
|
||||
public void FromQuaternion(Quaternion q) { this.x = q.x; this.y = q.y ; this.z = q.z; this.w = q.w; }
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct CameraToolsData
|
||||
{
|
||||
public byte cameraEnabled;
|
||||
public byte cameraMovementLocked;
|
||||
public byte reserved1;
|
||||
public byte reserved2;
|
||||
public float fov;
|
||||
public Vec3 coordinates;
|
||||
public Vec4 lookQuaternion;
|
||||
public Vec3 rotationMatrixUpVector;
|
||||
public Vec3 rotationMatrixRightVector;
|
||||
public Vec3 rotationMatrixForwardVector;
|
||||
public float pitch;
|
||||
public float yaw;
|
||||
public float roll;
|
||||
}
|
||||
|
||||
enum SessionStatus : int
|
||||
{
|
||||
Ok = 0,
|
||||
Error_CameraNotEnabled = 1,
|
||||
Error_CameraPathPlaying = 2,
|
||||
Error_AlreadySessionActive = 3,
|
||||
Error_CameraFeatureNotAvailable = 4,
|
||||
Error_UnknownError = 5
|
||||
}
|
||||
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[DllImport("kernel32.dll")]
|
||||
@@ -26,7 +72,7 @@ namespace CinematicUnityExplorer.Cinematic
|
||||
private delegate void MoveCameraCallback(float step_left, float step_up, float fov, int from_start);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate void SessionCallback();
|
||||
private delegate int SessionCallback();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate IntPtr U_IGCS_Initialize(MoveCameraCallback callback, SessionCallback start_cb, SessionCallback end_cb);
|
||||
@@ -49,13 +95,60 @@ namespace CinematicUnityExplorer.Cinematic
|
||||
// This object *must* be used with a Lock.
|
||||
private readonly Queue<StepCommand> commands = new();
|
||||
|
||||
private IntPtr CameraStatus = IntPtr.Zero;
|
||||
private IntPtr AllCamerasData = IntPtr.Zero;
|
||||
|
||||
private IEnumerable<IntPtr> GetValidCameras()
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
IntPtr camPtr = Marshal.ReadIntPtr(AllCamerasData, i * IntPtr.Size);
|
||||
|
||||
if (camPtr == IntPtr.Zero)
|
||||
yield break;
|
||||
|
||||
yield return camPtr;
|
||||
}
|
||||
}
|
||||
public void UpdateFreecamStatus(bool enabled)
|
||||
{
|
||||
if (CameraStatus == IntPtr.Zero) return;
|
||||
|
||||
Marshal.WriteByte(CameraStatus, enabled ? (byte)0x1 : (byte)0x0);
|
||||
if (AllCamerasData == IntPtr.Zero) return;
|
||||
unsafe
|
||||
{
|
||||
foreach (IntPtr pCamera in this.GetValidCameras())
|
||||
{
|
||||
CameraToolsData* data = (CameraToolsData*)pCamera;
|
||||
data->cameraEnabled = enabled ? (byte)1 : (byte) 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdateCameraData(Camera cam)
|
||||
{
|
||||
if (AllCamerasData == IntPtr.Zero) return;
|
||||
|
||||
Transform transform = cam.transform;
|
||||
unsafe
|
||||
{
|
||||
foreach (IntPtr pCamera in this.GetValidCameras())
|
||||
{
|
||||
CameraToolsData* data = (CameraToolsData*)pCamera;
|
||||
data->fov = cam.fieldOfView;
|
||||
data->cameraMovementLocked = _isActive ? (byte)1 : (byte)0;
|
||||
|
||||
data->coordinates.FromVector3(transform.position);
|
||||
|
||||
data->lookQuaternion.FromQuaternion(transform.rotation);
|
||||
|
||||
data->rotationMatrixRightVector.FromVector3(transform.right);
|
||||
data->rotationMatrixUpVector.FromVector3(transform.up);
|
||||
data->rotationMatrixForwardVector.FromVector3(transform.forward);
|
||||
|
||||
Vector3 rot = transform.eulerAngles;
|
||||
data->pitch = rot.x * Mathf.Deg2Rad;
|
||||
data->yaw = rot.y * Mathf.Deg2Rad;
|
||||
data->roll = rot.z * Mathf.Deg2Rad;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteCameraCommand(Camera cam)
|
||||
@@ -92,9 +185,11 @@ namespace CinematicUnityExplorer.Cinematic
|
||||
commands.Enqueue(new StepCommand(stepLeft, stepUp));
|
||||
}
|
||||
}
|
||||
private void StartSession()
|
||||
private int StartSession()
|
||||
{
|
||||
if (_isActive) return (int)SessionStatus.Error_AlreadySessionActive;
|
||||
_isActive = true;
|
||||
return (int)SessionStatus.Ok;
|
||||
}
|
||||
|
||||
// At the EndSession, since we have a queue system, we have to have a special check when the session ends and
|
||||
@@ -111,7 +206,7 @@ namespace CinematicUnityExplorer.Cinematic
|
||||
endSessionPosition = null;
|
||||
}
|
||||
|
||||
private void EndSession()
|
||||
private int EndSession()
|
||||
{
|
||||
endSessionPosition = position;
|
||||
position = null;
|
||||
@@ -119,6 +214,8 @@ namespace CinematicUnityExplorer.Cinematic
|
||||
|
||||
lock (commands)
|
||||
commands.Clear();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public UnityIGCSConnector()
|
||||
@@ -143,8 +240,8 @@ namespace CinematicUnityExplorer.Cinematic
|
||||
delegates.Add(new SessionCallback(StartSession));
|
||||
delegates.Add(new SessionCallback(EndSession));
|
||||
|
||||
CameraStatus = initFunc((MoveCameraCallback)delegates[0], (SessionCallback)delegates[1], (SessionCallback)delegates[2]);
|
||||
if (CameraStatus == IntPtr.Zero){
|
||||
AllCamerasData = initFunc((MoveCameraCallback)delegates[0], (SessionCallback)delegates[1], (SessionCallback)delegates[2]);
|
||||
if (AllCamerasData == IntPtr.Zero){
|
||||
// This is actually a InvalidDataException, but some games dont allow you to throw that.
|
||||
throw new Exception("IGCSDof returned an invalid pointer which means something went wrong");
|
||||
}
|
||||
|
||||
@@ -1263,6 +1263,9 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
Transform movingTransform = FreeCamPanel.GetFreecam().transform;
|
||||
|
||||
// update camera data
|
||||
FreeCamPanel.connector?.UpdateCameraData(FreeCamPanel.GetFreecam());
|
||||
|
||||
if (!FreeCamPanel.blockFreecamMovementToggle.isOn && !FreeCamPanel.cameraPathMover.playingPath && FreeCamPanel.connector?.IsActive != true && !IsInputFieldInFocus()) {
|
||||
ProcessInput(movingTransform);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user