diff --git a/Campofinale/Campofinale.csproj b/Campofinale/Campofinale.csproj index 5cc10f4..113136d 100644 --- a/Campofinale/Campofinale.csproj +++ b/Campofinale/Campofinale.csproj @@ -21,15 +21,11 @@ - - - - diff --git a/Campofinale/Commands/Handlers/CommandHeal.cs b/Campofinale/Commands/Handlers/CommandHeal.cs index 992c2b2..60c049d 100644 --- a/Campofinale/Commands/Handlers/CommandHeal.cs +++ b/Campofinale/Commands/Handlers/CommandHeal.cs @@ -10,21 +10,8 @@ namespace Campofinale.Commands.Handlers [Server.Command("heal", "Revives/Heals your team characters", true)] public static void Handle(Player sender, string cmd, string[] args, Player target) { - target.GetCurTeam().ForEach(chara => - { - chara.curHp = chara.CalcAttributes()[AttributeType.MaxHp].val; - ScCharSyncStatus state = new ScCharSyncStatus() - { - Objid=chara.guid, - IsDead=chara.curHp < 1, - BattleInfo = new() - { - Hp=chara.curHp, - Ultimatesp=chara.ultimateSp - } - }; - target.Send(ScMsgId.ScCharSyncStatus, state); - }); + target.RestTeam(); + target.Send(ScMsgId.ScSceneRevival, new ScSceneRevival() { diff --git a/Campofinale/Database/DatabaseManager.cs b/Campofinale/Database/DatabaseManager.cs index e769373..9235701 100644 --- a/Campofinale/Database/DatabaseManager.cs +++ b/Campofinale/Database/DatabaseManager.cs @@ -4,6 +4,8 @@ using MongoDB.Bson; using System.Reflection; using static Campofinale.Game.Factory.FactoryNode; using Campofinale.Game.Inventory; +using Campofinale.Game.Factory; +using Campofinale.Game.Factory.BuildingsBehaviour; namespace Campofinale.Database { @@ -66,6 +68,7 @@ namespace Campofinale.Database BsonSerializer.RegisterSerializer(typeof(Dictionary), new CustomDictionarySerializer()); RegisterSubclasses(); + RegisterSubclasses(); Logger.Print("Connecting to MongoDB..."); try { diff --git a/Campofinale/Game/Factory/BlockCalculator.cs b/Campofinale/Game/Factory/BlockCalculator.cs new file mode 100644 index 0000000..ba4b72b --- /dev/null +++ b/Campofinale/Game/Factory/BlockCalculator.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Campofinale.Resource.ResourceManager; + +namespace Campofinale.Game.Factory +{ + public class BlockCalculator + { + public static int CalculateTotalBlocks(List points) + { + if (points == null || points.Count < 2) + return 0; + + HashSet> blocks = new HashSet>(); + + for (int i = 0; i < points.Count - 1; i++) + { + Vector3f p1 = points[i]; + Vector3f p2 = points[i + 1]; + + AddBlocksForLineSegment3D(p1, p2, blocks); + } + + return blocks.Count; + } + + private static void AddBlocksForLineSegment3D(Vector3f p1, Vector3f p2, HashSet> blocks) + { + int x0 = (int)Math.Floor(p1.x); + int y0 = (int)Math.Floor(p1.y); + int z0 = (int)Math.Floor(p1.z); + int x1 = (int)Math.Floor(p2.x); + int y1 = (int)Math.Floor(p2.y); + int z1 = (int)Math.Floor(p2.z); + + int dx = Math.Abs(x1 - x0); + int dy = Math.Abs(y1 - y0); + int dz = Math.Abs(z1 - z0); + int sx = x0 < x1 ? 1 : -1; + int sy = y0 < y1 ? 1 : -1; + int sz = z0 < z1 ? 1 : -1; + + if (dx >= dy && dx >= dz) + { + int err1 = 2 * dy - dx; + int err2 = 2 * dz - dx; + for (int i = 0; i < dx; i++) + { + blocks.Add(Tuple.Create(x0, y0, z0)); + if (err1 > 0) + { + y0 += sy; + err1 -= 2 * dx; + } + if (err2 > 0) + { + z0 += sz; + err2 -= 2 * dx; + } + err1 += 2 * dy; + err2 += 2 * dz; + x0 += sx; + } + } + else if (dy >= dx && dy >= dz) + { + int err1 = 2 * dx - dy; + int err2 = 2 * dz - dy; + for (int i = 0; i < dy; i++) + { + blocks.Add(Tuple.Create(x0, y0, z0)); + if (err1 > 0) + { + x0 += sx; + err1 -= 2 * dy; + } + if (err2 > 0) + { + z0 += sz; + err2 -= 2 * dy; + } + err1 += 2 * dx; + err2 += 2 * dz; + y0 += sy; + } + } + else + { + int err1 = 2 * dy - dz; + int err2 = 2 * dx - dz; + for (int i = 0; i < dz; i++) + { + blocks.Add(Tuple.Create(x0, y0, z0)); + if (err1 > 0) + { + y0 += sy; + err1 -= 2 * dz; + } + if (err2 > 0) + { + x0 += sx; + err2 -= 2 * dz; + } + err1 += 2 * dy; + err2 += 2 * dx; + z0 += sz; + } + } + + blocks.Add(Tuple.Create(x1, y1, z1)); + } + } +} diff --git a/Campofinale/Game/Factory/BuildingsBehaviour/NodeBuildingBehaviour.cs b/Campofinale/Game/Factory/BuildingsBehaviour/NodeBuildingBehaviour.cs new file mode 100644 index 0000000..f024b38 --- /dev/null +++ b/Campofinale/Game/Factory/BuildingsBehaviour/NodeBuildingBehaviour.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Campofinale.Game.Factory.BuildingsBehaviour +{ + public class NodeBuildingBehaviour + { + public virtual void Update(FactoryChapter chapter, FactoryNode node) + { + + } + //Executed the first time when created a node that use the specific behaviour + public virtual void Init(FactoryChapter chapter, FactoryNode node) + { + + } + } +} diff --git a/Campofinale/Game/Factory/BuildingsBehaviour/NodeBuilding_Producer.cs b/Campofinale/Game/Factory/BuildingsBehaviour/NodeBuilding_Producer.cs new file mode 100644 index 0000000..333a907 --- /dev/null +++ b/Campofinale/Game/Factory/BuildingsBehaviour/NodeBuilding_Producer.cs @@ -0,0 +1,112 @@ +using Campofinale.Game.Factory.Components; +using Campofinale.Protocol; +using Campofinale.Resource; +using Campofinale.Resource.Table; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Campofinale.Resource; +using static Campofinale.Resource.ResourceManager; +using System.Xml.Linq; + +namespace Campofinale.Game.Factory.BuildingsBehaviour +{ + public class NodeBuilding_Producer : NodeBuildingBehaviour + { + public uint inputCacheId = 0; + public uint outputCacheId = 0; + public uint producerId = 0; + public long timestampFinish = 0; + public override void Init(FactoryChapter chapter, FactoryNode node) + { + FComponentCache cache1 = (FComponentCache)new FComponentCache(chapter.nextCompV(), FCComponentPos.CacheIn1).Init(); + FComponentCache cache2 = (FComponentCache)new FComponentCache(chapter.nextCompV(), FCComponentPos.CacheOut1).Init(); + FComponentProducer producer = (FComponentProducer)new FComponentProducer(chapter.nextCompV()).Init(); + node.components.Add(producer); + node.components.Add(new FComponentFormulaMan(chapter.nextCompV()).Init()); + node.components.Add(cache1); + node.components.Add(cache2); + inputCacheId = cache1.compId; + outputCacheId = cache2.compId; + producerId = producer.compId; + node.components.Add(new FComponentPortManager(chapter.nextCompV(), 3, cache1).Init()); + node.components.Add(new FComponentPortManager(chapter.nextCompV(), 3, cache2).Init()); + } + public string GetFormulaGroupId(string templateId) + { + FactoryMachineCraftTable table = factoryMachineCraftTable.Values.ToList().Find(r => r.machineId == templateId); + if (table != null) + { + return table.formulaGroupId; + } + else + { + return ""; + } + } + public override void Update(FactoryChapter chapter, FactoryNode node) + { + + if (node.powered) + { + FComponentProducer producer = node.GetComponent(producerId); + FComponentCache inCache = node.GetComponent(inputCacheId); + FComponentCache outCache = node.GetComponent(outputCacheId); + FComponentFormulaMan formulaManager = node.GetComponent(); + + if (formulaManager == null) return; + formulaManager.currentGroup = GetFormulaGroupId(node.templateId); + FactoryMachineCraftTable craftingRecipe = null; + string recipe = ResourceManager.FindFactoryMachineCraftIdUsingCacheItems(inCache.items,formulaManager.currentGroup); + producer.formulaId = recipe; + ResourceManager.factoryMachineCraftTable.TryGetValue(producer.formulaId, out craftingRecipe); + + if (craftingRecipe != null) + { + producer.inBlock = outCache.IsFull(); + if (craftingRecipe.CacheHaveItems(inCache) && !outCache.IsFull()) + { + producer.inProduce = true; + + producer.lastFormulaId = recipe; + if (timestampFinish == 0) + { + timestampFinish = DateTime.UtcNow.ToUnixTimestampMilliseconds() + 1000 * craftingRecipe.progressRound; + } + producer.progress = (DateTime.UtcNow.ToUnixTimestampMilliseconds()/timestampFinish)* craftingRecipe.totalProgress; + if (DateTime.UtcNow.ToUnixTimestampMilliseconds() >= timestampFinish) + { + timestampFinish= DateTime.UtcNow.ToUnixTimestampMilliseconds()+1000* craftingRecipe.progressRound; + List toConsume = craftingRecipe.GetIngredients(); + inCache.ConsumeItems(toConsume); + craftingRecipe.outcomes.ForEach(e => + { + e.group.ForEach(i => + { + outCache.AddItem(i.id, i.count); + }); + + }); + } + } + else + { + producer.inProduce = false; + producer.progress = 0; + timestampFinish = 0; + } + } + else + { + producer.inBlock = false; + producer.inProduce = false; + producer.progress = 0; + timestampFinish = 0; + } + } + + } + } +} diff --git a/Campofinale/Game/Factory/BuildingsBehaviour/NodeBuilding_ProducerFurnace.cs b/Campofinale/Game/Factory/BuildingsBehaviour/NodeBuilding_ProducerFurnace.cs new file mode 100644 index 0000000..a9bf040 --- /dev/null +++ b/Campofinale/Game/Factory/BuildingsBehaviour/NodeBuilding_ProducerFurnace.cs @@ -0,0 +1,120 @@ +using Campofinale.Game.Factory.Components; +using Campofinale.Protocol; +using Campofinale.Resource; +using Campofinale.Resource.Table; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Campofinale.Resource; +using static Campofinale.Resource.ResourceManager; +using System.Xml.Linq; + +namespace Campofinale.Game.Factory.BuildingsBehaviour +{ + public class NodeBuilding_ProducerFurnace : NodeBuildingBehaviour + { + public uint inputCacheId = 0; + public uint outputCacheId = 0; + public uint inputCacheIdFluid = 0; + public uint outputCacheIdFluid = 0; + public uint producerId = 0; + public long timestampFinish = 0; + public override void Init(FactoryChapter chapter, FactoryNode node) + { + FComponentCache cache1 = (FComponentCache)new FComponentCache(chapter.nextCompV(), FCComponentPos.CacheIn1).Init(); + FComponentCache cache2 = (FComponentCache)new FComponentCache(chapter.nextCompV(), FCComponentPos.CacheOut1).Init(); + FComponentCache cache3 = (FComponentCache)new FComponentCache(chapter.nextCompV(), FCComponentPos.CacheFluidIn1).Init(); + FComponentCache cache4 = (FComponentCache)new FComponentCache(chapter.nextCompV(), FCComponentPos.CacheFluidOut1).Init(); + FComponentProducer producer = (FComponentProducer)new FComponentProducer(chapter.nextCompV()).Init(); + node.components.Add(producer); + node.components.Add(new FComponentFormulaMan(chapter.nextCompV()).Init()); + node.components.Add(cache1); + node.components.Add(cache2); + node.components.Add(cache3); + node.components.Add(cache4); + inputCacheId = cache1.compId; + outputCacheId = cache2.compId; + inputCacheIdFluid = cache3.compId; + outputCacheIdFluid = cache4.compId; + producerId = producer.compId; + node.components.Add(new FComponentPortManager(chapter.nextCompV(), 4, cache1).Init()); + node.components.Add(new FComponentPortManager(chapter.nextCompV(), 4, cache2).Init()); + } + public string GetFormulaGroupId(string templateId) + { + FactoryMachineCraftTable table = factoryMachineCraftTable.Values.ToList().Find(r => r.machineId == templateId); + if (table != null) + { + return table.formulaGroupId; + } + else + { + return ""; + } + } + public override void Update(FactoryChapter chapter, FactoryNode node) + { + + if (node.powered) + { + FComponentProducer producer = node.GetComponent(producerId); + FComponentCache inCache = node.GetComponent(inputCacheId); + FComponentCache outCache = node.GetComponent(outputCacheId); + FComponentFormulaMan formulaManager = node.GetComponent(); + + if (formulaManager == null) return; + formulaManager.currentGroup = GetFormulaGroupId(node.templateId); + FactoryMachineCraftTable craftingRecipe = null; + string recipe = ResourceManager.FindFactoryMachineCraftIdUsingCacheItems(inCache.items,formulaManager.currentGroup); + producer.formulaId = recipe; + ResourceManager.factoryMachineCraftTable.TryGetValue(producer.formulaId, out craftingRecipe); + + if (craftingRecipe != null) + { + producer.inBlock = outCache.IsFull(); + if (craftingRecipe.CacheHaveItems(inCache) && !outCache.IsFull()) + { + producer.inProduce = true; + + producer.lastFormulaId = recipe; + if (timestampFinish == 0) + { + timestampFinish = DateTime.UtcNow.ToUnixTimestampMilliseconds() + 1000 * craftingRecipe.progressRound; + } + producer.progress = (DateTime.UtcNow.ToUnixTimestampMilliseconds() / timestampFinish) * craftingRecipe.totalProgress; + if (DateTime.UtcNow.ToUnixTimestampMilliseconds() >= timestampFinish) + { + timestampFinish = DateTime.UtcNow.ToUnixTimestampMilliseconds() + 1000 * craftingRecipe.progressRound; + List toConsume = craftingRecipe.GetIngredients(); + inCache.ConsumeItems(toConsume); + craftingRecipe.outcomes.ForEach(e => + { + e.group.ForEach(i => + { + outCache.AddItem(i.id, i.count); + }); + + }); + } + } + else + { + producer.inProduce = false; + producer.progress = 0; + timestampFinish = 0; + } + } + else + { + producer.inBlock = false; + producer.inProduce = false; + producer.progress = 0; + timestampFinish = 0; + } + } + + } + } +} diff --git a/Campofinale/Game/Factory/Components/FComponentBattle.cs b/Campofinale/Game/Factory/Components/FComponentBattle.cs new file mode 100644 index 0000000..f48cd53 --- /dev/null +++ b/Campofinale/Game/Factory/Components/FComponentBattle.cs @@ -0,0 +1,23 @@ +using Campofinale.Resource; +using static Campofinale.Game.Factory.FactoryNode; + +namespace Campofinale.Game.Factory.Components +{ + public class FComponentBattle : FComponent + { + public int EnergyCurrent=100; + public FComponentBattle(uint id) : base(id, FCComponentType.Battle, FCComponentPos.Battle1) + { + } + + public override void SetComponentInfo(ScdFacCom proto) + { + proto.Battle = new() + { + EnergyCurrent=100, + EnergyMax=100, + InOverloading=false + }; + } + } +} diff --git a/Campofinale/Game/Factory/Components/FComponentBoxConveyor.cs b/Campofinale/Game/Factory/Components/FComponentBoxConveyor.cs new file mode 100644 index 0000000..c63d964 --- /dev/null +++ b/Campofinale/Game/Factory/Components/FComponentBoxConveyor.cs @@ -0,0 +1,37 @@ +using Campofinale.Resource; +using static Campofinale.Game.Factory.FactoryNode; +using static Campofinale.Resource.ResourceManager; + +namespace Campofinale.Game.Factory.Components +{ + public class FComponentBoxConveyor : FComponent + { + public long lastPopTms = 0; + public List items = new(); + public FComponentBoxConveyor(uint id) : base(id, FCComponentType.BoxConveyor,FCComponentPos.BoxConveyor) + { + lastPopTms=DateTime.UtcNow.ToUnixTimestampMilliseconds(); + } + + public override void SetComponentInfo(ScdFacCom proto) + { + if (items == null) + { + items = new List(); + } + + proto.BoxConveyor = new() + { + LastPopTms = lastPopTms, + + }; + + items.ForEach(item => + { + if(item!=null) + proto.BoxConveyor.Items.Add(item.ToFactoryItemProto()); + }); + + } + } +} diff --git a/Campofinale/Game/Factory/Components/FComponentCache.cs b/Campofinale/Game/Factory/Components/FComponentCache.cs new file mode 100644 index 0000000..e76407d --- /dev/null +++ b/Campofinale/Game/Factory/Components/FComponentCache.cs @@ -0,0 +1,100 @@ +using Campofinale.Resource; +using static Campofinale.Game.Factory.FactoryNode; +using static Campofinale.Resource.ResourceManager; + +namespace Campofinale.Game.Factory.Components +{ + public class FComponentCache : FComponent + { + + public List items = new(); + public FComponentCache(uint id,FCComponentPos pos) : base(id, FCComponentType.Cache,pos) + { + } + public int GetItemCount(string id) + { + int count = 0; + ItemCount item = items.Find(i=>i.id == id); + if (item != null) + { + count += item.count; + } + return count; + } + public override void SetComponentInfo(ScdFacCom proto) + { + if(items.Count < 1) + { + //Add 1 empty item as default + items.Add(new ItemCount()); + } + proto.Cache = new() + { + Items = + { + }, + Size=items.Count, + + }; + items.ForEach(item => + { + proto.Cache.Items.Add(item.ToFactoryItemProto()); + }); + } + + public void ConsumeItems(List toConsume) + { + foreach (var consume in toConsume) + { + ItemCount item = items.Find(i => i.id == consume.id); + if (item != null) + { + item.count-=consume.count; + if(item.count < 1) + { + item.count = 0; + item.id = ""; + } + } + } + } + + public bool IsFull() + { + int maxItems = items.Count * 50; + int count = 0; + foreach (var item in items) + { + count += item.count; + }; + return count>=maxItems; + } + + public void AddItem(string id, int count) + { + int remaining = count; + foreach (var item in items) + { + int space = 50-item.count; + if (item.id==id) + { + if (space >= remaining) + { + item.count +=remaining; + remaining = 0; + } + else + { + item.count += space; + remaining -= space; + } + } + else if(item.id.Length < 1) + { + item.id = id; + item.count = remaining; + } + } + } + } +} diff --git a/Campofinale/Game/Factory/Components/FComponentFormulaMan.cs b/Campofinale/Game/Factory/Components/FComponentFormulaMan.cs new file mode 100644 index 0000000..993892c --- /dev/null +++ b/Campofinale/Game/Factory/Components/FComponentFormulaMan.cs @@ -0,0 +1,32 @@ +using Campofinale.Resource; + + +namespace Campofinale.Game.Factory.Components +{ + public class FComponentFormulaMan : FComponent + { + public string currentGroup = "group_grinder_normal"; + public string currentMode = "normal"; + public List formulaIds = new(); + public FComponentFormulaMan(uint id) : base(id, FCComponentType.FormulaMan) + { + } + public List GetFormulaIds() + { + List ids = ResourceManager.factoryMachineCraftTable.Where(i => i.Value.formulaGroupId == currentGroup).Select(i => i.Value.id).ToList(); + return ids; + } + public override void SetComponentInfo(ScdFacCom proto) + { + formulaIds = GetFormulaIds(); + proto.FormulaMan = new() + { + CurrentGroup = currentGroup, + CurrentMode = currentMode, + FormulaIds = { + formulaIds + } + }; + } + } +} diff --git a/Campofinale/Game/Factory/Components/FComponentPortManager.cs b/Campofinale/Game/Factory/Components/FComponentPortManager.cs index 43e473d..fa83d87 100644 --- a/Campofinale/Game/Factory/Components/FComponentPortManager.cs +++ b/Campofinale/Game/Factory/Components/FComponentPortManager.cs @@ -35,9 +35,45 @@ namespace Campofinale.Game.Factory.Components }); } } - + public FComponentPortManager(uint id, int size) : base(id, FCComponentType.PortManager) + { + for (int i = 0; i < size; i++) + { + ports.Add(new FPort() + { + index = i, + ownerComId = 0, + touchComId = 0 + }); + } + } + public FComponentPortManager(uint id, int size, FComponentCache cache) : base(id, FCComponentType.PortManager) + { + if( cache.customPos == FCComponentPos.CacheIn1 || + cache.customPos == FCComponentPos.CacheIn2 || + cache.customPos == FCComponentPos.CacheIn3 || + cache.customPos == FCComponentPos.CacheIn4) + { + customPos = FCComponentPos.PortInManager; + } + else + { + customPos = FCComponentPos.PortOutManager; + } + + for (int i = 0; i < size; i++) + { + ports.Add(new FPort() + { + index = i, + ownerComId = cache.compId, + touchComId = 0 + }); + } + } public override void SetComponentInfo(ScdFacCom proto) { + proto.PortManager = new(); foreach(FPort port in ports) { diff --git a/Campofinale/Game/Factory/Components/FComponentProducer.cs b/Campofinale/Game/Factory/Components/FComponentProducer.cs new file mode 100644 index 0000000..4452420 --- /dev/null +++ b/Campofinale/Game/Factory/Components/FComponentProducer.cs @@ -0,0 +1,29 @@ +using Campofinale.Resource; +using static Campofinale.Game.Factory.FactoryNode; + +namespace Campofinale.Game.Factory.Components +{ + public class FComponentProducer : FComponent + { + public string formulaId = ""; + public string lastFormulaId = ""; + public bool inProduce, inBlock; + public long progress; + public FComponentProducer(uint id) : base(id, FCComponentType.Producer) + { + + } + + public override void SetComponentInfo(ScdFacCom proto) + { + proto.Producer = new() + { + FormulaId=formulaId, + InBlock=inBlock, + CurrentProgress=progress, + InProduce=inProduce, + LastFormulaId=lastFormulaId + }; + } + } +} diff --git a/Campofinale/Game/Factory/FComponent.cs b/Campofinale/Game/Factory/FComponent.cs new file mode 100644 index 0000000..89058d3 --- /dev/null +++ b/Campofinale/Game/Factory/FComponent.cs @@ -0,0 +1,111 @@ +using Campofinale.Game.Factory.Components; +using Campofinale.Resource; +using MongoDB.Bson.Serialization.Attributes; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Campofinale.Game.Factory +{ + [BsonDiscriminator(Required = true)] + [BsonKnownTypes(typeof(FComponentSelector))] + + public class FComponent + { + public class FCompInventory + { + public ScdFacComInventory ToProto() + { + return new ScdFacComInventory() + { + + }; + } + } + public uint compId; + public FCComponentType type; + public FCompInventory inventory; + public FCComponentPos customPos = FCComponentPos.Invalid; + public FComponent(uint id, FCComponentType t, FCComponentPos custom= FCComponentPos.Invalid) + { + this.compId = id; + this.type = t; + this.customPos = custom; + } + public FCComponentPos GetComPos() + { + if(customPos == FCComponentPos.Invalid) + { + switch (type) + { + case FCComponentType.PowerPole: + return FCComponentPos.PowerPole; + case FCComponentType.TravelPole: + return FCComponentPos.TravelPole; + case FCComponentType.Battle: + return FCComponentPos.Battle1; + case FCComponentType.Producer: + return FCComponentPos.Producer; + case FCComponentType.FormulaMan: + return FCComponentPos.FormulaMan; + case FCComponentType.BusLoader: + return FCComponentPos.BusLoader; + case FCComponentType.StablePower: + return FCComponentPos.StablePower; + case FCComponentType.Selector: + return FCComponentPos.Selector; + case FCComponentType.PowerSave: + return FCComponentPos.PowerSave; + default: + return FCComponentPos.Invalid; + } + } + + return customPos; + } + public ScdFacCom ToProto() + { + ScdFacCom proto = new ScdFacCom() + { + ComponentType = (int)type, + ComponentId = compId, + + }; + SetComponentInfo(proto); + return proto; + } + + public virtual void SetComponentInfo(ScdFacCom proto) + { + if (inventory != null) + { + proto.Inventory = inventory.ToProto(); + } + else if (type == FCComponentType.PowerPole) + { + proto.PowerPole = new() + { + + }; + } + } + + public virtual FComponent Init() + { + switch (type) + { + case FCComponentType.Inventory: + inventory = new(); + break; + default: + break; + } + return this; + } + + + } +} diff --git a/Campofinale/Game/Factory/FactoryChapter.cs b/Campofinale/Game/Factory/FactoryChapter.cs new file mode 100644 index 0000000..7a461d3 --- /dev/null +++ b/Campofinale/Game/Factory/FactoryChapter.cs @@ -0,0 +1,722 @@ +using Campofinale.Game.Factory.Components; +using Campofinale.Game.Inventory; +using Campofinale.Packets.Sc; +using Campofinale.Protocol; +using Campofinale.Resource; +using Campofinale.Resource.Table; +using Newtonsoft.Json; +using System.Xml.Linq; +using static Campofinale.Resource.ResourceManager; + +namespace Campofinale.Game.Factory +{ + public class FactoryChapter + { + public string chapterId; + public ulong ownerId; + public List nodes = new(); + public uint v = 1; + public uint compV = 0; + public int bandwidth = 200; + public FactoryBlackboard blackboard = new(); + public class FactoryBlackboard + { + public uint inventoryNodeId=1; + public FacBbPower power = new(); + + public class FacBbPower + { + public long powerGen; + public long powerSaveMax; + public long powerSaveCurrent; + public long powerCost; + public bool isStopByPower; + } + public ScdFactorySyncBlackboard ToProto() + { + return new ScdFactorySyncBlackboard() + { + InventoryNodeId = inventoryNodeId, + Power = new() + { + IsStopByPower=power.isStopByPower, + PowerCost=power.powerCost, + PowerGen=power.powerGen, + PowerSaveCurrent=power.powerSaveCurrent, + PowerSaveMax=power.powerSaveMax, + } + }; + } + + public ScdFactoryHsBb ToProtoHsBb() + { + return new ScdFactoryHsBb() + { + Power = new() + { + IsStopByPower = power.isStopByPower, + PowerSaveCurrent = power.powerSaveCurrent, + PowerSaveMax = power.powerSaveMax, + + }, + + }; + } + } + public ScFactorySyncChapter ToProto() + { + blackboard = new(); + ScFactorySyncChapter chapter = new() + { + ChapterId = chapterId, + Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(), + Blackboard = new(), + Statistic = new() + { + LastDay = new() + { + + }, + Other = new() + { + InPowerBuilding = nodes.FindAll(n=>n.lastPowered==true).Count, + + } + }, + PinBoard = new() + { + Cards = + { + + }, + + }, + }; + blackboard.power.powerSaveCurrent = bandwidth; + domainDataTable[chapterId].levelGroup.ForEach(levelGroup => + { + int grade = GetOwner().sceneManager.GetScene(GetSceneNumIdFromLevelData(levelGroup)).grade; + LevelGradeInfo sceneGrade = ResourceManager.levelGradeTable[levelGroup].grades.Find(g => g.grade == grade); + if (sceneGrade != null) + { + blackboard.power.powerGen += sceneGrade.bandwidth; + blackboard.power.powerSaveMax += sceneGrade.bandwidth; + + var scene = new ScdFactorySyncScene() + { + SceneId = GetSceneNumIdFromLevelData(levelGroup), + + Bandwidth = new() + { + Current = 0, + Max = sceneGrade.bandwidth, + TravelPoleMax = sceneGrade.travelPoleLimit, + + BattleCurrent = 0, + BattleMax = sceneGrade.battleBuildingLimit, + }, + Settlements = + { + + }, + + Panels = + { + + } + }; + int index = 0; + LevelScene scen = GetLevelData(GetSceneNumIdFromLevelData(levelGroup)); + foreach (var reg in scen.levelData.factoryRegions) + { + foreach (var area in reg.areas) + { + var lvData = area.levelData.Find(l => l.level == grade); + if (lvData == null) + { + lvData = area.levelData.Last(); + } + if (lvData.levelBounds.Count > 0) + { + var bounds = lvData.levelBounds[0]; + scene.Panels.Add(new ScdFactorySyncScenePanel() + { + Index = index, + Level = lvData.level, + MainMesh = + { + new ScdRectInt() + { + X=(int)bounds.start.x, + Z=(int)bounds.start.z, + Y=(int)bounds.start.y, + W=(int)bounds.size.x, + H=(int)bounds.size.y, + L=(int)bounds.size.z, + } + } + }); + index++; + } + + } + } + chapter.Scenes.Add(scene); + } + + }); + try + { + nodes.ForEach(node => + { + chapter.Nodes.Add(node.ToProto()); + }); + } + catch(Exception e) + { + + } + chapter.Blackboard = blackboard.ToProto(); + chapter.Maps.AddRange(GetMaps()); + return chapter; + } + public List GetMaps() + { + List maps = new(); + string levelId = domainDataTable[chapterId].levelGroup[0]; + string mapId = GetLevelData(GetSceneNumIdFromLevelData(levelId)).mapIdStr; + maps.Add(new ScdFactorySyncMap() + { + MapId = ResourceManager.strIdNumTable.chapter_map_id.dic[mapId], + + Wires = + { + GetWires() + }, + + }); + return maps; + } + + public List GetWires() + { + List wires = new(); + HashSet<(ulong, ulong)> addedConnections = new(); + ulong i = 0; + + foreach (FactoryNode node in nodes) + { + foreach (var conn in node.connectedComps) + { + ulong compA = conn.Key; + ulong compB = conn.Value; + + var key = (compA, compB); + + if (!addedConnections.Contains(key)) + { + wires.Add(new ScdFactorySyncMapWire() + { + Index = i, + FromComId = compA, + ToComId = compB, + + }); + + addedConnections.Add(key); + i++; + } + } + } + + return wires; + } + + + public void Update() + { + try + { + UpdatePowerGrid(nodes); + foreach (FactoryNode node in nodes) + { + try + { + node.Update(this); + } + catch (Exception e) + { + Logger.PrintError($"Error occured while updating nodeId {node.nodeId}: {e.Message}"); + } + + } + } + catch (Exception e) + { + + } + + } + public List GetNodesInRange(Vector3f pos, float range) + { + return nodes.FindAll(n => n.position.Distance(pos) <= range); + } + + public void ExecOp(CsFactoryOp op, ulong seq) + { + + switch (op.OpType) + { + case FactoryOpType.Place: + CreateNode(op, seq); + break; + case FactoryOpType.MoveNode: + MoveNode(op, seq); + break; + case FactoryOpType.Dismantle: + DismantleNode(op, seq); + break; + case FactoryOpType.AddConnection: + AddConnection(op, seq); + break; + case FactoryOpType.MoveItemBagToCache: + MoveItemBagToCache(op, seq); + break; + case FactoryOpType.MoveItemCacheToBag: + MoveItemCacheToBag(op, seq); + break; + case FactoryOpType.ChangeProducerMode: + ChangeProducerMode(op, seq); + break; + case FactoryOpType.EnableNode: + EnableNode(op, seq); + break; + case FactoryOpType.PlaceConveyor: + PlaceConveyor(op, seq); + break; + case FactoryOpType.DismantleBoxConveyor: + DismantleBoxConveyor(op, seq); + break; + case FactoryOpType.UseHealTowerPoint: + //TODO + break; + case FactoryOpType.SetTravelPoleDefaultNext: + FactoryNode travelNode = GetNodeByCompId(op.SetTravelPoleDefaultNext.ComponentId); + travelNode.GetComponent().defaultNext = op.SetTravelPoleDefaultNext.DefaultNext; + GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, travelNode)); + GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), 0, op), seq); + break; + default: + break; + } + + } + public void DismantleBoxConveyor(CsFactoryOp op, ulong seq) + { + var dismantle = op.DismantleBoxConveyor; + + FactoryNode nodeRem = nodes.Find(n => n.nodeId == dismantle.NodeId); + if (nodeRem != null) + { + RemoveConnectionsToNode(nodeRem, nodes); + nodes.Remove(nodeRem); + GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, nodeRem.nodeId)); + GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), nodeRem.nodeId, op), seq); + } + else + { + ScFactoryOpRet ret = new() + { + RetCode = FactoryOpRetCode.Fail, + + }; + GetOwner().Send(ScMsgId.ScFactoryOpRet, ret, seq); + } + } + public void EnableNode(CsFactoryOp op, ulong seq) + { + var enableNode = op.EnableNode; + FactoryNode node = nodes.Find(n => n.nodeId == enableNode.NodeId); + if(node!= null) + { + node.deactive = !enableNode.Enable; + GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, node)); + } + GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), 0, op), seq); + } + public void ChangeProducerMode(CsFactoryOp op, ulong seq) + { + var changeMode = op.ChangeProducerMode; + FactoryNode node = nodes.Find(n=>n.nodeId == changeMode.NodeId); + if(node != null) + { + FComponentFormulaMan formula = node.GetComponent(); + if (formula != null) + { + formula.currentMode = changeMode.ToMode; //test, not sure + } + + } + GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), 0, op), seq); + + } + public void MoveItemCacheToBag(CsFactoryOp op, ulong seq) + { + var move = op.MoveItemCacheToBag; + FComponentCache cacheComp = GetCompById(move.ComponentId); + if (cacheComp != null) + { + ItemCount cacheItem = cacheComp.items[move.CacheGridIndex]; + Item gridItem = null; + GetOwner().inventoryManager.items.bag.TryGetValue(move.GridIndex, out gridItem); + if (gridItem == null) + { + GetOwner().inventoryManager.items.bag.Add(move.GridIndex, new Item(ownerId,cacheItem.id,cacheItem.count)); + cacheItem.id = ""; + cacheItem.count = 0; + + } + else + { + if(gridItem.id == cacheItem.id) + { + int availableSpace = 50 - gridItem.amount; + if(cacheItem.count > availableSpace) + { + gridItem.amount += availableSpace; + cacheItem.count-= availableSpace; + } + else + { + gridItem.amount += cacheItem.count; + cacheItem.id = ""; + cacheItem.count = 0; + } + } + else + { + //TODO Swap + } + + } + } + GetOwner().inventoryManager.items.UpdateBagInventoryPacket(); + GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), 0, op), seq); + } + public void MoveItemBagToCache(CsFactoryOp op, ulong seq) + { + var move = op.MoveItemBagToCache; + FComponentCache cacheComp = GetCompById(move.ComponentId); + if (cacheComp != null) + { + Item gridItem = null; + GetOwner().inventoryManager.items.bag.TryGetValue(move.GridIndex, out gridItem); + if (gridItem != null) + { + if(cacheComp.items[move.CacheGridIndex].id == "" || cacheComp.items[move.CacheGridIndex].id == gridItem.id) + { + int canAdd = 50 - cacheComp.items[move.CacheGridIndex].count; + + if (canAdd >= gridItem.amount) + { + cacheComp.items[move.CacheGridIndex].id = gridItem.id; + cacheComp.items[move.CacheGridIndex].count += gridItem.amount; + GetOwner().inventoryManager.items.bag.Remove(move.GridIndex); + GetOwner().inventoryManager.items.UpdateBagInventoryPacket(); + } + else + { + cacheComp.items[move.CacheGridIndex].id = gridItem.id; + cacheComp.items[move.CacheGridIndex].count += canAdd; + gridItem.amount-=canAdd; + GetOwner().inventoryManager.items.UpdateBagInventoryPacket(); + } + } + } + + } + GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), 0, op), seq); + } + + public void MoveNode(CsFactoryOp op, ulong seq) + { + var move = op.MoveNode; + FactoryNode node = nodes.Find(n => n.nodeId == move.NodeId); + if (node != null) + { + node.direction = new Vector3f(move.Direction); + node.position = new Vector3f(move.Position); + node.worldPosition = new Vector3f(move.InteractiveParam.Position); + GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, node)); + GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), node.nodeId, op), seq); + node.SendEntity(GetOwner(), chapterId); + } + else + { + ScFactoryOpRet ret = new() + { + RetCode = FactoryOpRetCode.Fail, + }; + GetOwner().Send(ScMsgId.ScFactoryOpRet, ret, seq); + } + } + public void DismantleNode(CsFactoryOp op, ulong seq) + { + var dismantle = op.Dismantle; + + FactoryNode nodeRem = nodes.Find(n => n.nodeId == dismantle.NodeId); + if (nodeRem != null) + { + RemoveConnectionsToNode(nodeRem, nodes); + nodes.Remove(nodeRem); + GetOwner().Send(ScMsgId.ScFactoryModifyChapterMap, new ScFactoryModifyChapterMap() + { + ChapterId = chapterId, + MapId = nodeRem.mapId, + Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(), + Wires = + { + GetWires() + } + }); + GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, nodeRem.nodeId)); + GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), nodeRem.nodeId, op), seq); + } + else + { + ScFactoryOpRet ret = new() + { + RetCode = FactoryOpRetCode.Fail, + + }; + GetOwner().Send(ScMsgId.ScFactoryOpRet, ret, seq); + } + } + public void RemoveConnectionsToNode(FactoryNode nodeRem, List allNodes) + { + // Ottieni tutti i compId del nodo da rimuovere + HashSet remCompIds = nodeRem.components.Select(c => (ulong)c.compId).ToHashSet(); + + foreach (var node in allNodes) + { + node.connectedComps.RemoveAll(conn => + remCompIds.Contains(conn.Key) || remCompIds.Contains(conn.Value)); + } + } + + + public uint nextCompV() + { + compV++; + return compV; + } + public FComponent GetCompById(ulong compId) + { + foreach (FactoryNode node in nodes) + { + if (node.components.Find(c => c.compId == compId) != null) + { + return node.components.Find(c => c.compId == compId); + } + } + return null; + } + public FComponent GetCompById(ulong compId) where FComponent : class + { + foreach (FactoryNode node in nodes) + { + if (node.components.Find(c => c.compId == compId) != null) + { + return node.components.Find(c => c.compId == compId && c is FComponent) as FComponent; + } + } + return null; + } + public FactoryNode GetNodeByCompId(ulong compId) + { + foreach (FactoryNode node in nodes) + { + if (node.components.Find(c => c.compId == compId) != null) + { + return node; + } + } + return null; + } + private void AddConnection(CsFactoryOp op, ulong seq) + { + FComponent nodeFrom = GetCompById(op.AddConnection.FromComId); + FComponent nodeTo = GetCompById(op.AddConnection.ToComId); + + if (nodeFrom != null && nodeTo != null) + { + GetNodeByCompId(nodeFrom.compId).connectedComps.Add(new(nodeFrom.compId, nodeTo.compId)); + GetNodeByCompId(nodeTo.compId).connectedComps.Add(new(nodeTo.compId, nodeFrom.compId)); + GetOwner().Send(ScMsgId.ScFactoryModifyChapterMap, new ScFactoryModifyChapterMap() + { + ChapterId = chapterId, + MapId = GetNodeByCompId(nodeFrom.compId).mapId, + Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(), + Wires = + { + GetWires() + } + }); + var wire = GetWires().Find(w => + (w.FromComId == op.AddConnection.FromComId && w.ToComId == op.AddConnection.ToComId) || + (w.FromComId == op.AddConnection.ToComId && w.ToComId == op.AddConnection.FromComId)); + + if (wire != null) + { + GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), (uint)wire.Index, op), seq); + } + else + { + // Facoltativo: log di errore + Console.WriteLine($"[WARN] Connessione non trovata tra {op.AddConnection.FromComId} e {op.AddConnection.ToComId}"); + } + + } + + } + void ResetAllPower(List allNodes) + { + foreach (var node in allNodes) + node.powered = false; + } + void UpdatePowerGrid(List allNodes) + { + ResetAllPower(allNodes); + + HashSet visited = new(); + + foreach (var node in allNodes) + { + if (node.templateId.Contains("hub") || node.templateId == "power_diffuser_1") + { + //if(node.forcePowerOn) + if (node.templateId == "power_diffuser_1") + { + //Check inside factory region + + } + else + { + PropagatePowerFrom(node, visited); + } + + } + } + } + void PropagatePowerFrom(FactoryNode node, HashSet visited) + { + if (visited.Contains(node.nodeId)) + return; + + visited.Add(node.nodeId); + node.powered = true; + if (node.templateId == "power_diffuser_1") + { + //get builds in area test + List nodes = GetNodesInRange(node.position, 15); + foreach (FactoryNode propagateNode in nodes) + { + if (propagateNode.GetComponent() == null) + { + propagateNode.powered = true; + } + } + } + if (node.GetComponent() != null) + foreach (var connectedCompId in node.connectedComps) + { + FactoryNode connectedNode = GetNodeByCompId(connectedCompId.Value); + if (connectedNode != null) + { + PropagatePowerFrom(connectedNode, visited); + } + } + } + public void PlaceConveyor(CsFactoryOp op, ulong seq) + { + var placeConveyor = op.PlaceConveyor; + v++; + uint nodeId = v; + List points = new(); + foreach(var point in placeConveyor.Points) + { + points.Add(new Vector3f(point)); + } + FactoryNode node = new() + { + nodeId = nodeId, + templateId = placeConveyor.TemplateId, + mapId = placeConveyor.MapId, + sceneNumId = GetOwner().sceneManager.GetCurScene().sceneNumId, + nodeType = FCNodeType.BoxConveyor, + position = new Vector3f(placeConveyor.Points[0]), + direction = new(), + directionIn = new Vector3f(placeConveyor.DirectionIn), + directionOut = new Vector3f(placeConveyor.DirectionOut), + worldPosition = null, + points = points, + guid = GetOwner().random.NextRand(), + }; + + node.InitComponents(this); + GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, node)); + nodes.Add(node); + + GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), nodeId, op), seq); + } + private void CreateNode(CsFactoryOp op, ulong seq) + { + v++; + uint nodeId = v; + CsdFactoryOpPlace place = op.Place; + FactoryBuildingTable table = ResourceManager.factoryBuildingTable[place.TemplateId]; + FactoryNode node = new() + { + nodeId = nodeId, + templateId = place.TemplateId, + mapId = place.MapId, + sceneNumId = GetOwner().sceneManager.GetCurScene().sceneNumId, + nodeType = table.GetNodeType(), + position = new Vector3f(place.Position), + direction = new Vector3f(place.Direction), + worldPosition = new Vector3f(place.InteractiveParam.Position), + guid = GetOwner().random.NextRand(), + + }; + + node.InitComponents(this); + GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, node)); + nodes.Add(node); + node.SendEntity(GetOwner(), chapterId); + + GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), node.nodeId, op), seq); + + } + + public FactoryChapter(string chapterId, ulong ownerId) + { + this.ownerId = ownerId; + this.chapterId = chapterId; + FactoryNode node = new() + { + nodeId = v, + templateId = "__inventory__", + nodeType = FCNodeType.Inventory, + mapId = 0, + deactive = true, + guid = GetOwner().random.NextRand() + }; + node.InitComponents(this); + nodes.Add(node); + } + public Player GetOwner() + { + return Server.clients.Find(c => c.roleId == ownerId); + } + } +} diff --git a/Campofinale/Game/Factory/FactoryManager.cs b/Campofinale/Game/Factory/FactoryManager.cs index d62ae5d..81f4e51 100644 --- a/Campofinale/Game/Factory/FactoryManager.cs +++ b/Campofinale/Game/Factory/FactoryManager.cs @@ -1,15 +1,12 @@ using Campofinale.Database; using Campofinale.Game.Entities; using Campofinale.Game.Factory.Components; +using Campofinale.Network; using Campofinale.Packets.Sc; using Campofinale.Protocol; using Campofinale.Resource; -using Campofinale.Resource.Table; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; -using System.Linq; -using System.Numerics; -using System.Xml.Linq; using static Campofinale.Resource.ResourceManager; namespace Campofinale.Game.Factory @@ -19,6 +16,7 @@ namespace Campofinale.Game.Factory public Player player; public List chapters = new(); public ObjectId _id; + public class FactoryData { public ulong roleId; @@ -71,829 +69,38 @@ namespace Campofinale.Game.Factory player.Send(ScMsgId.ScFactoryOpRet, ret, seq); } } + public void SendFactoryHsSync() + { + if (!player.Initialized) return; + if (player.GetCurrentChapter() == "") return; + List nodeUpdateList = new(); + foreach (var node in GetChapter(player.GetCurrentChapter()).nodes) + { + if (node != null) + { + if (node.position.DistanceXZ(player.position) < 150 && node.nodeBehaviour!=null) + { + nodeUpdateList.Add(node); + } + } + } + player.Send(new PacketScFactoryHsSync(player,GetChapter(player.GetCurrentChapter()), nodeUpdateList)); + } public void Update() { + if (!player.Initialized) return; foreach (FactoryChapter chapter in chapters) { chapter.Update(); } + } public FactoryChapter GetChapter(string id) { return chapters.Find(c=>c.chapterId==id); } } - public class FactoryChapter - { - public string chapterId; - public ulong ownerId; - public List nodes=new(); - public uint v = 1; - public uint compV = 0; - public int bandwidth = 200; - - public ScFactorySyncChapter ToProto() - { - ScFactorySyncChapter chapter = new() - { - ChapterId = chapterId, - Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds()/1000, - Blackboard = new() - { - Power = new() - { - PowerGen = 0, - PowerSaveMax = 0, - PowerSaveCurrent = 0, - PowerCost = 0 - }, - InventoryNodeId = 1 - }, - Statistic = new() - { - LastDay = new() - { - - }, - Other = new() - { - InPowerBuilding = 1 - } - }, - PinBoard = new() - { - Cards = - { - - }, - - }, - }; - chapter.Blackboard.Power.PowerSaveCurrent = bandwidth; - domainDataTable[chapterId].levelGroup.ForEach(levelGroup => - { - int grade = GetOwner().sceneManager.GetScene(GetSceneNumIdFromLevelData(levelGroup)).grade; - LevelGradeInfo sceneGrade = ResourceManager.levelGradeTable[levelGroup].grades.Find(g=>g.grade==grade); - if (sceneGrade != null) - { - chapter.Blackboard.Power.PowerGen += sceneGrade.bandwidth; - chapter.Blackboard.Power.PowerSaveMax += sceneGrade.bandwidth; - - var scene = new ScdFactorySyncScene() - { - SceneId = GetSceneNumIdFromLevelData(levelGroup), - - Bandwidth = new() - { - Current = 0, - Max = sceneGrade.bandwidth, - TravelPoleMax = sceneGrade.travelPoleLimit, - - BattleCurrent = 0, - BattleMax = sceneGrade.battleBuildingLimit, - }, - Settlements = - { - - }, - - Panels = - { - - } - }; - int index = 0; - LevelScene scen = GetLevelData(GetSceneNumIdFromLevelData(levelGroup)); - foreach (var reg in scen.levelData.factoryRegions) - { - foreach (var area in reg.areas) - { - var lvData = area.levelData.Find(l=>l.level==grade); - if (lvData == null) - { - lvData = area.levelData.Last(); - } - if (lvData.levelBounds.Count > 0) - { - var bounds = lvData.levelBounds[0]; - scene.Panels.Add(new ScdFactorySyncScenePanel() - { - Index = index, - Level = lvData.level, - MainMesh = - { - new ScdRectInt() - { - X=(int)bounds.start.x, - Z=(int)bounds.start.z, - Y=(int)bounds.start.y, - W=(int)bounds.size.x, - H=(int)bounds.size.y, - L=(int)bounds.size.z, - } - } - }); - index++; - } - - } - } - chapter.Scenes.Add(scene); - } - - }); - nodes.ForEach(node => - { - chapter.Nodes.Add(node.ToProto()); - }); - chapter.Maps.AddRange(GetMaps()); - return chapter; - } - public List GetMaps() - { - List maps = new(); - string levelId = domainDataTable[chapterId].levelGroup[0]; - string mapId = GetLevelData(GetSceneNumIdFromLevelData(levelId)).mapIdStr; - maps.Add(new ScdFactorySyncMap() - { - MapId = ResourceManager.strIdNumTable.chapter_map_id.dic[mapId], - Wires = - { - GetWires() - } - }); - return maps; - } - - public List GetWires() - { - List wires = new(); - HashSet<(ulong, ulong)> addedConnections = new(); // evita doppioni esatti - ulong i = 0; - - foreach (FactoryNode node in nodes) - { - foreach (var conn in node.connectedComps) - { - ulong compA = conn.Key; - ulong compB = conn.Value; - - var key = (compA, compB); - - if (!addedConnections.Contains(key)) - { - wires.Add(new ScdFactorySyncMapWire() - { - Index = i, - FromComId = compA, - ToComId = compB - }); - - addedConnections.Add(key); - i++; - } - } - } - - return wires; - } - - - public void Update() - { - try - { - UpdatePowerGrid(nodes); - foreach (FactoryNode node in nodes) - { - node.Update(this); - } - } - catch (Exception e) - { - - } - - } - public List GetNodesInRange(Vector3f pos,float range) - { - return nodes.FindAll(n => n.position.Distance(pos) <= range); - } - - public void ExecOp(CsFactoryOp op, ulong seq) - { - - switch (op.OpType) - { - case FactoryOpType.Place: - CreateNode(op, seq); - break; - case FactoryOpType.MoveNode: - MoveNode(op, seq); - break; - case FactoryOpType.Dismantle: - DismantleNode(op, seq); - break; - case FactoryOpType.AddConnection: - AddConnection(op, seq); - break; - case FactoryOpType.SetTravelPoleDefaultNext: - FactoryNode travelNode = GetNodeByCompId(op.SetTravelPoleDefaultNext.ComponentId); - travelNode.GetComponent().defaultNext = op.SetTravelPoleDefaultNext.DefaultNext; - GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, travelNode)); - GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), 0, op), seq); - break; - default: - break; - } - - } - public void MoveNode(CsFactoryOp op, ulong seq) - { - var move = op.MoveNode; - FactoryNode node = nodes.Find(n => n.nodeId == move.NodeId); - if (node != null) - { - node.direction = new Vector3f(move.Direction); - node.position = new Vector3f(move.Position); - node.worldPosition = new Vector3f(move.InteractiveParam.Position); - GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, node)); - GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), node.nodeId, op), seq); - node.SendEntity(GetOwner(), chapterId); - } - else - { - ScFactoryOpRet ret = new() - { - RetCode = FactoryOpRetCode.Fail, - }; - GetOwner().Send(ScMsgId.ScFactoryOpRet, ret, seq); - } - } - public void DismantleNode(CsFactoryOp op, ulong seq) - { - var dismantle = op.Dismantle; - - FactoryNode nodeRem = nodes.Find(n => n.nodeId == dismantle.NodeId); - if (nodeRem != null) - { - RemoveConnectionsToNode(nodeRem, nodes); - nodes.Remove(nodeRem); - GetOwner().Send(ScMsgId.ScFactoryModifyChapterMap, new ScFactoryModifyChapterMap() - { - ChapterId = chapterId, - MapId = nodeRem.mapId, - Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds() / 1000, - Wires = - { - GetWires() - } - }); - GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, nodeRem.nodeId)); - GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), nodeRem.nodeId, op), seq); - } - else - { - ScFactoryOpRet ret = new() - { - RetCode = FactoryOpRetCode.Fail, - - }; - GetOwner().Send(ScMsgId.ScFactoryOpRet, ret, seq); - } - } - public void RemoveConnectionsToNode(FactoryNode nodeRem, List allNodes) - { - // Ottieni tutti i compId del nodo da rimuovere - HashSet remCompIds = nodeRem.components.Select(c => (ulong)c.compId).ToHashSet(); - - foreach (var node in allNodes) - { - node.connectedComps.RemoveAll(conn => - remCompIds.Contains(conn.Key) || remCompIds.Contains(conn.Value)); - } - } - - - public uint nextCompV() - { - compV++; - return compV; - } - public FactoryNode.FComponent GetCompById(ulong compId) - { - foreach(FactoryNode node in nodes) - { - if (node.components.Find(c => c.compId == compId) != null) - { - return node.components.Find(c => c.compId == compId); - } - } - return null; - } - public FactoryNode GetNodeByCompId(ulong compId) - { - foreach (FactoryNode node in nodes) - { - if (node.components.Find(c => c.compId == compId) != null) - { - return node; - } - } - return null; - } - private void AddConnection(CsFactoryOp op,ulong seq) - { - FactoryNode.FComponent nodeFrom = GetCompById(op.AddConnection.FromComId); - FactoryNode.FComponent nodeTo = GetCompById(op.AddConnection.ToComId); - - if(nodeFrom!=null && nodeTo != null) - { - GetNodeByCompId(nodeFrom.compId).connectedComps.Add(new(nodeFrom.compId, nodeTo.compId)); - GetNodeByCompId(nodeTo.compId).connectedComps.Add(new(nodeTo.compId, nodeFrom.compId)); - GetOwner().Send(ScMsgId.ScFactoryModifyChapterMap, new ScFactoryModifyChapterMap() - { - ChapterId = chapterId, - MapId = GetNodeByCompId(nodeFrom.compId).mapId, - Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds()/1000, - Wires = - { - GetWires() - } - }); - var wire = GetWires().Find(w => - (w.FromComId == op.AddConnection.FromComId && w.ToComId == op.AddConnection.ToComId) || - (w.FromComId == op.AddConnection.ToComId && w.ToComId == op.AddConnection.FromComId)); - - if (wire != null) - { - GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), (uint)wire.Index, op), seq); - } - else - { - // Facoltativo: log di errore - Console.WriteLine($"[WARN] Connessione non trovata tra {op.AddConnection.FromComId} e {op.AddConnection.ToComId}"); - } - - } - - } - void ResetAllPower(List allNodes) - { - foreach (var node in allNodes) - node.powered = false; - } - void UpdatePowerGrid(List allNodes) - { - ResetAllPower(allNodes); - - HashSet visited = new(); - - foreach (var node in allNodes) - { - if (node.templateId.Contains("hub") || node.templateId == "power_diffuser_1") - { - //if(node.forcePowerOn) - if(node.templateId== "power_diffuser_1") - { - //Check inside factory region - - } - else - { - PropagatePowerFrom(node, visited); - } - - } - } - } - void PropagatePowerFrom(FactoryNode node, HashSet visited) - { - if (visited.Contains(node.nodeId)) - return; - - visited.Add(node.nodeId); - node.powered = true; - if(node.templateId == "power_diffuser_1") - { - //get builds in area test - List nodes=GetNodesInRange(node.position, 15); - foreach(FactoryNode propagateNode in nodes) - { - if (propagateNode.GetComponent() == null) - { - propagateNode.powered = true; - } - } - } - if (node.GetComponent() != null) - foreach (var connectedCompId in node.connectedComps) - { - FactoryNode connectedNode = GetNodeByCompId(connectedCompId.Value); - if (connectedNode != null) - { - PropagatePowerFrom(connectedNode, visited); - } - } - } - private void CreateNode(CsFactoryOp op, ulong seq) - { - v++; - uint nodeId = v; - CsdFactoryOpPlace place = op.Place; - FactoryBuildingTable table = ResourceManager.factoryBuildingTable[place.TemplateId]; - FactoryNode node = new() - { - nodeId = nodeId, - templateId = place.TemplateId, - mapId = place.MapId, - sceneNumId = GetOwner().sceneManager.GetCurScene().sceneNumId, - nodeType = table.GetNodeType(), - position = new Vector3f(place.Position), - direction = new Vector3f(place.Direction), - worldPosition = new Vector3f(place.InteractiveParam.Position), - guid = GetOwner().random.NextRand(), - - }; - - node.InitComponents(this); - GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, node)); - nodes.Add(node); - node.SendEntity(GetOwner(), chapterId); - - GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), node.nodeId,op),seq); - - } - - public FactoryChapter(string chapterId,ulong ownerId) - { - this.ownerId = ownerId; - this.chapterId = chapterId; - FactoryNode node = new() - { - nodeId = v, - templateId= "__inventory__", - nodeType=FCNodeType.Inventory, - mapId=0, - deactive=true, - guid = GetOwner().random.NextRand() - }; - node.InitComponents(this); - nodes.Add(node); - } - public Player GetOwner() - { - return Server.clients.Find(c => c.roleId == ownerId); - } - } - public class FactoryNode - { - public uint nodeId; - public FCNodeType nodeType; - public string templateId; - public Vector3f position=new(); - public Vector3f direction = new(); - public Vector3f worldPosition = new(); - public string instKey=""; - public bool deactive = false; - public int mapId; - public int sceneNumId; - public bool forcePowerOn = false; - public List components = new(); - [BsonIgnore] - public bool powered = false; - [BsonIgnore] - public bool lastPowered = false; - public List connectedComps = new(); - public ulong guid; - - public class ConnectedComp - { - public ulong Key; - public ulong Value; - public ConnectedComp(ulong key, ulong value) - { - this.Key = key; - this.Value = value; - } - } - public void Update(FactoryChapter chapter) - { - LevelScene scen = GetLevelData(sceneNumId); - if (lastPowered != powered) - { - lastPowered = powered; - chapter.GetOwner().Send(new PacketScFactoryModifyChapterNodes(chapter.GetOwner(), chapter.chapterId, this)); - } - - } - public bool InPower() - { - if (forcePowerOn) - { - return true; - } - return powered; - } - public FComponent GetComponent() where FComponent : class - { - return components.Find(c => c is FComponent) as FComponent; - } - public FMesh GetMesh() - { - FMesh mesh = new FMesh(); - - if (ResourceManager.factoryBuildingTable.TryGetValue(templateId, out FactoryBuildingTable table)) - { - float width = table.range.width - 1; - float height = table.range.height - 1; - float depth = table.range.depth-1; - - Vector3f p1_final = new Vector3f(); - Vector3f p2_final = new Vector3f(); - - switch (direction.y) - { - case 0f: - case 360f: - default: - p1_final = position + new Vector3f(table.range.x, table.range.y, table.range.z); - p2_final = p1_final + new Vector3f(width, height, depth); - break; - - case 90f: - // Rotazione 90°: Larghezza e profondità si scambiano. - // Il mesh parte da 'position' ma si estende su assi diversi. - p1_final = position + new Vector3f(table.range.x, table.range.y, table.range.z - width); - p2_final = p1_final + new Vector3f(depth, height, width); - break; - - case 180f: - // Rotazione 180°: Larghezza e profondità mantengono i loro valori - // ma il mesh si estende in direzioni negative. - p1_final = position + new Vector3f(table.range.x - width, table.range.y, table.range.z - depth); - p2_final = p1_final + new Vector3f(width, height, depth); - break; - - case 270f: - // Rotazione 270°: Larghezza e profondità si scambiano. - // Il mesh si estende in direzioni diverse rispetto alla rotazione di 90°. - p1_final = position + new Vector3f(table.range.x - depth, table.range.y, table.range.z); - p2_final = p1_final + new Vector3f(depth, height, width); - break; - } - - mesh.points.Add(p1_final); - mesh.points.Add(p2_final); - } - - return mesh; - } - - - public ScdFacNode ToProto() - { - ScdFacNode node = new ScdFacNode() - { - InstKey = instKey, - NodeId=nodeId, - TemplateId=templateId, - StableId= GetStableId(), - IsDeactive= deactive, - - Power = new() - { - InPower= InPower(), - NeedInPower=true, - }, - - NodeType=(int)nodeType, - Transform = new() - { - Position = position.ToProtoScd(), - Direction=direction.ToProtoScd(), - MapId=mapId, - - - } - }; - if(templateId!="__inventory__") - { - node.Transform.Mesh = GetMesh().ToProto(); - node.Transform.Position = position.ToProtoScd(); - node.Transform.WorldPosition = worldPosition.ToProto(); - node.Transform.WorldRotation = direction.ToProto(); - node.InteractiveObject = new() - { - ObjectId=guid, - }; - node.Flag = 0; - node.InstKey = ""; - } - foreach(FComponent comp in components) - { - node.Components.Add(comp.ToProto()); - node.ComponentPos.Add((int)comp.GetComPos(), comp.compId); - } - - return node; - } - public uint GetStableId() - { - return 10000+nodeId; - } - public FCComponentType GetMainCompType() - { - string nodeTypeName = nodeType.ToString(); - if (Enum.TryParse(nodeTypeName, out FCComponentType fromName)) - { - return fromName; - } - return FCComponentType.Invalid; - } - public void InitComponents(FactoryChapter chapter) - { - switch (nodeType) - { - case FCNodeType.PowerPole: - components.Add(new FComponentPowerPole(chapter.nextCompV()).Init()); - break; - case FCNodeType.PowerDiffuser: - components.Add(new FComponentPowerPole(chapter.nextCompV()).Init()); - break; - case FCNodeType.TravelPole: - components.Add(new FComponentTravelPole(chapter.nextCompV()).Init()); - break; - case FCNodeType.Hub: - components.Add(new FComponentSelector(chapter.nextCompV()).Init()); - components.Add(new FComponentPowerPole(chapter.nextCompV()).Init()); - components.Add(new FComponentPowerSave(chapter.nextCompV()).Init()); - components.Add(new FComponentStablePower(chapter.nextCompV()).Init()); - components.Add(new FComponentBusLoader(chapter.nextCompV()).Init()); - components.Add(new FComponentPortManager(chapter.nextCompV(),GetComponent().compId).Init()); - forcePowerOn = true; - break; - case FCNodeType.SubHub: - components.Add(new FComponentSubHub(chapter.nextCompV()).Init()); - components.Add(new FComponentSelector(chapter.nextCompV()).Init()); - components.Add(new FComponentPowerPole(chapter.nextCompV()).Init()); - components.Add(new FComponentPowerSave(chapter.nextCompV()).Init()); - components.Add(new FComponentStablePower(chapter.nextCompV()).Init()); - components.Add(new FComponentBusLoader(chapter.nextCompV()).Init()); - components.Add(new FComponentPortManager(chapter.nextCompV(), GetComponent().compId).Init()); - forcePowerOn = true; - break; - default: - components.Add(new FComponent(chapter.nextCompV(), GetMainCompType()).Init()); - break; - } - - } - - public void SendEntity(Player player, string chapterId) - { - Entity exist = player.sceneManager.GetCurScene().entities.Find(e => e.guid == guid); - if (exist != null) - { - exist.Position = worldPosition; - exist.Rotation = direction; - ScMoveObjectMove move = new() - { - ServerNotify = true, - MoveInfo = - { - new MoveObjectMoveInfo() - { - Objid = guid, - SceneNumId=sceneNumId, - MotionInfo = new() - { - Position=exist.Position.ToProto(), - Rotation=exist.Rotation.ToProto(), - Speed=new Vector() - { - - }, - State=MotionState.MotionNone - } - } - } - }; - player.Send(ScMsgId.ScMoveObjectMove, move); - } - else - { - EntityInteractive e = new(interactiveFacWrapperTable[templateId].interactiveTemplateId, player.roleId, worldPosition, direction, sceneNumId, guid); - e.InitDefaultProperties(); - e.SetPropValue(nodeId, "factory_inst_id"); - - player.sceneManager.GetCurScene().entities.Add(e); - player.sceneManager.GetCurScene().SpawnEntity(e); - } - - } - - [BsonDiscriminator(Required = true)] - [BsonKnownTypes(typeof(FComponentSelector))] - - public class FComponent - { - public class FCompInventory - { - public ScdFacComInventory ToProto() - { - return new ScdFacComInventory() - { - - }; - } - } - public uint compId; - public FCComponentType type; - public FCompInventory inventory; - - public FComponent(uint id, FCComponentType t) - { - this.compId = id; - this.type = t; - } - public FCComponentPos GetComPos() - { - - string compTypeName = type.ToString(); - if (Enum.TryParse(compTypeName, out FCComponentPos fromName)) - { - return fromName; - } - switch (type) - { - case FCComponentType.PowerPole: - return FCComponentPos.PowerPole; - } - return FCComponentPos.Invalid; - } - public ScdFacCom ToProto() - { - ScdFacCom proto = new ScdFacCom() - { - ComponentType = (int)type, - ComponentId = compId, - - }; - SetComponentInfo(proto); - return proto; - } - - public virtual void SetComponentInfo(ScdFacCom proto) - { - if (inventory != null) - { - proto.Inventory = inventory.ToProto(); - } - else if (type == FCComponentType.PowerPole) - { - proto.PowerPole = new() - { - - }; - } - } - - public virtual FComponent Init() - { - switch (type) - { - case FCComponentType.Inventory: - inventory = new(); - break; - default: - break; - } - return this; - } - } - public class FMesh - { - public FCMeshType type; - public List points=new(); - public ScdFacMesh ToProto() - { - ScdFacMesh m = new ScdFacMesh() - { - MeshType = (int)type - }; - foreach (Vector3f p in points) - { - m.Points.Add(new ScdVec3Int() - { - X = (int)p.x, - Y = (int)p.y, - Z = (int)p.z - }); - } - return m; - } - } - } + + } diff --git a/Campofinale/Game/Factory/FactoryNode.cs b/Campofinale/Game/Factory/FactoryNode.cs new file mode 100644 index 0000000..d469806 --- /dev/null +++ b/Campofinale/Game/Factory/FactoryNode.cs @@ -0,0 +1,598 @@ +using Campofinale.Game.Entities; +using Campofinale.Game.Factory.Components; +using Campofinale.Packets.Sc; +using Campofinale.Protocol; +using Campofinale.Resource.Table; +using Campofinale.Resource; +using MongoDB.Bson.Serialization.Attributes; +using static Campofinale.Resource.ResourceManager; +using Campofinale.Game.Factory.BuildingsBehaviour; +using static Campofinale.Resource.ResourceManager.FactoryBuildingTable; +using Newtonsoft.Json; +using System.Drawing; +using Campofinale.Game.Inventory; +using System.Numerics; + +namespace Campofinale.Game.Factory +{ + public class FactoryNode + { + public uint nodeId; + public FCNodeType nodeType; + public string templateId; + public Vector3f position = new(); + public Vector3f direction = new(); + public Vector3f worldPosition = new(); + + public Vector3f directionIn; + public Vector3f directionOut; + public string instKey = ""; + public bool deactive = false; + public int mapId; + public int sceneNumId; + public bool forcePowerOn = false; + public List components = new(); + //Conveyor only + public List points; + public bool powered = false; + public bool lastPowered = false; + public List connectedComps = new(); + public ulong guid; + public NodeBuildingBehaviour nodeBehaviour; + public class ConnectedComp + { + public ulong Key; + public ulong Value; + public ConnectedComp(ulong key, ulong value) + { + this.Key = key; + this.Value = value; + } + } + public void Update(FactoryChapter chapter) + { + LevelScene scen = GetLevelData(sceneNumId); + if (lastPowered != powered) + { + lastPowered = powered; + chapter.GetOwner().Send(new PacketScFactoryModifyChapterNodes(chapter.GetOwner(), chapter.chapterId, this)); + } + if (nodeBehaviour != null && !deactive) + { + nodeBehaviour.Update(chapter,this); + } + foreach (var comp in components.FindAll(c => c is FComponentPortManager)) + { + var portmanager = (FComponentPortManager)comp; + if (portmanager.customPos != FCComponentPos.PortOutManager) + { + UpdatePortManager(chapter, portmanager); + } + } + foreach (var comp in components.FindAll(c => c is FComponentPortManager)) + { + var portmanager = (FComponentPortManager)comp; + if (portmanager.customPos == FCComponentPos.PortOutManager) + { + UpdatePortManager(chapter, portmanager); + } + } + + } + public FactoryBuildingTable GetBuildingTable() + { + ResourceManager.factoryBuildingTable.TryGetValue(templateId, out FactoryBuildingTable table); + if (table == null) + { + table = new FactoryBuildingTable(); + } + return table; + } + public void UpdatePortManager(FactoryChapter chapter,FComponentPortManager manager) + { + if (ResourceManager.factoryBuildingTable.TryGetValue(templateId, out FactoryBuildingTable table)) + { + List ports = new(); + if (manager.customPos == FCComponentPos.PortOutManager) + { + ports = GetTransformedPorts(table.outputPorts); + List conveyors = chapter.nodes.FindAll(n => n.points != null); + foreach (var port in ports) + { + Vector3f front = port.GetFront(); + FactoryNode node = conveyors.Find(c => + c.nodeType == FCNodeType.BoxConveyor && + c.points.Any(p => p.x == front.x && p.y == front.y && p.z == front.z)); + var compPort = manager.ports.Find(p => p.index == port.index); + if (compPort != null) + { + if (node != null) + { + compPort.touchComId = node.GetComponent().compId; + } + else + { + compPort.touchComId = 0; + } + } + + } + //Output items + foreach (var port in manager.ports) + { + FComponentBoxConveyor output = chapter.GetCompById(port.touchComId); + FComponentCache outputCache = chapter.GetCompById(port.ownerComId); + FactoryNode conveyorNode = chapter.GetNodeByCompId(port.touchComId); + if (outputCache != null && output != null && conveyorNode != null) + { + bool did = false; + outputCache.items.ForEach(i => + { + if (!did && i.count > 0) + { + ItemCount add = new ItemCount() + { + id = i.id, + count = 1 + }; + + if (conveyorNode.AddConveyorItem(chapter,add)) + { + did = true; + outputCache.ConsumeItems(new List() { add }); + } + + } + }); + } + } + + } + else + { + ports = GetTransformedPorts(table.inputPorts); + List conveyors = chapter.nodes.FindAll(n => n.points != null); + foreach (var port in ports) + { + Vector3f back = port.GetBack(); + FactoryNode node = conveyors.Find(c => + c.nodeType == FCNodeType.BoxConveyor && + c.points.Any(p => p.x == back.x && p.y == back.y && p.z == back.z)); + var compPort = manager.ports.Find(p => p.index == port.index); + + if (compPort != null) + { + if (node != null) + { + compPort.touchComId = node.GetComponent().compId; + } + else + { + compPort.touchComId = 0; + } + } + + } + + //Input items + foreach (var port in manager.ports) + { + FComponentBoxConveyor input = chapter.GetCompById(port.touchComId); + FComponentCache inputCache = chapter.GetCompById(port.ownerComId); + FactoryNode conveyorNode = chapter.GetNodeByCompId(port.touchComId); + if (inputCache != null && input != null && conveyorNode != null) + { + bool did = false; + ItemCount toRemove = null; + foreach (var item in input.items) + { + if (!did && item.count > 0 && item.IsItemAtConveyorEnd(BlockCalculator.CalculateTotalBlocks(conveyorNode.points))) + { + + if (!inputCache.IsFull()) + { + did = true; + toRemove = item; + inputCache.AddItem(item.id, item.count); + break; + } + + } + } + if(toRemove!=null) + conveyorNode.RemoveConveyorItem(chapter,toRemove); + + } + } + } + } + + } + + private void RemoveConveyorItem(FactoryChapter chapter,ItemCount toRemove) + { + FComponentBoxConveyor conveyorComp = GetComponent(); + conveyorComp.items.Remove(toRemove); + chapter.GetOwner().Send(new PacketScFactoryHsSync(chapter.GetOwner(), chapter, new List() { this})); + } + + private bool AddConveyorItem(FactoryChapter chapter,ItemCount i) + { + float length=BlockCalculator.CalculateTotalBlocks(points); + FComponentBoxConveyor conveyorComp = GetComponent(); + if (conveyorComp != null) + { + if(conveyorComp.items.Count < (int)length) + { + long timestamp = i.tms - conveyorComp.lastPopTms; + if(timestamp >= 2000) + { + conveyorComp.items.Add(i); + i.tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(); + conveyorComp.lastPopTms = i.tms; + chapter.GetOwner().Send(new PacketScFactoryHsSync(chapter.GetOwner(), chapter, new List() { this })); + return true; + } + else + { + return false; + } + + + } + } + return false; + } + + public bool InPower() + { + if (forcePowerOn) + { + return true; + } + return lastPowered; + } + public FComponent GetComponent() where FComponent : class + { + return components.Find(c => c is FComponent) as FComponent; + } + public FComponent GetComponent(uint compid) where FComponent : class + { + return components.Find(c => c is FComponent && c.compId==compid) as FComponent; + } + public List GetTransformedPorts(List originalPorts) + { + List transformedPorts = new List(); + + if (originalPorts == null || originalPorts.Count == 0) + return transformedPorts; + + FMesh mesh = GetMesh(); + if (mesh.points.Count < 2) + return transformedPorts; + + Vector3f objectPosition = mesh.points[0]; + float objectRotationY = direction.y % 360f; + + FactoryBuildingTable table; + if (!ResourceManager.factoryBuildingTable.TryGetValue(templateId, out table)) + return transformedPorts; + + float width = table.range.width - 1; + float depth = table.range.depth - 1; + + foreach (FacPort originalPort in originalPorts) + { + FacPort transformedPort = new FacPort + { + index = originalPort.index, + isOutput = originalPort.isOutput, + isPipe = originalPort.isPipe, + trans = new FacPort.FacPortTrans() + }; + + Vector3f originalPos = originalPort.trans.position; + Vector3f transformedPos = objectPosition; + + switch ((int)objectRotationY) + { + case 0: + transformedPos += originalPos; + break; + + case 90: + transformedPos += new Vector3f(originalPos.z, originalPos.y, width - originalPos.x); + break; + + case 180: + transformedPos += new Vector3f(width - originalPos.x, originalPos.y, depth - originalPos.z); + break; + + case 270: + transformedPos += new Vector3f(depth - originalPos.z, originalPos.y, originalPos.x); + break; + } + + transformedPort.trans.position = transformedPos; + + transformedPort.trans.rotation = new Vector3f( + originalPort.trans.rotation.x, + (originalPort.trans.rotation.y + objectRotationY) % 360f, + originalPort.trans.rotation.z + ); + + transformedPorts.Add(transformedPort); + } + + return transformedPorts; + } + + public FMesh GetMesh() + { + FMesh mesh = new FMesh(); + if(points != null) + { + points.ForEach(p => + { + mesh.points.Add(p); + }); + mesh.type = FCMeshType.Line; + return mesh; + } + if (ResourceManager.factoryBuildingTable.TryGetValue(templateId, out FactoryBuildingTable table)) + { + float width = table.range.width - 1; + float height = table.range.height - 1; + float depth = table.range.depth - 1; + + Vector3f p1_final = new Vector3f(); + Vector3f p2_final = new Vector3f(); + + switch (direction.y) + { + case 0f: + case 360f: + default: + p1_final = position + new Vector3f(table.range.x, table.range.y, table.range.z); + p2_final = p1_final + new Vector3f(width, height, depth); + break; + + case 90f: + p1_final = position + new Vector3f(table.range.x, table.range.y, table.range.z - width); + p2_final = p1_final + new Vector3f(depth, height, width); + break; + + case 180f: + p1_final = position + new Vector3f(table.range.x - width, table.range.y, table.range.z - depth); + p2_final = p1_final + new Vector3f(width, height, depth); + break; + + case 270f: + p1_final = position + new Vector3f(table.range.x - depth, table.range.y, table.range.z); + p2_final = p1_final + new Vector3f(depth, height, width); + break; + } + + mesh.points.Add(p1_final); + mesh.points.Add(p2_final); + } + + return mesh; + } + + + public ScdFacNode ToProto() + { + ScdFacNode node = new ScdFacNode() + { + InstKey = instKey, + NodeId = nodeId, + TemplateId = templateId, + StableId = GetStableId(), + IsDeactive = deactive, + + Power = new() + { + InPower = InPower(), + NeedInPower = true, + PowerCost= GetBuildingTable().bandwidth, + PowerCostShow= GetBuildingTable().bandwidth, + }, + + NodeType = (int)nodeType, + Transform = new() + { + Position = position.ToProtoScd(), + Direction = direction.ToProtoScd(), + MapId = mapId, + + } + }; + + if (templateId != "__inventory__") + { + if(nodeType != FCNodeType.BoxConveyor) + { + node.Transform.Mesh = GetMesh().ToProto(); + node.Transform.Position = position.ToProtoScd(); + node.Transform.WorldPosition = worldPosition.ToProto(); + node.Transform.WorldRotation = direction.ToProto(); + node.InteractiveObject = new() + { + ObjectId = guid, + }; + node.Flag = 0; + node.InstKey = ""; + } + else + { + node.Transform.Mesh = GetMesh().ToProto(); + node.Transform.Position = position.ToProtoScd(); + node.Transform.WorldPosition = null; + node.Transform.WorldRotation = null; + node.InteractiveObject =null; + node.Transform.BcPortIn = new() + { + Direction = directionIn.ToProtoScd(), + Position = points[0].ToProtoScd() + }; + node.Transform.BcPortOut = new() + { + Direction = directionOut.ToProtoScd(), + Position = points[points.Count-1].ToProtoScd() + }; + node.Flag = 0; + node.InstKey = ""; + } + + } + + foreach (FComponent comp in components) + { + node.Components.Add(comp.ToProto()); + node.ComponentPos.Add((int)comp.GetComPos(), comp.compId); + } + + return node; + } + public uint GetStableId() + { + return 10000 + nodeId; + } + public FCComponentType GetMainCompType() + { + string nodeTypeName = nodeType.ToString(); + if (Enum.TryParse(nodeTypeName, out FCComponentType fromName)) + { + return fromName; + } + return FCComponentType.Invalid; + } + public void InitComponents(FactoryChapter chapter) + { + switch (nodeType) + { + case FCNodeType.PowerPole: + components.Add(new FComponentPowerPole(chapter.nextCompV()).Init()); + break; + case FCNodeType.PowerDiffuser: + components.Add(new FComponentPowerPole(chapter.nextCompV()).Init()); + break; + case FCNodeType.Battle: + components.Add(new FComponentBattle(chapter.nextCompV()).Init()); + break; + case FCNodeType.Producer: + if (templateId == "grinder_1") + { + nodeBehaviour = new NodeBuilding_Producer(); + }else if (templateId == "furnance_1") + { + nodeBehaviour = new NodeBuilding_ProducerFurnace(); + } + if(nodeBehaviour!=null) + nodeBehaviour.Init(chapter, this); + break; + case FCNodeType.BoxConveyor: + components.Add(new FComponentBoxConveyor(chapter.nextCompV()).Init()); + break; + case FCNodeType.TravelPole: + components.Add(new FComponentTravelPole(chapter.nextCompV()).Init()); + break; + case FCNodeType.Hub: + components.Add(new FComponentSelector(chapter.nextCompV()).Init()); + components.Add(new FComponentPowerPole(chapter.nextCompV()).Init()); + components.Add(new FComponentPowerSave(chapter.nextCompV()).Init()); + components.Add(new FComponentStablePower(chapter.nextCompV()).Init()); + components.Add(new FComponentBusLoader(chapter.nextCompV()).Init()); + components.Add(new FComponentPortManager(chapter.nextCompV(), GetComponent().compId).Init()); + forcePowerOn = true; + break; + case FCNodeType.SubHub: + components.Add(new FComponentSubHub(chapter.nextCompV()).Init()); + components.Add(new FComponentSelector(chapter.nextCompV()).Init()); + components.Add(new FComponentPowerPole(chapter.nextCompV()).Init()); + components.Add(new FComponentPowerSave(chapter.nextCompV()).Init()); + components.Add(new FComponentStablePower(chapter.nextCompV()).Init()); + components.Add(new FComponentBusLoader(chapter.nextCompV()).Init()); + components.Add(new FComponentPortManager(chapter.nextCompV(), GetComponent().compId).Init()); + forcePowerOn = true; + break; + default: + components.Add(new FComponent(chapter.nextCompV(), GetMainCompType()).Init()); + break; + } + + } + + public void SendEntity(Player player, string chapterId) + { + Entity exist = player.sceneManager.GetCurScene().entities.Find(e => e.guid == guid); + if (exist != null) + { + exist.Position = worldPosition; + exist.Rotation = direction; + ScMoveObjectMove move = new() + { + ServerNotify = true, + MoveInfo = + { + new MoveObjectMoveInfo() + { + Objid = guid, + SceneNumId=sceneNumId, + MotionInfo = new() + { + Position=exist.Position.ToProto(), + Rotation=exist.Rotation.ToProto(), + Speed=new Vector() + { + + }, + State=MotionState.MotionNone + } + } + } + }; + player.Send(ScMsgId.ScMoveObjectMove, move); + } + else + { + if (interactiveFacWrapperTable.ContainsKey(templateId)) + { + EntityInteractive e = new(interactiveFacWrapperTable[templateId].interactiveTemplateId, player.roleId, worldPosition, direction, sceneNumId, guid); + e.InitDefaultProperties(); + e.SetPropValue(nodeId, "factory_inst_id"); + + player.sceneManager.GetCurScene().entities.Add(e); + player.sceneManager.GetCurScene().SpawnEntity(e); + } + + } + + } + + + public class FMesh + { + public FCMeshType type; + public List points = new(); + public ScdFacMesh ToProto() + { + ScdFacMesh m = new ScdFacMesh() + { + MeshType = (int)type + }; + foreach (Vector3f p in points) + { + m.Points.Add(new ScdVec3Int() + { + X = (int)p.x, + Y = (int)p.y, + Z = (int)p.z + }); + } + return m; + } + } + } +} diff --git a/Campofinale/Game/Inventory/Item.cs b/Campofinale/Game/Inventory/Item.cs index a35230a..13afaa9 100644 --- a/Campofinale/Game/Inventory/Item.cs +++ b/Campofinale/Game/Inventory/Item.cs @@ -11,7 +11,6 @@ using static Campofinale.Resource.ResourceManager; using Google.Protobuf.Collections; using Campofinale.Packets.Sc; using Campofinale.Protocol; -using CsvHelper.Configuration.Attributes; namespace Campofinale.Game.Inventory { @@ -141,14 +140,15 @@ namespace Campofinale.Game.Inventory Inst = new() { InstId = guid, - + Equip = new() { - + EquipCharId = GetOwner().chars.Find(c => c.IsEquipped(guid)) != null ? GetOwner().chars.Find(c => c.IsEquipped(guid)).guid : 0, Equipid = guid, Templateid = ResourceManager.GetItemTemplateId(id), + }, IsLock = locked } @@ -241,6 +241,7 @@ namespace Campofinale.Game.Inventory }; GetOwner().Send(ScMsgId.ScWeaponAddExp, levelUp); + GetOwner().Send(new PacketScSyncWallet(GetOwner())); } } @@ -258,6 +259,10 @@ namespace Campofinale.Game.Inventory return false; case ItemValuableDepotType.MissionItem: return true; + case ItemValuableDepotType.Factory: + return false; + case ItemValuableDepotType.CommercialItem: + return false; default: return false; } diff --git a/Campofinale/Game/SceneManager.cs b/Campofinale/Game/SceneManager.cs index c000be1..b185c34 100644 --- a/Campofinale/Game/SceneManager.cs +++ b/Campofinale/Game/SceneManager.cs @@ -27,8 +27,18 @@ namespace Campofinale.Game } public void Update() { - if (GetCurScene()!=null) - GetCurScene().UpdateShowEntities(); + if (GetCurScene() != null) + { + try + { + GetCurScene().UpdateShowEntities(); + } + catch(Exception e) + { + + } + } + } public Entity GetEntity(ulong guid) { @@ -267,7 +277,7 @@ namespace Campofinale.Game public List activeScripts = new(); public List scripts = new(); - public int grade = 0; + public int grade = 1; public int GetCollection(string id) { @@ -311,6 +321,10 @@ namespace Campofinale.Game } public void Load() { + if (grade == 0) + { + grade = 1; + } Unload(); LevelScene lv_scene = ResourceManager.GetLevelData(sceneNumId); diff --git a/Campofinale/Packets/Cs/HandleCsCharPotentialUnlock.cs b/Campofinale/Packets/Cs/HandleCsCharPotentialUnlock.cs index 6ca8531..121ea0e 100644 --- a/Campofinale/Packets/Cs/HandleCsCharPotentialUnlock.cs +++ b/Campofinale/Packets/Cs/HandleCsCharPotentialUnlock.cs @@ -15,6 +15,7 @@ namespace Campofinale.Packets.Cs Character character = session.chars.Find(c => c.guid == req.CharObjId); if (character != null) { + character.potential=req.Level; //TODO consume Item ID diff --git a/Campofinale/Packets/Cs/HandleCsFactoryHsFb.cs b/Campofinale/Packets/Cs/HandleCsFactoryHsFb.cs index 853efe5..51a565d 100644 --- a/Campofinale/Packets/Cs/HandleCsFactoryHsFb.cs +++ b/Campofinale/Packets/Cs/HandleCsFactoryHsFb.cs @@ -1,4 +1,5 @@ -using Campofinale.Network; +using Campofinale.Game.Factory; +using Campofinale.Network; using Campofinale.Protocol; namespace Campofinale.Packets.Cs @@ -10,14 +11,33 @@ namespace Campofinale.Packets.Cs public static void Handle(Player session, CsMsgId cmdId, Packet packet) { CsFactoryHsFb req = packet.DecodeBody(); - long curtimestamp = DateTime.UtcNow.ToUnixTimestampMilliseconds(); + + List comps = new(); - ScFactoryHs hs = new() + foreach (var id in req.NodeIdList) { - - + FactoryNode node=session.factoryManager.GetChapter(req.ChapterId).nodes.Find(n=>n.nodeId == id); + if (node != null) + { + node.components.ForEach(c => + { + comps.Add(c.ToProto()); + }); + } + } + + long curtimestamp = DateTime.UtcNow.ToUnixTimestampMilliseconds(); + ScFactoryHsSync hs = new() + { + Tms = curtimestamp, + CcList = + { + comps, + }, + Blackboard = session.factoryManager.GetChapter(req.ChapterId).ToProto().Blackboard, + ChapterId=req.ChapterId, }; - session.Send(ScMsgId.ScFactoryHs, hs); + session.Send(ScMsgId.ScFactoryHsSync, hs,packet.csHead.UpSeqid); } diff --git a/Campofinale/Packets/Cs/HandleCsGachaTenPullReq.cs b/Campofinale/Packets/Cs/HandleCsGachaTenPullReq.cs index 407d1b5..41e7f26 100644 --- a/Campofinale/Packets/Cs/HandleCsGachaTenPullReq.cs +++ b/Campofinale/Packets/Cs/HandleCsGachaTenPullReq.cs @@ -19,107 +19,6 @@ namespace Campofinale.Packets.Cs CsGachaTenPullReq req = packet.DecodeBody(); session.gachaManager.upSeqId = packet.csHead.UpSeqid; session.gachaManager.DoGacha(req.GachaPoolId, 10); - /* Random rng = new Random(); - List chars = new List(); - const double prob6Star = 0.008; // 0.8% - const double prob5Star = 0.08; // 8% - const double fiftyfifty = 0.50; // 50% - GachaCharPoolTable table = ResourceManager.gachaCharPoolTable[req.GachaPoolId]; - GachaCharPoolContentTable content = ResourceManager.gachaCharPoolContentTable[req.GachaPoolId]; - int sixstarcount = 0; - int fivestarcount = 0; - List fiveStars = content.list.FindAll(c => c.starLevel == 5); - List sixStars = content.list.FindAll(c => c.starLevel == 6); - int fiveStarGuaranteedIndex = new Random().Next(9); - for (int i=0; i < 10; i++) - { - double roll = rng.NextDouble(); - double fifty = rng.NextDouble(); - - if (roll < prob6Star) - { - sixstarcount++; - - if (table.upCharIds.Count > 0) - { - if (fifty >= fiftyfifty) - { - chars.Add(ResourceManager.characterTable[table.upCharIds[0]].charId); - } - else - { - chars.Add(sixStars[new Random().Next(sixStars.Count - 1)].charId); - } - - } - else - { - chars.Add(sixStars[new Random().Next(sixStars.Count - 1)].charId); - } - } - else if (roll < prob6Star + prob5Star || fiveStarGuaranteedIndex == i) - { - fivestarcount++; - if(table.upCharIds.Count > 1) - { - if(fifty >= fiftyfifty) - { - chars.Add(ResourceManager.characterTable[table.upCharIds[1]].charId); - } - else - { - chars.Add(fiveStars[new Random().Next(fiveStars.Count - 1)].charId); - } - - } - else - { - chars.Add(fiveStars[new Random().Next(fiveStars.Count-1)].charId); - } - - } - else - { - chars.Add(ResourceManager.characterTable.Values.ToList().FindAll(c=>c.rarity == 4)[new Random().Next(ResourceManager.characterTable.Values.ToList().FindAll(c => c.rarity == 4).Count - 1)].charId); - } - - } - ScGachaSyncPullResult result = new ScGachaSyncPullResult() - { - GachaPoolId=req.GachaPoolId, - GachaType=req.GachaType, - - OriResultIds = - { - }, - Star5GotCount= fivestarcount, - Star6GotCount= sixstarcount, - FinalResults = - { - - }, - UpGotCount= fivestarcount+ sixstarcount, - - }; - foreach(string ch in chars) - { - bool exist = session.chars.Find(c => c.id == ch) != null; - result.OriResultIds.Add(ch); - result.FinalResults.Add(new ScdGachaFinalResult() - { - IsNew= !exist, - ItemId=ch, - - }); - } - - - //session.Send(Packet.EncodePacket((int)CsMessageId.CsGachaTenPullReq, req)); - - session.Send(ScMessageId.ScGachaSyncPullResult, result); */ - // session.Send(CsMessageId.CsGachaEnd, new Empty()); - // session.Send(ScMessageId.ScGachaBegin, new Empty()); - } } diff --git a/Campofinale/Packets/Cs/HandleCsItemBagSetItemLock.cs b/Campofinale/Packets/Cs/HandleCsItemBagSetItemLock.cs new file mode 100644 index 0000000..8c33136 --- /dev/null +++ b/Campofinale/Packets/Cs/HandleCsItemBagSetItemLock.cs @@ -0,0 +1,34 @@ +using Campofinale.Game.Char; +using Campofinale.Game.Inventory; +using Campofinale.Network; +using Campofinale.Protocol; + +namespace Campofinale.Packets.Cs +{ + public class HandleCsItemBagSetItemLock + { + [Server.Handler(CsMsgId.CsItemBagSetItemLock)] + public static void Handle(Player session, CsMsgId cmdId, Packet packet) + { + CsItemBagSetItemLock req = packet.DecodeBody(); + + foreach (var info in req.LockInfoList) + { + Item item = session.inventoryManager.items.items.Find(i=>i.guid==info.InstId); + if (item != null) + { + item.locked = info.IsLock; + } + } + ScItemBagSetItemLock rsp = new() + { + LockInfoList = + { + req.LockInfoList, + } + }; + session.Send(ScMsgId.ScItemBagSetItemLock, rsp); + } + + } +} diff --git a/Campofinale/Packets/Cs/HandleCsLogin.cs b/Campofinale/Packets/Cs/HandleCsLogin.cs index 412ee09..db853ec 100644 --- a/Campofinale/Packets/Cs/HandleCsLogin.cs +++ b/Campofinale/Packets/Cs/HandleCsLogin.cs @@ -89,7 +89,8 @@ namespace Campofinale.Packets.Cs IsFirstLogin = false, IsReconnect=false, LastRecvUpSeqid = packet.csHead.UpSeqid, - + ServerTimeZone=2, + ServerTime=DateTime.UtcNow.ToUnixTimestampMilliseconds(), }; byte[] encKey = GenerateRandomBytes(32); string serverPublicKeyPem = req.ClientPublicKey.ToStringUtf8(); diff --git a/Campofinale/Packets/Cs/HandleCsMoveObjectMove.cs b/Campofinale/Packets/Cs/HandleCsMoveObjectMove.cs index dafe2a2..276a787 100644 --- a/Campofinale/Packets/Cs/HandleCsMoveObjectMove.cs +++ b/Campofinale/Packets/Cs/HandleCsMoveObjectMove.cs @@ -12,6 +12,7 @@ namespace Campofinale.Packets.Cs public static void Handle(Player session, CsMsgId cmdId, Packet packet) { CsMoveObjectMove req = packet.DecodeBody(); + if (session.sceneLoadState != Player.SceneLoadState.OK) return; foreach (var moveInfo in req.MoveInfo) { diff --git a/Campofinale/Packets/Cs/HandleCsPing.cs b/Campofinale/Packets/Cs/HandleCsPing.cs index f3cccf3..7fa8e39 100644 --- a/Campofinale/Packets/Cs/HandleCsPing.cs +++ b/Campofinale/Packets/Cs/HandleCsPing.cs @@ -17,25 +17,7 @@ namespace Campofinale.Packets.Cs ClientTs = req.ClientTs, ServerTs = (ulong)curtimestamp, })); - /*ScFactoryHsSync s = new() - { - Blackboard = new() - { - InventoryNodeId = 0, - Power = new() - { - - } - }, - CcList = - { - - }, - Tms = curtimestamp / 1000, - ChapterId = session.GetCurrentChapter() - }; - - session.Send(ScMessageId.ScFactoryHsSync,s);*/ + session.factoryManager.SendFactoryHsSync(); //Logger.Print("Server: " + curtimestamp + " client: " + req.ClientTs); } diff --git a/Campofinale/Packets/Cs/HandleCsSceneRepatriate.cs b/Campofinale/Packets/Cs/HandleCsSceneRepatriate.cs index 75b40ad..d6e2917 100644 --- a/Campofinale/Packets/Cs/HandleCsSceneRepatriate.cs +++ b/Campofinale/Packets/Cs/HandleCsSceneRepatriate.cs @@ -1,5 +1,7 @@ using Campofinale.Network; +using Campofinale.Packets.Sc; using Campofinale.Protocol; +using Campofinale.Resource; namespace Campofinale.Packets.Cs { @@ -30,6 +32,7 @@ namespace Campofinale.Packets.Cs } // Not correctly fixed, need to find the issue - SuikoAkari // No idea how pass_through_data is used, it's not part of the packet sent by the official server + session.Send(new PacketScSelfSceneInfo(session, SelfInfoReasonType.SlrReviveRest)); session.Send(ScMsgId.ScSceneRepatriate, new ScSceneRepatriate() { SceneNumId = session.savedSaveZone.sceneNumId, diff --git a/Campofinale/Packets/Cs/HandleCsSceneRest.cs b/Campofinale/Packets/Cs/HandleCsSceneRest.cs new file mode 100644 index 0000000..00649a8 --- /dev/null +++ b/Campofinale/Packets/Cs/HandleCsSceneRest.cs @@ -0,0 +1,28 @@ +using Campofinale.Network; +using Campofinale.Packets.Sc; +using Campofinale.Protocol; +using Campofinale.Resource; + +namespace Campofinale.Packets.Cs +{ + public class HandleCsSceneRest + { + + [Server.Handler(CsMsgId.CsSceneRest)] + public static void Handle(Player session, CsMsgId cmdId, Packet packet) + { + CsSceneRest req = packet.DecodeBody(); + if (session.sceneLoadState == Player.SceneLoadState.Loading) return; + ScSceneRevival revival = new() + { + + }; + session.RestTeam(); + session.sceneManager.LoadCurrentTeamEntities(); + session.Send(ScMsgId.ScSceneRevival, revival, packet.csHead.UpSeqid); + session.Send(new PacketScSelfSceneInfo(session, SelfInfoReasonType.SlrReviveRest)); + + } + + } +} diff --git a/Campofinale/Packets/Cs/HandleCsSceneTeleport.cs b/Campofinale/Packets/Cs/HandleCsSceneTeleport.cs index b4c77b6..6a85ee1 100644 --- a/Campofinale/Packets/Cs/HandleCsSceneTeleport.cs +++ b/Campofinale/Packets/Cs/HandleCsSceneTeleport.cs @@ -1,6 +1,7 @@ using Campofinale.Network; using Campofinale.Protocol; using Campofinale.Utils; +using static Campofinale.Resource.ResourceManager; namespace Campofinale.Packets.Cs { @@ -15,7 +16,7 @@ namespace Campofinale.Packets.Cs if (session.curSceneNumId != req.SceneNumId) { session.EnterScene(req.SceneNumId, new Resource.ResourceManager.Vector3f(req.Position), new Resource.ResourceManager.Vector3f(req.Rotation)); - /* ScSceneTeleport t = new() + ScSceneTeleport t = new() { TeleportReason = req.TeleportReason, PassThroughData = req.PassThroughData, @@ -23,7 +24,7 @@ namespace Campofinale.Packets.Cs Rotation = req.Rotation, SceneNumId = req.SceneNumId, }; - session.Send(ScMsgId.ScSceneTeleport, t);*/ + session.Send(ScMsgId.ScSceneTeleport, t); } else { @@ -41,6 +42,9 @@ namespace Campofinale.Packets.Cs TpUuid= (ulong)id }; session.curSceneNumId = t.SceneNumId; + session.position = new Vector3f(req.Position); + session.rotation = new Vector3f(req.Rotation); + session.sceneLoadState = Player.SceneLoadState.Loading; session.Send(ScMsgId.ScSceneTeleport, t); } diff --git a/Campofinale/Packets/Cs/HandleCsSceneTeleportFinish.cs b/Campofinale/Packets/Cs/HandleCsSceneTeleportFinish.cs new file mode 100644 index 0000000..110a647 --- /dev/null +++ b/Campofinale/Packets/Cs/HandleCsSceneTeleportFinish.cs @@ -0,0 +1,19 @@ +using Campofinale.Network; +using Campofinale.Protocol; +using Campofinale.Utils; +using static Campofinale.Resource.ResourceManager; + +namespace Campofinale.Packets.Cs +{ + public class HandleCsSceneTeleportFinish + { + + [Server.Handler(CsMsgId.CsSceneTeleportFinish)] + public static void Handle(Player session, CsMsgId cmdId, Packet packet) + { + CsSceneTeleportFinish req = packet.DecodeBody(); + session.sceneLoadState=Player.SceneLoadState.OK; + } + + } +} diff --git a/Campofinale/Packets/Sc/PacketScFactoryHsSync.cs b/Campofinale/Packets/Sc/PacketScFactoryHsSync.cs new file mode 100644 index 0000000..3d4286d --- /dev/null +++ b/Campofinale/Packets/Sc/PacketScFactoryHsSync.cs @@ -0,0 +1,31 @@ +using Campofinale.Game.Factory; +using Campofinale.Network; +using Campofinale.Protocol; +using System.Numerics; + +namespace Campofinale.Packets.Sc +{ + public class PacketScFactoryHsSync : Packet + { + + public PacketScFactoryHsSync(Player client, FactoryChapter chapter, List nodes) { + + long curtimestamp = DateTime.UtcNow.ToUnixTimestampMilliseconds(); + ScFactoryHsSync hs = new() + { + Tms = curtimestamp, + Blackboard = chapter.blackboard.ToProto(), + ChapterId = chapter.chapterId, + }; + nodes.ForEach(node => + { + node.components.ForEach(c => + { + hs.CcList.Add(c.ToProto()); + }); + }); + SetData(ScMsgId.ScFactoryHsSync, hs); + } + + } +} diff --git a/Campofinale/Packets/Sc/PacketScFactoryModifyChapterNodes.cs b/Campofinale/Packets/Sc/PacketScFactoryModifyChapterNodes.cs index d34a9d9..85a3409 100644 --- a/Campofinale/Packets/Sc/PacketScFactoryModifyChapterNodes.cs +++ b/Campofinale/Packets/Sc/PacketScFactoryModifyChapterNodes.cs @@ -11,7 +11,7 @@ namespace Campofinale.Packets.Sc ScFactoryModifyChapterNodes edit = new() { ChapterId = chapterId, - Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds()/1000, + Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(), Nodes = { node.ToProto() @@ -24,7 +24,7 @@ namespace Campofinale.Packets.Sc ScFactoryModifyChapterNodes edit = new() { ChapterId = chapterId, - Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds() / 1000, + Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(), RemoveNodes = { nodeId diff --git a/Campofinale/Packets/Sc/PacketScFactoryOpRet.cs b/Campofinale/Packets/Sc/PacketScFactoryOpRet.cs index 0dcb19c..d406b6f 100644 --- a/Campofinale/Packets/Sc/PacketScFactoryOpRet.cs +++ b/Campofinale/Packets/Sc/PacketScFactoryOpRet.cs @@ -42,6 +42,20 @@ namespace Campofinale.Packets.Sc }; } + if (op.OpType == FactoryOpType.DismantleBoxConveyor) + { + proto.DismantleBoxConveyor = new() + { + + }; + } + if (op.OpType == FactoryOpType.ChangeProducerMode) + { + proto.ChangeProducerMode = new() + { + + }; + } if (op.OpType == FactoryOpType.SetTravelPoleDefaultNext) { proto.SetTravelPoleDefaultNext = new() @@ -49,9 +63,50 @@ namespace Campofinale.Packets.Sc }; } + if (op.OpType == FactoryOpType.EnableNode) + { + proto.EnableNode = new() + { + + }; + } + + if (op.OpType == FactoryOpType.MoveItemBagToCache) + { + proto.MoveItemBagToCache = new() + { + + }; + } + if(op.OpType == FactoryOpType.MoveItemCacheToBag) + { + proto.MoveItemCacheToBag = new(); + } proto.Index=op.Index; SetData(ScMsgId.ScFactoryOpRet, proto); } + public PacketScFactoryOpRet(Player client, List val, CsFactoryOp op) + { + ScFactoryOpRet proto = new ScFactoryOpRet() + { + RetCode = FactoryOpRetCode.Ok, + OpType = op.OpType, + + }; + + if (op.OpType == FactoryOpType.PlaceConveyor) + { + proto.PlaceConveyor = new() + { + NodeId = + { + val + } + }; + } + proto.Index = op.Index; + SetData(ScMsgId.ScFactoryOpRet, proto); + } } } diff --git a/Campofinale/Packets/Sc/PacketScSelfSceneInfo.cs b/Campofinale/Packets/Sc/PacketScSelfSceneInfo.cs index fbb5069..f54189c 100644 --- a/Campofinale/Packets/Sc/PacketScSelfSceneInfo.cs +++ b/Campofinale/Packets/Sc/PacketScSelfSceneInfo.cs @@ -22,7 +22,7 @@ namespace Campofinale.Packets.Sc TeamType = CharBagTeamType.Main }, - SceneGrade = 4, + SceneGrade = session.sceneManager.GetCurScene().grade, Detail = new() { diff --git a/Campofinale/Player.cs b/Campofinale/Player.cs index ebce970..e85cf9b 100644 --- a/Campofinale/Player.cs +++ b/Campofinale/Player.cs @@ -312,24 +312,6 @@ namespace Campofinale teams.Add(new Team()); teams.Add(new Team()); bitsetManager.Load(new Dictionary>()); - /*mails.Add(new Mail() - { - expireTime=DateTime.UtcNow.AddDays(30).Ticks, - sendTime=DateTime.UtcNow.Ticks, - claimed=false, - guid=random.Next(), - owner=roleId, - isRead=false, - content=new Mail_Content() - { - content= "Welcome to Campofinale, Join our Discord for help: https://discord.gg/5uJGJJEFHa", - senderName="SuikoAkari", - title="Welcome", - templateId="", - } - - });*/ - spaceshipManager.Load(); } @@ -348,8 +330,6 @@ namespace Campofinale } else { - //sceneManager.UnloadCurrent(false); - //sceneManager.LoadCurrent(); sceneLoadState = SceneLoadState.Loading; Send(new PacketScEnterSceneNotify(this, curSceneNumId)); } @@ -370,7 +350,6 @@ namespace Campofinale } public SceneLoadState sceneLoadState=0; - // public bool LoadFinish = true; public void EnterScene(int sceneNumId, Vector3f pos, Vector3f rot, PassThroughData passThroughData = null) { // if (!LoadFinish) return; @@ -573,15 +552,10 @@ namespace Campofinale { } - - - - Disconnect(); } public void Kick(CODE code, string optionalMsg="") { - Send(ScMsgId.ScNtfErrorCode, new ScNtfErrorCode() { Details = optionalMsg, @@ -606,8 +580,6 @@ namespace Campofinale Logger.Print($"{nickname} Disconnected"); socket.Disconnect(false); } - - } public void Save() { @@ -759,5 +731,24 @@ namespace Campofinale } } + + public void RestTeam() + { + GetCurTeam().ForEach(chara => + { + chara.curHp = chara.CalcAttributes()[AttributeType.MaxHp].val; + ScCharSyncStatus state = new ScCharSyncStatus() + { + Objid = chara.guid, + IsDead = chara.curHp < 1, + BattleInfo = new() + { + Hp = chara.curHp, + Ultimatesp = chara.ultimateSp + } + }; + Send(ScMsgId.ScCharSyncStatus, state); + }); + } } } diff --git a/Campofinale/Program.cs b/Campofinale/Program.cs index 78e50ad..00b5597 100644 --- a/Campofinale/Program.cs +++ b/Campofinale/Program.cs @@ -13,7 +13,7 @@ class Program static void Main(string[] args) { StartServer(args); - //FakeClientTester(); + //FakeClientTester(); } public static byte[] ConcatenateByteArrays(byte[] array1, byte[] array2) { @@ -22,7 +22,7 @@ class Program private static void FakeClientTester() { // - string serverIp = "beyond-cn.hypergryph.com"; + string serverIp = "beyond-ric.gryphline.com"; int serverPort = 30000; Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); @@ -32,7 +32,8 @@ class Program socket.Connect(new IPEndPoint(ipAddress, serverPort)); - socket.Send(Packet.EncodePacket((int)CsMsgId.CsLogin,new CsLogin() { ClientVersion="0.5.5",Uid= "", Token= "", Env=EnvType.Prod,PlatformId=ClientPlatformType.Windows,Area=AreaType.Oversea,ClientResVersion="", LoginToken= "" }.ToByteArray())); + socket.Send(Packet.EncodePacket((int)CsMsgId.CsLogin,new CsLogin() { ClientVersion="0.5.5",Uid= "", Token= "", Env=EnvType.Prod,PlatformId=ClientPlatformType.Windows,Area=AreaType.Oversea,ClientResVersion="", LoginToken= "" }.ToByteArray())); + //socket.Send(Packet.EncodePacket((int)CsMsgId.CsFriendListSync, new CsFriendListSync() { }.ToByteArray())); while (true) { byte[] buffer = new byte[3]; diff --git a/Campofinale/Resource/ResourceManager.cs b/Campofinale/Resource/ResourceManager.cs index 37d0b90..44ae964 100644 --- a/Campofinale/Resource/ResourceManager.cs +++ b/Campofinale/Resource/ResourceManager.cs @@ -69,6 +69,7 @@ namespace Campofinale.Resource public static DialogIdTable dialogIdTable = new();// public static Dictionary levelShortIdTable = new(); public static Dictionary factoryBuildingTable = new(); + public static Dictionary factoryMachineCraftTable = new(); public static Dictionary facSTTNodeTable = new(); public static Dictionary facSTTLayerTable = new(); public static Dictionary itemTypeTable = new(); // @@ -339,12 +340,63 @@ namespace Campofinale.Resource { return strIdNumTable.item_id.dic[item_id]; } + + public static string FindFactoryMachineCraftIdUsingCacheItems(List items, string group) + { + // Estrae solo gli ID degli items in input e li ordina + var inputItemIds = items.Select(item => item.id).OrderBy(id => id).ToList(); + + foreach (var recipe in factoryMachineCraftTable.Values.ToList().FindAll(r=>r.formulaGroupId==group)) + { + // Raccoglie tutti gli ID degli ingredienti della ricetta + var recipeItemIds = new List(); + foreach (var ingr in recipe.ingredients) + { + recipeItemIds.AddRange(ingr.group.Select(item => item.id)); + } + + // Ordina gli ID degli ingredienti della ricetta + var sortedRecipeItemIds = recipeItemIds.OrderBy(id => id).ToList(); + + // Confronta le due liste di ID (ignorando le quantità) + if (inputItemIds.SequenceEqual(sortedRecipeItemIds)) + { + return recipe.id; // Trovata corrispondenza + } + } + + return ""; // Nessuna corrispondenza trovata + } + public class InteractiveData { public string id; public Dictionary propertyKeyToIdMap = new(); public List saveProperties = new(); } + public class ItemCount + { + public int count; + public string id = ""; + public long tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(); + + public ScdFactorySyncItem ToFactoryItemProto() + { + return new ScdFactorySyncItem() + { + Count = count, + Id = id, + Tms = tms + }; + } + public bool IsItemAtConveyorEnd(float conveyorSize) + { + long spawnTms = tms; + long endTms = spawnTms + (long)(2000 * conveyorSize); + long cur = DateTime.UtcNow.ToUnixTimestampMilliseconds(); + return cur > endTms; + } + } public class FactoryBuildingTable { public int bandwidth; @@ -354,15 +406,107 @@ namespace Campofinale.Resource public int powerConsume; public FacBuildingType type; public FBuildingRange range; + public List outputPorts = new(); + public List inputPorts = new(); + public class FacPort + { + public int index; + public int isOutput; + public bool isPipe; + public FacPortTrans trans = new(); + public Vector3f GetBack() + { + float angleY = trans.rotation.y % 360f; + + Vector3f offset; + + switch ((int)angleY) + { + default: + case 360: + case 0: + offset = new Vector3f(0, 0, -1); + break; + case 90: + offset = new Vector3f(-1, 0, 0); + break; + case 180: + offset = new Vector3f(0, 0, 1); + break; + case 270: + offset = new Vector3f(1, 0, 0); + break; + } + + return trans.position + offset; + } + public Vector3f GetFront() + { + float angleY = trans.rotation.y % 360f; + + Vector3f offset=new(); + + switch ((int)angleY) + { + default: + case 360: + case 0: + offset = new Vector3f(0, 0, 1); + break; + case 90: + offset = new Vector3f(1, 0, 0); + break; + case 180: + offset = new Vector3f(0, 0, -1); + break; + case 270: + offset = new Vector3f(-1, 0, 0); + break; + } + + return trans.position + offset; + } + + public class FacPortTrans + { + public Vector3f position=new(); + public Vector3f rotation = new(); + } + } public FCNodeType GetNodeType() { - string nodeTypeName = type.ToString(); - if (Enum.TryParse(nodeTypeName, out FCNodeType fromName)) + switch (type) { - return fromName; + case FacBuildingType.Battle: + return FCNodeType.Battle; + case FacBuildingType.Hub: + return FCNodeType.Hub; + case FacBuildingType.SubHub: + return FCNodeType.SubHub; + case FacBuildingType.MachineCrafter: + return FCNodeType.Producer; + case FacBuildingType.PowerPort: + return FCNodeType.PowerPort; + case FacBuildingType.PowerPole: + return FCNodeType.PowerPole; + case FacBuildingType.PowerDiffuser: + return FCNodeType.PowerDiffuser; + case FacBuildingType.TravelPole: + return FCNodeType.TravelPole; + case FacBuildingType.Medic: + return FCNodeType.HealTower; + case FacBuildingType.Unloader: + return FCNodeType.BusUnloader; + case FacBuildingType.Loader: + return FCNodeType.BusLoader; + case FacBuildingType.Miner: + return FCNodeType.Collector; + case FacBuildingType.Storager: + return FCNodeType.DepositBox; + default: + return FCNodeType.Invalid; } - return FCNodeType.Invalid; } public struct FBuildingRange { @@ -978,7 +1122,20 @@ namespace Campofinale.Resource public float x; public float y; public float z; - + + public override bool Equals(object obj) + { + if (obj is Vector3f v) + { + return x == v.x && y == v.y && z == v.z; + } + return false; + } + + public override int GetHashCode() + { + return HashCode.Combine(x, y, z); + } public Vector3f() { diff --git a/Campofinale/Resource/Table/FactoryMachineCraftTable.cs b/Campofinale/Resource/Table/FactoryMachineCraftTable.cs new file mode 100644 index 0000000..880d691 --- /dev/null +++ b/Campofinale/Resource/Table/FactoryMachineCraftTable.cs @@ -0,0 +1,53 @@ +using Campofinale.Game.Factory.Components; +using static Campofinale.Resource.ResourceManager; + +namespace Campofinale.Resource.Table +{ + [TableCfgType("TableCfg/FactoryMachineCraftTable.json", LoadPriority.LOW)] + public class FactoryMachineCraftTable + { + public string id; + public string machineId; + public int progressRound; + public long totalProgress; + public int signal; + public string formulaGroupId; + public List ingredients = new(); + public List outcomes = new(); + + public bool CacheHaveItems(FComponentCache inCache) + { + bool enough = true; + ingredients.ForEach(i => + { + i.group.ForEach(item => + { + if(inCache.GetItemCount(item.id) < item.count) + { + enough = false; + + } + }); + }); + return enough; + } + + internal List GetIngredients() + { + List items = new(); + ingredients.ForEach(i => + { + i.group.ForEach(item => + { + items.Add(item); + }); + }); + return items; + } + + public class FactoryMachineCraftIngredient + { + public List group = new(); + } + } +} diff --git a/Campofinale/Server.cs b/Campofinale/Server.cs index 4f2b587..2963a4b 100644 --- a/Campofinale/Server.cs +++ b/Campofinale/Server.cs @@ -59,7 +59,7 @@ namespace Campofinale public delegate void HandlerDelegate(Player sender, string command, string[] args, Player target); } public static List clients = new List(); - public static string ServerVersion = "1.1.6"; + public static string ServerVersion = "1.1.7"; public static bool Initialized = false; public static bool showLogs = true; public static bool showWarningLogs = true; @@ -67,7 +67,7 @@ namespace Campofinale public static Dispatch? dispatch; public static ConfigFile? config; public static List csMessageToHide = new() { CsMsgId.CsMoveObjectMove, CsMsgId.CsBattleOp,CsMsgId.CsPing }; - public static List scMessageToHide = new() { ScMsgId.ScMoveObjectMove, ScMsgId.ScPing,ScMsgId.ScObjectEnterView }; + public static List scMessageToHide = new() { ScMsgId.ScMoveObjectMove, ScMsgId.ScPing,ScMsgId.ScObjectEnterView,ScMsgId.ScFactoryHsSync }; public void Start(ConfigFile config) { { @@ -152,7 +152,7 @@ namespace Campofinale try { clients.ForEach(client => { if (client != null) client.Update(); }); - Thread.Sleep(1000); + Thread.Sleep(250); } catch (Exception ex) { diff --git a/Dotfuscator1.xml b/Dotfuscator1.xml deleted file mode 100644 index 44bfed3..0000000 --- a/Dotfuscator1.xml +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file