Compare commits

...

100 Commits

Author SHA1 Message Date
Akari
9b7bc980fe
Merge pull request #3 from Campofinale/development
Some checks failed
Stable / build (Campofinale-${{github.ref_name}}-Linux, ubuntu-latest) (push) Has been cancelled
Stable / build (Campofinale-${{github.ref_name}}-Windows, windows-latest) (push) Has been cancelled
1.1.7 ready
2025-08-20 23:31:25 +02:00
翠紅 灯
68f93eb80d revert 2025-08-20 23:30:18 +02:00
翠紅 灯
c2ba13b5f7 1.1.8-dev start 2025-08-20 23:29:37 +02:00
翠紅 灯
b125394b79 1.1.7 ready 2025-08-20 23:28:08 +02:00
翠紅 灯
69d832d376 item bag set item lock 2025-08-20 22:39:06 +02:00
AlessandroCH
460bfe527c cleaning code 2025-08-09 19:00:11 +02:00
AlessandroCH
f210746859 improvements 2025-08-09 17:41:24 +02:00
AlessandroCH
96048df57c CsSceneRest fix, teleport improvements, cache max item amount now is 50 2025-08-08 23:05:37 +02:00
AlessandroCH
388a71df7f CsSceneRest 2025-08-08 19:06:50 +02:00
AlessandroCH
4abb9d0bb5 working conveyors and implemented furnace build 2025-08-08 18:00:09 +02:00
AlessandroCH
ff7332fdaf set to grade 1 if grade is 0 on scene load 2025-08-08 02:08:32 +02:00
AlessandroCH
c92afab33f scene grade send correctly on self scene info 2025-08-08 02:08:07 +02:00
AlessandroCH
eb63e350a7 default 1 scene grade 2025-08-08 02:06:19 +02:00
AlessandroCH
34a904442d many stuff 2025-08-08 02:04:38 +02:00
AlessandroCH
99a7aceee2 some factory components (not finished) 2025-08-07 01:45:49 +02:00
Akari
fe29f9c14c
Merge pull request #2 from Campofinale/development
Some checks failed
Stable / build (Campofinale-${{github.ref_name}}-Linux, ubuntu-latest) (push) Has been cancelled
Stable / build (Campofinale-${{github.ref_name}}-Windows, windows-latest) (push) Has been cancelled
1.1.6 Ready
2025-08-07 01:11:53 +02:00
AlessandroCH
f9af58687c 1.1.6 2025-08-07 01:06:39 +02:00
AlessandroCH
aa59766cfd factory manager now is working!! 2025-08-07 01:05:16 +02:00
AlessandroCH
fee2df2fd9 Sending ScSceneInteractiveEventTrigger to prevent issues on mobile cbt 2025-08-03 15:07:11 +02:00
AlessandroCH
3df44653ae some changes 2025-08-01 22:03:24 +02:00
AlessandroCH
3d99dc303b some changes 2025-07-30 19:40:11 +02:00
AlessandroCH
0f2a3dade4 bug fix 2025-07-27 15:58:32 +02:00
AlessandroCH
fb63df9eb2 de-hardcoding ultimateSp in CsBattleOp 2025-07-27 00:56:56 +02:00
AlessandroCH
775baf5c3b Player.SeamlessEnterScene (not working...) 2025-07-26 23:13:48 +02:00
AlessandroCH
bb7c9831b4 GateBulletin hardcoded + bug fix 2025-07-25 17:41:39 +02:00
AlessandroCH
67d3acea54 AdventureBookManager 2025-07-22 23:54:55 +02:00
AlessandroCH
35f8fbb2b2 another try to improve entity spawning and fix loading but still loading issues 2025-07-18 14:49:33 +02:00
AlessandroCH
f47ec48073 FakeClientTester 2025-07-09 22:38:12 +02:00
AlessandroCH
623f7a111c planning to add option to use external sdk for login 2025-07-09 19:35:51 +02:00
AlessandroCH
3fbe2b6fc1 added disableLevelscripts on config file 2025-06-18 12:26:36 +02:00
AlessandroCH
80f0d16154 bug fix 2025-06-12 20:27:36 +02:00
AlessandroCH
5e68f54c48 real enemy drops, improved code etc, i dont remember everything i made LOL 2025-06-10 21:14:38 +02:00
AlessandroCH
c00d7cf0d7 os android cbt 2025-06-09 16:04:19 +02:00
AlessandroCH
723b81d5e4 some fix 2025-06-04 14:31:56 +02:00
AlessandroCH
864f4307c8 levelscript saving 2025-05-30 19:58:55 +02:00
AlessandroCH
e26138d170 spawners, todo: saving levelscript states and properties 2025-05-30 15:36:49 +02:00
AlessandroCH
5ae50be507 new levelscriptevent action types 2025-05-30 00:32:25 +02:00
AlessandroCH
f416665d40 new types 2025-05-29 00:32:39 +02:00
AlessandroCH
0a42b80772 scene manager "test" 2025-05-28 17:45:23 +02:00
AlessandroCH
7c0a512ad6 test 2025-05-28 12:12:04 +02:00
AlessandroCH
4e280f18b5 mission system now save, characters at start only 1 if quests are enabled 2025-05-26 22:23:03 +02:00
AlessandroCH
8563aeb739 removing useless variables 2025-05-25 17:56:33 +02:00
AlessandroCH
9d62c1783c 1.1.6-dev 2025-05-25 17:54:41 +02:00
Akari
1c5cd8fafc
Merge pull request #1 from Campofinale/development
1.1.5 ver
2025-05-25 17:45:25 +02:00
AlessandroCH
f65555fbcf mission data not required 2025-05-25 17:43:00 +02:00
AlessandroCH
d55e35aae0 1.1.5 final so i can plan new version features 2025-05-25 17:31:00 +02:00
AlessandroCH
7b6541a35b disabling watermark 2025-05-25 17:30:19 +02:00
AlessandroCH
0cef94edfc enableCBT2AccessForbidden on FALSE OMG 2025-05-25 14:19:00 +02:00
AlessandroCH
4c25f00235 fix for a log 2025-05-23 23:19:43 +02:00
AlessandroCH
62df1581a9 i hope some fix 2025-05-23 23:11:58 +02:00
AlessandroCH
482197b5fe let's hope this work 2025-05-23 20:54:35 +02:00
AlessandroCH
e8264118af api changes 2025-05-22 18:10:24 +02:00
AlessandroCH
4ec1bdb05d testing some things with factory manager 2025-05-20 19:56:14 +02:00
AlessandroCH
cb70fa6f1b MissionSystem + Event system (manually re implementation) 2025-05-18 16:46:05 +02:00
AlessandroCH
dab3723540 entity spawn only once when in range, fixed waypoints for use the depot 2025-05-17 23:39:55 +02:00
Hexafluorine
9621cf8274 Track Missions 2025-05-17 12:28:10 -07:00
AlessandroCH
e75ada13c0 hardcoded stuff and every entity is sent only one time when the distance is lower than 250 2025-05-17 19:44:21 +02:00
Hexafluorine
4432406caa Improve Logging 2025-05-16 16:40:53 -07:00
Hexafluorine
27c8a06a4f Reduce Log Spam 2025-05-16 14:24:43 -07:00
AlessandroCH
91103aaac8 re hardcoded missions from pcap for now 2025-05-16 22:53:22 +02:00
AlessandroCH
8fc6d623b0 levelscript starting 2025-05-16 21:32:38 +02:00
AlessandroCH
18414087f3 moved dispatch cn thing to it's own class 2025-05-13 15:12:40 +02:00
AlessandroCH
2e2469cf00 Added GachaWeaponPoolTable but weapons banners not work (idk why) 2025-05-10 17:45:59 +02:00
AlessandroCH
1bd767d9ce modified readme 2025-05-10 17:06:58 +02:00
AlessandroCH
a66f7e8d7e TODO: MissionSystem 2025-05-10 16:56:37 +02:00
AlessandroCH
d9f06c2704 removing useless imports 2025-05-10 16:52:01 +02:00
AlessandroCH
b3f24c83ec Preparing "MissionDataTable" (not original name, the original name in dump.cs is: Beyond.Gameplay.MissionRuntimeAsset) 2025-05-10 16:49:11 +02:00
Hexafluorine
d46a63c386
Clean up 2025-05-05 22:26:37 -07:00
Hexafluorine
9cc32bbe3a Fix MongoDB Issue
Ensures MongoDB service has started so it doesn't throw an error when accessing the db (Windows only)
2025-03-20 20:34:04 -07:00
Hexafluorine
2273c3989e Clean up imports 2025-03-20 18:06:02 -07:00
AlessandroCH
75dafc17b2 fix 2025-03-16 20:53:37 +01:00
AlessandroCH
4c62f9f7ef fix 2025-03-16 20:53:37 +01:00
Xannix246
28674c0aed ingame cmd update
Now commands are transfering via base64, and teleport command can increase/decreae position (+ before cords value to increase and -- to decrease)
2025-03-16 01:26:00 +03:00
CloudTronX
209bd16248 added support to decimal coordinate teleportation 2025-03-15 12:22:53 -07:00
Albert
23c6f57bb1
Update README_ru-RU.md 2025-03-15 21:06:04 +03:00
CloudTron
c6b38f06fb
Update README_zh-CN.md 2025-03-15 01:46:51 -07:00
CloudTron
a8863e9b3e
Update README.md 2025-03-15 01:46:14 -07:00
CloudTron
5e4fee92ef
Update README_zh-CN.md 2025-03-15 01:45:53 -07:00
CloudTron
8e1713877a
Update README.md 2025-03-15 01:44:38 -07:00
AlessandroCH
ed0d4252a7 bag saving, grid move and drop 2025-03-11 20:11:05 +01:00
AlessandroCH
2e1b633682 fix 2025-03-11 17:36:21 +01:00
AlessandroCH
4b27010ddd more server status info 2025-03-11 17:29:59 +01:00
AlessandroCH
cf91c97812 server status api 2025-03-11 17:12:12 +01:00
AlessandroCH
6a39a2960e gift to chars work 2025-03-10 21:08:13 +01:00
AlessandroCH
d0e91fdc78 some summary comments 2025-03-09 22:14:29 +01:00
AlessandroCH
c375fb9af7 remove comments 2025-03-09 22:08:29 +01:00
AlessandroCH
b0eb526818 Working on a better resource loader 2025-03-09 22:07:48 +01:00
AlessandroCH
dc3eace03b some summary texts 2025-03-09 18:56:45 +01:00
AlessandroCH
9c1f691fa3 another fix :( 2025-03-09 17:02:38 +01:00
AlessandroCH
cd45f63bd9 fix 2025-03-09 17:01:52 +01:00
AlessandroCH
0c268cb978 fix 2025-03-09 16:56:48 +01:00
AlessandroCH
aedf2a885d some bug fix, new improved inventory manager (but still very bad but atleast you can give some items inside the bag) 2025-03-09 16:28:12 +01:00
Akari
feb6922244
Merge pull request #1 from Smi1eDoge/development
CN Translation and Some Docs Fixes
2025-03-09 07:45:16 +01:00
Smi1eDoge
ae32b92cb6 Markdown Links Fix 2025-03-09 12:35:45 +08:00
Smi1eDoge
6b3d648b5c quick fix 2025-03-09 12:30:11 +08:00
Smi1eDoge
e6122f8817 Add README_zh-CN.md 2025-03-09 12:30:02 +08:00
AlessandroCH
1277d16ec5 fix 2025-03-08 17:12:00 +01:00
AlessandroCH
4ad771a690 fix 2025-03-08 17:10:21 +01:00
AlessandroCH
d7ba6dcb6b new config options 2025-03-08 17:09:30 +01:00
AlessandroCH
5f488b67d9 saving player gender 2025-03-08 15:26:54 +01:00
219 changed files with 14618 additions and 3067 deletions

View File

@ -19,6 +19,10 @@
<ItemGroup>
<Protobuf Include="*.proto" ProtoRoot="." GrpcServices="None" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Campofinale.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="AbilityActionCreateGadget.proto" />
<None Remove="AbilityActionSummon.proto" />
@ -897,5 +901,8 @@
<None Remove="WorktopOptionNotify.proto" />
<None Remove="WorldPlayerReviveReq.proto" />
</ItemGroup>
<ItemGroup>
<None Include="Campofinale.cs" />
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Protocol
{
public enum CsMsgId : int
namespace Campofinale.Protocol
{
public enum CsMsgId : int
{
CsMessageBegin = 0,
CsLogin = 1,
CsCreateRole = 2,
@ -325,5 +319,5 @@ public enum CsMsgId : int
CsActivityEnd = 1510,
CsMessageEnd = 4095,
}
}
}

View File

@ -1,13 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Protocol
{
public enum ScMsgId : int
namespace Campofinale.Protocol
{
public enum ScMsgId : int
{
ScMessageBegin = 0,
ScLogin = 1,
ScSyncBaseData = 2,
@ -397,5 +391,5 @@ public enum ScMsgId : int
ScActivityEnd = 1690,
ScMessageEnd = 4095,
}
}
}

View File

@ -8,6 +8,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Platforms>AnyCPU;x86;ARM32</Platforms>
<StartupObject>Program</StartupObject>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
@ -20,15 +21,12 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CsvHelper" Version="33.0.1" />
<PackageReference Include="Google.Protobuf" Version="3.27.2" />
<PackageReference Include="HttpServerLite" Version="2.1.5" />
<PackageReference Include="MongoDB.Driver" Version="3.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLua" Version="1.7.3" />
<PackageReference Include="Pastel" Version="5.1.0" />
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
<PackageReference Include="SQLiteNetExtensions" Version="2.1.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.3" />
</ItemGroup>
<ItemGroup>
@ -48,6 +46,9 @@
<None Update="93_ScSceneMapMarkSync.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Data\Conditions.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Data\GachaHistory\index_noplayerfound.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>

View File

@ -1,15 +1,4 @@
using Campofinale.Database;
using Campofinale.Game.Entities;
using Campofinale.Protocol;
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Commands
namespace Campofinale.Commands
{
public static class BaseCommands
{

View File

@ -1,15 +1,10 @@
namespace Campofinale.Commands
{
using Pastel;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Collections.Immutable;
using System.Linq.Expressions;
using System.Reflection;
using System.Net.Sockets;
using Campofinale.Protocol;
using Campofinale.Network;
public static class CommandManager
{

View File

@ -1,9 +1,4 @@
using Campofinale.Database;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Commands.Handlers
{

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Game.Inventory;
using Campofinale.Packets.Sc;
@ -28,15 +23,12 @@ public static class CommandAdd
case "item":
Item item=target.inventoryManager.AddItem(args[1], int.Parse(args[2]));
message = $"Item {args[1]} was added to {target.nickname}";
target.Send(new PacketScItemBagScopeModify(target, item));
break;
case "weapon":
Item wep = target.inventoryManager.AddWeapon(args[1], Convert.ToUInt64(args[2]));
message = $"Weapon {args[1]} was added to {target.nickname}";
target.Send(new PacketScItemBagScopeModify(target, wep));
break;
case "char":
@ -77,7 +69,7 @@ public static class CommandAdd
return;
}
target.inventoryManager.Save();
CommandManager.SendMessage(sender, $"{message}.");
}
catch (Exception err)

View File

@ -1,12 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MongoDB.Bson;
using static Campofinale.Resource.ResourceManager;
using Newtonsoft.Json;
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Database;
using Campofinale.Game.Inventory;

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Commands.Handlers
namespace Campofinale.Commands.Handlers
{
public static class CommandClear
{

View File

@ -1,12 +1,6 @@
using Campofinale.Game.Entities;
using Campofinale.Packets.Sc;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Commands.Handlers
{
@ -16,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()
{

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Commands.Handlers
namespace Campofinale.Commands.Handlers
{
public static class CommandHelp
{

View File

@ -1,8 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Commands.Handlers

View File

@ -1,9 +1,4 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Commands.Handlers
{

View File

@ -1,9 +1,8 @@
using Campofinale.Commands;
using Campofinale.Database;
using Campofinale.Packets.Sc;
using Campofinale.Resource;
namespace Campofinale.Game.Character
namespace Campofinale.Game.Char
{
public static class CharacterManager
{
@ -61,7 +60,7 @@ namespace Campofinale.Game.Character
}
int updatedItemCount = 0;
foreach (var item in target.inventoryManager.items)
foreach (var item in target.inventoryManager.items.items)
{
if (item.id.StartsWith("wpn_"))
{

View File

@ -1,8 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Campofinale.Packets.Sc;
namespace Campofinale.Commands.Handlers
@ -19,11 +14,6 @@ namespace Campofinale.Commands.Handlers
return;
}
for (int i=0; i < args.Length; i++)
{
args[i] = Uri.UnescapeDataString(args[i]);
}
target.nickname = string.Join(" ", args);
target.Save();
target.Send(new PacketScSetName(target, target.nickname));

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Commands.Handlers
namespace Campofinale.Commands.Handlers
{
public static class CommandPlayers
{

View File

@ -1,10 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Campofinale.Database;
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Packets.Sc;
namespace Campofinale.Commands.Handlers;

View File

@ -1,10 +1,5 @@
using Campofinale.Game.Entities;
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Commands.Handlers
{

View File

@ -1,11 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
using Campofinale.Packets.Sc;
using MongoDB.Bson;
using System.Globalization;
namespace Campofinale.Commands.Handlers
{
@ -23,20 +19,25 @@ namespace Campofinale.Commands.Handlers
for (int i=0; i < args.Length; i++)
{
args[i] = Uri.UnescapeDataString(args[i]).Replace(".", ",");
args[i] = args[i].Replace(",", ".");
}
float x, y, z;
float[] pos = [target.position.x, target.position.y, target.position.z];
x = args[0] == "~" ? target.position.x : float.Parse(args[0]);
y = args[1] == "~" ? target.position.y : float.Parse(args[1]);
z = args[2] == "~" ? target.position.z : float.Parse(args[2]);
for (int i=0; i < args.Length; i++) {
if(args[i] == "~") continue;
float curPos = pos[i];
pos[i] = float.Parse(args[i].StartsWith("--") ? args[i].Trim('-') : args[i], CultureInfo.InvariantCulture);
if (args[i].StartsWith('+')) pos[i] += curPos;
if (args[i].StartsWith("--")) pos[i] = curPos - pos[i];
}
Vector3f position = new Vector3f(new Vector()
{
X = x,
Y = y,
Z = z
X = pos[0],
Y = pos[1],
Z = pos[2]
});
target.position = position;

View File

@ -1,12 +1,6 @@
using Campofinale.Database;
using Campofinale.Packets.Sc;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Commands.Handlers
{

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale
namespace Campofinale
{
public class ConfigFile
{
@ -14,43 +8,54 @@ namespace Campofinale
public ServerOptions serverOptions = new();
public LogSettings logOptions = new();
}
public struct ServerOptions
public class ServerOptions
{
public int defaultSceneNumId = 98;
public int defaultSceneNumId = 87;
public int maxPlayers = 20;
/// <summary>
/// Experimental, Mission System is still a work in progress.
/// </summary>
public bool missionsEnabled = false;
public bool giveAllItems = false;
/// <summary>
/// Bug: on mobile some scenes doesn't want to load fine
/// </summary>
public bool disableLevelscripts = true;
/// <summary>
/// Not yet implemented
/// </summary>
public bool useEncryption = false;
public ServerOptions()
{
}
/* public struct WelcomeMail
{
}*/
}
public struct LogSettings
public class LogSettings
{
public bool packets;
public bool debugPrint=false;
public bool packets = true;
public bool packetWarnings = true;
public bool packetBodies = false;
public bool debugPrint = false;
public LogSettings()
{
}
}
public struct GameserverSettings
public class GameserverSettings
{
public string bindAddress = "127.0.0.1";
public int bindPort = 30000;
public string accessAddress = "127.0.0.1";
public int accessPort = 30000;
public bool useExternalAuthSdk = false;
public string externalAuthSdkUrl = "";
public GameserverSettings()
{
}
}
public struct DispatchServerSettings
public class DispatchServerSettings
{
public string bindAddress = "127.0.0.1";
public int bindPort = 5000;
public string accessAddress = "127.0.0.1";
public int accessPort = 5000;
@ -60,7 +65,7 @@ namespace Campofinale
}
}
public struct MongoDatabaseSettings
public class MongoDatabaseSettings
{
public string uri = "mongodb://localhost:27017";
public string collection = "Campofinale";

View File

@ -15,9 +15,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
using System;
using System.IO;
using System.Threading.Tasks;
using System.Runtime.Intrinsics;
using System.Runtime.CompilerServices;

View File

@ -0,0 +1,19 @@
{
"cond_ab_01_01":
{
"args": [
"10"
]
},
"cond_daily_001":{
"args":[
"DailyLogin"
]
},
"cond_daily_005":
{
"args":[
"DailyCharLevelUp"
]
}
}

View File

@ -154,7 +154,7 @@
try {
const url = new URL('%dispatchip%/pcSdk/console');
url.searchParams.append('command', command);
url.searchParams.append('command', btoa(unescape(encodeURIComponent(command))));
url.searchParams.append('token', token);
const response = await fetch(url.toString(), {

View File

@ -0,0 +1 @@
{"isInitial":true,"files":[{"index":1,"name":"VFS/CA2A581090AB4133/CA2A581090AB4133.blc","hash":"e75b8886d2426ec6b1e7f362bcd5255d","size":302,"urlPath":null,"manifest":7},{"index":2,"name":"VFS/CA2A581090AB4133/0DBA81C558A36AFC1D7D1C0A5A704A09.chk","hash":null,"size":80879438,"urlPath":null,"manifest":0},{"index":3,"name":"VFS/8F0DD938C04FD953/8F0DD938C04FD953.blc","hash":"d236d4691a5815ba973fa365ff6357f9","size":59,"urlPath":null,"manifest":3},{"index":4,"name":"VFS/16BB5AC00009A71B/16BB5AC00009A71B.blc","hash":"689374e7c7ec263dfd66fd255351fded","size":331,"urlPath":null,"manifest":3},{"index":5,"name":"VFS/16BB5AC00009A71B/6A2B02D8FCE1ED28849D1596D779CFA9.chk","hash":null,"size":14236423,"urlPath":null,"manifest":4},{"index":6,"name":"VFS/16BB5AC00009A71B/DA88C18EED8D9DEE8326BAA9AB78AA78.chk","hash":null,"size":1193655,"urlPath":null,"manifest":4},{"index":7,"name":"VFS/AAD6005BEB6AE986/AAD6005BEB6AE986.blc","hash":"51603590679e7d8590a3a1f908a38ed1","size":27360,"urlPath":null,"manifest":3},{"index":8,"name":"VFS/AAD6005BEB6AE986/1745D582258DFD069CDA135DDC740D34.chk","hash":null,"size":124467976,"urlPath":null,"manifest":4},{"index":9,"name":"VFS/B28236B7FAB03015/B28236B7FAB03015.blc","hash":"1baf1a032b9e204652eac0a7256621a7","size":15912,"urlPath":null,"manifest":7},{"index":10,"name":"VFS/B28236B7FAB03015/86BC72728AE017306E7CBE8DC67C93A9.chk","hash":null,"size":46679427,"urlPath":null,"manifest":0}],"types":null,"version":null}

View File

@ -0,0 +1 @@
4Fmf1Xuly6yikdJUcayl2cpjWMibo8erW2rBrVmhocjKr1icY2OEppqdy1RxWomquGZ5o2R4l3BqYJ9ieHpnlZhqZaVzaaNtcWGWa2d5dZiWammQlKPFWmVSzpOqoFWeh5xtl5RvmnBvlJhmaW6Yx5uZZ8dpnZVua5LJlmxqaJnJWWKEpaDcnVtqmWJpZFXZ16OGw6afhHKnpdKeY1qgxdOgnMelq4RycK2SrVmhocjKr1icZGOEppqdy1RxWomquGZ5o2R4l3BqYJ9ieHpnlZhqZZJ2eaNwanObZ295ZpqmfXmTdm6maXxgp2d4b2OYpmdvkJWfzVplUs6TqqBVntOsos5eWdWhs5WIbG9oa5uea2maXlnXqqWAx6afWm3S2qOijlSkw6ailsulq1ptlOJjsYSbpcadsVKgZWNaocXSnFicVI2oi2horGJ7fGyXnXpmlnh7m21sX554Z3x3nZhveZJmfaZxbmOUlKObVZCHn5fVmlmcWp1imWibbGmdlphrmmNsxJlyZ5mYmGtpmcudbJVnbshxW1yIpaCymIafbG+OVKzUpImR2ppZcqHZ0aNihJ+Y0KGfldmmWXJm4ZGyWMugm8ewW2qaXlmmlNHKWXCEiH21Z2pmqHRseXaUlWdmm3Nuk3poYZx0eW10p5VnZpJreJlpe17InppaX4bNmKnKVHGEbnFpmWlrnWrHnJyZlGhqxp6dZpyYm2pomZhsZ8iWnMZaZVLZm7GdVZ6YameOVKzUpImR2ppZcqHZ0aNihJ+Y0KGfldmmWXJm4ZGyWMugm8ewW2qbXlmmlNHKWXCEiH21Z2pmqHRseXaUlWdmm3Nuk3poZqdkeWhlqJ19eadjfKZqcWiaa3tpaJ2be22Za3qoeXJeyZqiWl+GzZipylRx0K2lnJJUqqGtyYdxZ5Zkaphsa2OSVKyqn7TGq56EbKXXpKVciJ+YppzKyqqqhGxr32S0Us+gm52rhp9tYoSgmM+dW2qIiH2LYpWbeXiXc3qSaGlgn3NuaXWTqXhumnVomn1+dJ52cHx4qZ1qaJh0eKNxenKdanh5apyTmp7NVGOEoJqjzlRxpqjQ0WNY1Zuxx1pzYZdram5omZFZq9Seh8OsoVKgoKykn5CHpJfQm53Hq61SoGa0ZK6GzqWax6pZnG9lUtSTpJ1VnoeNfLVheKN8b2CWZ3l9dZqmfG+aaGajeX1mlmJsenimm3h7m2ptkJqlk4heWaCU181ZcIRnaJhobGWfYm1vbMmcm26Xa2fDa5phzGtncJSXnZyak1RjhKuiqstUcWpql5tnYoSnqc6ImqTOVHGmqNDRY1jPk6XLnp6j2lRxa7CQ4Fmf0Jac2lpzaJJUpZmgyYdxWLh4ipF5enScYmdtdamnbXena2+YZ2pnmmd7bWuWl2xupnh7km5yc6pzaGtoqKl6bZZie5VsZ5POnVlkVczGqp6EbKXXpKVciKWgspiGn2holmZtmXFwZpJUrKqftMarnoRspdekpVyIn5imnMrKqqqEbGvfZLRSz6CbnauGn3BihKCYz51baoiIfYtippdvaJVoeZl+enKWZWdpaJOnaW6UZW2kb39xqGJqaGSZk5mixVRjhKCao85UcVpkxsadZ8NiapSacpWYYmtuaJbKmJmSk26UbW9mmGOYb1WQh6qf3JdZnGluaZdkY1qo1tGHl9aaWZymrpzSXlmllNLOnZvVplmcb7Zc4VSgppfJ3Vlwk2JjhKaanctUcVqJqrhmeJRqaZVue2esc3loZpSWbGWaaHmlb2tnmGp4fWOVnGpmmHdupXp+aKp1bW92nZh4b5CVn81aZVLOk6qgVZ7TrKLOXlnVobOViGxrbmmbnmtomV5Z16qlgMemn1pt0tqjoo5UpMOmopbLpatabZTilGKEprDSnaxSoKCspJ+Qh62b1KWg0aZbatSno6Sw

View File

@ -1,21 +1,18 @@
using Campofinale.Game;
using Campofinale.Game.Character;
using Campofinale.Game.Adventure;
using Campofinale.Game.Char;
using Campofinale.Game.Gacha;
using Campofinale.Game.Inventory;
using Campofinale.Game.MissionSys;
using Campofinale.Game.Spaceship;
using Campofinale.Resource;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Player;
using static Campofinale.Game.Adventure.AdventureBookManager;
using static Campofinale.Game.Factory.FactoryManager;
using static Campofinale.Resource.ResourceManager;
using static SQLite.SQLite3;
namespace Campofinale.Database
{
@ -39,9 +36,20 @@ namespace Campofinale.Database
public long maxDashEnergy = 250;
public uint curStamina;
public long nextRecoverTime;
public long nextDailyReset;
public List<Scene> scenes = new();
public Dictionary<int, List<int>> bitsets = new();
public PlayerSafeZoneInfo savedSafeZone = new();
public Gender gender = Gender.GenFemale;
public Dictionary<int, Item> bag = new();
}
public class MissionData
{
[BsonId]
public ulong roleId;
public List<GameMission> missions = new();
public List<GameQuest> quests = new();
public string curMission = "e0m0";
}
public class Account
{
@ -69,12 +77,21 @@ namespace Campofinale.Database
public Database(string connectionString, string dbName)
{
var client = new MongoClient(connectionString);
_database = client.GetDatabase(dbName);
}
public List<Mail> LoadMails(ulong roleId)
{
return _database.GetCollection<Mail>("mails").Find(c => c.owner == roleId).ToList();
}
public MissionData LoadMissionData(ulong roleId)
{
return _database.GetCollection<MissionData>("missionsData").Find(c => c.roleId == roleId).FirstOrDefault();
}
public AdventureBookData LoadAdventureBookData(ulong roleId)
{
return _database.GetCollection<AdventureBookData>("adventureBookData").Find(c => c.roleId == roleId).FirstOrDefault();
}
public List<Character> LoadCharacters(ulong roleId)
{
return _database.GetCollection<Character>("avatars").Find(c=>c.owner== roleId).ToList();
@ -87,7 +104,10 @@ namespace Campofinale.Database
{
return _database.GetCollection<SpaceshipRoom>("spaceship_rooms").Find(c => c.owner == roleId).ToList();
}
public FactoryData LoadFactoryData(ulong roleId)
{
return _database.GetCollection<FactoryData>("factory").Find(c => c.roleId == roleId).ToList().FirstOrDefault();
}
public List<Item> LoadInventoryItems(ulong roleId)
{
return _database.GetCollection<Item>("items").Find(c => c.owner == roleId).ToList();
@ -141,7 +161,10 @@ namespace Campofinale.Database
noSpawnAnymore = player.noSpawnAnymore,
scenes=player.sceneManager.scenes,
bitsets=player.bitsetManager.bitsets,
savedSafeZone = player.savedSaveZone
savedSafeZone = player.savedSaveZone,
gender=player.gender,
bag=player.inventoryManager.items.bag,
nextDailyReset = player.nextDailyReset,
};
UpsertPlayerData(data);
}
@ -179,6 +202,19 @@ namespace Campofinale.Database
new ReplaceOptions { IsUpsert = true }
);
}
public void UpsertMissionData(MissionData data)
{
var collection = _database.GetCollection<MissionData>("missionsData");
var filter =
Builders<MissionData>.Filter.Eq(p => p.roleId, data.roleId);
collection.ReplaceOne(
filter,
data,
new ReplaceOptions { IsUpsert = true }
);
}
public void UpsertAccount(Account player)
{
var collection = _database.GetCollection<Account>("accounts");
@ -232,6 +268,23 @@ namespace Campofinale.Database
new ReplaceOptions { IsUpsert = true }
);
}
public void UpsertAdventureBookData(AdventureBookManager.AdventureBookData data)
{
if (data._id == ObjectId.Empty)
{
data._id = ObjectId.GenerateNewId();
}
var collection = _database.GetCollection<AdventureBookManager.AdventureBookData>("adventureBookData");
var filter =
Builders<AdventureBookManager.AdventureBookData>.Filter.Eq(c => c.roleId, data.roleId);
var result = collection.ReplaceOne(
filter,
data,
new ReplaceOptions { IsUpsert = true }
);
}
public void UpsertCharacter(Character character)
{
if (character._id == ObjectId.Empty)
@ -270,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<FactoryData>("factory");
var filter =
Builders<FactoryData>.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)
@ -338,6 +407,11 @@ namespace Campofinale.Database
}
public Account GetAccountByTokenGrant(string token)
{
if (Server.config.gameServer.useExternalAuthSdk)
{
//TODO get account info from external auth sdk
return null;
}
try
{
return _database.GetCollection<Account>("accounts").Find(p => p.grantToken == token).ToList().FirstOrDefault();

View File

@ -1,14 +1,11 @@
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Bson.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.IO;
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
{
@ -68,7 +65,10 @@ namespace Campofinale.Database
{
BsonSerializer.RegisterSerializer(typeof(Dictionary<int, ulong>), new CustomDictionarySerializer<int, ulong>());
BsonSerializer.RegisterSerializer(typeof(Dictionary<int, List<int>>), new CustomDictionarySerializer<int, List<int>>());
BsonSerializer.RegisterSerializer(typeof(Dictionary<int, Item>), new CustomDictionarySerializer<int, Item>());
RegisterSubclasses<FComponent>();
RegisterSubclasses<NodeBuildingBehaviour>();
Logger.Print("Connecting to MongoDB...");
try
{

View File

@ -0,0 +1,252 @@
using Campofinale.Database;
using Campofinale.Game.Factory;
using Campofinale.Game.Spaceship;
using Campofinale.Resource;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
using MongoDB.Bson.Serialization.IdGenerators;
using Campofinale.Game.Char;
using Campofinale.Resource.Json;
using Campofinale.Protocol;
namespace Campofinale.Game.Adventure
{
public class AdventureBookManager
{
public Player player;
public AdventureBookData data = new();
public AdventureBookManager(Player player)
{
this.player = player;
}
public void Load()
{
AdventureBookData toLoad= DatabaseManager.db.LoadAdventureBookData(player.roleId);
if (toLoad != null)
{
data = toLoad;
}
else
{
data.roleId = player.roleId;
}
if (data.adventureBookStage == 0)
{
InitNextStage();
}
}
public void DailyReset()
{
data.tasks.RemoveAll(t => t.GetTaskTable().taskType == AdventureTaskType.Daily);
data.dailyActivation = 0;
data.dailyCharLevelUp = 0;
data.dailyLogin = 0;
ResourceManager.adventureTaskTable.Values.ToList().ForEach(task =>
{
if (task.taskType == AdventureTaskType.Daily)
{
data.tasks.Add(new GameAdventureTask()
{
adventureTaskId = task.adventureTaskId,
claimed = false
});
}
});
}
public void Save()
{
DatabaseManager.db.UpsertAdventureBookData(data);
}
public void TaskUpdate(ConditionType condType, object obj=null)
{
List<GameAdventureTask> toUpdate = new();
data.tasks.FindAll(t=>t.GetTaskTable().conditionType==condType).ForEach(task =>
{
if(task.TaskUpdate(this.player, obj))
{
toUpdate.Add(task);
}
});
if (toUpdate.Count > 0)
{
ScAdventureTaskModify modify = new ScAdventureTaskModify()
{
};
toUpdate.ForEach(t =>
{
modify.Tasks.Add(t.ToProto());
});
player.Send(ScMsgId.ScAdventureTaskModify, modify);
}
}
public void InitNextStage(bool notify=false)
{
data.adventureBookStage++;
data.tasks.RemoveAll(t => t.GetTaskTable().taskType == AdventureTaskType.AdventureBook);
ResourceManager.adventureTaskTable.Values.ToList().ForEach(task =>
{
if(task.adventureBookStage == data.adventureBookStage)
{
data.tasks.Add(new GameAdventureTask()
{
adventureTaskId = task.adventureTaskId,
claimed=false
});
}
});
//TODO Update everything
}
public void ClaimTask(string taskId)
{
data.tasks.ForEach(t =>
{
if (t.adventureTaskId == taskId && t.GetState() == AdventureTaskState.Completed)
{
t.ClaimRewards(player);
}
});
}
public void ClaimTasks(AdventureTaskType taskType)
{
data.tasks.ForEach(t =>
{
if (t.GetTaskTable().taskType==taskType && t.GetState() == AdventureTaskState.Completed)
{
t.ClaimRewards(player);
}
});
}
public class GameAdventureTask
{
public string adventureTaskId;
public int progress;
public bool claimed;
public void ClaimRewards(Player player)
{
player.inventoryManager.AddRewards(GetTaskTable().rewardId, player.position, 0);
claimed= true;
ScAdventureTaskModify modify = new()
{
Tasks =
{
ToProto()
}
};
player.Send(ScMsgId.ScAdventureTaskModify, modify);
}
public AdventureTaskState GetState()
{
if(progress < GetTaskTable().progressToCompare)
{
return AdventureTaskState.Processing;
}else if (!claimed)
{
return AdventureTaskState.Completed;
}
else
{
return AdventureTaskState.Rewarded;
}
}
public bool TaskUpdate(Player owner, object obj)
{
ConditionType condType = GetTaskTable().conditionType;
ConditionData cond;
if(ResourceManager.conditions.TryGetValue(GetTaskTable().conditionId, out cond))
{
int count = 0;
switch (condType)
{
case ConditionType.CheckStatisticVal:
switch (Enum.Parse(typeof(StatType), cond.Get(0)))
{
case StatType.DailyCharLevelUp:
count = owner.adventureBookManager.data.dailyCharLevelUp;
break;
case StatType.DailyLogin:
count = owner.adventureBookManager.data.dailyLogin;
break;
default:
break;
}
if (count > progress)
{
progress = count;
return true;
}
else
{
return false;
}
case ConditionType.CheckGreaterCharLevelNum:
count = 0;
owner.chars.ForEach(c =>
{
if(c.level >= cond.ToInt(0))
{
count++;
}
});
if (count > progress)
{
progress = count;
return true;
}
else
{
return false;
}
default:
return false;
}
}
else
{
return false;
}
}
public AdventureTaskTable GetTaskTable()
{
return ResourceManager.adventureTaskTable.Values.ToList().Find(a => a.adventureTaskId == adventureTaskId);
}
public AdventureTask ToProto()
{
return new AdventureTask()
{
Progress = progress,
State = (int)GetState(),
TaskId = adventureTaskId,
};
}
}
public class AdventureBookData
{
[BsonId(IdGenerator = typeof(ObjectIdGenerator))]
public ObjectId _id { get; set; }
public ulong roleId;
public int adventureBookStage = 0;
public int dailyActivation = 0;
public List<GameAdventureTask> tasks = new();
public int dailyCharLevelUp = 0;
public int dailyLogin = 0;
}
}
}

View File

@ -1,9 +1,4 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Game

View File

@ -6,18 +6,11 @@ using Google.Protobuf.Collections;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.IdGenerators;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
using static Campofinale.Resource.ResourceManager.CharGrowthTable;
using static Campofinale.Resource.ResourceManager.WeaponUpgradeTemplateTable;
namespace Campofinale.Game.Character
namespace Campofinale.Game.Char
{
public class Character
{
@ -149,6 +142,11 @@ namespace Campofinale.Game.Character
guid = GetOwner().random.Next();
this.weaponGuid = GetOwner().inventoryManager.AddWeapon(ResourceManager.charGrowthTable[id].defaultWeaponId, 1).guid;
this.curHp = CalcAttributes()[AttributeType.MaxHp].val;
if (level < 20) breakNode = "";
if (level >= 20 && level <= 40) breakNode = "charBreak20";
if (level > 40 && level <= 60) breakNode = "charBreak40";
if (level > 60 && level <= 70) breakNode = "charBreak60";
if (level > 70) breakNode = "charBreak70";
}
public int GetSkillMaxLevel()
{
@ -461,8 +459,6 @@ namespace Campofinale.Game.Character
ScCharLevelUp levelUp = new()
{
CharObjID = guid,
};
ScCharSyncLevelExp synclevel = new()
{
@ -473,6 +469,10 @@ namespace Campofinale.Game.Character
GetOwner().Send(ScMsgId.ScCharSyncLevelExp, synclevel);
GetOwner().Send(ScMsgId.ScCharLevelUp, levelUp);
GetOwner().Send(new PacketScSyncWallet(GetOwner()));
GetOwner().adventureBookManager.TaskUpdate(ConditionType.CheckGreaterCharLevelNum);
GetOwner().adventureBookManager.TaskUpdate(ConditionType.CharMaxLevel);
GetOwner().adventureBookManager.data.dailyCharLevelUp++;
GetOwner().adventureBookManager.TaskUpdate(ConditionType.CheckStatisticVal);
}
}
}

View File

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Game.Dungeons
@ -18,5 +15,34 @@ namespace Campofinale.Game.Dungeons
{
}
public void Enter()
{
player.sceneManager.GetScene(GetSceneNumIdFromLevelData(table.sceneId)).activeScripts.Clear();
player.sceneManager.GetScene(GetSceneNumIdFromLevelData(table.sceneId)).scripts.ForEach(script =>
{
script.state = 1;
});
ScEnterDungeon enter = new()
{
DungeonId = table.dungeonId,
SceneId = table.sceneId,
};
player.Send(new PacketScSyncAllUnlock(player));
player.EnterScene(GetSceneNumIdFromLevelData(table.sceneId));
player.Send(ScMsgId.ScEnterDungeon, enter);
}
public void Leave()
{
ScLeaveDungeon rsp = new()
{
DungeonId = table.dungeonId,
};
player.Send(new PacketScSyncAllUnlock(player));
player.currentDungeon = null;
player.EnterScene(prevPlayerSceneNumId, prevPlayerPos, prevPlayerRot);
player.Send(ScMsgId.ScLeaveDungeon, rsp);
}
}
}

View File

@ -1,9 +1,5 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using static Campofinale.Resource.ResourceManager;
using static Campofinale.Resource.ResourceManager.LevelScene.LevelData;
@ -26,6 +22,7 @@ namespace Campofinale.Game.Entities
public List<ParamKeyValue> properties=new();
public int sceneNumId;
public bool spawned = false;
public bool defaultHide = false;
public Entity()
{
@ -45,6 +42,10 @@ namespace Campofinale.Game.Entities
public virtual void Heal(double heal)
{
}
public virtual void OnDie()
{
}
public virtual bool Interact(string eventName, Google.Protobuf.Collections.MapField<string, DynamicParameter> properties)
{

View File

@ -1,10 +1,4 @@
using Campofinale.Game.Character;
using Campofinale.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Campofinale.Protocol;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Game.Entities
@ -104,7 +98,7 @@ namespace Campofinale.Game.Entities
GetOwner().Send(ScMsgId.ScCharSyncStatus, state);
GetOwner().Send(ScMsgId.ScEntityPropertyChange, prop);
}
public Character.Character GetChar()
public Char.Character GetChar()
{
return GetOwner().chars.Find(c => c.guid == guid);
}

View File

@ -1,11 +1,6 @@
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
using static Campofinale.Resource.ResourceManager.LevelScene.LevelData;
@ -19,6 +14,7 @@ namespace Campofinale.Game.Entities
{
}
public EntityInteractive(string templateId, ulong worldOwner, Vector3f pos, Vector3f rot, int scene, ulong g=0)
{
if (g == 0)
@ -37,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()
{
@ -47,7 +59,7 @@ namespace Campofinale.Game.Entities
{
CommonInfo = new()
{
Hp = 100,
Hp = 1,
Id = guid,
Templateid = templateId,
@ -91,6 +103,7 @@ namespace Campofinale.Game.Entities
(bool, int) index = GetPropertyIndex(prop.key, proto.Properties.Keys.Count > 0 ? proto.Properties.Keys.Max() : 0);
if (p != null && index.Item1)
{
if(!proto.Properties.ContainsKey(index.Item2))
proto.Properties.Add(index.Item2, p);
}
@ -108,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);
}

View File

@ -1,10 +1,7 @@
using Campofinale.Protocol;
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Campofinale.Resource.Table;
using System.Threading;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Game.Entities
@ -12,6 +9,7 @@ namespace Campofinale.Game.Entities
public class EntityMonster : Entity
{
public string templateId;
public ulong originId;
public EntityMonster()
{
@ -45,7 +43,11 @@ namespace Campofinale.Game.Entities
{
List<AttrInfo> 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()
{
@ -88,6 +90,7 @@ namespace Campofinale.Game.Entities
Type =(int) ObjectTypeIndex.Enemy,
},
OriginId= originId,
Attrs =
{
GetAttributes()
@ -100,6 +103,23 @@ namespace Campofinale.Game.Entities
};
return proto;
}
public override void OnDie()
{
if (!wikiEnemyDropTable.ContainsKey(templateId)) return;
WikiEnemyDropTable table = wikiEnemyDropTable[templateId];
if (table!=null)
{
table.dropItemIds.ForEach(id =>
{
GetOwner().sceneManager.CreateDrop(Position, new RewardTable.ItemBundle()
{
id = id,
count = 1
});
});
}
}
public override void Damage(double dmg)
{
curHp -= dmg;

View File

@ -1,11 +1,4 @@
using Campofinale.Protocol;
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Game.Entities
{

View File

@ -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<Vector3f> points)
{
if (points == null || points.Count < 2)
return 0;
HashSet<Tuple<int, int, int>> blocks = new HashSet<Tuple<int, int, int>>();
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<Tuple<int, int, int>> 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));
}
}
}

View File

@ -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)
{
}
}
}

View File

@ -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<FComponentProducer>(producerId);
FComponentCache inCache = node.GetComponent<FComponentCache>(inputCacheId);
FComponentCache outCache = node.GetComponent<FComponentCache>(outputCacheId);
FComponentFormulaMan formulaManager = node.GetComponent<FComponentFormulaMan>();
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<ItemCount> 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;
}
}
}
}
}

View File

@ -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<FComponentProducer>(producerId);
FComponentCache inCache = node.GetComponent<FComponentCache>(inputCacheId);
FComponentCache outCache = node.GetComponent<FComponentCache>(outputCacheId);
FComponentFormulaMan formulaManager = node.GetComponent<FComponentFormulaMan>();
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<ItemCount> 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;
}
}
}
}
}

View File

@ -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
};
}
}
}

View File

@ -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<ItemCount> 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<ItemCount>();
}
proto.BoxConveyor = new()
{
LastPopTms = lastPopTms,
};
items.ForEach(item =>
{
if(item!=null)
proto.BoxConveyor.Items.Add(item.ToFactoryItemProto());
});
}
}
}

View File

@ -1,9 +1,4 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Game.Factory.FactoryNode;
namespace Campofinale.Game.Factory.Components

View File

@ -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<ItemCount> 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<ItemCount> 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;
}
}
}
}
}

View File

@ -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<string> formulaIds = new();
public FComponentFormulaMan(uint id) : base(id, FCComponentType.FormulaMan)
{
}
public List<string> GetFormulaIds()
{
List<string> 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
}
};
}
}
}

View File

@ -1,9 +1,4 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Game.Factory.FactoryNode;
namespace Campofinale.Game.Factory.Components
@ -40,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)
{

View File

@ -1,9 +1,4 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Game.Factory.FactoryNode;
namespace Campofinale.Game.Factory.Components

View File

@ -1,9 +1,4 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Game.Factory.FactoryNode;
namespace Campofinale.Game.Factory.Components

View File

@ -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
};
}
}
}

View File

@ -1,9 +1,4 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Game.Factory.FactoryNode;
namespace Campofinale.Game.Factory.Components

View File

@ -1,9 +1,4 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Game.Factory.FactoryNode;
namespace Campofinale.Game.Factory.Components

View File

@ -1,9 +1,4 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Game.Factory.FactoryNode;
namespace Campofinale.Game.Factory.Components

View File

@ -1,22 +1,21 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Game.Factory.FactoryNode;
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
};
}
}
}

View File

@ -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;
}
}
}

View File

@ -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<FactoryNode> 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<ScdFactorySyncMap> GetMaps()
{
List<ScdFactorySyncMap> 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<ScdFactorySyncMapWire> GetWires()
{
List<ScdFactorySyncMapWire> 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<FactoryNode> 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<FComponentTravelPole>().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<FComponentFormulaMan>();
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<FComponentCache>(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<FComponentCache>(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<FactoryNode> allNodes)
{
// Ottieni tutti i compId del nodo da rimuovere
HashSet<ulong> 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<FComponent>(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<FactoryNode> allNodes)
{
foreach (var node in allNodes)
node.powered = false;
}
void UpdatePowerGrid(List<FactoryNode> allNodes)
{
ResetAllPower(allNodes);
HashSet<uint> 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<uint> 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<FactoryNode> nodes = GetNodesInRange(node.position, 15);
foreach (FactoryNode propagateNode in nodes)
{
if (propagateNode.GetComponent<FComponentPowerPole>() == null)
{
propagateNode.powered = true;
}
}
}
if (node.GetComponent<FComponentPowerPole>() != 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<Vector3f> 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);
}
}
}

View File

@ -1,14 +1,12 @@
using Campofinale.Game.Factory.Components;
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 MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Game.Factory
@ -17,18 +15,41 @@ namespace Campofinale.Game.Factory
{
public Player player;
public List<FactoryChapter> chapters = new();
public ObjectId _id;
public class FactoryData
{
public ulong roleId;
public ObjectId _id;
public List<FactoryChapter> 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)
{
@ -48,412 +69,38 @@ namespace Campofinale.Game.Factory
player.Send(ScMsgId.ScFactoryOpRet, ret, seq);
}
}
public void SendFactoryHsSync()
{
if (!player.Initialized) return;
if (player.GetCurrentChapter() == "") return;
List<FactoryNode> 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<FactoryNode> nodes=new();
public uint v = 1;
public uint compV = 0;
public void Update()
{
try
{
foreach (FactoryNode node in nodes)
{
node.Update(this);
}
}
catch (Exception e)
{
}
}
public List<FactoryNode> 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.Place, seq);
break;
default:
break;
}
}
public uint nextCompV()
{
compV++;
return compV;
}
private void CreateNode(CsdFactoryOpPlace place, ulong seq)
{
v++;
uint nodeId = v;
FactoryBuildingTable table = ResourceManager.factoryBuildingTable[place.TemplateId];
FactoryNode node = new()
{
nodeId = nodeId,
templateId = place.TemplateId,
mapId = place.MapId,
nodeType = table.GetNodeType(),
position = new Vector3f(place.Position),
direction = new Vector3f(place.Direction),
guid = GetOwner().random.NextRand()
};
node.InitComponents(this);
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));
GetOwner().Send(ScMsgId.ScFactoryModifyChapterNodes, edit);
GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), node.nodeId,FactoryOpType.Place),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 string instKey="";
public bool deactive = false;
public int mapId;
public bool forcePowerOn = false;
public List<FComponent> components = new();
[BsonIgnore]
public bool powered = false;
[BsonIgnore]
public uint connectedPowerNode = 0;
public ulong guid;
public void Update(FactoryChapter chapter)
{
if(!templateId.Contains("hub"))
if (GetComponent<FComponentPowerPole>() != null)
{
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
}
}
}
public bool InPower()
{
if (forcePowerOn)
{
return true;
}
return powered;
}
public FComponent GetComponent<FComponent>() where FComponent : class
{
return components.Find(c => c is FComponent) as FComponent;
}
public FMesh GetMesh()
{
FMesh mesh = new FMesh();
if (ResourceManager.factoryBuildingTable.ContainsKey(templateId))
{
FactoryBuildingTable table = ResourceManager.factoryBuildingTable[templateId];
double centerX = position.x + table.range.width / 2.0;
double centerZ = position.z + table.range.depth / 2.0;
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
);
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);
}
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()
{
InstKey = instKey,
NodeId=nodeId,
TemplateId=templateId,
StableId= GetStableId(),
IsDeactive= deactive,
Power = new()
{
InPower= InPower(),
NeedInPower=false,
},
NodeType=(int)nodeType,
Transform = new()
{
Position = position.ToProtoScd(),
Direction=direction.ToProtoScd(),
MapId=mapId,
}
};
if(templateId!="__inventory__")
{
node.Transform.Mesh = GetMesh().ToProto();
node.Transform.WorldPosition = position.ToProto();
node.Transform.WorldRotation = direction.ToProto();
node.InteractiveObject = new()
{
};
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<FComponentBusLoader>().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<FComponentBusLoader>().compId).Init());
forcePowerOn = true;
break;
default:
components.Add(new FComponent(chapter.nextCompV(), GetMainCompType()).Init());
break;
}
}
[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<Vector3f> 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;
}
}
}
}

View File

@ -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<FComponent> components = new();
//Conveyor only
public List<Vector3f> points;
public bool powered = false;
public bool lastPowered = false;
public List<ConnectedComp> 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<FacPort> ports = new();
if (manager.customPos == FCComponentPos.PortOutManager)
{
ports = GetTransformedPorts(table.outputPorts);
List<FactoryNode> 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<FComponentBoxConveyor>().compId;
}
else
{
compPort.touchComId = 0;
}
}
}
//Output items
foreach (var port in manager.ports)
{
FComponentBoxConveyor output = chapter.GetCompById<FComponentBoxConveyor>(port.touchComId);
FComponentCache outputCache = chapter.GetCompById<FComponentCache>(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<ItemCount>() { add });
}
}
});
}
}
}
else
{
ports = GetTransformedPorts(table.inputPorts);
List<FactoryNode> 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<FComponentBoxConveyor>().compId;
}
else
{
compPort.touchComId = 0;
}
}
}
//Input items
foreach (var port in manager.ports)
{
FComponentBoxConveyor input = chapter.GetCompById<FComponentBoxConveyor>(port.touchComId);
FComponentCache inputCache = chapter.GetCompById<FComponentCache>(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<FComponentBoxConveyor>();
conveyorComp.items.Remove(toRemove);
chapter.GetOwner().Send(new PacketScFactoryHsSync(chapter.GetOwner(), chapter, new List<FactoryNode>() { this}));
}
private bool AddConveyorItem(FactoryChapter chapter,ItemCount i)
{
float length=BlockCalculator.CalculateTotalBlocks(points);
FComponentBoxConveyor conveyorComp = GetComponent<FComponentBoxConveyor>();
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<FactoryNode>() { this }));
return true;
}
else
{
return false;
}
}
}
return false;
}
public bool InPower()
{
if (forcePowerOn)
{
return true;
}
return lastPowered;
}
public FComponent GetComponent<FComponent>() where FComponent : class
{
return components.Find(c => c is FComponent) as FComponent;
}
public FComponent GetComponent<FComponent>(uint compid) where FComponent : class
{
return components.Find(c => c is FComponent && c.compId==compid) as FComponent;
}
public List<FacPort> GetTransformedPorts(List<FacPort> originalPorts)
{
List<FacPort> transformedPorts = new List<FacPort>();
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<FComponentBusLoader>().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<FComponentBusLoader>().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<Vector3f> 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;
}
}
}
}

View File

@ -1,12 +1,6 @@
using Campofinale.Database;
using Campofinale.Protocol;
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Game.Gacha
@ -16,7 +10,7 @@ namespace Campofinale.Game.Gacha
public Player player;
internal ulong upSeqId;
const double fiftyfifty = 0.45; // 50% (make it less than real 50, because the randomness make win fifty fifty every time
const double fiftyfifty = 0.50;
private static readonly Random random = new Random();
public GachaManager(Player player)
@ -176,7 +170,6 @@ namespace Campofinale.Game.Gacha
RewardIds =
{
$"reward_{transaction.rarity}starChar_weaponCoin",
},
});
@ -220,11 +213,7 @@ namespace Campofinale.Game.Gacha
}
else
{
int index = random.Next(0,items.Count); // Miglior randomizzazione
// index = (int)((1 - Math.Pow(random.NextDouble(), 2)) * (items.Count - 1));
// Se vuoi evitare di prendere spesso i primi 2-3 elementi:
// index = (int)Math.Pow(random.NextDouble(), 1.5) * items.Count;
int index = random.Next(0,items.Count);
if (index > items.Count-1)
{
index = items.Count-1;

View File

@ -1,10 +1,5 @@
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MongoDB.Bson.Serialization.IdGenerators;
namespace Campofinale.Game.Gacha

View File

@ -1,16 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Game
namespace Campofinale.Game
{
public static class GameConstants
{
//TODO, have to check if this is really userful for support different platform or if android version doesn't need the GAME_VERSION_ASSET_URL (probably not?)
//So, in case is useful only if the android build it's different than 0.5.28
/*public static List<GameVersionConst> GAME_VERSIONS = new()
{
new GameVersionConst("0.5.28"), //Windows CBT2
new GameVersionConst("0.5.5"), //Android CBT2
};*/
//Not used on top ^
public static string GAME_VERSION = "0.5.28"; //CBT 2
public static string GAME_VERSION_ANDROID = "0.5.5"; //CBT 2 ANDROID
public static string GAME_VERSION_ASSET_URL = "https://beyond.hg-cdn.com/uXUuLlNbIYmMMTlN/0.5/update/6/1/Windows/0.5.28_U1mgxrslUitdn3hb/files";//CBT 2
public static int MAX_TEAMS_NUMBER = 5; //Not used yet
public static (long, string) SERVER_UID = (99, "99"); //Not used yet, no friend chat in current Beta
}
/* public class GameVersionConst
{
public string GAME_VERSION = "0.5.28";
public string GAME_VERSION_ASSET_URL = "https://beyond.hg-cdn.com/uXUuLlNbIYmMMTlN/0.5/update/6/1/Windows/0.5.28_U1mgxrslUitdn3hb/files";//CBT 2
public GameVersionConst() { }
public GameVersionConst(string version)
{
this.GAME_VERSION = version;
}
}*/
}

View File

@ -0,0 +1,272 @@
using Campofinale.Database;
using Campofinale.Packets.Sc;
namespace Campofinale.Game.Inventory
{
public class InventoryList
{
public List<Item> items = new();
public Dictionary<int, Item> bag = new();
public int maxBagSize = 30;
public Player player;
public InventoryList(Player player)
{
this.player = player;
}
public enum FindType
{
Items,
FactoryDepots,
Bag
}
public void UpdateInventoryPacket()
{
}
public void UpdateBagInventoryPacket()
{
player.Send(new PacketScItemBagScopeSync(this.player,Resource.ItemValuableDepotType.Invalid));
}
private void AddToBagAvailableSlot(Item item)
{
for (int i = 0; i < maxBagSize; i++)
{
if (!bag.ContainsKey(i))
{
bag.Add(i, item);
return;
}
}
}
///
///<summary>Add a item directly to the bag if there is enough space or increment current stack value</summary>
///
public bool AddToBag(Item item)
{
Item existOne = Find(i=>i.id == item.id && i.amount < item.GetItemTable().maxStackCount,FindType.Bag);
if (existOne != null)
{
if(existOne.amount+item.amount > item.GetItemTable().maxStackCount)
{
int max = existOne.GetItemTable().maxStackCount;
int toAddInNewSlotAmount = existOne.amount + item.amount - max;
item.amount = toAddInNewSlotAmount;
if (SlotAvailableInBag())
{
existOne.amount = max;
AddToBagAvailableSlot(item);
UpdateBagInventoryPacket();
return true;
}
else
{
return false;
}
}
else
{
existOne.amount += item.amount;
UpdateBagInventoryPacket();
return true;
}
}
else
{
if(bag.Count < maxBagSize)
{
AddToBagAvailableSlot(item);
UpdateBagInventoryPacket();
return true;
}
else
{
return false;
}
}
}
public bool SlotAvailableInBag()
{
bool availableSlot = false;
for (int i = 0; i < maxBagSize; i++)
{
if (!bag.ContainsKey(i))
{
return true;
}
}
return availableSlot;
}
public Item FindInAll(Predicate<Item> match)
{
var item = items.Find(match);
if (item != null)
{
return item;
}
var itemB = bag.Values.ToList().Find(match);
if (itemB != null)
{
return itemB;
}
return null;
}
public Item Find(Predicate<Item> match,FindType findType = FindType.Items)
{
switch (findType)
{
case FindType.Items:
var item = items.Find(match);
if (item != null)
{
return item;
}
break;
case FindType.FactoryDepots:
//TODO
break;
case FindType.Bag:
var itemB = bag.Values.ToList().Find(match);
if (itemB != null)
{
return itemB;
}
break;
}
return null;
}
public List<Item> FindAll(Predicate<Item> match, FindType findType = FindType.Items)
{
switch (findType)
{
case FindType.Items:
return items.FindAll(match);
break;
case FindType.FactoryDepots:
//TODO
break;
case FindType.Bag:
var itemB = bag.Values.ToList().FindAll(match);
if (itemB != null)
{
return itemB;
}
break;
}
return null;
}
///<summary>
///Add an item to the inventory (or increment it's amount if it's not an instance type, else add a new one or add to bag if it's a Factory item
///</summary>
public Item Add(Item item)
{
if (item.StorageSpace() == Resource.ItemStorageSpace.BagAndFactoryDepot)
{
AddToBag(item);
return null;
}
if (item.InstanceType())
{
items.Add(item);
DatabaseManager.db.UpsertItem(item);
return item;
}
else
{
Item exist=Find(i=>i.id==item.id);
if (exist != null)
{
exist.amount += item.amount;
DatabaseManager.db.UpsertItem(exist);
return exist;
}
else
{
items.Add(item);
DatabaseManager.db.UpsertItem(item);
return item;
}
}
}
/// <summary>
/// Get the item amount from all depots
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public int GetItemAmount(string id)
{
int amt = 0;
Item item=Find(i=>i.id==id);
if (item != null)
{
amt += item.amount;
}
List<Item> bagItems = FindAll(i=>i.id==id,FindType.Bag);
foreach (Item bagItem in bagItems)
{
amt += bagItem.amount;
}
return amt;
}
public void Remove(Item item)
{
if (items.Remove(item))
{
this.player.Send(new PacketScItemBagScopeModify(this.player, item));
DatabaseManager.db.DeleteItem(item);
}
else if (RemoveFromBag(item))
{
UpdateBagInventoryPacket();
}
}
private bool RemoveFromBag(Item item)
{
for (int i = 0; i < maxBagSize; i++)
{
Item bagItem = null;
if (bag.ContainsKey(i))
{
bagItem = bag[i];
if (bagItem.guid == item.guid)
{
bag.Remove(i);
return true;
}
}
}
return false;
}
/// <summary>
/// Move item from bag grid to another position
/// </summary>
/// <param name="fromGrid"></param>
/// <param name="toGrid"></param>
public void MoveBagItem(int fromGrid, int toGrid)
{
Item item1 = bag[fromGrid];
Item item2 = null;
if (bag.ContainsKey(toGrid))
{
item2 = bag[toGrid];
}
bag[toGrid] = item1;
if (item2 != null)
{
bag[fromGrid] = item2;
}
else
{
bag.Remove(fromGrid);
}
UpdateBagInventoryPacket();
}
}
}

View File

@ -1,13 +1,6 @@
using Campofinale.Database;
using Campofinale.Packets.Sc;
using Campofinale.Resource;
using Google.Protobuf.Collections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Game.Inventory
@ -15,7 +8,7 @@ namespace Campofinale.Game.Inventory
public class InventoryManager
{
public Player owner;
public List<Item> items= new List<Item>();
public InventoryList items;
public int item_diamond_amt
{
@ -36,12 +29,12 @@ namespace Campofinale.Game.Inventory
public Item GetItemById(string id)
{
return items.Find(i => i.id == id);
return items.FindInAll(i => i.id == id);
}
public InventoryManager(Player o) {
owner = o;
items=new(o);
}
public void AddRewards(string rewardTemplateId, Vector3f pos, int sourceType=1)
{
@ -70,8 +63,12 @@ namespace Campofinale.Game.Inventory
{
id=bundle.id
};
if (!item.InstanceType())
if(bundle.id == "item_daily_activation")
{
owner.adventureBookManager.data.dailyActivation += bundle.count;
continue;
}
if (!item.InstanceType() || sourceType == 0)
{
item = AddItem(bundle.id, bundle.count);
end.RewardVirtualList.Add(new RewardItem()
@ -110,46 +107,25 @@ namespace Campofinale.Game.Inventory
}
public void Save()
{
foreach (Item item in items)
foreach (Item item in items.items)
{
DatabaseManager.db.UpsertItem(item);
}
}
public void Load()
{
items = DatabaseManager.db.LoadInventoryItems(owner.roleId);
items.items = DatabaseManager.db.LoadInventoryItems(owner.roleId);
}
public Item AddItem(string id, int amt)
public Item AddItem(string id, int amt, bool notify=false)
{
Item it = new()
{
id = id,
};
if(!it.InstanceType())
{
Item item = items.Find(i=>i.id == id);
if (item != null)
{
// Logger.Print(id + ": " + amt+" added to existing");
item.amount += amt;
return item;
}
else
{
// Logger.Print(id + ": " + amt + " added to new");
item = new Item(owner.roleId, id, amt);
items.Add(item);
return item;
}
}
else
{
//Logger.Print(id + ": " + amt + " added to new as instance");
Item item = new Item(owner.roleId, id, amt);
items.Add(item);
return item;
Item itemNew = items.Add(item);
if (notify && itemNew != null)
{
this.owner.Send(new PacketScItemBagScopeModify(this.owner, itemNew));
}
return item;
}
public void RemoveItem(Item item,int amt)
{
@ -157,9 +133,46 @@ namespace Campofinale.Game.Inventory
if(item.amount <= 0)
{
items.Remove(item);
DatabaseManager.db.DeleteItem(item);
}
else
{
this.owner.Send(new PacketScItemBagScopeModify(this.owner, item));
items.UpdateBagInventoryPacket();
}
}
public bool ConsumeItem(string id, int amt)
{
Item item=items.FindInAll(i=>i.id== id);
if (item != null)
{
if(item.amount >= amt)
{
item.amount -= amt;
if(item.amount < 1)
{
items.Remove(item);
}
else
{
this.owner.Send(new PacketScItemBagScopeModify(this.owner, item));
items.UpdateBagInventoryPacket();
}
return true;
}
else
{
int toConsume = amt - item.amount;
item.amount = 0;
items.Remove(item);
return ConsumeItem(id, toConsume);
}
}
else
{
return false;
}
}
public bool ConsumeItems(MapField<string, ulong> costItemId2Count)
{
@ -179,16 +192,8 @@ namespace Campofinale.Game.Inventory
bool found = true;
foreach (ItemInfo item in items)
{
Item i= GetItemById(item.ResId);
if (i != null)
{
if(i.amount < item.ResCount)
{
found = false;
break;
}
}
else
int amount = this.items.GetItemAmount(item.ResId);
if(amount < item.ResCount)
{
found = false;
break;
@ -196,14 +201,7 @@ namespace Campofinale.Game.Inventory
}
foreach (ItemInfo item in items)
{
Item i = GetItemById(item.ResId);
if (i != null)
{
if (i.amount >= item.ResCount)
{
RemoveItem(i,item.ResCount);
}
}
ConsumeItem(item.ResId, item.ResCount);
}
return found;
}
@ -211,13 +209,37 @@ namespace Campofinale.Game.Inventory
public Dictionary<uint, int> GetInventoryChapter(string chapterId)
{
Dictionary<uint, int> dir= new Dictionary<uint, int>();
List<Item> citems = items.FindAll(i=>!i.InstanceType());
/*List<Item> citems = items.FindAll(i=>!i.InstanceType());
foreach (Item item in citems)
{
dir.Add((uint)ResourceManager.strIdNumTable.item_id.dic[item.id], item.amount);
}
}*/
return dir;
}
public void DropItemsBag(CsItemBagAbandonInBag req)
{
if(req.TargetObjectId == 0)
{
foreach (var i in req.GridCut)
{
Item item = items.bag[i.Key];
item.amount -= i.Value;
if(item.amount <= 0)
{
items.bag.Remove(i.Key);
}
owner.sceneManager.CreateDrop(owner.position, new RewardTable.ItemBundle()
{
count=i.Value,
id=item.id,
});
}
}
items.UpdateBagInventoryPacket();
}
}
}

View File

@ -48,6 +48,10 @@ namespace Campofinale.Game.Inventory
this.level = level;
guid = GetOwner().random.Next();
}
public ItemStorageSpace StorageSpace()
{
return ResourceManager.itemTypeTable[GetItemTable().type].storageSpace;
}
public ulong GetDefaultLevel()
{
switch (ItemType)
@ -68,10 +72,15 @@ namespace Campofinale.Game.Inventory
}
public ItemValuableDepotType ItemType
{
get{
get
{
return ResourceManager.GetItemTable(id).valuableTabType;
}
}
public ItemTable GetItemTable()
{
return ResourceManager.GetItemTable(id);
}
public virtual ScdItemGrid ToProto()
{
try
@ -139,6 +148,7 @@ namespace Campofinale.Game.Inventory
Equipid = guid,
Templateid = ResourceManager.GetItemTemplateId(id),
},
IsLock = locked
}
@ -231,6 +241,7 @@ namespace Campofinale.Game.Inventory
};
GetOwner().Send(ScMsgId.ScWeaponAddExp, levelUp);
GetOwner().Send(new PacketScSyncWallet(GetOwner()));
}
}
@ -248,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;
}

View File

@ -1,11 +1,6 @@
using Campofinale.Resource;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MongoDB.Bson.Serialization.IdGenerators;
namespace Campofinale.Game

View File

@ -0,0 +1,25 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Game.MissionSys
{
public class GameMission
{
public string missionId;
public MissionState state;
public GameMission()
{
}
public GameMission(string id, MissionState state = MissionState.Available)
{
missionId = id;
this.state = state;
}
}
}

View File

@ -0,0 +1,24 @@
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Game.MissionSys
{
public class GameQuest
{
public string questId;
public QuestState state;
public GameQuest()
{
}
public GameQuest(string id, QuestState state = QuestState.Available)
{
questId = id;
this.state = state;
}
}
}

View File

@ -0,0 +1,271 @@
using Campofinale.Database;
using Campofinale.Protocol;
using Campofinale.Resource;
using Campofinale.Resource.Table;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Campofinale.Game.MissionSys
{
public class MissionSystem
{
public Player owner;
public List<GameMission> missions=new();
public List<GameQuest> quests=new();
public string curMission = "e0m0";
public MissionSystem(Player o)
{
owner = o;
}
public ScSyncAllMission ToProto()
{
if (!Server.config.serverOptions.missionsEnabled)
{
string json1 = File.ReadAllText("44_ScSyncAllMission.json");
ScSyncAllMission m = Newtonsoft.Json.JsonConvert.DeserializeObject<ScSyncAllMission>(json1);
m.TrackMissionId = "";
return m;
}
ScSyncAllMission sync = new ScSyncAllMission();
sync.TrackMissionId = curMission;
missions.ForEach(m =>
{
if(!sync.Missions.ContainsKey(m.missionId))
sync.Missions.Add(m.missionId, new Mission()
{
MissionId = m.missionId,
MissionState = (int)m.state,
});
});
quests.ForEach(q =>
{
Quest quest=new Quest()
{
QuestId = q.questId,
QuestState = (int)q.state,
};
var data = GetQuestData(q.questId);
data.objectiveList.ForEach(o =>
{
quest.QuestObjectives.Add(new QuestObjective()
{
ConditionId = o.condition.uniqueId,
Values =
{
{o.condition.uniqueId,0 }
}
});
});
sync.CurQuests.Add(q.questId, quest);
});
return sync;
}
public MissionDataTable.QuestInfo GetQuestData(string id)
{
MissionDataTable.QuestInfo quest = null;
foreach(MissionDataTable m in ResourceManager.missionDataTable)
{
if(m.questDic.TryGetValue(id, out quest))
{
return quest;
}
};
return quest;
}
public void Save()
{
DatabaseManager.db.UpsertMissionData(new MissionData()
{
roleId=owner.roleId,
curMission=curMission,
missions=missions,
quests=quests,
});
}
public void Load()
{
MissionData data= DatabaseManager.db.LoadMissionData(owner.roleId);
if (data != null)
{
curMission = data.curMission;
missions = data.missions;
quests = data.quests;
}
}
public void AddMission(string id,MissionState state = MissionState.Available, bool notify=false)
{
MissionDataTable data = ResourceManager.missionDataTable.Find(m=>m.missionId == id);
if (data != null)
{
missions.Add(new GameMission(id, state));
if (notify)
{
ScMissionStateUpdate s = new()
{
MissionId = data.missionId,
MissionState = (int)state,
SucceedId=-1,
};
}
int i = 0;
foreach (var q in data.questDic.Values)
{
AddQuest(q, false);
}
}
}
public GameQuest GetQuestById(string id)
{
return quests.Find(q => q.questId == id);
}
public void AddQuest(MissionDataTable.QuestInfo data,bool notify=false)
{
GameQuest quest = GetQuestById(data.questId);
if (quest == null)
{
quest = new GameQuest(data.questId);
quest.state = QuestState.Available;
if (notify)
{
ScQuestObjectivesUpdate upd = new()
{
QuestId = data.questId,
};
data.objectiveList.ForEach(o =>
{
upd.QuestObjectives.Add(new QuestObjective()
{
ConditionId=o.condition.uniqueId,
Values =
{
{o.condition.uniqueId,0 }
}
});
});
ScQuestStateUpdate update = new()
{
QuestId = quest.questId,
QuestState = (int)quest.state,
RoleBaseInfo = owner.GetRoleBaseInfo()
};
owner.Send(ScMsgId.ScQuestStateUpdate, update);
owner.Send(ScMsgId.ScQuestObjectivesUpdate, upd);
}
quests.Add(quest);
}
}
public void ProcessQuest(string id)
{
GameQuest quest = GetQuestById(id);
if (quest != null)
{
quest.state = QuestState.Processing;
var data = GetQuestData(id);
ScQuestStateUpdate update = new()
{
QuestId = quest.questId,
QuestState = (int)quest.state,
RoleBaseInfo = owner.GetRoleBaseInfo()
};
ScQuestObjectivesUpdate upd = new()
{
QuestId = data.questId,
};
data.objectiveList.ForEach(o =>
{
upd.QuestObjectives.Add(new QuestObjective()
{
ConditionId = o.condition.uniqueId,
Values =
{
{o.condition.uniqueId,0 }
}
});
});
owner.Send(ScMsgId.ScQuestObjectivesUpdate, upd);
owner.Send(ScMsgId.ScQuestStateUpdate, update);
}
}
public void CompleteQuest(string id)
{
GameQuest quest = GetQuestById(id);
if (quest != null)
{
quest.state = QuestState.Completed;
var data = GetQuestData(id);
ScQuestStateUpdate update = new()
{
QuestId = quest.questId,
QuestState=(int)quest.state,
};
ScQuestObjectivesUpdate upd = new()
{
QuestId = data.questId,
};
data.objectiveList.ForEach(o =>
{
upd.QuestObjectives.Add(new QuestObjective()
{
ConditionId = o.condition.uniqueId,
IsComplete=true,
Values =
{
{o.condition.uniqueId,1 }
}
});
});
owner.Send(ScMsgId.ScQuestObjectivesUpdate, upd);
owner.Send(ScMsgId.ScQuestStateUpdate, update);
quests.Remove(quest);
}
}
public void TrackMission(string v)
{
curMission = v;
owner.Send(ScMsgId.ScTrackMissionChange, new ScTrackMissionChange()
{
MissionId = curMission,
});
}
public void CompleteMission(string v)
{
if(curMission == v)
{
TrackMission("");
}
GameMission mission = missions.Find(m => m.missionId == v);
MissionDataTable data = ResourceManager.missionDataTable.Find(m => m.missionId == v);
if (mission != null && data != null)
{
mission.state=MissionState.Completed;
ScMissionStateUpdate s = new()
{
MissionId = mission.missionId,
MissionState = (int)mission.state,
SucceedId = -1,
};
owner.Send(ScMsgId.ScMissionStateUpdate, s);
//TODO rewards
}
}
}
}

View File

@ -2,17 +2,16 @@
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 SharpCompress.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Diagnostics;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using static Campofinale.Resource.Dynamic.SpawnerConfig;
using static Campofinale.Resource.ResourceManager;
using static Campofinale.Resource.ResourceManager.LevelScene.LevelData;
using static Campofinale.Resource.ResourceManager.LevelScene.LevelData.LevelFunctionAreaData;
namespace Campofinale.Game
{
@ -28,9 +27,19 @@ namespace Campofinale.Game
}
public void Update()
{
if (GetCurScene()!=null)
if (GetCurScene() != null)
{
try
{
GetCurScene().UpdateShowEntities();
}
catch(Exception e)
{
}
}
}
public Entity GetEntity(ulong guid)
{
Scene scene = scenes.Find(s => s.sceneNumId == player.curSceneNumId);
@ -49,7 +58,7 @@ namespace Campofinale.Game
public void LoadCurrentTeamEntities()
{
globalEntities.RemoveAll(e => e is EntityCharacter);
foreach (Character.Character chara in player.GetCurTeam())
foreach (Char.Character chara in player.GetCurTeam())
{
EntityCharacter ch = new(chara.guid, player.roleId);
globalEntities.Add(ch);
@ -95,24 +104,10 @@ namespace Campofinale.Game
if (scene != null)
{
if(GetEntity(guid) is EntityMonster)
Entity entity = GetEntity(guid);
if (entity != null)
{
EntityMonster monster = (EntityMonster)GetEntity(guid);
CreateDrop(monster.Position, new RewardTable.ItemBundle()
{
id = "item_gem_rarity_3",
count=1
});
LevelScene lv_scene = ResourceManager.GetLevelData(GetEntity(guid).sceneNumId);
LevelEnemyData d = lv_scene.levelData.enemies.Find(l => l.levelLogicId == monster.guid);
if (d != null)
{
if (!d.respawnable)
{
player.noSpawnAnymore.Add(monster.guid);
}
}
}
entity.OnDie();
if (killClient)
{
ScSceneDestroyEntity destroy = new()
@ -122,15 +117,26 @@ namespace Campofinale.Game
SceneNumId = GetEntity(guid).sceneNumId,
};
player.Send(Protocol.ScMsgId.ScSceneDestroyEntity, destroy);
}
if (GetEntity(guid) != null)
if (entity is EntityMonster monster)
{
if(scenes.Find(s => s.sceneNumId == GetEntity(guid).sceneNumId) != null)
LevelScene lv_scene = ResourceManager.GetLevelData(entity.sceneNumId);
LevelEnemyData d = lv_scene.levelData.enemies.Find(l => l.levelLogicId == monster.guid);
if (d != null)
{
scenes.Find(s => s.sceneNumId == GetEntity(guid).sceneNumId).entities.Remove(GetEntity(guid));
if (!d.respawnable)
{
player.noSpawnAnymore.Add(monster.guid);
}
}
}
if (scenes.Find(s => s.sceneNumId == entity.sceneNumId) != null)
{
scenes.Find(s => s.sceneNumId == entity.sceneNumId).entities.Remove(entity);
}
}
}
}
@ -222,18 +228,22 @@ namespace Campofinale.Game
{
return scenes.Find(s=>s.sceneNumId == sceneNumId).guid;
}
//TODO Save and get
public void Load()
{
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
});
}
}
@ -244,13 +254,17 @@ namespace Campofinale.Game
{
if (scene != null)
{
scene.alreadyLoaded = false;
scene.Unload();
}
}
}
}
public class LevelScript
{
public ulong scriptId;
public int state;
public Dictionary<string, ScriptProperty> properties = new();
}
public class Scene
{
public ulong ownerId;
@ -260,7 +274,11 @@ namespace Campofinale.Game
[BsonIgnore,JsonIgnore]
public List<Entity> entities = new();
[BsonIgnore, JsonIgnore]
public bool alreadyLoaded = false;
public List<ulong> activeScripts = new();
public List<LevelScript> scripts = new();
public int grade = 1;
public int GetCollection(string id)
{
if (collections.ContainsKey(id))
@ -285,12 +303,14 @@ namespace Campofinale.Game
{
return entities.FindAll(c => c is not EntityCharacter);
}
public void Unload()
{
List<ulong> guids = new();
foreach(Entity e in entities)
foreach(Entity e in GetEntityExcludingChar().FindAll(e => e.spawned))
{
guids.Add(e.guid);
e.spawned = false;
}
entities.Clear();
GetOwner().Send(new PacketScObjectLeaveView(GetOwner(), guids));
@ -301,14 +321,27 @@ namespace Campofinale.Game
}
public void Load()
{
if (info().isSeamless && alreadyLoaded) return;
alreadyLoaded = true;
if (grade == 0)
{
grade = 1;
}
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 (en.defaultHide || GetOwner().noSpawnAnymore.Contains(en.levelLogicId))
if (GetOwner().noSpawnAnymore.Contains(en.levelLogicId) && sceneNumId != 87)
{
return;
}
@ -325,7 +358,7 @@ namespace Campofinale.Game
});
lv_scene.levelData.factoryRegions.ForEach(en =>
{
if (en.defaultHide || GetOwner().noSpawnAnymore.Contains(en.levelLogicId))
if (GetOwner().noSpawnAnymore.Contains(en.levelLogicId) && sceneNumId!=87)
{
return;
}
@ -336,23 +369,27 @@ namespace Campofinale.Game
levelLogicId = en.levelLogicId,
type = en.entityType,
};
entities.Add(entity);
});
lv_scene.levelData.enemies.ForEach(en =>
{
if(en.defaultHide || GetOwner().noSpawnAnymore.Contains(en.levelLogicId)) return;
EntityMonster entity = new(en.entityDataIdKey,en.level,ownerId,en.position,en.rotation, sceneNumId, en.levelLogicId)
if(GetOwner().noSpawnAnymore.Contains(en.levelLogicId) && sceneNumId != 87) return;
EntityMonster entity = new(en.entityDataIdKey,sceneGrade.monsterBaseLevel+ en.level,ownerId,en.position,en.rotation, sceneNumId, en.levelLogicId)
{
type=en.entityType,
belongLevelScriptId=en.belongLevelScriptId,
levelLogicId = en.levelLogicId
levelLogicId = en.levelLogicId,
};
entity.defaultHide=en.defaultHide;
entities.Add(entity);
});
lv_scene.levelData.npcs.ForEach(en =>
{
if (en.defaultHide) return;
if (en.npcGroupId.Contains("chr")) return;
if (en.npcGroupId.Contains("chr") && sceneNumId == 98) return;
EntityNpc entity = new(en.entityDataIdKey,ownerId,en.position,en.rotation, sceneNumId, en.levelLogicId)
{
belongLevelScriptId = en.belongLevelScriptId,
@ -360,39 +397,75 @@ namespace Campofinale.Game
type = en.entityType,
};
entity.defaultHide = en.defaultHide;
entities.Add(entity);
});
/*GetEntityExcludingChar().ForEach(e =>
GetOwner().factoryManager.chapters.ForEach(ch =>
{
GetOwner().Send(new PacketScObjectEnterView(GetOwner(),new List<Entity>() { e}));
});*/
UpdateShowEntities();
ch.nodes.ForEach(n =>
{
if (n.sceneNumId == sceneNumId)
{
n.SendEntity(GetOwner(), ch.chapterId);
}
public void UpdateShowEntities()
{
foreach(Entity en in GetEntityExcludingChar())
{
if (en.Position.Distance(GetOwner().position) < 200)
{
if (!en.spawned)
});
});
UpdateShowEntities();
}
public void SpawnEntity(Entity en,bool spawnedCheck=true)
{
en.spawned = true;
GetOwner().Send(new PacketScObjectEnterView(GetOwner(), new List<Entity>() { en }));
}
public bool GetActiveScript(ulong id)
{
LevelScript script = scripts.Find(s => s.scriptId == id);
if (script != null)
{
return script.state > 2;
}
else
{
if (en.spawned)
{
en.spawned = false;
GetOwner().Send(new PacketScObjectLeaveView(GetOwner(), new List<ulong>() { en.guid }));
en.Position=en.BornPos;
en.Rotation = en.Rotation;
return true;
}
}
//Bug on scene 101: spawning entities in this way make the game break if you try to load another scene from scene 101
public async void UpdateShowEntities()
{
List<Entity> toSpawn = new();
List<Entity> toCheck = GetEntityExcludingChar().FindAll(e => e.spawned == false);
toCheck.Sort((a, b) => a.Position.Distance(GetOwner().position).CompareTo(b.Position.Distance(GetOwner().position)));
foreach (Entity e in toCheck)
{
if(e.Position.Distance(GetOwner().position) > 300 && sceneNumId != 87)
{
continue;
}
if(e.spawned==false)
{
if (!e.defaultHide)
{
if (GetActiveScript(e.belongLevelScriptId))
{
toSpawn.Add(e);
e.spawned = true;
}
}
}
}
if (toSpawn.Count > 0)
{
for (int i = 0; i < toSpawn.Count; i += 5)
{
int chunkSize = Math.Min(5, toSpawn.Count - i);
var chunk = toSpawn.GetRange(i, chunkSize);
GetOwner().Send(new PacketScObjectEnterView(GetOwner(), chunk));
}
}
}
@ -400,5 +473,64 @@ namespace Campofinale.Game
{
return Server.clients.Find(c => c.roleId == ownerId);
}
public void SpawnEnemyByScriptId(ulong id)
{
GetEntityExcludingChar().FindAll(e => e.belongLevelScriptId == id).ForEach(e =>
{
e.spawned = true;
});
GetOwner().Send(new PacketScObjectEnterView(GetOwner(), GetEntityExcludingChar().FindAll(e => e.belongLevelScriptId == id)));
}
public void SpawnEnemy(ulong v, bool scriptSpawn=false)
{
LevelScene lv_scene = ResourceManager.GetLevelData(sceneNumId);
LevelEnemyData en = lv_scene.levelData.enemies.Find(e=>e.levelLogicId == v);
if(en!=null)
{
EntityMonster entity = new(en.entityDataIdKey, en.level, ownerId, en.position, en.rotation, sceneNumId, en.levelLogicId)
{
type = en.entityType,
belongLevelScriptId = en.belongLevelScriptId,
levelLogicId = en.levelLogicId,
};
entities.Add(entity);
Logger.Print($"Enemy Id {v} found on scene {sceneNumId}:{lv_scene.mapIdStr}");
SpawnEntity(entity);
}
else
{
Logger.PrintWarn($"Enemy Id {v} not found on scene {sceneNumId}:{lv_scene.mapIdStr}");
}
}
public void SpawnWaveEnemy(ulong spawnerId, int waveId)
{
LevelSpawnerData data=info().levelData.spawners.Find(s => s.spawnerId == spawnerId);
if (data!=null)
{
SpawnerConfig config = spawnerConfigs.Find(s => s.configId == data.configId);
if (config != null)
{
foreach(var group in config.waveMap[$"{waveId}"].groupMap.Values)
{
foreach (var act in group.actionMap.Values)
{
EnemyLibraryData enemyData = config.enemyLibrary.Find(e=>e.key==act.libraryKey);
if (enemyData != null)
{
entities.Add(new EntityMonster(enemyData.enemyId, enemyData.enemyLevel, ownerId, act.position, act.rotation, sceneNumId)
{
defaultHide = false,
spawned = false,
belongLevelScriptId = data.belongLevelScriptId
});
}
}
}
}
}
}
}
}

View File

@ -1,11 +1,5 @@
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
using MongoDB.Bson.Serialization.IdGenerators;
using Campofinale.Resource;
@ -46,6 +40,7 @@ namespace Campofinale.Game.Spaceship
IsWorking = isWorking,
PhysicalStrength = physicalStrength,
StationedRoomId = stationedRoomId,
Skills =
{
new ScdSpaceshipCharSkill()

View File

@ -1,15 +1,6 @@
using Campofinale.Database;
using Campofinale.Game.Inventory;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MongoDB.Bson.Serialization.IdGenerators;
using static Campofinale.Resource.ResourceManager;
using Campofinale.Resource;
using Campofinale.Resource.Table;
namespace Campofinale.Game.Spaceship
{
@ -84,6 +75,39 @@ namespace Campofinale.Game.Spaceship
}
}
}
public void GiftToChar(CsSpaceshipPresentGiftToChar req)
{
SpaceshipChar chara = GetChar(req.CharId);
if (chara != null)
{
foreach (var item in req.Gifts)
{
GiftItemTable giftItem = ResourceManager.giftItemTable[item.Id];
chara.favorability += giftItem.favorablePoint * item.Count;
//TODO item consume
}
ScSpaceshipPresentGiftToChar confirm = new()
{
CurFav = chara.favorability,
CharId = chara.id,
RecvGiftCnt = req.Gifts.Count,
};
//TODO packet class
/*ScSpaceshipCharFavorabilityChange change = new()
{
ChangeInfos =
{
new SpaceshipCharFavorabilityChangeInfo()
{
CharId = chara.id,
CurFav=chara.favorability,
}
}
};*/
owner.Send(Protocol.ScMsgId.ScSpaceshipPresentGiftToChar, confirm);
}
}
}

View File

@ -1,10 +1,5 @@
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
using Campofinale.Resource;
using MongoDB.Bson.Serialization.IdGenerators;

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Game
namespace Campofinale.Game
{
public class Team
{

View File

@ -1,18 +1,6 @@
using Campofinale.Database;
using Campofinale.Game;
using Campofinale.Game.Gacha;
using Google.Protobuf.WellKnownTypes;
using Campofinale.Game;
using HttpServerLite;
using MongoDB.Bson.IO;
using SQLite;
using SQLiteNetExtensions.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Channels;
using System.Threading.Tasks;
using static Campofinale.Game.Gacha.GachaManager;
using Newtonsoft.Json;
namespace Campofinale.Http
{
@ -65,11 +53,10 @@ namespace Campofinale.Http
await data(ctx);
}
[StaticRoute(HttpServerLite.HttpMethod.POST, "/u8/pay/getAllProductList")]
public static async Task getAllProductList(HttpContext ctx)
[StaticRoute(HttpServerLite.HttpMethod.GET, "/serverStatus")]
public static async Task serverStatus(HttpContext ctx)
{
string resp = "{\"productList\":[]}";
string resp = "{\"maxPlayers\":" + Server.config.serverOptions.maxPlayers + ", \"players\":" + Server.clients.Count + ", \"status\":\"Online\", \"gameVersion\": \"" + GameConstants.GAME_VERSION + "\", \"serverVersion\": \"" + Server.ServerVersion + "\"}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentLength = resp.Length;
@ -77,6 +64,53 @@ namespace Campofinale.Http
await ctx.Response.SendAsync(resp);
}
public class U8ProductInfo
{
public string app_id;
public string channel_id;
public int world_id;
public int store_id;
public string product_id;
public string desc;
public string name;
public int type;
public long price;
public string extra_data;
public string appstore_id;
public string channel_product_id;
}
public class U8ProductListData
{
public List<U8ProductInfo> productList = new();
}
[StaticRoute(HttpServerLite.HttpMethod.POST, "/u8/pay/getAllProductList")]
public static async Task getAllProductList(HttpContext ctx)
{
string resp = "{\"productList\":[]}";
U8ProductListData rsp = new();
rsp.productList.Add(new U8ProductInfo()
{
appstore_id="0",
app_id="1",
channel_id="1",
channel_product_id="1",
desc="Test",
name="Test",
price=10,
type=0,
product_id="1",
store_id=1,
world_id=0,
});
resp = JsonConvert.SerializeObject(rsp);
ctx.Response.StatusCode = 200;
ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
//WINDOWS
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/game/get_latest")]
public static async Task get_latest(HttpContext ctx)
{
@ -89,6 +123,18 @@ namespace Campofinale.Http
await ctx.Response.SendAsync(resp);
}
//ANDROID
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/game/get_latest_game_info")]
public static async Task get_latest_game_info(HttpContext ctx)
{
string resp = "{\"version\":\""+ GameConstants.GAME_VERSION_ANDROID + "\",\"action\":0,\"update_type\":0,\"update_info\":{\"package\":null,\"patch\":null,\"custom_info\":\"\",\"source_package\":null},\"client_version\":\"\"}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/1003/prod-cbt/default/default/network_config")]
public static async Task network_config(HttpContext ctx)
{
@ -100,21 +146,11 @@ namespace Campofinale.Http
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/3/prod-cbt/default/default/network_config")]
public static async Task network_config_cn(HttpContext ctx)
{
string resp = "{\"asset\":\"https://beyond.hg-cdn.com/asset/\",\"hgage\":\"\",\"sdkenv\":\"2\",\"u8root\":\"https://u8.gryphline.com/u8\",\"appcode\":4,\"channel\":\"prod\",\"netlogid\":\"GFz8RRMDN45w\",\"gameclose\":false,\"netlogurl\":\"http://native-log-collect.gryphline.com:32000/\",\"accounturl\":\"https://binding-api-account-prod.gryphline.com\",\"launcherurl\":\"https://launcher.gryphline.com\"}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/1003/prod-cbt/default/Windows/game_config")]
public static async Task game_config(HttpContext ctx)
{
string resp = "{\"mockLogin\": false, \"selectSrv\": false, \"enableHotUpdate\": false, \"enableEntitySpawnLog\": false}";
string resp = "{\"mockLogin\": false, \"selectSrv\": false, \"enableHotUpdate\": false, \"enableEntitySpawnLog\": false, \"enableCBT2AccessForbidden\": false}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentLength = resp.Length;
@ -122,13 +158,15 @@ namespace Campofinale.Http
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/3/prod-cbt/default/Windows/game_config")]
public static async Task game_config_cn(HttpContext ctx)
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/1003/prod-cbt/default/Windows/res_version")]
public static async Task os_windows_res_version(HttpContext ctx)
{
string resp = "{\"mockLogin\": false, \"selectSrv\": false, \"enableHotUpdate\": false, \"enableEntitySpawnLog\": false}";
string resp = "{\"version\": \"2089329-32\", \"kickFlag\": true}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentLength = resp.Length;
//ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
@ -151,7 +189,25 @@ namespace Campofinale.Http
[StaticRoute(HttpServerLite.HttpMethod.GET, "/app/v1/config")]
public static async Task config_check(HttpContext ctx)
{
string resp = "{\"data\":{\"agreementUrl\":{\"register\":\"https://user.gryphline.com/{language}/protocol/plain/terms_of_service\",\"privacy\":\"https://user.gryphline.com/{language}/protocol/plain/privacy_policy\",\"unbind\":\"https://user.gryphline.com/{language}/protocol/plain/endfield/privacy_policy\",\"account\":\"https://user.gryphline.com/{language}/protocol/plain/terms_of_service\",\"game\":\"https://user.gryphline.com/{language}/protocol/plain/endfield/privacy_policy\"},\"app\":{\"googleAndroidClientId\":\"\",\"googleIosClientId\":\"\",\"enableAutoLogin\":true,\"enablePayment\":true,\"enableGuestRegister\":false,\"needShowName\":true,\"displayName\":{\"en-us\":\"Arknights: Endfield\",\"ja-jp\":\"アークナイツ:エンドフィールド\",\"ko-kr\":\"명일방주:엔드필드\",\"zh-cn\":\"明日方舟:终末地\",\"zh-tw\":\"明日方舟:終末地\"},\"unbindAgreement\":[],\"unbindLimitedDays\":30,\"unbindCoolDownDays\":14,\"customerServiceUrl\":\"https://gryphline.helpshift.com/hc/{language}/4-arknights-endfield\",\"enableUnbindGrant\":false},\"customerServiceUrl\":\"https://gryphline.helpshift.com/hc/{language}/4-arknights-endfield\",\"thirdPartyRedirectUrl\":\"https://web-api.gryphline.com/callback/thirdPartyAuth.html\",\"scanUrl\":{\"login\":\"yj://scan_login\"},\"loginChannels\":[],\"userCenterUrl\":\"https://user.gryphline.com/pcSdk/userInfo?language={language}\"},\"msg\":\"OK\",\"status\":0,\"type\":\"A\"}";
string appCode = ctx.Request.Query.Elements["appCode"];
string resp = "{\"data\":{\"agreementUrl\":{\"register\":\"https://user.gryphline.com/{language}/protocol/plain/terms_of_service\",\"privacy\":\"https://user.gryphline.com/{language}/protocol/plain/privacy_policy\",\"unbind\":\"https://user.gryphline.com/{language}/protocol/plain/endfield/privacy_policy\",\"account\":\"https://user.gryphline.com/{language}/protocol/plain/terms_of_service\",\"game\":\"https://user.gryphline.com/{language}/protocol/plain/endfield/privacy_policy\"},\"app\":{\"googleAndroidClientId\":\"\",\"googleIosClientId\":\"\",\"enableAutoLogin\":true,\"enablePayment\":true,\"enableGuestRegister\":true,\"needShowName\":true,\"displayName\":{\"en-us\":\"Arknights: Endfield\",\"ja-jp\":\"アークナイツ:エンドフィールド\",\"ko-kr\":\"명일방주:엔드필드\",\"zh-cn\":\"明日方舟:终末地\",\"zh-tw\":\"明日方舟:終末地\"},\"unbindAgreement\":[],\"unbindLimitedDays\":30,\"unbindCoolDownDays\":14,\"customerServiceUrl\":\"https://gryphline.helpshift.com/hc/{language}/4-arknights-endfield\",\"enableUnbindGrant\":false},\"customerServiceUrl\":\"https://gryphline.helpshift.com/hc/{language}/4-arknights-endfield\",\"thirdPartyRedirectUrl\":\"https://web-api.gryphline.com/callback/thirdPartyAuth.html\",\"scanUrl\":{\"login\":\"yj://scan_login\"},\"loginChannels\":[],\"userCenterUrl\":\"https://user.gryphline.com/pcSdk/userInfo?language={language}\"},\"msg\":\"OK\",\"status\":0,\"type\":\"A\"}";
if(appCode == "a65356244d22261b")
{
resp = "{ \"data\": { \"antiAddiction\": { \"minorPeriodEnd\": 21, \"minorPeriodStart\": 20 }, \"payment\": [ { \"key\": \"alipay\", \"recommend\": true }, { \"key\": \"wechat\", \"recommend\": false }, { \"key\": \"pcredit\", \"recommend\": false } ], \"customerServiceUrl\": \"https://chat.hypergryph.com/chat/h5/v2/index.html?sysnum=889ee281e3564ddf883942fe85764d44&channelid=2\", \"cancelDeactivateUrl\": \"https://user-stable.hypergryph.com/cancellation\", \"agreementUrl\": { \"game\": \"https://hg-protocol-static-web-stable.hypergryph.net/protocol/plain/ak/index\", \"unbind\": \"https://hg-protocol-static-web-stable.hypergryph.net/protocol/plain/ak/cancellation\", \"gameService\": \"https://hg-protocol-static-web-stable.hypergryph.net/protocol/plain/ak/service\", \"account\": \"https://user.hypergryph.com/protocol/plain/index\", \"privacy\": \"https://user.hypergryph.com/protocol/plain/privacy\", \"register\": \"https://user.hypergryph.com/protocol/plain/registration\", \"updateOverview\": \"https://user.hypergryph.com/protocol/plain/overview_of_changes\", \"childrenPrivacy\": \"https://user.hypergryph.com/protocol/plain/children_privacy\" }, \"app\": { \"enablePayment\": true, \"enableAutoLogin\": true, \"enableAuthenticate\": true, \"enableAntiAddiction\": true, \"enableUnbindGrant\": true, \"wechatAppId\": \"wxeea7cc50e03edb28\", \"alipayAppId\": \"2021004129658342\", \"oneLoginAppId\": \"496b284079be97612a46266a9fdbfbd7\", \"enablePaidApp\": false, \"appName\": \"明日方舟终末地\", \"appAmount\": 600, \"needShowName\": true, \"customerServiceUrl\": \"https://web-biz-platform-cs-center-stable.hypergryph.net/hg/?hg_token={hg_token}&source_from=sdk\", \"needAntiAddictionAlert\": true, \"enableScanLogin\": false, \"deviceCheckMode\": 0, \"enableGiftCode\": false }, \"scanUrl\": { \"login\": \"hypergryph://scan_login\" }, \"userCenterUrl\": \"https://user-center-account-stable.hypergryph.net/pcSdk/userInfo\" }, \"msg\": \"OK\", \"status\": 0, \"type\": \"A\"}";
}
ctx.Response.StatusCode = 200;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/general/v1/server_time")]
public static async Task server_time(HttpContext ctx)
{
string resp = "{\"data\":{\"serverTime\":1748021408,\"isHoliday\":true},\"msg\":\"OK\",\"status\":0,\"type\":\"A\"}";
@ -169,35 +225,8 @@ namespace Campofinale.Http
public string password;
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/3/prod-cbt/default/Windows/res_version")]
public static async Task cn_res_version(HttpContext ctx)
{
string resp = "{\"version\": \"2089329-32\", \"kickFlag\": true}";
ctx.Response.StatusCode = 200;
//ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/3/prod-cbt/default/default/server_config_China")]
public static async Task server_config_China(HttpContext ctx)
{
string requestBody = ctx.Request.DataAsString;
Console.WriteLine(requestBody);
string resp = "{\"addr\": \"" + Server.config.gameServer.accessAddress + "\", \"port\": " + Server.config.gameServer.accessPort + "}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/1003/prod-cbt/default/default/server_config_EUAndUS")]
public static async Task server_config_EUAndUS(HttpContext ctx)
{
@ -259,6 +288,31 @@ namespace Campofinale.Http
await ctx.Response.SendAsync(resp);
}
//ANDROID
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/1003/prod-cbt/default/Android/res_version")]
public static async Task os_android_res_version(HttpContext ctx)
{
string resp = "{\"version\": \"2413221-312\", \"kickFlag\": false}";
ctx.Response.StatusCode = 200;
//ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/1003/prod-cbt/default/Android/game_config")]
public static async Task game_config_os_android(HttpContext ctx)
{
string resp = "{\"mockLogin\": false, \"selectSrv\": false, \"enableHotUpdate\": true, \"enableNpcOptimize\": false, \"enableEntitySpawnLog\": false, \"enableCBT2AccessForbidden\": false, \"enableMobileFullScreenWaterMark\": false}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
public static async Task data(HttpContext ctx)
{

View File

@ -0,0 +1,90 @@
using HttpServerLite;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Http
{
internal class DispatchCN
{
//SERVER
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/3/prod-cbt/default/default/server_config_China")]
public static async Task server_config_China(HttpContext ctx)
{
string requestBody = ctx.Request.DataAsString;
Console.WriteLine(requestBody);
string resp = "{\"addr\": \"" + Server.config.gameServer.accessAddress + "\", \"port\": " + Server.config.gameServer.accessPort + "}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
//DEFAULT
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/3/prod-cbt/default/default/network_config")]
public static async Task network_config_cn(HttpContext ctx)
{
string resp = "{ \"asset\": \"https://beyond.hycdn.cn/asset/\", \"hgage\": \"https://web.hycdn.cn/endfield/protocol/cadpa-age.txt\", \"sdkenv\": \"2\", \"u8root\": \"https://as.hypergryph.com/u8\", \"appcode\": 4, \"channel\": \"prod\", \"netlogid\": \"56RqF5G2gU9j\", \"gameclose\": false, \"netlogurl\": \"http://native-log-collect.hypergryph.com:32000\", \"accounturl\": \"https://binding-api-account-prod.hypergryph.com\", \"launcherurl\": \"https://launcher.hypergryph.com\"}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
//WINDOWS
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/3/prod-cbt/default/Windows/res_version")]
public static async Task cn_res_version(HttpContext ctx)
{
string resp = "{\"version\": \"2089329-32\", \"kickFlag\": false}";
ctx.Response.StatusCode = 200;
//ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/3/prod-cbt/default/Windows/game_config")]
public static async Task game_config_cn_windows(HttpContext ctx)
{
string resp = "{\"mockLogin\": false, \"selectSrv\": false, \"enableHotUpdate\": true, \"enableEntitySpawnLog\": false, \"enableCBT2AccessForbidden\": false}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
//ANDROID
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/3/prod-cbt/default/Android/res_version")]
public static async Task cn_android_res_version(HttpContext ctx)
{
string resp = "{\"version\": \"2377591-182\", \"kickFlag\": false}";
ctx.Response.StatusCode = 200;
//ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/api/remote_config/get_remote_config/3/prod-cbt/default/Android/game_config")]
public static async Task game_config_cn_android(HttpContext ctx)
{
string resp = "{\"mockLogin\": false, \"selectSrv\": false, \"enableHotUpdate\": true, \"enableNpcOptimize\": false, \"enableEntitySpawnLog\": false, \"enableCBT2AccessForbidden\": false, \"enableMobileFullScreenWaterMark\": false}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
}
}

View File

@ -0,0 +1,145 @@
using Campofinale.Database;
using HttpServerLite;
using MongoDB.Driver;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using static Campofinale.Http.GateBulletin.DetailRsp;
using static Campofinale.Http.GateBulletin.DetailRsp.DetailData;
using static System.Net.Mime.MediaTypeNames;
namespace Campofinale.Http
{
public class GateBulletin
{
//http://192.168.1.3:5000/bulletin/aggregate?lang=en-us&platform=Windows&server=EUAndUS&type=0&code=endfield_cbt2_overseas&hideDetail=1
public class AggregateRsp
{
public int code = 0;
public string msg = "";
public Data data = new Data();
public class Data
{
public string topicCid = "2113";
public int type = 1;
public string platform = "Windows";
public string server = "#DEFAULT";
public string channel = "#DEFAULT";
public string lang = "en";
public string key = "1:Windows:#DEFAULT:#DEFAULT:en";
public string version = "d41d8cd98f00b204e9800998ecf8427e";
public List<string> onlineList = new();
public List<string> popupList = new();
public int popupVersion;
public int updatedAt = 0;
public List<BulletinEntry> list = new();
public class BulletinEntry
{
public string cid;
public string type;
public string tab;
public string title;
public int startAt;
public string? tag;
public int? sort;
}
}
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/bulletin/aggregate")]
public static async Task bulletin_aggregate(HttpContext ctx)
{
string resp = "{}";
AggregateRsp rsp = new();
rsp.data.list.Add(new AggregateRsp.Data.BulletinEntry()
{
cid = "1",
title = "Endfield Private Server",
type = "news",
tab = "news",
sort = 0,
tag = "campaign",
startAt = 0,
});
rsp.data.list.Add(new AggregateRsp.Data.BulletinEntry()
{
cid = "2",
title = "Informations",
type = "news",
tab = "news",
sort = 1,
tag = "campaign",
startAt = 0,
});
resp = JsonConvert.SerializeObject(rsp);
ctx.Response.StatusCode = 200;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
public class DetailRsp
{
public int code = 0;
public string msg = "";
public DetailData data=new();
public class DetailData
{
public string title = "Test";
public string header = "Test";
public TextData data = new();
public string content = "null";
public string displayType = "rich_text";
public class TextData
{
public string html;
public string text;
}
}
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/bulletin/detail/2")]
public static async Task bulletin_1(HttpContext ctx)
{
string resp = "{}";
DetailRsp rsp = new();
rsp.data.title = "Informations";
rsp.data.header = "Informations";
rsp.data.data = new TextData()
{
html= "Repository <a href='https://git.muiegratis.online/suikoakari/Campofinale'>https://git.muiegratis.online/suikoakari/Campofinale</a>",
};
resp = JsonConvert.SerializeObject(rsp);
ctx.Response.StatusCode = 200;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/bulletin/detail/1")]
public static async Task bulletin_2(HttpContext ctx)
{
string resp = "{}";
DetailRsp rsp = new();
rsp.data.title = "Endfield Private Server";
rsp.data.header = "Endfield Private Server";
rsp.data.data = new TextData()
{
html = "Welcome to Campofinale! A private server for Arknights: Endfield!",
};
resp = JsonConvert.SerializeObject(rsp);
ctx.Response.StatusCode = 200;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
}
}

View File

@ -1,10 +1,6 @@
using Campofinale.Commands;
using Campofinale.Commands.Handlers;
using Campofinale.Database;
using HttpServerLite;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -30,7 +26,8 @@ namespace Campofinale.Http
[StaticRoute(HttpServerLite.HttpMethod.GET, "/pcSdk/console")]
public static async Task ConsoleResponce(HttpContext ctx)
{
string cmd = ctx.Request.Query.Elements["command"].Replace("+"," ");
string encodedCmd = Uri.UnescapeDataString(ctx.Request.Query.Elements["command"]);
string cmd = Encoding.UTF8.GetString(Convert.FromBase64String(encodedCmd));
string token = ctx.Request.Query.Elements["token"];
string message = "";
string[] split = cmd.Split(" ");

View File

@ -1,11 +1,9 @@
using Campofinale.Database;
using Campofinale.Resource;
using HttpServerLite;
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json;
using static Campofinale.Game.Gacha.GachaManager;
using static Campofinale.Http.Dispatch;
@ -20,16 +18,24 @@ namespace Campofinale.Http
string requestBody = ctx.Request.DataAsString;
Console.WriteLine(requestBody);
string resp = "{}";
ctx.Response.StatusCode = 200;
//ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/user/pay/v1/query_app_order")]
public static async Task query_app_order(HttpContext ctx)
{
string requestBody = ctx.Request.DataAsString;
Console.WriteLine(requestBody);
string resp = "{\"data\":{\"paidApp\":true,\"hasMinorOrder\":false},\"msg\":\"OK\",\"status\":0,\"type\":\"A\"}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.POST, "/user/auth/v1/token_by_phone_password")]
public static async Task token_login_phone_cn(HttpContext ctx)
{
@ -48,7 +54,6 @@ namespace Campofinale.Http
}
ctx.Response.StatusCode = 200;
//ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
@ -72,14 +77,17 @@ namespace Campofinale.Http
}
ctx.Response.StatusCode = 200;
//ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/batch_event")]
public static async Task batch_event(HttpContext ctx)
{
await ctx.Response.SendAsync("OK");
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/user/info/v1/basic")]
public static async Task account_info_get(HttpContext ctx)
{
@ -88,7 +96,10 @@ namespace Campofinale.Http
string resp = "{\"data\":{\"hgId\":\"1799321925\",\"email\":\"dispatch@endfield.ps\",\"realEmail\":\"dispatch@endfield.ps\",\"isLatestUserAgreement\":true,\"nickName\":\"Campofinale\"},\"msg\":\"OK\",\"status\":0,\"type\":1}";
if (account != null)
{
resp = "{\"data\":{\"idCardNum\": 110102200610048887,\"hgId\":\"" + account.id + "\",\"email\":\"" + account.username +Server.config.dispatchServer.emailFormat +"\",\"realEmail\":\"" + account.username + Server.config.dispatchServer.emailFormat + "\",\"isLatestUserAgreement\":true,\"nickName\":\"" + account.username + "\",\"name\":\"AAAA\"},\"msg\":\"OK\",\"status\":0,\"type\":1}";
/*
* {"data":{"hgId":"**********","phone":"153****5243","email":null,"identityNum":"5002**********1619","identityName":"金*","isMinor":false,"isLatestUserAgreement":true},"msg":"OK","status":0,"type":"A"}
*/
resp = "{\"data\":{\"phone\":\"153****5243\", \"identityNum\": \"5002**********1619\",\"identityName\":\"金*\",\"isMinor\":false,\"hgId\":\"" + account.id + "\",\"email\":\"" + account.username +Server.config.dispatchServer.emailFormat +"\",\"realEmail\":\"" + account.username + Server.config.dispatchServer.emailFormat + "\",\"isLatestUserAgreement\":true,\"nickName\":\"" + account.username + "\"},\"msg\":\"OK\",\"status\":0,\"type\":\"A\"}";
}
else
{
@ -99,27 +110,74 @@ namespace Campofinale.Http
ctx.Response.StatusCode = 200;
//ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
public struct GrantData
public class GrantReqData
{
public string token;
public string encodeNonce;
public string appCode;
}
[StaticRoute(HttpServerLite.HttpMethod.POST, "/user/oauth2/v2/grant")]
public static async Task account_ugrant(HttpContext ctx)
public class GrantRsp
{
public Data data;
public string msg;
public int status;
public string type;
public class Data
{
public string token;
public string code;
public string hgId;
public string uid;
public string encodeSign;
}
}
/*[StaticRoute(HttpServerLite.HttpMethod.POST, "/user/oauth2/v2/grant")]
public static async Task account_ugrant_old(HttpContext ctx)
{
string requestBody = ctx.Request.DataAsString;
GrantData grant = Newtonsoft.Json.JsonConvert.DeserializeObject<GrantData>(requestBody);
GrantReqData grant = Newtonsoft.Json.JsonConvert.DeserializeObject<GrantReqData>(requestBody);
Account account = DatabaseManager.db.GetAccountByToken(grant.token);
string resp = "{\"msg\": \"Error\", \"status\": 2, \"type\": \"A\"}";
if (account != null)
{
resp = "{\"data\": { \"uid\": \"" + account.id + "\", \"code\": \"" + DatabaseManager.db.GrantCode(account) + "\" }, \"msg\": \"OK\", \"status\": 0, \"type\": \"A\"}";
if(grant.appCode== "2289f1dd2b923c53")
{
var url = "https://as.hypergryph.com/user/oauth2/v2/grant";
var b = new
{
appCode = "2289f1dd2b923c53",
encodeNonce = grant.encodeNonce,
token = "/kKCPAzTCkGOKft+X7sE7T0W",
type = 1
};
var json = JsonSerializer.Serialize(b);
var handler = new HttpClientHandler
{
UseProxy = false,
};
using var client = new HttpClient(handler);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, content);
var responseString = await response.Content.ReadAsStringAsync();
Logger.Print(responseString);
GrantRspOff rsp = JsonSerializer.Deserialize<GrantRspOff>(responseString);
resp = "{ \"data\": { \"token\": \"" + DatabaseManager.db.GrantCode(account) + "\", \"hgId\": \"" + account.id + "\", \"encodeSign\": \""+ rsp.data.encodeSign + "\" }, \"msg\": \"OK\", \"status\": 0, \"type\": \"A\"}";
}
}
ctx.Response.StatusCode = 200;
@ -127,25 +185,70 @@ namespace Campofinale.Http
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}*/
[StaticRoute(HttpServerLite.HttpMethod.POST, "/user/oauth2/v2/grant")]
public static async Task account_ugrant(HttpContext ctx)
{
string requestBody = ctx.Request.DataAsString;
GrantReqData grant = Newtonsoft.Json.JsonConvert.DeserializeObject<GrantReqData>(requestBody);
GrantRsp rsp = new GrantRsp();
Account account = DatabaseManager.db.GetAccountByToken(grant.token);
rsp.type = "A";
if (account != null)
{
rsp.msg = "OK";
string grantedToken = DatabaseManager.db.GrantCode(account);
rsp.data = new()
{
hgId = account.id,
uid = account.id,
token = grantedToken,
code = grantedToken
};
}
else
{
rsp.status = 2;
rsp.msg = "Error";
}
ctx.Response.StatusCode = 200;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(JsonConvert.SerializeObject(rsp));
}
[StaticRoute(HttpServerLite.HttpMethod.POST, "/u8/user/auth/v2/grant")]
public static async Task account_grant(HttpContext ctx)
{
string requestBody = ctx.Request.DataAsString;
GrantData grant = Newtonsoft.Json.JsonConvert.DeserializeObject<GrantData>(requestBody);
GrantReqData grant = Newtonsoft.Json.JsonConvert.DeserializeObject<GrantReqData>(requestBody);
GrantRsp rsp = new GrantRsp();
Account account = DatabaseManager.db.GetAccountByTokenGrant(grant.token);
string resp = "{\"msg\": \"Error\", \"status\": 2, \"type\": \"A\"}";
rsp.type = "A";
if (account != null)
{
resp = "{\"data\": { \"uid\": \"" + account.id + "\", \"code\": \"" + account.grantToken + "\" }, \"msg\": \"OK\", \"status\": 0, \"type\": \"A\"}";
rsp.msg = "OK";
rsp.data = new()
{
hgId = account.id,
uid = account.id,
token = account.token,
code = account.grantToken,
};
}
else
{
rsp.status = 2;
rsp.msg = "Error";
}
ctx.Response.StatusCode = 200;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
await ctx.Response.SendAsync(JsonConvert.SerializeObject(rsp));
}
public class TokenChannelData
@ -180,14 +283,7 @@ namespace Campofinale.Http
}
}
/*{
"appCode": "2fe67ec91610377d",
"code": "121212",
"email": "aaaa@a.cc",
"from": 0,
"password": "aaaaaaaaaaaaaa1"
}*/
public struct RegisterData
public struct RegisterFormData
{
public string appCode;
public string code;
@ -201,7 +297,7 @@ namespace Campofinale.Http
{
string requestBody = ctx.Request.DataAsString;
Console.WriteLine(requestBody);
RegisterData data = Newtonsoft.Json.JsonConvert.DeserializeObject<RegisterData>(requestBody);
RegisterFormData data = Newtonsoft.Json.JsonConvert.DeserializeObject<RegisterFormData>(requestBody);
string username = data.email.Split("@")[0];
(string,int) msg=DatabaseManager.db.CreateAccount(username);
string resp = "";
@ -244,10 +340,8 @@ namespace Campofinale.Http
{
transactions.transactionList = new();
}
string resp = Newtonsoft.Json.JsonConvert.SerializeObject(transactions);
ctx.Response.StatusCode = 200;
await ctx.Response.SendAsync(resp);
await ctx.Response.SendAsync(JsonConvert.SerializeObject(transactions));
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/gachahistory")]
public static async Task gachahistory(HttpContext ctx)
@ -265,9 +359,6 @@ namespace Campofinale.Http
resp = File.ReadAllText("Data/GachaHistory/index_noplayerfound.html");
}
ctx.Response.StatusCode = 200;
await ctx.Response.SendAsync(resp);

View File

@ -1,9 +1,7 @@
using Campofinale;
using Pastel;
using System;
using System.Diagnostics;
using System.IO;
using static System.Net.Mime.MediaTypeNames;
public static class Logger
{
@ -20,6 +18,10 @@ public static class Logger
var method = frame?.GetMethod();
return method?.DeclaringType?.Name ?? "Server";
}
/// <summary>
/// Print a text in the console
/// </summary>
/// <param name="text"></param>
public static void Print(string text)
{
string className = GetCallingClassName();
@ -27,6 +29,10 @@ public static class Logger
string prefix = "<" + "INFO".Pastel("03fcce") + $":{className.Pastel("999")}>";
Console.WriteLine($"{prefix} " + text);
}
/// <summary>
/// Print a text in the console as Error
/// </summary>
/// <param name="text"></param>
public static void PrintError(string text)
{
string className = GetCallingClassName();
@ -34,8 +40,15 @@ public static class Logger
string prefix = "<" + "ERROR".Pastel("eb4034") + $":{className.Pastel("999")}>";
Console.WriteLine($"{prefix} " + text.Pastel("917e7e"));
}
/// <summary>
/// Print a text in the console as a Warn
/// </summary>
/// <param name="text"></param>
public static void PrintWarn(string text)
{
if (!Server.config.logOptions.packetWarnings)
return;
string className = GetCallingClassName();
Logger.Log(text);
string prefix = "<" + "WARN".Pastel("ff9100") + $":{className.Pastel("999")}>";
@ -43,7 +56,9 @@ public static class Logger
}
public static string GetColor(string c)
{
if (ClassColors.ContainsKey(c)) return ClassColors[c];
if (ClassColors.ContainsKey(c))
return ClassColors[c];
return "999";
}
private static StreamWriter logWriter;
@ -52,24 +67,27 @@ public static class Logger
public static void Initialize(bool hideLogs = false)
{
Logger.hideLogs = hideLogs;
logWriter = new StreamWriter("latest.log", false);
}
public static void Log(string message)
{
if (!hideLogs)
logWriter = new StreamWriter("latest.log", false);
logWriter.AutoFlush = true;
}
/// <summary>
/// Log a message
/// </summary>
/// <param name="message"></param>
private static void Log(string message)
{
if(hideLogs)
return;
try
{
logWriter.WriteLine($"{DateTime.Now}: {message}");
logWriter.Flush();
}
catch(Exception e)
{
}
}
}
public static void Close()

View File

@ -1,20 +1,9 @@
using Campofinale.Protocol;
using Google.Protobuf;
using Pastel;
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Campofinale.Network
{
@ -61,6 +50,11 @@ namespace Campofinale.Network
byte networkValue = buf[index];
return networkValue;
}
/// <summary>
/// Parse the body using a specific IMessage proto class
/// </summary>
/// <typeparam name="TBody"></typeparam>
/// <returns></returns>
public TBody DecodeBody<TBody>() where TBody : IMessage<TBody>, new()
{
return new MessageParser<TBody>(() => new()).ParseFrom(finishedBody);
@ -76,35 +70,10 @@ namespace Campofinale.Network
Buffer.BlockCopy(source, 0, destination, offset, source.Length);
}
public static byte[] ToByteArray(IntPtr ptr, int length)
{
if (ptr == IntPtr.Zero)
{
throw new ArgumentException("Pointer cannot be null", nameof(ptr));
}
byte[] byteArray = new byte[length];
Marshal.Copy(ptr, byteArray, 0, length);
return byteArray;
}
public static IntPtr ByteArrayToIntPtr(byte[] data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
// Allocate unmanaged memory
IntPtr ptr = Marshal.AllocHGlobal(data.Length);
// Copy the byte array to the unmanaged memory
Marshal.Copy(data, 0, ptr, data.Length);
return ptr;
}
public static byte[] EncryptWithPublicKey(byte[] data, string publicKey)
{
// Crea un oggetto RSA
using (RSA rsa = RSA.Create())
{
publicKey = publicKey.Replace("-----BEGIN PUBLIC KEY-----", "");
publicKey = publicKey.Replace("\r", "");
publicKey = publicKey.Replace("\n", "");
@ -112,24 +81,44 @@ namespace Campofinale.Network
publicKey = publicKey.Trim();
Logger.Print(publicKey);
byte[] publicKey_ = Convert.FromBase64String(publicKey);
// Importa la chiave pubblica
rsa.ImportSubjectPublicKeyInfo(publicKey_, out _);
// Crittografa i dati
return rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
}
}
/// <summary>
/// Set the data of the packet with the Message Id and the body
/// </summary>
/// <param name="msgId"></param>
/// <param name="body">The proto message</param>
/// <returns>The current Packet</returns>
public Packet SetData(ScMsgId msgId, IMessage body)
{
set_body = body;
cmdId = (int)msgId;
return this;
}
/// <summary>
/// Encode the packet using the Packet class
/// </summary>
/// <param name="packet">The packet</param>
/// <param name="seq">the sequence id</param>
/// <param name="totalPackCount">the pack count</param>
/// <param name="currentPackIndex"></param>
/// <returns></returns>
public static byte[] EncodePacket(Packet packet,ulong seq = 0, uint totalPackCount = 1, uint currentPackIndex = 0)
{
return EncodePacket(packet.cmdId,packet.set_body,seq, totalPackCount, currentPackIndex);
}
public static ulong seqNext = 1;
/// <summary>
/// Encode the packet using the msgId and the body
/// </summary>
/// <param name="msgId"></param>
/// <param name="body"></param>
/// <param name="seqNext_"></param>
/// <param name="totalPackCount"></param>
/// <param name="currentPackIndex"></param>
/// <returns></returns>
public static byte[] EncodePacket(int msgId, IMessage body, ulong seqNext_ = 0, uint totalPackCount=1,uint currentPackIndex=0)
{
if (seqNext_ == 0)
@ -145,10 +134,19 @@ namespace Campofinale.Network
PutByteArray(data, head.ToByteArray(), 3);
PutByteArray(data, body.ToByteArray(), 3+head.ToByteArray().Length);
if(Server.config.logOptions.packets && !Server.scMessageToHide.Contains((ScMsgId)msgId))
Logger.Print($"Sending packet: {((ScMsgId)msgId).ToString().Pastel(Color.LightBlue)} id: {msgId} with {data.Length} bytes");
Logger.Print($"Sending Packet: {((ScMsgId)msgId).ToString().Pastel(Color.LightBlue)} Id: {msgId} with {data.Length} Bytes");
return data;
}
/// <summary>
/// Encode the packet with msgId and body as byte array
/// </summary>
/// <param name="msgId"></param>
/// <param name="body"></param>
/// <param name="seqNext_"></param>
/// <param name="totalPackCount"></param>
/// <param name="currentPackIndex"></param>
/// <returns></returns>
public static byte[] EncodePacket(int msgId, byte[] body, ulong seqNext_ = 0, uint totalPackCount = 1, uint currentPackIndex = 0)
{
if (seqNext_ == 0)
@ -167,11 +165,18 @@ namespace Campofinale.Network
PutUInt16(data, (ushort)body.Length, 1);
PutByteArray(data, head.ToByteArray(), 3);
PutByteArray(data, body, 3 + head.ToByteArray().Length);
if(Server.config!=null)
if (Server.config.logOptions.packets && !Server.scMessageToHide.Contains((ScMsgId)msgId))
Logger.Print($"Sending packet: {((ScMsgId)msgId).ToString().Pastel(Color.LightBlue)} id: {msgId} with {data.Length} bytes");
Logger.Print($"Sending Packet: {((ScMsgId)msgId).ToString().Pastel(Color.LightBlue)} Id: {msgId} with {data.Length} Bytes");
return data;
}
/// <summary>
/// Read the byteArray as a valid packet
/// </summary>
/// <param name="client"></param>
/// <param name="byteArray"></param>
/// <returns>The decoded packet</returns>
public static Packet Read(Player client,byte[] byteArray)
{
byte headLength = GetByte(byteArray, 0);
@ -182,12 +187,34 @@ namespace Campofinale.Network
Array.Copy(byteArray, 3, csHeadBytes, 0, headLength);
Array.Copy(byteArray, 3+ headLength, BodyBytes, 0, bodyLength);
CSHead csHead_ = CSHead.Parser.ParseFrom(csHeadBytes);
if (Server.config.logOptions.packets)
/*if (Server.config.logOptions.packets && !Server.csMessageToHide.Contains((CsMsgId)csHead_.Msgid))
{
Logger.Print(csHead_.ToString());
}
}*/
seqNext = csHead_.UpSeqid;
return new Packet() { csHead = csHead_, finishedBody = BodyBytes,cmdId=csHead_.Msgid };
}
/// <summary>
/// Read the byteArray as a valid packet
/// </summary>
/// <param name="byteArray"></param>
/// <returns>The decoded packet</returns>
public static Packet Read(byte[] byteArray)
{
byte headLength = GetByte(byteArray, 0);
ushort bodyLength = GetUInt16(byteArray, 1);
byte[] csHeadBytes = new byte[headLength];
byte[] BodyBytes = new byte[bodyLength];
Array.Copy(byteArray, 3, csHeadBytes, 0, headLength);
Array.Copy(byteArray, 3 + headLength, BodyBytes, 0, bodyLength);
CSHead csHead_ = CSHead.Parser.ParseFrom(csHeadBytes);
/*if (Server.config.logOptions.packets && !Server.csMessageToHide.Contains((CsMsgId)csHead_.Msgid))
{
Logger.Print(csHead_.ToString());
}*/
seqNext = csHead_.UpSeqid;
return new Packet() { csHead = csHead_, finishedBody = BodyBytes, cmdId = csHead_.Msgid };
}
}
}

View File

@ -7,7 +7,6 @@
using System.Collections.Immutable;
using System.Linq.Expressions;
using System.Reflection;
using System.Net.Sockets;
using Campofinale.Protocol;
using Campofinale.Network;
@ -48,17 +47,23 @@
s_notifyReqGroup = handlers.ToImmutable();
}
public static void Notify(Player session, CsMsgId cmdId, Network.Packet packet)
public static async void Notify(Player session, CsMsgId cmdId, Network.Packet packet)
{
await Task.Run(() =>
{
if (s_notifyReqGroup.TryGetValue(cmdId, out var handler))
{
handler.Item2.Invoke(session, ((int)cmdId), packet);
}
else
{
if (!Server.hideLog.Contains(cmdId) && Server.config.logOptions.packets)
if (!Server.csMessageToHide.Contains(cmdId) && Server.config.logOptions.packets)
Logger.PrintWarn($"Can't find handler for {(Enum.GetName(typeof(CsMsgId), cmdId)).ToString().Pastel(Color.FromArgb(165, 229, 250))} ({(cmdId).ToString().Pastel(Color.FromArgb(165, 229, 250))})");
}
});
}
public static void AddReqGroupHandler(Type type)

View File

@ -0,0 +1,19 @@
using Campofinale.Network;
using Campofinale.Protocol;
using Campofinale.Resource;
namespace Campofinale.Packets.Cs
{
public class HandleCsAdventureTakeRewardAll
{
[Server.Handler(CsMsgId.CsAdventureTakeRewardAll)]
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsAdventureTakeRewardAll req = packet.DecodeBody<CsAdventureTakeRewardAll>();
//TODO
}
}
}

View File

@ -1,17 +1,7 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Game.Entities;
using Campofinale.Network;
using Campofinale.Protocol;
using Google.Protobuf;
using MongoDB.Driver.Core.Clusters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{
@ -29,6 +19,7 @@ namespace Campofinale.Packets.Cs
{
case BattleActionOperateType.BattleOpEntityValueModify:
OnEntityValueModify(session, data);
break;
case BattleActionOperateType.BattleOpSkillStartCast:
@ -44,7 +35,7 @@ namespace Campofinale.Packets.Cs
OnEntityDie(session, data.EntityDieOpData);
break;
default:
Logger.PrintWarn($"Unsupported BattleActionOperateType.{data.OpType}");
Logger.PrintWarn($"Unimplemented BattleActionOperateType.{data.OpType}");
break;
}
}
@ -83,9 +74,8 @@ namespace Campofinale.Packets.Cs
HealEntity(session, item);
}
break;
default:
Logger.PrintWarn($"Unsupported ServerBattleActionType.{data.Action.ActionType}");
Logger.PrintWarn($"Unimplemented ServerBattleActionType.{data.Action.ActionType}");
break;
}
}
@ -116,7 +106,6 @@ namespace Campofinale.Packets.Cs
private static void OnSkillStartCast(Player session, BattleClientOpData data)
{
ulong casterId = data.OwnerId;
Character character = session.chars.Find(c => c.guid == casterId);
if (character != null)
{
@ -150,7 +139,7 @@ namespace Campofinale.Packets.Cs
BattleInfo = new()
{
Hp = character.curHp,
Ultimatesp = character.ultimateSp+1
Ultimatesp = character.ultimateSp
},
Objid = character.guid,
};
@ -164,17 +153,17 @@ namespace Campofinale.Packets.Cs
private static void OnEntityValueModify(Player session, BattleClientOpData data)
{
Logger.PrintWarn("EntityValueModify called: " + data.EntityValueModifyData.ToString());
Character character = session.chars.Find(c => c.guid == data.EntityValueModifyData.EntityInstId);
if (character != null)
{
character.curHp = data.EntityValueModifyData.Value.Hp;
character.ultimateSp = data.EntityValueModifyData.Value.Ultimatesp;
ScCharSyncStatus s = new()
{
BattleInfo = new()
{
Hp = data.EntityValueModifyData.Value.Hp,
Hp = character.curHp,
Ultimatesp = character.ultimateSp
},
Objid = character.guid,

View File

@ -1,17 +1,7 @@
using Campofinale.Game.Character;
using Campofinale.Network;
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Campofinale.Resource;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{
@ -26,7 +16,7 @@ namespace Campofinale.Packets.Cs
{
session.bitsetManager.AddValue((BitsetType)req.Type, (int)item);
}
session.Send(new PacketScBitsetAdd(session,req.Type,req.Value.ToList()));
session.Send(new PacketScBitsetAdd(session,req.Type,req.Value.ToList()),packet.csHead.UpSeqid);
}

View File

@ -1,17 +1,7 @@
using Campofinale.Game.Character;
using Campofinale.Network;
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Campofinale.Resource;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{

View File

@ -1,21 +1,7 @@
using BeyondTools.VFS.Crypto;
using Campofinale.Network;
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Campofinale.Resource;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using static Campofinale.Resource.ResourceManager;
using static System.Net.Mime.MediaTypeNames;
namespace Campofinale.Packets.Cs
{

View File

@ -1,15 +1,6 @@
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{
@ -23,16 +14,7 @@ namespace Campofinale.Packets.Cs
session.teams[req.TeamIndex].leader=req.LeaderId;
session.teams[req.TeamIndex].members= req.CharTeam.ToList();
ScCharBagSetTeam team = new()
{
CharTeam = { req.CharTeam },
LeaderId = req.LeaderId,
ScopeName = 1,
TeamIndex = req.TeamIndex,
TeamType = CharBagTeamType.Main,
};
session.Send(ScMsgId.ScCharBagSetTeam,team);
session.Send(new PacketScCharBagSetTeam(session,session.teams[req.TeamIndex], req.TeamIndex));
session.Send(new PacketScSelfSceneInfo(session, Resource.SelfInfoReasonType.SlrChangeTeam));
}

View File

@ -1,15 +1,5 @@
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{

View File

@ -1,14 +1,5 @@
using Campofinale.Network;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{

View File

@ -1,15 +1,6 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{

View File

@ -1,16 +1,6 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{
@ -25,7 +15,9 @@ 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
ScCharPotentialUnlock unlock = new()

View File

@ -1,16 +1,6 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{

View File

@ -0,0 +1,22 @@
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Campofinale.Resource;
namespace Campofinale.Packets.Cs
{
public class HandleCsCheckName
{
[Server.Handler(CsMsgId.CsCheckName)]
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsCheckName req = packet.DecodeBody<CsCheckName>();
session.Send(ScMsgId.ScCheckName, new ScCheckName()
{
Name = req.Name,
Pass=true
},packet.csHead.UpSeqid);
}
}
}

View File

@ -0,0 +1,22 @@
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Campofinale.Resource;
namespace Campofinale.Packets.Cs
{
public class HandleCsCheckSensitive
{
[Server.Handler(CsMsgId.CsCheckSensitive)]
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsCheckSensitive req = packet.DecodeBody<CsCheckSensitive>();
session.Send(ScMsgId.ScCheckSensitive, new ScCheckSensitive()
{
});
}
}
}

View File

@ -1,14 +1,5 @@
using Campofinale.Network;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{

View File

@ -1,15 +1,6 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{

View File

@ -1,15 +1,6 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{

View File

@ -1,14 +1,6 @@
using Campofinale.Network;
using Campofinale.Game.Factory;
using Campofinale.Network;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{
@ -19,14 +11,33 @@ namespace Campofinale.Packets.Cs
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsFactoryHsFb req = packet.DecodeBody<CsFactoryHsFb>();
long curtimestamp = DateTime.UtcNow.ToUnixTimestampMilliseconds();
ScFactoryHs hs = new()
List<ScdFacCom> comps = 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);
}

Some files were not shown because too many files have changed in this diff Show More