Skip to content

Commit

Permalink
Server: WIP Implementation of (weapon) item equipment. One serializat…
Browse files Browse the repository at this point in the history
…ion bug and corresponding redscript implementations of equipping the weapon remain
  • Loading branch information
MeFisto94 committed Dec 25, 2023
1 parent f9fff8a commit 8827df1
Show file tree
Hide file tree
Showing 15 changed files with 183 additions and 11 deletions.
27 changes: 21 additions & 6 deletions client/RedscriptModule/src/Cyberverse.reds
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,21 @@ protected cb func OnUnmountingEvent(evt: ref<UnmountingEvent>) -> Bool {
GameInstance.GetNetworkGameSystem().playerActionTracker.OnUnmounting(evt);
return result;
}

// replaces the OnWeapoNEquipEvent as we need the counterpart for unequiping anyway?
// protected cb func OnWeaponEquipEvent(evt: ref<WeaponEquipEvent>) -> Bool {
@wrapMethod(PlayerPuppet)
public final func OnItemEquipped(slot: TweakDBID, item: ItemID) -> Void {
let isWeapon = RPGManager.IsItemWeapon(item);
GameInstance.GetNetworkGameSystem().playerActionTracker.OnItemEquipped(slot, item, isWeapon);
}
@wrapMethod(PlayerPuppet)
public final func OnItemUnequipped(slot: TweakDBID, item: ItemID) -> Void {
let isWeapon = RPGManager.IsItemWeapon(item);
GameInstance.GetNetworkGameSystem().playerActionTracker.OnItemUnequipped(slot, item, isWeapon);
}
@wrapMethod(BaseProjectile)
protected cb func OnShoot(eventData: ref<gameprojectileShootEvent>) -> Bool {
wrappedMethod(eventData);
Expand All @@ -92,12 +107,12 @@ protected cb func OnShootTarget(eventData: ref<gameprojectileShootTargetEvent>)
FTLog("Shoot Target");
}
@wrapMethod(GameObject)
protected cb func OnHit(evt: ref<gameHitEvent>) -> Bool {
wrappedMethod(evt);
FTLog("OnHit");
GameInstance.GetNetworkGameSystem().playerActionTracker.OnHit(this, evt);
}
// @wrapMethod(GameObject)
// protected cb func OnHit(evt: ref<gameHitEvent>) -> Bool {
// wrappedMethod(evt);
// FTLog("OnHit");
// GameInstance.GetNetworkGameSystem().playerActionTracker.OnHit(this, evt);
// }
// @wrapMethod(JumpEvents)
// protected cb func OnEnter(stateContext: ref<StateContext>, scriptInterface: ref<StateGameScriptInterface>) -> Void {}
2 changes: 2 additions & 0 deletions client/RedscriptModule/src/Network/PlayerActionTracker.reds
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ public native class PlayerActionTracker {
public native func OnHit(gameObject: ref<GameObject>, event: ref<gameHitEvent>);
public native func OnMounting(evt: ref<MountingEvent>);
public native func OnUnmounting(evt: ref<UnmountingEvent>);
public native func OnItemEquipped(slot: TweakDBID, item: ItemID, isWeapon: Bool);
public native func OnItemUnequipped(slot: TweakDBID, item: ItemID, isWeapon: Bool);
}
1 change: 1 addition & 0 deletions client/red4ext/src/NetworkGameSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,6 @@ RTTI_DEFINE_CLASS(NetworkGameSystem, {
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);
template bool NetworkGameSystem::EnqueueMessage(uint8_t channel_id, PlayerEquipItem msg);

#endif //NETWORKMANAGERCONTROLLER_H
22 changes: 22 additions & 0 deletions client/red4ext/src/PlayerActionTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,25 @@ void PlayerActionTracker::OnUnmounting(RED4ext::Handle<RED4ext::game::mounting::
const PlayerUnmountCar unmount_car = {};
Red::GetGameSystem<NetworkGameSystem>()->EnqueueMessage(0, unmount_car);
}

void PlayerActionTracker::OnItemEquipped(const RED4ext::TweakDBID slot, const RED4ext::ItemID item, const bool isWeapon)
{
SDK->logger->InfoF(PLUGIN, "Item Equipped at slot %llu with item %llu", slot.value, item.tdbid.value);
PlayerEquipItem player_equip = {};
player_equip.slot = slot.value;
player_equip.itemId = item.tdbid.value;
player_equip.isWeapon = isWeapon;
player_equip.isUnequipping = false;
Red::GetGameSystem<NetworkGameSystem>()->EnqueueMessage(0, player_equip);
}

void PlayerActionTracker::OnItemUnequipped(const RED4ext::TweakDBID slot, const RED4ext::ItemID item, const bool isWeapon)
{
SDK->logger->InfoF(PLUGIN, "Item Unequipped at slot %llu with item %llu", slot.value, item.tdbid.value);
PlayerEquipItem player_equip = {};
player_equip.slot = slot.value;
player_equip.itemId = item.tdbid.value;
player_equip.isWeapon = isWeapon;
player_equip.isUnequipping = true;
Red::GetGameSystem<NetworkGameSystem>()->EnqueueMessage(0, player_equip);
}
5 changes: 5 additions & 0 deletions client/red4ext/src/PlayerActionTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#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"
#include "RED4ext/Scripting/Natives/Generated/game/weapon/Object.hpp"

class PlayerActionTracker final : public Red::IScriptable
{
Expand All @@ -19,6 +20,8 @@ class PlayerActionTracker final : public Red::IScriptable
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);
void OnItemEquipped(RED4ext::TweakDBID slot, RED4ext::ItemID item, bool isWeapon);
void OnItemUnequipped(RED4ext::TweakDBID slot, RED4ext::ItemID item, bool isWeapon);
private:
RTTI_IMPL_TYPEINFO(PlayerActionTracker);
RTTI_IMPL_ALLOCATOR();
Expand All @@ -30,5 +33,7 @@ RTTI_DEFINE_CLASS(PlayerActionTracker, {
RTTI_METHOD(OnHit);
RTTI_METHOD(OnMounting);
RTTI_METHOD(OnUnmounting);
RTTI_METHOD(OnItemEquipped);
RTTI_METHOD(OnItemUnequipped);
RTTI_ALIAS("Cyberverse.Network.Managers.PlayerActionTracker");
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ public enum EMessageTypeClientbound: ushort
InitAuthResult = 0,
SpawnEntity = 1,
TeleportEntity = 2,
DestroyEntity = 3
DestroyEntity = 3,
EquipItemEntity = 4,
}
18 changes: 18 additions & 0 deletions server/Managed/NativeLayer/Protocol/Clientbound/EquipItemEntity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Runtime.InteropServices;

namespace Cyberverse.Server.NativeLayer.Protocol.Clientbound;

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct EquipItemEntity: IClientBoundPacket
{
public ulong NetworkedEntityId;
public ulong Slot;
public ulong ItemId;
public bool isWeapon;
public bool isUnequipping;

public EMessageTypeClientbound GetMessageType()
{
return EMessageTypeClientbound.EquipItemEntity;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ public enum EMessageTypeServerbound: ushort
PlayerPositionUpdate = 3,
PlayerSpawnCar = 4,
PlayerMountCar = 5, // TODO: Implement
PlayerUnmountCar = 6
PlayerUnmountCar = 6,
PlayerEquipItem = 7
}
12 changes: 12 additions & 0 deletions server/Managed/NativeLayer/Protocol/Serverbound/PlayerEquipItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Runtime.InteropServices;

namespace Cyberverse.Server.NativeLayer.Protocol.Serverbound;

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct PlayerEquipItem
{
public ulong slot;
public ulong itemId;
public bool isWeapon;
public bool isUnequipping; // TODO: For some reason this flag is always false. Is this a packing issue because the bools got bitpacked?
}
49 changes: 48 additions & 1 deletion server/Managed/PacketHandling/PlayerPacketHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class PlayerPacketHandler
private readonly TypedPacketHandler<PlayerPositionUpdate> _playerMoveHandler;
private readonly TypedPacketHandler<PlayerSpawnCar> _playerSpawnCarHandler;
private readonly TypedPacketHandler<PlayerUnmountCar> _playerUnmountHandler;
private readonly TypedPacketHandler<PlayerEquipItem> _playerEquipHandler;
private EntityTracker? _tracker = null;
private PlayerService? _players = null;

Expand All @@ -27,6 +28,7 @@ public PlayerPacketHandler()
_playerMoveHandler = new TypedPacketHandler<PlayerPositionUpdate>(HandlePositionUpdate);
_playerSpawnCarHandler = new TypedPacketHandler<PlayerSpawnCar>(HandleSpawnCar);
_playerUnmountHandler = new TypedPacketHandler<PlayerUnmountCar>(HandleUnmountCar);
_playerEquipHandler = new TypedPacketHandler<PlayerEquipItem>(HandleEquip);
}

protected void HandleJoinWorld(GameServer server, EMessageTypeServerbound messageType, byte channelId, uint connectionId, PlayerJoinWorld content)
Expand Down Expand Up @@ -132,6 +134,50 @@ protected void HandleUnmountCar(GameServer server, EMessageTypeServerbound messa
DespawnAllVehiclesForPlayer(server, connectionId);
}

private void HandleEquip(GameServer server, EMessageTypeServerbound messageType, byte channelId,
uint connectionId, PlayerEquipItem content)
{
Logger.Info($"Player did (un: {content.isUnequipping})equip an item (slot {content.slot}). Is it a weapon? {content.isWeapon}");
if (content.isUnequipping)
{
// Try to find existing cars for that owner.
var existingItems = server.EntityService.SpawnedEntities
.Select(x => x.Value)
.Where(x => x.NetworkIdOwner == connectionId)
.Where(x => x.RecordId == content.itemId)
.ToList();

// TODO: As long as we don't have NetworkedEntityIds, we need to unequip all of those.
foreach (var item in existingItems)
{
item.NetworkIdOwner = 0;
_tracker!.StopTrackingOf(item);
server.EntityService.RemoveEntity(item.NetworkedEntityId);
}
}
else
{
// TODO: How are we supposed to flag things as items? dedicated maps? But it'll still be entities in the end.
// Also this is relevant when we have our own EquipItemEntity. Right now they are entities in the world.
var playerEntity = server.EntityService.SpawnedEntities
.Select(x => x.Value)
.FirstOrDefault(x => x.NetworkIdOwner == connectionId);

if (playerEntity == null)
{
return;
}

var entity = server.EntityService.CreateEntity(content.itemId);
entity.WorldTransform = playerEntity.WorldTransform; // TODO
entity.Yaw = playerEntity.Yaw; // TODO
entity.NetworkIdOwner = connectionId;
entity.IsVehicle = false;

_tracker!.UpdateTrackingOf(entity);
}
}

public void RegisterOnServer(GameServer server)
{
_tracker = server.EntityTracker; // TODO: Service registry or even using DI
Expand All @@ -141,5 +187,6 @@ public void RegisterOnServer(GameServer server)
server.AddPacketHandler(EMessageTypeServerbound.PlayerPositionUpdate, _playerMoveHandler.HandlePacket);
server.AddPacketHandler(EMessageTypeServerbound.PlayerSpawnCar, _playerSpawnCarHandler.HandlePacket);
server.AddPacketHandler(EMessageTypeServerbound.PlayerUnmountCar, _playerUnmountHandler.HandlePacket);
server.AddPacketHandler(EMessageTypeServerbound.PlayerEquipItem, _playerEquipHandler.HandlePacket);
}
}
}
19 changes: 19 additions & 0 deletions server/Native/src/GameServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,20 @@ void GameServer::PollIncomingMessages()
}
break;

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

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

default:
printf("Message Type: %d\n", frame.message_type);
break;
Expand Down Expand Up @@ -418,6 +432,11 @@ void GameServer::ProcessSendQueue()
}
break;

case eEquipItemEntity:
{
EnqueueMessage(val.connectionId, val.channelId, *reinterpret_cast<EquipItemEntity*>(val.data));
}
break;

default:
printf("Unknown messageType: %d\n", val.messageType);
Expand Down
3 changes: 2 additions & 1 deletion shared/protocol/clientbound/EMessageTypeClientbound.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ enum EMessageTypeClientbound: uint16_t {
EINIT_AUTH_RESULT = 0,
eSpawnEntity = 1,
eTeleportEntity = 2,
eDestroyEntity = 3
eDestroyEntity = 3,
eEquipItemEntity = 4,
};
14 changes: 14 additions & 0 deletions shared/protocol/clientbound/WorldPacketsClientBound.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,17 @@ struct TeleportEntity
frame.channel_id = 1; // TODO:
}
};

struct EquipItemEntity {
uint64_t networkedEntityId;
uint64_t slot;
uint64_t itemId;
bool isWeapon;
bool isUnequipping;

inline static void FillMessageFrame(MessageFrame& frame)
{
frame.message_type = eEquipItemEntity;
frame.channel_id = 0; // TODO
}
};
3 changes: 2 additions & 1 deletion shared/protocol/serverbound/EMessageTypeServerbound.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ enum EMessageTypeServerbound: uint16_t {
ePlayerPositionUpdate = 3,
ePlayerSpawnCar = 4,
ePlayerMountCar = 5, // TODO: Implement
ePlayerUnmountCar = 6
ePlayerUnmountCar = 6,
ePlayerEquipItem = 7
};
13 changes: 13 additions & 0 deletions shared/protocol/serverbound/WorldPacketsServerBound.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,17 @@ struct PlayerUnmountCar {
frame.message_type = ePlayerUnmountCar;
frame.channel_id = 0; // TODO
}
};

struct PlayerEquipItem {
uint64_t slot;
uint64_t itemId;
bool isWeapon;
bool isUnequipping;

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

0 comments on commit 8827df1

Please sign in to comment.