Files
K-C-Multiplayer/Packets/Game/GameWorld/WorldPlace.cs
devbeni 7d6c915b49 Fix: Prevent duplicate building placement via guid check
- Check if building with same guid already exists before placing
- Prevents buildings overlapping from network packet retries
- Logs skip when duplicate detected

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 10:51:53 +01:00

154 lines
6.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace KCM.Packets.Game.GameWorld
{
public class WorldPlace : Packet
{
public override ushort packetId => (int)Enums.Packets.WorldPlace;
public string customName { get; set; }
public Guid guid { get; set; }
public string uniqueName { get; set; }
public Quaternion rotation { get; set; }
public Vector3 globalPosition { get; set; }
public Vector3 localPosition { get; set; }
public bool built { get; set; }
public bool placed { get; set; }
public bool open { get; set; }
public bool doBuildAnimation { get; set; }
public bool constructionPaused { get; set; }
public float constructionProgress { get; set; }
public float life { get; set; }
public float ModifiedMaxLife { get; set; }
public int yearBuilt { get; set; }
public float decayProtection { get; set; }
public bool seenByPlayer { get; set; }
public override void HandlePacketClient()
{
if (clientId == KCClient.client.Id) return; //prevent double placing on same client
PlaceBuilding();
}
public override void HandlePacketServer()
{
//PlaceBuilding();
//SendToAll(clientId);
}
public void PlaceBuilding()
{
Main.helper.Log("Received place building packet for " + uniqueName + " from " + player.name + $"({player.id})");
// Check for duplicate building by guid to prevent double placement from network retries
var existingBuilding = player.inst.Buildings.data.FirstOrDefault(b => b != null && b.guid == guid);
if (existingBuilding != null)
{
Main.helper.Log($"Building with guid {guid} already exists for player {player.name}, skipping duplicate placement");
return;
}
//var originalPlayer = Player.inst;
//Player.inst = player.inst;
Building.BuildingSaveData structureData = new Building.BuildingSaveData()
{
uniqueName = uniqueName,
customName = customName,
guid = guid,
rotation = rotation,
globalPosition = globalPosition,
localPosition = localPosition,
built = built,
placed = placed,
open = open,
doBuildAnimation = doBuildAnimation,
constructionPaused = constructionPaused,
constructionProgress = constructionProgress,
life = life,
ModifiedMaxLife = ModifiedMaxLife,
//CollectForBuild = CollectForBuild,
yearBuilt = yearBuilt,
decayProtection = decayProtection,
seenByPlayer = seenByPlayer
};
//Player originalInst = Player.inst;
//Player.inst = player.inst;
Building Building = GameState.inst.GetPlaceableByUniqueName(structureData.uniqueName);
bool flag = Building;
if (flag)
{
Building building = UnityEngine.Object.Instantiate<Building>(Building);
building.transform.position = structureData.globalPosition;
Main.helper.Log("Building init");
building.Init();
building.transform.SetParent(player.inst.buildingContainer.transform, true);
Main.helper.Log("Building unpack");
structureData.Unpack(building);
Main.helper.Log(player.inst.ToString());
Main.helper.Log((player.inst.PlayerLandmassOwner == null).ToString());
Main.helper.Log(building.LandMass().ToString());
Main.helper.Log("Player add Building unpacked");
player.inst.AddBuilding(building);
try
{
player.inst.PlayerLandmassOwner.TakeOwnership(building.LandMass());
bool flag2 = building.GetComponent<Keep>() != null && building.TeamID() == player.inst.PlayerLandmassOwner.teamId;
Main.helper.Log("Set keep " + flag2);
if (flag2)
{
player.inst.keep = building.GetComponent<Keep>();
}
}
catch (Exception e)
{
Main.helper.Log(e.Message);
}
Main.helper.Log("Place from load");
Cell cell = World.inst.PlaceFromLoad(building);
Main.helper.Log("unpack stage 2");
structureData.UnpackStage2(building);
building.SetVisibleForFog(false);
Main.helper.Log("Landmass owner take ownership");
Main.helper.Log($"{player.id} (team {player.inst.PlayerLandmassOwner.teamId}) banner: {player.inst.PlayerLandmassOwner.bannerIdx} Placed building {building.name} at {building.transform.position}");
//Player.inst = originalInst; // Reset player back to normal // Might not be needed anymore with player ref patches?
Main.helper.Log($"Host player Landmass Names Count: {Player.inst.LandMassNames.Count}, Contents: {string.Join(", ", Player.inst.LandMassNames)}");
Main.helper.Log($"Client player ({player.name}) Landmass Names Count: {player.inst.LandMassNames.Count}, Contents: {string.Join(", ", player.inst.LandMassNames)}");
player.inst.LandMassNames[building.LandMass()] = player.kingdomName;
Player.inst.LandMassNames[building.LandMass()] = player.kingdomName;
//Player.inst = originalPlayer;
}
else
{
Main.helper.Log(structureData.uniqueName + " failed to load correctly");
}
//building.Init();
}
}
}