Skip to content

Commit

Permalink
Implement proper unmounting/leaving of vehicles
Browse files Browse the repository at this point in the history
  • Loading branch information
MeFisto94 committed Dec 24, 2023
1 parent 64b73b7 commit f9fff8a
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 15 deletions.
7 changes: 6 additions & 1 deletion client/RedscriptModule/src/Cyberverse.reds
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,16 @@ protected cb func OnAction(action: ListenerAction, consumer: ListenerActionConsu
@wrapMethod(PlayerPuppet)
protected cb func OnMountingEvent(evt: ref<MountingEvent>) -> Bool {
let result = wrappedMethod(evt);
FTLog("Entered a car");
GameInstance.GetNetworkGameSystem().playerActionTracker.OnMounting(evt);
return result;
}

@wrapMethod(PlayerPuppet)
protected cb func OnUnmountingEvent(evt: ref<UnmountingEvent>) -> Bool {
let result = wrappedMethod(evt);
GameInstance.GetNetworkGameSystem().playerActionTracker.OnUnmounting(evt);
return result;
}
@wrapMethod(BaseProjectile)
protected cb func OnShoot(eventData: ref<gameprojectileShootEvent>) -> Bool {
wrappedMethod(eventData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ public native class PlayerActionTracker {
public native func OnShoot(event: ref<gameprojectileShootEvent>) -> Void;
public native func OnHit(gameObject: ref<GameObject>, event: ref<gameHitEvent>);
public native func OnMounting(evt: ref<MountingEvent>);
public native func OnUnmounting(evt: ref<UnmountingEvent>);
}
1 change: 1 addition & 0 deletions client/red4ext/src/NetworkGameSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,6 @@ RTTI_DEFINE_CLASS(NetworkGameSystem, {
// relevant caller CU (but that may be more than one for the same packet, making template hell even worse).
template bool NetworkGameSystem::EnqueueMessage(uint8_t channel_id, PlayerActionTracked msg);
template bool NetworkGameSystem::EnqueueMessage(uint8_t channel_id, PlayerSpawnCar msg);
template bool NetworkGameSystem::EnqueueMessage(uint8_t channel_id, PlayerUnmountCar msg);

#endif //NETWORKMANAGERCONTROLLER_H
47 changes: 41 additions & 6 deletions client/red4ext/src/PlayerActionTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ void PlayerActionTracker::RecordPlayerAction(RED4ext::CName actionName, RED4ext:
float value)
{
const auto name = std::string(actionName.ToString());
//SDK->logger->InfoF(PLUGIN, "Player Action %s (%d) -> %f", name.c_str(), actionType, value);
// SDK->logger->InfoF(PLUGIN, "Player Action %s (%d) -> %f", name.c_str(), actionType, value);

// We ignore movement inputs like Forward, MoveX, MoveY for now, because we don't care about animations but just
// want the most recent position And for that, those inputs are very unreliable due to physics/collision etc anyway.
Expand Down Expand Up @@ -79,17 +79,20 @@ void PlayerActionTracker::OnMounting(RED4ext::Handle<RED4ext::game::mounting::Mo

if (event->relationship.otherObject.Expired())
{
SDK->logger->Warn(PLUGIN, "Cannot Process PlayerActionTracker::OnMounting as the vehicle's weak ref has expried");
SDK->logger->Warn(PLUGIN,
"Cannot Process PlayerActionTracker::OnMounting as the vehicle's weak ref has expried");
return;
}

// Keep alive as long as the derived vehicleInstance
const auto strongLock = event->relationship.otherObject.Lock();
const RED4ext::game::Object* ptr = strongLock; // TODO: if you figure out how to inline that, you're welcome to do so.
// TODO: if you figure out how to inline that, you're welcome to do so.
const RED4ext::game::Object* ptr = strongLock;
const auto vehicleInstance = RED4ext::Handle((RED4ext::VehicleObject*)ptr);

// TODO: vehicles.swift, there is VehicleObject.GetRecordID(), but there is also GameObject::GetTDBID(go) which is more generic and handles casting,
// so it works for puppets, devices _and_ vehicles. Question is if we should here just implement both so we can avoid casting and misleading?
// TODO: vehicles.swift, there is VehicleObject.GetRecordID(), but there is also GameObject::GetTDBID(go) which is
// more generic and handles casting, so it works for puppets, devices _and_ vehicles. Question is if we should here
// just implement both so we can avoid casting and misleading?

const auto recordId = Cyberverse::Utils::VehicleObject_GetRecordID(vehicleInstance);
const auto [X, Y, Z, W] = Cyberverse::Utils::Entity_GetWorldPosition(vehicleInstance);
Expand All @@ -98,8 +101,40 @@ void PlayerActionTracker::OnMounting(RED4ext::Handle<RED4ext::game::mounting::Mo

PlayerSpawnCar spawnCar = {};
spawnCar.recordId = recordId.value;
spawnCar.worldTransform = Vector3 { X, Y, Z };
spawnCar.worldTransform = Vector3{X, Y, Z};
spawnCar.yaw = Yaw;

Red::GetGameSystem<NetworkGameSystem>()->EnqueueMessage(0, spawnCar);
}

void PlayerActionTracker::OnUnmounting(RED4ext::Handle<RED4ext::game::mounting::UnmountingEvent> event)
{
if (event->relationship.otherMountableType != RED4ext::game::MountingObjectType::Vehicle)
{
// mountingSubType would tell us whether bike or car.
return;
}

if (event->relationship.relationshipType != RED4ext::game::MountingRelationshipType::Parent)
{
// If the car mounts us, do nothing
return;
}

if (event->relationship.otherObject.Expired())
{
SDK->logger->Warn(PLUGIN, "Cannot Process PlayerActionTracker::OnUnmounting as the vehicle's weak ref "
"has expried");
return;
}

// Keep alive as long as the derived vehicleInstance
const auto strongLock = event->relationship.otherObject.Lock();
// TODO: if you figure out how to inline that, you're welcome to do so.
const RED4ext::game::Object* ptr = strongLock;
const auto vehicleInstance = RED4ext::Handle((RED4ext::VehicleObject*)ptr);

// TODO: Read the networkedEntityId from the entity, so we can be precise and the server doesn't need to guess.
const PlayerUnmountCar unmount_car = {};
Red::GetGameSystem<NetworkGameSystem>()->EnqueueMessage(0, unmount_car);
}
5 changes: 5 additions & 0 deletions client/red4ext/src/PlayerActionTracker.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#pragma once

#include <RED4ext/RED4ext.hpp>
#include "RedLib.hpp"

#include "RED4ext/CName.hpp"
#include "RED4ext/Scripting/Natives/Generated/game/Object.hpp"
#include "RED4ext/Scripting/Natives/Generated/game/events/HitEvent.hpp"
#include "RED4ext/Scripting/Natives/Generated/game/input/ActionType.hpp"
#include "RED4ext/Scripting/Natives/Generated/game/mounting/MountingEvent.hpp"
#include "RED4ext/Scripting/Natives/Generated/game/mounting/UnmountingEvent.hpp"
#include "RED4ext/Scripting/Natives/Generated/game/projectile/ShootEvent.hpp"

class PlayerActionTracker final : public Red::IScriptable
Expand All @@ -15,6 +18,7 @@ class PlayerActionTracker final : public Red::IScriptable
void OnShoot(RED4ext::Handle<RED4ext::gameprojectileShootEvent> event);
void OnHit(RED4ext::Handle<RED4ext::GameObject> gameObject, RED4ext::Handle<RED4ext::gameHitEvent> event);
void OnMounting(RED4ext::Handle<RED4ext::game::mounting::MountingEvent> event);
void OnUnmounting(RED4ext::Handle<RED4ext::game::mounting::UnmountingEvent> event);
private:
RTTI_IMPL_TYPEINFO(PlayerActionTracker);
RTTI_IMPL_ALLOCATOR();
Expand All @@ -25,5 +29,6 @@ RTTI_DEFINE_CLASS(PlayerActionTracker, {
RTTI_METHOD(OnShoot);
RTTI_METHOD(OnHit);
RTTI_METHOD(OnMounting);
RTTI_METHOD(OnUnmounting);
RTTI_ALIAS("Cyberverse.Network.Managers.PlayerActionTracker");
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ public enum EMessageTypeServerbound: ushort
PlayerActionTracked = 2,
PlayerPositionUpdate = 3,
PlayerSpawnCar = 4,
PlayerMountCar = 5, // TODO: Implement
PlayerUnmountCar = 6
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Runtime.InteropServices;

namespace Cyberverse.Server.NativeLayer.Protocol.Serverbound;

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct PlayerUnmountCar
{
}
29 changes: 21 additions & 8 deletions server/Managed/PacketHandling/PlayerPacketHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class PlayerPacketHandler
private readonly TypedPacketHandler<PlayerJoinWorld> _playerJoinHandler;
private readonly TypedPacketHandler<PlayerPositionUpdate> _playerMoveHandler;
private readonly TypedPacketHandler<PlayerSpawnCar> _playerSpawnCarHandler;
private readonly TypedPacketHandler<PlayerUnmountCar> _playerUnmountHandler;
private EntityTracker? _tracker = null;
private PlayerService? _players = null;

Expand All @@ -25,6 +26,7 @@ public PlayerPacketHandler()
_playerJoinHandler = new TypedPacketHandler<PlayerJoinWorld>(HandleJoinWorld);
_playerMoveHandler = new TypedPacketHandler<PlayerPositionUpdate>(HandlePositionUpdate);
_playerSpawnCarHandler = new TypedPacketHandler<PlayerSpawnCar>(HandleSpawnCar);
_playerUnmountHandler = new TypedPacketHandler<PlayerUnmountCar>(HandleUnmountCar);
}

protected void HandleJoinWorld(GameServer server, EMessageTypeServerbound messageType, byte channelId, uint connectionId, PlayerJoinWorld content)
Expand Down Expand Up @@ -96,6 +98,19 @@ protected void HandleSpawnCar(GameServer server, EMessageTypeServerbound message

Logger.Trace($"Player spawned a {hash} [{len}] at {content.worldTransform}");

DespawnAllVehiclesForPlayer(server, connectionId);

var entity = server.EntityService.CreateEntity(content.recordId);
entity.WorldTransform = content.worldTransform; // Spawn the entity at the right spot already
entity.Yaw = content.yaw;
entity.NetworkIdOwner = connectionId;
entity.IsVehicle = true;

_tracker!.UpdateTrackingOf(entity);
}

private void DespawnAllVehiclesForPlayer(GameServer server, uint connectionId)
{
// Try to find existing cars for that owner.
var existingVehicles = server.EntityService.SpawnedEntities
.Select(x => x.Value)
Expand All @@ -109,15 +124,12 @@ protected void HandleSpawnCar(GameServer server, EMessageTypeServerbound message
_tracker!.StopTrackingOf(vehicle);
server.EntityService.RemoveEntity(vehicle.NetworkedEntityId);
}
}

var entity = server.EntityService.CreateEntity(content.recordId);
entity.WorldTransform = content.worldTransform; // Spawn the entity at the right spot already
entity.Yaw = content.yaw;
entity.NetworkIdOwner = connectionId;
entity.IsVehicle = true;

_tracker!.UpdateTrackingOf(entity);

protected void HandleUnmountCar(GameServer server, EMessageTypeServerbound messageType, byte channelId,
uint connectionId, PlayerUnmountCar content)
{
DespawnAllVehiclesForPlayer(server, connectionId);
}

public void RegisterOnServer(GameServer server)
Expand All @@ -128,5 +140,6 @@ public void RegisterOnServer(GameServer server)
server.AddPacketHandler(EMessageTypeServerbound.PlayerJoinWorld, _playerJoinHandler.HandlePacket);
server.AddPacketHandler(EMessageTypeServerbound.PlayerPositionUpdate, _playerMoveHandler.HandlePacket);
server.AddPacketHandler(EMessageTypeServerbound.PlayerSpawnCar, _playerSpawnCarHandler.HandlePacket);
server.AddPacketHandler(EMessageTypeServerbound.PlayerUnmountCar, _playerUnmountHandler.HandlePacket);
}
}
14 changes: 14 additions & 0 deletions server/Native/src/GameServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,20 @@ void GameServer::PollIncomingMessages()
}
break;

case ePlayerUnmountCar:
{
PlayerUnmountCar player_unmount_car = {};
if (zpp::bits::failure(in(player_unmount_car)))
{
fprintf(stderr, "Faulty packet: PlayerUnmountCar\n");
pIncomingMsg->Release();
continue;
}

AddToRecvQueue(frame.message_type, pIncomingMsg->m_conn, frame.channel_id, player_unmount_car);
}
break;

default:
printf("Message Type: %d\n", frame.message_type);
break;
Expand Down
2 changes: 2 additions & 0 deletions shared/protocol/serverbound/EMessageTypeServerbound.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ enum EMessageTypeServerbound: uint16_t {
ePlayerActionTracked = 2,
ePlayerPositionUpdate = 3,
ePlayerSpawnCar = 4,
ePlayerMountCar = 5, // TODO: Implement
ePlayerUnmountCar = 6
};
10 changes: 10 additions & 0 deletions shared/protocol/serverbound/WorldPacketsServerBound.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,14 @@ struct PlayerSpawnCar {
frame.message_type = ePlayerSpawnCar;
frame.channel_id = 0; // TODO
}
};

struct PlayerUnmountCar {
// TODO: NetworkedEntityId

inline static void FillMessageFrame(MessageFrame& frame)
{
frame.message_type = ePlayerUnmountCar;
frame.channel_id = 0; // TODO
}
};

0 comments on commit f9fff8a

Please sign in to comment.