diff --git a/Campofinale/Database/Database.cs b/Campofinale/Database/Database.cs index d174064..7f5009a 100644 --- a/Campofinale/Database/Database.cs +++ b/Campofinale/Database/Database.cs @@ -11,6 +11,7 @@ using MongoDB.Driver; using System.Security.Cryptography; using System.Text; using static Campofinale.Game.Adventure.AdventureBookManager; +using static Campofinale.Game.Factory.FactoryManager; using static Campofinale.Resource.ResourceManager; namespace Campofinale.Database @@ -103,7 +104,10 @@ namespace Campofinale.Database { return _database.GetCollection("spaceship_rooms").Find(c => c.owner == roleId).ToList(); } - + public FactoryData LoadFactoryData(ulong roleId) + { + return _database.GetCollection("factory").Find(c => c.roleId == roleId).ToList().FirstOrDefault(); + } public List LoadInventoryItems(ulong roleId) { return _database.GetCollection("items").Find(c => c.owner == roleId).ToList(); @@ -319,6 +323,22 @@ namespace Campofinale.Database new ReplaceOptions { IsUpsert = true } ); } + public void UpsertFactoryData(FactoryData item) + { + if (item._id == ObjectId.Empty) + { + item._id = ObjectId.GenerateNewId(); + } + var collection = _database.GetCollection("factory"); + var filter = + Builders.Filter.Eq(c => c.roleId, item.roleId); + + var result = collection.ReplaceOne( + filter, + item, + new ReplaceOptions { IsUpsert = true } + ); + } public void UpsertItem(Item item) { if (item._id == ObjectId.Empty) @@ -427,6 +447,6 @@ namespace Campofinale.Database } } - + } } diff --git a/Campofinale/Game/Entities/EntityInteractive.cs b/Campofinale/Game/Entities/EntityInteractive.cs index 9034815..2a633d8 100644 --- a/Campofinale/Game/Entities/EntityInteractive.cs +++ b/Campofinale/Game/Entities/EntityInteractive.cs @@ -33,9 +33,25 @@ namespace Campofinale.Game.Entities this.BornRot = rot; this.templateId = templateId; this.sceneNumId = scene; + } - + public void InitDefaultProperties() + { + InteractiveData data = ResourceManager.interactiveData.Find(i => i.id == templateId); + if (data != null) + { + properties.AddRange(data.saveProperties); + } + } + public void SetPropValue(uint val, string key) + { + ParamKeyValue keyValue = properties.Find(p => p.key == key); + if (keyValue != null) + { + keyValue.value.valueArray[0].valueBit64 = val; + } + } public SceneInteractive ToProto() { @@ -105,15 +121,17 @@ namespace Campofinale.Game.Entities { string oriTemplateId = ResourceManager.interactiveTable.interactiveDataDict[templateId].templateId; InteractiveData data=ResourceManager.interactiveData.Find(i=>i.id == oriTemplateId); + if(data != null) { return (true,data.propertyKeyToIdMap[key]); } + Logger.PrintError("Interactive Data not found"); return (false, maxCur + 1); } catch (Exception ex) { - //Logger.PrintError(ex.Message); + Logger.PrintError(ex.Message); return (false,maxCur+1); } diff --git a/Campofinale/Game/Entities/EntityMonster.cs b/Campofinale/Game/Entities/EntityMonster.cs index 08cdc94..7917dcb 100644 --- a/Campofinale/Game/Entities/EntityMonster.cs +++ b/Campofinale/Game/Entities/EntityMonster.cs @@ -43,7 +43,11 @@ namespace Campofinale.Game.Entities { List attrInfo = new(); EnemyTable table = ResourceManager.enemyTable[templateId]; - enemyAttributeTemplateTable[table.attrTemplateId].levelDependentAttributes[level].attrs.ForEach(attr => + if(level >= enemyAttributeTemplateTable[table.attrTemplateId].levelDependentAttributes.Count) + { + level = 80; + } + enemyAttributeTemplateTable[table.attrTemplateId].levelDependentAttributes[level-1].attrs.ForEach(attr => { attrInfo.Add(new AttrInfo() { diff --git a/Campofinale/Game/Factory/Components/FComponentTravelPole.cs b/Campofinale/Game/Factory/Components/FComponentTravelPole.cs index cda4e62..d3f1931 100644 --- a/Campofinale/Game/Factory/Components/FComponentTravelPole.cs +++ b/Campofinale/Game/Factory/Components/FComponentTravelPole.cs @@ -5,13 +5,17 @@ namespace Campofinale.Game.Factory.Components { public class FComponentTravelPole : FComponent { + public uint defaultNext; public FComponentTravelPole(uint id) : base(id, FCComponentType.TravelPole) { } public override void SetComponentInfo(ScdFacCom proto) { - proto.TravelPole = new(); + proto.TravelPole = new() + { + DefaultNext = defaultNext + }; } } } diff --git a/Campofinale/Game/Factory/FactoryManager.cs b/Campofinale/Game/Factory/FactoryManager.cs index 2367b33..d62ae5d 100644 --- a/Campofinale/Game/Factory/FactoryManager.cs +++ b/Campofinale/Game/Factory/FactoryManager.cs @@ -1,9 +1,15 @@ -using Campofinale.Game.Entities; +using Campofinale.Database; +using Campofinale.Game.Entities; using Campofinale.Game.Factory.Components; 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 @@ -12,18 +18,40 @@ namespace Campofinale.Game.Factory { public Player player; public List chapters = new(); - - + public ObjectId _id; + public class FactoryData + { + public ulong roleId; + public ObjectId _id; + public List chapters = new(); + } public FactoryManager(Player player) { - this.player = player; } public void Load() { - //TODO Save - chapters.Add(new FactoryChapter("domain_1", player.roleId)); - chapters.Add(new FactoryChapter("domain_2", player.roleId)); + FactoryData data = DatabaseManager.db.LoadFactoryData(player.roleId); + if (data != null) + { + _id=data._id; + chapters = data.chapters; + } + if(!ChapterExist("domain_1")) chapters.Add(new FactoryChapter("domain_1", player.roleId)); + if(!ChapterExist("domain_2")) chapters.Add(new FactoryChapter("domain_2", player.roleId)); + } + public bool ChapterExist(string id) + { + return chapters.Find(c=>c.chapterId==id)!=null; + } + public void Save() + { + DatabaseManager.db.UpsertFactoryData(new FactoryData() + { + _id= _id, + roleId=player.roleId, + chapters=chapters + }); } public void ExecOp(CsFactoryOp op, ulong seq) { @@ -62,11 +90,180 @@ namespace Campofinale.Game.Factory 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); @@ -89,51 +286,242 @@ namespace Campofinale.Game.Factory switch (op.OpType) { case FactoryOpType.Place: - CreateNode(op.Place, seq); + 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; } - private void CreateNode(CsdFactoryOpPlace place, ulong seq) + 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), - guid = GetOwner().random.NextRand() + worldPosition = new Vector3f(place.InteractiveParam.Position), + guid = GetOwner().random.NextRand(), + }; node.InitComponents(this); + GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, node)); nodes.Add(node); - ScFactoryModifyChapterNodes edit = new() - { - ChapterId = chapterId, - Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(), - - }; - GetOwner().Send(new PacketScFactorySyncChapter(GetOwner(), chapterId)); - edit.Nodes.Add(node.ToProto()); - Logger.Print(Newtonsoft.Json.JsonConvert.SerializeObject(edit, Newtonsoft.Json.Formatting.Indented)); - EntityInteractive e = new(place.TemplateId, GetOwner().roleId, new Vector3f(place.Position), new Vector3f(place.Direction), GetOwner().sceneManager.GetCurScene().sceneNumId, node.guid); - GetOwner().sceneManager.GetCurScene().entities.Add(e); - GetOwner().sceneManager.GetCurScene().SpawnEntity(e); - GetOwner().Send(ScMsgId.ScFactoryModifyChapterNodes, edit); - GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), node.nodeId,FactoryOpType.Place),seq); + node.SendEntity(GetOwner(), chapterId); + + GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), node.nodeId,op),seq); } @@ -165,46 +553,39 @@ namespace Campofinale.Game.Factory 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 uint connectedPowerNode = 0; + 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) { - if(!templateId.Contains("hub")) - if (GetComponent() != null) + LevelScene scen = GetLevelData(sceneNumId); + if (lastPowered != powered) { - FactoryNode curEnergyNode = chapter.nodes.Find(n => n.nodeId == connectedPowerNode && n.position.Distance(position) <= 20 && n.InPower()); - if (templateId != "power_pole_2") - { - FactoryNode energyNode = chapter.GetNodesInRange(position, 20).Find(n=>n.GetComponent< FComponentPowerPole>()!=null && n.InPower()); - if (energyNode != null && curEnergyNode==null && energyNode.connectedPowerNode!=nodeId) - { - powered= true; - connectedPowerNode = energyNode.nodeId; - chapter.GetOwner().Send(ScMsgId.ScFactoryModifyChapterNodes, new ScFactoryModifyChapterNodes() { Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(), Nodes = { this.ToProto()} }); - } - else - { - if (curEnergyNode == null && powered==true) - { - powered = false; - connectedPowerNode = 0; - chapter.GetOwner().Send(ScMsgId.ScFactoryModifyChapterNodes, new ScFactoryModifyChapterNodes() { Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(), Nodes = { this.ToProto() } }); - } - } - } - else - { - //Check near - } + lastPowered = powered; + chapter.GetOwner().Send(new PacketScFactoryModifyChapterNodes(chapter.GetOwner(), chapter.chapterId, this)); } + } public bool InPower() { @@ -222,41 +603,54 @@ namespace Campofinale.Game.Factory { FMesh mesh = new FMesh(); - if (ResourceManager.factoryBuildingTable.ContainsKey(templateId)) + if (ResourceManager.factoryBuildingTable.TryGetValue(templateId, out FactoryBuildingTable table)) { - FactoryBuildingTable table = ResourceManager.factoryBuildingTable[templateId]; + float width = table.range.width - 1; + float height = table.range.height - 1; + float depth = table.range.depth-1; - double centerX = position.x + table.range.width / 2.0; - double centerZ = position.z + table.range.depth / 2.0; + Vector3f p1_final = new Vector3f(); + Vector3f p2_final = new Vector3f(); - Vector3f p1 = new Vector3f(position.x, position.y, position.z); - Vector3f p2 = new Vector3f( - position.x + table.range.width, - position.y + table.range.height, - position.z + table.range.depth - ); + 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; - p1 = RotateAroundY(p1, new Vector3f((float)centerX, position.y, (float)centerZ), direction.y); - p2 = RotateAroundY(p2, new Vector3f((float)centerX, position.y, (float)centerZ), direction.y); - mesh.points.Add(p1); - mesh.points.Add(p2); + 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; } - private Vector3f RotateAroundY(Vector3f point, Vector3f origin, double angleDegrees) - { - double angleRadians = angleDegrees * (Math.PI / 180.0); - double cosTheta = Math.Cos(angleRadians); - double sinTheta = Math.Sin(angleRadians); - double dx = point.x - origin.x; - double dz = point.z - origin.z; - double rotatedX = origin.x + (dx * cosTheta - dz * sinTheta); - double rotatedZ = origin.z + (dx * sinTheta + dz * cosTheta); - - return new Vector3f((float)rotatedX, point.y, (float)rotatedZ); - } public ScdFacNode ToProto() { ScdFacNode node = new ScdFacNode() @@ -270,7 +664,7 @@ namespace Campofinale.Game.Factory Power = new() { InPower= InPower(), - NeedInPower=false, + NeedInPower=true, }, NodeType=(int)nodeType, @@ -286,7 +680,8 @@ namespace Campofinale.Game.Factory if(templateId!="__inventory__") { node.Transform.Mesh = GetMesh().ToProto(); - node.Transform.WorldPosition = position.ToProto(); + node.Transform.Position = position.ToProtoScd(); + node.Transform.WorldPosition = worldPosition.ToProto(); node.Transform.WorldRotation = direction.ToProto(); node.InteractiveObject = new() { @@ -354,6 +749,50 @@ namespace Campofinale.Game.Factory } } + + 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))] diff --git a/Campofinale/Game/SceneManager.cs b/Campofinale/Game/SceneManager.cs index 33f2deb..c000be1 100644 --- a/Campofinale/Game/SceneManager.cs +++ b/Campofinale/Game/SceneManager.cs @@ -3,8 +3,10 @@ using Campofinale.Game.Inventory; using Campofinale.Packets.Sc; using Campofinale.Resource; using Campofinale.Resource.Dynamic; +using Campofinale.Resource.Table; using MongoDB.Bson.Serialization.Attributes; using System; +using System.Diagnostics; using System.Text.Json.Serialization; using static Campofinale.Resource.Dynamic.SpawnerConfig; using static Campofinale.Resource.ResourceManager; @@ -220,13 +222,18 @@ namespace Campofinale.Game { foreach (var level in ResourceManager.levelDatas) { - if(scenes.Find(s=>s.sceneNumId==level.idNum) == null) + int grade = 1; + if (ResourceManager.levelGradeTable.ContainsKey(level.id)) + { + grade = ResourceManager.levelGradeTable[level.id].grades.Last().grade; + } + if (scenes.Find(s=>s.sceneNumId==level.idNum) == null) scenes.Add(new Scene() { guid = (ulong)player.random.Next(), ownerId=player.roleId, sceneNumId=level.idNum, - + grade= grade }); } } @@ -260,6 +267,8 @@ namespace Campofinale.Game public List activeScripts = new(); public List scripts = new(); + public int grade = 0; + public int GetCollection(string id) { if (collections.ContainsKey(id)) @@ -304,7 +313,18 @@ namespace Campofinale.Game { Unload(); LevelScene lv_scene = ResourceManager.GetLevelData(sceneNumId); - + + LevelGradeInfo sceneGrade = null; + LevelGradeTable table = null; + ResourceManager.levelGradeTable.TryGetValue(lv_scene.id, out table); + if (table != null) + { + sceneGrade=table.grades.Find(g=>g.grade==grade); + } + if (sceneGrade == null) + { + sceneGrade = new(); + } lv_scene.levelData.interactives.ForEach(en => { if (GetOwner().noSpawnAnymore.Contains(en.levelLogicId) && sceneNumId != 87) @@ -342,7 +362,7 @@ namespace Campofinale.Game { if(GetOwner().noSpawnAnymore.Contains(en.levelLogicId) && sceneNumId != 87) return; - EntityMonster entity = new(en.entityDataIdKey,en.level,ownerId,en.position,en.rotation, sceneNumId, en.levelLogicId) + EntityMonster entity = new(en.entityDataIdKey,sceneGrade.monsterBaseLevel+ en.level,ownerId,en.position,en.rotation, sceneNumId, en.levelLogicId) { type=en.entityType, belongLevelScriptId=en.belongLevelScriptId, @@ -366,7 +386,16 @@ namespace Campofinale.Game entity.defaultHide = en.defaultHide; entities.Add(entity); }); - + GetOwner().factoryManager.chapters.ForEach(ch => + { + ch.nodes.ForEach(n => + { + if (n.sceneNumId == sceneNumId) + { + n.SendEntity(GetOwner(), ch.chapterId); + } + }); + }); UpdateShowEntities(); } diff --git a/Campofinale/Packets/Sc/PacketScFactoryModifyChapterNodes.cs b/Campofinale/Packets/Sc/PacketScFactoryModifyChapterNodes.cs new file mode 100644 index 0000000..d34a9d9 --- /dev/null +++ b/Campofinale/Packets/Sc/PacketScFactoryModifyChapterNodes.cs @@ -0,0 +1,37 @@ +using Campofinale.Game.Factory; +using Campofinale.Network; +using Campofinale.Protocol; + +namespace Campofinale.Packets.Sc +{ + public class PacketScFactoryModifyChapterNodes : Packet + { + + public PacketScFactoryModifyChapterNodes(Player client,string chapterId,FactoryNode node) { + ScFactoryModifyChapterNodes edit = new() + { + ChapterId = chapterId, + Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds()/1000, + Nodes = + { + node.ToProto() + } + }; + SetData(ScMsgId.ScFactoryModifyChapterNodes, edit); + } + public PacketScFactoryModifyChapterNodes(Player client, string chapterId, uint nodeId) + { + ScFactoryModifyChapterNodes edit = new() + { + ChapterId = chapterId, + Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds() / 1000, + RemoveNodes = + { + nodeId + } + }; + SetData(ScMsgId.ScFactoryModifyChapterNodes, edit); + } + + } +} diff --git a/Campofinale/Packets/Sc/PacketScFactoryOpRet.cs b/Campofinale/Packets/Sc/PacketScFactoryOpRet.cs index 9057871..0dcb19c 100644 --- a/Campofinale/Packets/Sc/PacketScFactoryOpRet.cs +++ b/Campofinale/Packets/Sc/PacketScFactoryOpRet.cs @@ -6,23 +6,50 @@ namespace Campofinale.Packets.Sc public class PacketScFactoryOpRet : Packet { - public PacketScFactoryOpRet(Player client, uint nodeId,FactoryOpType type) { + public PacketScFactoryOpRet(Player client, uint val,CsFactoryOp op) { ScFactoryOpRet proto = new ScFactoryOpRet() { RetCode=FactoryOpRetCode.Ok, - OpType=type, + OpType=op.OpType, }; - if(type == FactoryOpType.Place) + if(op.OpType == FactoryOpType.Place) { proto.Place = new() { - NodeId = nodeId + NodeId = val }; - proto.Index = "CHANNLE_BUILDING"; } - + if (op.OpType == FactoryOpType.MoveNode) + { + proto.MoveNode = new() + { + + }; + } + if (op.OpType == FactoryOpType.AddConnection) + { + proto.AddConnection = new() + { + Index = val, + }; + } + if (op.OpType == FactoryOpType.Dismantle) + { + proto.Dismantle = new() + { + + }; + } + if (op.OpType == FactoryOpType.SetTravelPoleDefaultNext) + { + proto.SetTravelPoleDefaultNext = new() + { + + }; + } + proto.Index=op.Index; SetData(ScMsgId.ScFactoryOpRet, proto); } diff --git a/Campofinale/Packets/Sc/PacketScFactorySyncChapter.cs b/Campofinale/Packets/Sc/PacketScFactorySyncChapter.cs index f154a82..eff592b 100644 --- a/Campofinale/Packets/Sc/PacketScFactorySyncChapter.cs +++ b/Campofinale/Packets/Sc/PacketScFactorySyncChapter.cs @@ -12,7 +12,7 @@ namespace Campofinale.Packets.Sc public PacketScFactorySyncChapter(Player client, string chapterId) { - string json = File.ReadAllText("ScFactorySyncChapter.json"); + /*string json = File.ReadAllText("ScFactorySyncChapter.json"); //ScFactorySyncChapter chapter = Newtonsoft.Json.JsonConvert.DeserializeObject(json); ScFactorySyncChapter chapter = new() @@ -61,7 +61,7 @@ namespace Campofinale.Packets.Sc } } - }*/ + } }, Blackboard = new() { @@ -119,7 +119,7 @@ namespace Campofinale.Packets.Sc { }, - });*/ + }); LevelGradeInfo sceneGrade = ResourceManager.levelGradeTable[levelGroup].grades[0]; chapter.Blackboard.Power.PowerGen += sceneGrade.bandwidth; chapter.Blackboard.Power.PowerSaveMax += sceneGrade.bandwidth; @@ -185,9 +185,9 @@ namespace Campofinale.Packets.Sc foreach(FactoryNode node in client.factoryManager.GetChapter(chapterId).nodes) { chapter.Nodes.Add(node.ToProto()); - } + }*/ //Logger.Print(Newtonsoft.Json.JsonConvert.SerializeObject(chapter,Newtonsoft.Json.Formatting.Indented)); - SetData(ScMsgId.ScFactorySyncChapter, chapter); + SetData(ScMsgId.ScFactorySyncChapter, client.factoryManager.GetChapter(chapterId).ToProto()); } } diff --git a/Campofinale/Player.cs b/Campofinale/Player.cs index b79b3be..ebce970 100644 --- a/Campofinale/Player.cs +++ b/Campofinale/Player.cs @@ -617,6 +617,7 @@ namespace Campofinale inventoryManager.Save(); spaceshipManager.Save(); adventureBookManager.Save(); + factoryManager.Save(); if(Server.config.serverOptions.missionsEnabled) missionSystem.Save(); SaveCharacters(); SaveMails(); diff --git a/Campofinale/Resource/ResourceManager.cs b/Campofinale/Resource/ResourceManager.cs index 739b6dc..37d0b90 100644 --- a/Campofinale/Resource/ResourceManager.cs +++ b/Campofinale/Resource/ResourceManager.cs @@ -5,6 +5,7 @@ using Newtonsoft.Json; using System.Numerics; using System; using static Campofinale.Resource.ResourceManager.LevelScene; +using static Campofinale.Resource.ResourceManager.LevelScene.LevelData; namespace Campofinale.Resource { @@ -73,6 +74,7 @@ namespace Campofinale.Resource public static Dictionary itemTypeTable = new(); // public static Dictionary snsChatTable = new();// public static Dictionary giftItemTable = new(); + public static Dictionary interactiveFacWrapperTable = new(); public static List missionDataTable = new(); public static InteractiveTable interactiveTable = new(); // @@ -225,6 +227,7 @@ namespace Campofinale.Resource foreach (string json in jsonFiles) { InteractiveData data = JsonConvert.DeserializeObject(ReadJsonFile(json)); + if (data != null) { interactiveData.Add(data); @@ -339,7 +342,8 @@ namespace Campofinale.Resource public class InteractiveData { public string id; - public Dictionary propertyKeyToIdMap; + public Dictionary propertyKeyToIdMap = new(); + public List saveProperties = new(); } public class FactoryBuildingTable { @@ -816,6 +820,10 @@ namespace Campofinale.Resource param.ValueIntList.Add(val.valueBit64); param.ValueType = (int)ParamValueType.Int; break; + case ParamRealType.UInt: + param.ValueIntList.Add(val.valueBit64); + param.ValueType = (int)ParamValueType.Int; + break; case ParamRealType.WaterVolumePtr: param.ValueIntList.Add(val.valueBit64); param.ValueType = (int)ParamValueType.Int; @@ -980,6 +988,10 @@ namespace Campofinale.Resource { return new Vector3f(v.x * scalar, v.y * scalar, v.z * scalar); } + public static Vector3f operator +(Vector3f v, Vector3f v2) + { + return new Vector3f(v.x + v2.x, v.y + v2.y, v.z + v2.z); + } public Vector3f(float x, float y, float z) { this.x = x; diff --git a/Campofinale/Resource/Table/InteractiveFacWrapperTable.cs b/Campofinale/Resource/Table/InteractiveFacWrapperTable.cs new file mode 100644 index 0000000..a4fcbd3 --- /dev/null +++ b/Campofinale/Resource/Table/InteractiveFacWrapperTable.cs @@ -0,0 +1,8 @@ +namespace Campofinale.Resource.Table +{ + [TableCfgType("TableCfg/InteractiveFacWrapperTable.json", LoadPriority.LOW)] + public class InteractiveFacWrapperTable + { + public string interactiveTemplateId; + } +}