Compare commits

...

28 Commits

Author SHA1 Message Date
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
83 changed files with 10129 additions and 754 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

@ -50,6 +50,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,4 +1,4 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Game.Inventory;
using Campofinale.Packets.Sc;

View File

@ -1,5 +1,5 @@
using static Campofinale.Resource.ResourceManager;
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Database;
using Campofinale.Game.Inventory;

View File

@ -2,7 +2,7 @@
using Campofinale.Packets.Sc;
using Campofinale.Resource;
namespace Campofinale.Game.Character
namespace Campofinale.Game.Char
{
public static class CharacterManager
{

View File

@ -1,5 +1,5 @@
using Campofinale.Database;
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Packets.Sc;
namespace Campofinale.Commands.Handlers;

View File

@ -12,22 +12,23 @@
{
public int defaultSceneNumId = 87;
public int maxPlayers = 20;
public CharactersOptions defaultCharacters = new();
/// <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 class CharactersOptions
{
public int defaultLevel = 1;
public bool giveAllCharacters = true;
public List<string> characters = new List<string>(); //used if giveAllCharacters is false
public CharactersOptions() { }
}
/* public struct WelcomeMail
{
}*/
}
public class LogSettings
{
@ -46,6 +47,8 @@
public int bindPort = 30000;
public string accessAddress = "127.0.0.1";
public int accessPort = 30000;
public bool useExternalAuthSdk = false;
public string externalAuthSdkUrl = "";
public GameserverSettings()
{
}

View File

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

View File

@ -1,13 +1,17 @@
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 MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
using System.Security.Cryptography;
using System.Text;
using static Campofinale.Game.Adventure.AdventureBookManager;
using static Campofinale.Game.Factory.FactoryManager;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Database
@ -32,12 +36,21 @@ 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
{
public string id;
@ -64,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();
@ -82,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();
@ -138,7 +163,8 @@ namespace Campofinale.Database
bitsets=player.bitsetManager.bitsets,
savedSafeZone = player.savedSaveZone,
gender=player.gender,
bag=player.inventoryManager.items.bag
bag=player.inventoryManager.items.bag,
nextDailyReset = player.nextDailyReset,
};
UpsertPlayerData(data);
}
@ -176,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");
@ -229,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)
@ -267,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)
@ -335,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

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

@ -10,7 +10,7 @@ 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
{
@ -459,8 +459,6 @@ namespace Campofinale.Game.Character
ScCharLevelUp levelUp = new()
{
CharObjID = guid,
};
ScCharSyncLevelExp synclevel = new()
{
@ -471,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,4 +1,6 @@
using static Campofinale.Resource.ResourceManager;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Game.Dungeons
{
@ -13,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,4 +1,5 @@
using Campofinale.Resource;
using System.Threading;
using static Campofinale.Resource.ResourceManager;
using static Campofinale.Resource.ResourceManager.LevelScene.LevelData;
@ -21,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()
{
@ -40,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

@ -98,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

@ -14,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)
@ -32,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()
{
@ -42,7 +59,7 @@ namespace Campofinale.Game.Entities
{
CommonInfo = new()
{
Hp = 100,
Hp = 1,
Id = guid,
Templateid = templateId,
@ -86,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);
}
@ -103,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,5 +1,7 @@
using Campofinale.Protocol;
using Campofinale.Resource;
using Campofinale.Resource.Table;
using System.Threading;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Game.Entities
@ -7,6 +9,7 @@ namespace Campofinale.Game.Entities
public class EntityMonster : Entity
{
public string templateId;
public ulong originId;
public EntityMonster()
{
@ -40,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()
{
@ -80,10 +87,10 @@ namespace Campofinale.Game.Entities
SceneNumId = sceneNumId,
Position = Position.ToProto(),
Rotation = Rotation.ToProto(),
Type =(int) ObjectTypeIndex.Enemy,
},
OriginId= originId,
Attrs =
{
GetAttributes()
@ -96,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

@ -5,13 +5,17 @@ namespace Campofinale.Game.Factory.Components
{
public class FComponentTravelPole : FComponent
{
public uint defaultNext;
public FComponentTravelPole(uint id) : base(id, FCComponentType.TravelPole)
{
}
public override void SetComponentInfo(ScdFacCom proto)
{
proto.TravelPole = new();
proto.TravelPole = new()
{
DefaultNext = defaultNext
};
}
}
}

View File

@ -1,9 +1,15 @@
using Campofinale.Game.Entities;
using Campofinale.Database;
using Campofinale.Game.Entities;
using Campofinale.Game.Factory.Components;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Campofinale.Resource;
using Campofinale.Resource.Table;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System.Linq;
using System.Numerics;
using System.Xml.Linq;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Game.Factory
@ -12,18 +18,40 @@ namespace Campofinale.Game.Factory
{
public Player player;
public List<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)
{
@ -62,11 +90,180 @@ namespace Campofinale.Game.Factory
public List<FactoryNode> nodes=new();
public uint v = 1;
public uint compV = 0;
public int bandwidth = 200;
public ScFactorySyncChapter ToProto()
{
ScFactorySyncChapter chapter = new()
{
ChapterId = chapterId,
Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds()/1000,
Blackboard = new()
{
Power = new()
{
PowerGen = 0,
PowerSaveMax = 0,
PowerSaveCurrent = 0,
PowerCost = 0
},
InventoryNodeId = 1
},
Statistic = new()
{
LastDay = new()
{
},
Other = new()
{
InPowerBuilding = 1
}
},
PinBoard = new()
{
Cards =
{
},
},
};
chapter.Blackboard.Power.PowerSaveCurrent = bandwidth;
domainDataTable[chapterId].levelGroup.ForEach(levelGroup =>
{
int grade = GetOwner().sceneManager.GetScene(GetSceneNumIdFromLevelData(levelGroup)).grade;
LevelGradeInfo sceneGrade = ResourceManager.levelGradeTable[levelGroup].grades.Find(g=>g.grade==grade);
if (sceneGrade != null)
{
chapter.Blackboard.Power.PowerGen += sceneGrade.bandwidth;
chapter.Blackboard.Power.PowerSaveMax += sceneGrade.bandwidth;
var scene = new ScdFactorySyncScene()
{
SceneId = GetSceneNumIdFromLevelData(levelGroup),
Bandwidth = new()
{
Current = 0,
Max = sceneGrade.bandwidth,
TravelPoleMax = sceneGrade.travelPoleLimit,
BattleCurrent = 0,
BattleMax = sceneGrade.battleBuildingLimit,
},
Settlements =
{
},
Panels =
{
}
};
int index = 0;
LevelScene scen = GetLevelData(GetSceneNumIdFromLevelData(levelGroup));
foreach (var reg in scen.levelData.factoryRegions)
{
foreach (var area in reg.areas)
{
var lvData = area.levelData.Find(l=>l.level==grade);
if (lvData == null)
{
lvData = area.levelData.Last();
}
if (lvData.levelBounds.Count > 0)
{
var bounds = lvData.levelBounds[0];
scene.Panels.Add(new ScdFactorySyncScenePanel()
{
Index = index,
Level = lvData.level,
MainMesh =
{
new ScdRectInt()
{
X=(int)bounds.start.x,
Z=(int)bounds.start.z,
Y=(int)bounds.start.y,
W=(int)bounds.size.x,
H=(int)bounds.size.y,
L=(int)bounds.size.z,
}
}
});
index++;
}
}
}
chapter.Scenes.Add(scene);
}
});
nodes.ForEach(node =>
{
chapter.Nodes.Add(node.ToProto());
});
chapter.Maps.AddRange(GetMaps());
return chapter;
}
public List<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(); // evita doppioni esatti
ulong i = 0;
foreach (FactoryNode node in nodes)
{
foreach (var conn in node.connectedComps)
{
ulong compA = conn.Key;
ulong compB = conn.Value;
var key = (compA, compB);
if (!addedConnections.Contains(key))
{
wires.Add(new ScdFactorySyncMapWire()
{
Index = i,
FromComId = compA,
ToComId = compB
});
addedConnections.Add(key);
i++;
}
}
}
return wires;
}
public void Update()
{
try
{
UpdatePowerGrid(nodes);
foreach (FactoryNode node in nodes)
{
node.Update(this);
@ -89,50 +286,242 @@ namespace Campofinale.Game.Factory
switch (op.OpType)
{
case FactoryOpType.Place:
CreateNode(op.Place, seq);
CreateNode(op, seq);
break;
case FactoryOpType.MoveNode:
MoveNode(op, seq);
break;
case FactoryOpType.Dismantle:
DismantleNode(op, seq);
break;
case FactoryOpType.AddConnection:
AddConnection(op, seq);
break;
case FactoryOpType.SetTravelPoleDefaultNext:
FactoryNode travelNode = GetNodeByCompId(op.SetTravelPoleDefaultNext.ComponentId);
travelNode.GetComponent<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 MoveNode(CsFactoryOp op, ulong seq)
{
var move = op.MoveNode;
FactoryNode node = nodes.Find(n => n.nodeId == move.NodeId);
if (node != null)
{
node.direction = new Vector3f(move.Direction);
node.position = new Vector3f(move.Position);
node.worldPosition = new Vector3f(move.InteractiveParam.Position);
GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, node));
GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), node.nodeId, op), seq);
node.SendEntity(GetOwner(), chapterId);
}
else
{
ScFactoryOpRet ret = new()
{
RetCode = FactoryOpRetCode.Fail,
};
GetOwner().Send(ScMsgId.ScFactoryOpRet, ret, seq);
}
}
public void DismantleNode(CsFactoryOp op, ulong seq)
{
var dismantle = op.Dismantle;
FactoryNode nodeRem = nodes.Find(n => n.nodeId == dismantle.NodeId);
if (nodeRem != null)
{
RemoveConnectionsToNode(nodeRem, nodes);
nodes.Remove(nodeRem);
GetOwner().Send(ScMsgId.ScFactoryModifyChapterMap, new ScFactoryModifyChapterMap()
{
ChapterId = chapterId,
MapId = nodeRem.mapId,
Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds() / 1000,
Wires =
{
GetWires()
}
});
GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, nodeRem.nodeId));
GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), nodeRem.nodeId, op), seq);
}
else
{
ScFactoryOpRet ret = new()
{
RetCode = FactoryOpRetCode.Fail,
};
GetOwner().Send(ScMsgId.ScFactoryOpRet, ret, seq);
}
}
public void RemoveConnectionsToNode(FactoryNode nodeRem, List<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;
}
private void CreateNode(CsdFactoryOpPlace place, ulong seq)
public FactoryNode.FComponent GetCompById(ulong compId)
{
foreach(FactoryNode node in nodes)
{
if (node.components.Find(c => c.compId == compId) != null)
{
return node.components.Find(c => c.compId == compId);
}
}
return null;
}
public FactoryNode GetNodeByCompId(ulong compId)
{
foreach (FactoryNode node in nodes)
{
if (node.components.Find(c => c.compId == compId) != null)
{
return node;
}
}
return null;
}
private void AddConnection(CsFactoryOp op,ulong seq)
{
FactoryNode.FComponent nodeFrom = GetCompById(op.AddConnection.FromComId);
FactoryNode.FComponent nodeTo = GetCompById(op.AddConnection.ToComId);
if(nodeFrom!=null && nodeTo != null)
{
GetNodeByCompId(nodeFrom.compId).connectedComps.Add(new(nodeFrom.compId, nodeTo.compId));
GetNodeByCompId(nodeTo.compId).connectedComps.Add(new(nodeTo.compId, nodeFrom.compId));
GetOwner().Send(ScMsgId.ScFactoryModifyChapterMap, new ScFactoryModifyChapterMap()
{
ChapterId = chapterId,
MapId = GetNodeByCompId(nodeFrom.compId).mapId,
Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds()/1000,
Wires =
{
GetWires()
}
});
var wire = GetWires().Find(w =>
(w.FromComId == op.AddConnection.FromComId && w.ToComId == op.AddConnection.ToComId) ||
(w.FromComId == op.AddConnection.ToComId && w.ToComId == op.AddConnection.FromComId));
if (wire != null)
{
GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), (uint)wire.Index, op), seq);
}
else
{
// Facoltativo: log di errore
Console.WriteLine($"[WARN] Connessione non trovata tra {op.AddConnection.FromComId} e {op.AddConnection.ToComId}");
}
}
}
void ResetAllPower(List<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);
}
}
}
private void CreateNode(CsFactoryOp op, ulong seq)
{
v++;
uint nodeId = v;
CsdFactoryOpPlace place = op.Place;
FactoryBuildingTable table = ResourceManager.factoryBuildingTable[place.TemplateId];
FactoryNode node = new()
{
nodeId = nodeId,
templateId = place.TemplateId,
mapId = place.MapId,
sceneNumId = GetOwner().sceneManager.GetCurScene().sceneNumId,
nodeType = table.GetNodeType(),
position = new Vector3f(place.Position),
direction = new Vector3f(place.Direction),
guid = GetOwner().random.NextRand()
worldPosition = new Vector3f(place.InteractiveParam.Position),
guid = GetOwner().random.NextRand(),
};
node.InitComponents(this);
GetOwner().Send(new PacketScFactoryModifyChapterNodes(GetOwner(), chapterId, node));
nodes.Add(node);
ScFactoryModifyChapterNodes edit = new()
{
ChapterId = chapterId,
Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(),
};
GetOwner().Send(new PacketScFactorySyncChapter(GetOwner(), chapterId));
edit.Nodes.Add(node.ToProto());
Logger.Print(Newtonsoft.Json.JsonConvert.SerializeObject(edit, Newtonsoft.Json.Formatting.Indented));
EntityInteractive e = new(place.TemplateId, GetOwner().roleId, new Vector3f(place.Position), new Vector3f(place.Direction), GetOwner().sceneManager.GetCurScene().sceneNumId, node.guid);
GetOwner().sceneManager.GetCurScene().entities.Add(e);
GetOwner().sceneManager.GetCurScene().SpawnEntity(e);
GetOwner().Send(ScMsgId.ScFactoryModifyChapterNodes, edit);
GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), node.nodeId,FactoryOpType.Place),seq);
node.SendEntity(GetOwner(), chapterId);
GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), node.nodeId,op),seq);
}
@ -164,46 +553,39 @@ namespace Campofinale.Game.Factory
public string templateId;
public Vector3f position=new();
public Vector3f direction = new();
public Vector3f worldPosition = new();
public string instKey="";
public bool deactive = false;
public int mapId;
public int sceneNumId;
public bool forcePowerOn = false;
public List<FComponent> components = new();
[BsonIgnore]
public bool powered = false;
[BsonIgnore]
public uint connectedPowerNode = 0;
public bool lastPowered = false;
public List<ConnectedComp> connectedComps = new();
public ulong guid;
public class ConnectedComp
{
public ulong Key;
public ulong Value;
public ConnectedComp(ulong key, ulong value)
{
this.Key = key;
this.Value = value;
}
}
public void Update(FactoryChapter chapter)
{
if(!templateId.Contains("hub"))
if (GetComponent<FComponentPowerPole>() != null)
LevelScene scen = GetLevelData(sceneNumId);
if (lastPowered != powered)
{
FactoryNode curEnergyNode = chapter.nodes.Find(n => n.nodeId == connectedPowerNode && n.position.Distance(position) <= 20 && n.InPower());
if (templateId != "power_pole_2")
{
FactoryNode energyNode = chapter.GetNodesInRange(position, 20).Find(n=>n.GetComponent< FComponentPowerPole>()!=null && n.InPower());
if (energyNode != null && curEnergyNode==null && energyNode.connectedPowerNode!=nodeId)
{
powered= true;
connectedPowerNode = energyNode.nodeId;
chapter.GetOwner().Send(ScMsgId.ScFactoryModifyChapterNodes, new ScFactoryModifyChapterNodes() { Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(), Nodes = { this.ToProto()} });
}
else
{
if (curEnergyNode == null && powered==true)
{
powered = false;
connectedPowerNode = 0;
chapter.GetOwner().Send(ScMsgId.ScFactoryModifyChapterNodes, new ScFactoryModifyChapterNodes() { Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(), Nodes = { this.ToProto() } });
}
}
}
else
{
//Check near
}
lastPowered = powered;
chapter.GetOwner().Send(new PacketScFactoryModifyChapterNodes(chapter.GetOwner(), chapter.chapterId, this));
}
}
public bool InPower()
{
@ -221,41 +603,54 @@ namespace Campofinale.Game.Factory
{
FMesh mesh = new FMesh();
if (ResourceManager.factoryBuildingTable.ContainsKey(templateId))
if (ResourceManager.factoryBuildingTable.TryGetValue(templateId, out FactoryBuildingTable table))
{
FactoryBuildingTable table = ResourceManager.factoryBuildingTable[templateId];
float width = table.range.width - 1;
float height = table.range.height - 1;
float depth = table.range.depth-1;
double centerX = position.x + table.range.width / 2.0;
double centerZ = position.z + table.range.depth / 2.0;
Vector3f p1_final = new Vector3f();
Vector3f p2_final = new Vector3f();
Vector3f p1 = new Vector3f(position.x, position.y, position.z);
Vector3f p2 = new Vector3f(
position.x + table.range.width,
position.y + table.range.height,
position.z + table.range.depth
);
switch (direction.y)
{
case 0f:
case 360f:
default:
p1_final = position + new Vector3f(table.range.x, table.range.y, table.range.z);
p2_final = p1_final + new Vector3f(width, height, depth);
break;
p1 = RotateAroundY(p1, new Vector3f((float)centerX, position.y, (float)centerZ), direction.y);
p2 = RotateAroundY(p2, new Vector3f((float)centerX, position.y, (float)centerZ), direction.y);
mesh.points.Add(p1);
mesh.points.Add(p2);
case 90f:
// Rotazione 90°: Larghezza e profondità si scambiano.
// Il mesh parte da 'position' ma si estende su assi diversi.
p1_final = position + new Vector3f(table.range.x, table.range.y, table.range.z - width);
p2_final = p1_final + new Vector3f(depth, height, width);
break;
case 180f:
// Rotazione 180°: Larghezza e profondità mantengono i loro valori
// ma il mesh si estende in direzioni negative.
p1_final = position + new Vector3f(table.range.x - width, table.range.y, table.range.z - depth);
p2_final = p1_final + new Vector3f(width, height, depth);
break;
case 270f:
// Rotazione 270°: Larghezza e profondità si scambiano.
// Il mesh si estende in direzioni diverse rispetto alla rotazione di 90°.
p1_final = position + new Vector3f(table.range.x - depth, table.range.y, table.range.z);
p2_final = p1_final + new Vector3f(depth, height, width);
break;
}
mesh.points.Add(p1_final);
mesh.points.Add(p2_final);
}
return mesh;
}
private Vector3f RotateAroundY(Vector3f point, Vector3f origin, double angleDegrees)
{
double angleRadians = angleDegrees * (Math.PI / 180.0);
double cosTheta = Math.Cos(angleRadians);
double sinTheta = Math.Sin(angleRadians);
double dx = point.x - origin.x;
double dz = point.z - origin.z;
double rotatedX = origin.x + (dx * cosTheta - dz * sinTheta);
double rotatedZ = origin.z + (dx * sinTheta + dz * cosTheta);
return new Vector3f((float)rotatedX, point.y, (float)rotatedZ);
}
public ScdFacNode ToProto()
{
ScdFacNode node = new ScdFacNode()
@ -269,7 +664,7 @@ namespace Campofinale.Game.Factory
Power = new()
{
InPower= InPower(),
NeedInPower=false,
NeedInPower=true,
},
NodeType=(int)nodeType,
@ -285,7 +680,8 @@ namespace Campofinale.Game.Factory
if(templateId!="__inventory__")
{
node.Transform.Mesh = GetMesh().ToProto();
node.Transform.WorldPosition = position.ToProto();
node.Transform.Position = position.ToProtoScd();
node.Transform.WorldPosition = worldPosition.ToProto();
node.Transform.WorldRotation = direction.ToProto();
node.InteractiveObject = new()
{
@ -353,6 +749,50 @@ namespace Campofinale.Game.Factory
}
}
public void SendEntity(Player player, string chapterId)
{
Entity exist = player.sceneManager.GetCurScene().entities.Find(e => e.guid == guid);
if (exist != null)
{
exist.Position = worldPosition;
exist.Rotation = direction;
ScMoveObjectMove move = new()
{
ServerNotify = true,
MoveInfo =
{
new MoveObjectMoveInfo()
{
Objid = guid,
SceneNumId=sceneNumId,
MotionInfo = new()
{
Position=exist.Position.ToProto(),
Rotation=exist.Rotation.ToProto(),
Speed=new Vector()
{
},
State=MotionState.MotionNone
}
}
}
};
player.Send(ScMsgId.ScMoveObjectMove, move);
}
else
{
EntityInteractive e = new(interactiveFacWrapperTable[templateId].interactiveTemplateId, player.roleId, worldPosition, direction, sceneNumId, guid);
e.InitDefaultProperties();
e.SetPropValue(nodeId, "factory_inst_id");
player.sceneManager.GetCurScene().entities.Add(e);
player.sceneManager.GetCurScene().SpawnEntity(e);
}
}
[BsonDiscriminator(Required = true)]
[BsonKnownTypes(typeof(FComponentSelector))]

View File

@ -63,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()

View File

@ -11,6 +11,7 @@ using static Campofinale.Resource.ResourceManager;
using Google.Protobuf.Collections;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using CsvHelper.Configuration.Attributes;
namespace Campofinale.Game.Inventory
{
@ -101,7 +102,7 @@ namespace Campofinale.Game.Inventory
GemId = guid,
TemplateId= ResourceManager.GetItemTemplateId(id),
WeaponId= GetOwner().inventoryManager.items.Find(i=>i.attachGemId==guid)!=null ? GetOwner().inventoryManager.items.Find(i => i.attachGemId == guid).guid: 0,
},
IsLock = locked
}

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

@ -19,10 +19,18 @@ namespace Campofinale.Game.MissionSys
}
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,
@ -71,18 +79,23 @@ namespace Campofinale.Game.MissionSys
}
public void Save()
{
DatabaseManager.db.UpsertMissionData(new MissionData()
{
roleId=owner.roleId,
curMission=curMission,
missions=missions,
quests=quests,
});
}
public void Load()
{
if (ResourceManager.missionDataTable.Count < 1)
MissionData data= DatabaseManager.db.LoadMissionData(owner.roleId);
if (data != null)
{
//Disabling if no missions
return;
curMission = data.curMission;
missions = data.missions;
quests = data.quests;
}
//TODO Saving and first initialization
AddMission("e0m0",MissionState.Processing);
}
public void AddMission(string id,MissionState state = MissionState.Available, bool notify=false)
{
@ -92,6 +105,7 @@ namespace Campofinale.Game.MissionSys
missions.Add(new GameMission(id, state));
if (notify)
{
ScMissionStateUpdate s = new()
{
MissionId = data.missionId,
@ -219,34 +233,39 @@ namespace Campofinale.Game.MissionSys
quests.Remove(quest);
}
}
}
public class GameQuest
{
public string questId;
public QuestState state;
public GameQuest()
{
}
public GameQuest(string id, QuestState state = QuestState.Available)
public void TrackMission(string v)
{
questId = id;
this.state = state;
}
}
public class GameMission
{
public string missionId;
public MissionState state;
public GameMission()
{
}
public GameMission(string id, MissionState state = MissionState.Available)
{
missionId = id;
this.state = state;
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,10 +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 System;
using System.Diagnostics;
using System.Text.Json.Serialization;
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
{
@ -42,7 +48,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);
@ -88,43 +94,40 @@ 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()
entity.OnDie();
if (killClient)
{
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)
ScSceneDestroyEntity destroy = new()
{
player.noSpawnAnymore.Add(monster.guid);
Id = guid,
Reason = reason,
SceneNumId = GetEntity(guid).sceneNumId,
};
player.Send(Protocol.ScMsgId.ScSceneDestroyEntity, destroy);
}
if (entity is EntityMonster monster)
{
LevelScene lv_scene = ResourceManager.GetLevelData(entity.sceneNumId);
LevelEnemyData d = lv_scene.levelData.enemies.Find(l => l.levelLogicId == monster.guid);
if (d != null)
{
if (!d.respawnable)
{
player.noSpawnAnymore.Add(monster.guid);
}
}
}
}
if (killClient)
{
ScSceneDestroyEntity destroy = new()
if (scenes.Find(s => s.sceneNumId == entity.sceneNumId) != null)
{
Id = guid,
Reason = reason,
SceneNumId = GetEntity(guid).sceneNumId,
};
player.Send(Protocol.ScMsgId.ScSceneDestroyEntity, destroy);
}
if (GetEntity(guid) != null)
{
if(scenes.Find(s => s.sceneNumId == GetEntity(guid).sceneNumId) != null)
{
scenes.Find(s => s.sceneNumId == GetEntity(guid).sceneNumId).entities.Remove(GetEntity(guid));
scenes.Find(s => s.sceneNumId == entity.sceneNumId).entities.Remove(entity);
}
}
}
}
public void CreateDrop(Vector3f pos,ResourceManager.RewardTable.ItemBundle bundle)
@ -215,18 +218,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
});
}
}
@ -237,13 +244,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;
@ -253,7 +264,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 = 0;
public int GetCollection(string id)
{
if (collections.ContainsKey(id))
@ -278,12 +293,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));
@ -294,11 +311,20 @@ namespace Campofinale.Game
}
public void Load()
{
if (info().isSeamless && alreadyLoaded) return;
alreadyLoaded = true;
Unload();
LevelScene lv_scene = ResourceManager.GetLevelData(sceneNumId);
LevelGradeInfo sceneGrade = null;
LevelGradeTable table = null;
ResourceManager.levelGradeTable.TryGetValue(lv_scene.id, out table);
if (table != null)
{
sceneGrade=table.grades.Find(g=>g.grade==grade);
}
if (sceneGrade == null)
{
sceneGrade = new();
}
lv_scene.levelData.interactives.ForEach(en =>
{
if (GetOwner().noSpawnAnymore.Contains(en.levelLogicId) && sceneNumId != 87)
@ -335,19 +361,21 @@ namespace Campofinale.Game
lv_scene.levelData.enemies.ForEach(en =>
{
if(GetOwner().noSpawnAnymore.Contains(en.levelLogicId) && sceneNumId != 87) return;
if (en.defaultHide) return;
EntityMonster entity = new(en.entityDataIdKey,en.level,ownerId,en.position,en.rotation, sceneNumId, en.levelLogicId)
EntityMonster entity = new(en.entityDataIdKey,sceneGrade.monsterBaseLevel+ en.level,ownerId,en.position,en.rotation, sceneNumId, en.levelLogicId)
{
type=en.entityType,
belongLevelScriptId=en.belongLevelScriptId,
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,
@ -355,70 +383,74 @@ 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}));
ch.nodes.ForEach(n =>
{
if (n.sceneNumId == sceneNumId)
{
n.SendEntity(GetOwner(), ch.chapterId);
}
});
});
UpdateShowEntities();
}
public void SpawnEntity(Entity en,bool spawnedCheck=true)
{
en.spawned = true;
List<Entity> toSpawn = new List<Entity>();
if(en.belongLevelScriptId != 0)
if (spawnedCheck)
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)
{
foreach (Entity e in GetEntityExcludingChar().FindAll(e => e.belongLevelScriptId == en.belongLevelScriptId && e.spawned == false))
{
e.spawned = true;
toSpawn.Add(e);
}
return script.state > 2;
}
else
{
foreach (Entity e in GetEntityExcludingChar().FindAll(e => e.belongLevelScriptId == en.belongLevelScriptId && e != en))
{
e.spawned = true;
toSpawn.Add(e);
}
return true;
}
toSpawn.Add(en);
toSpawn.ForEach(e =>
{
GetOwner().Send(new PacketScObjectEnterView(GetOwner(), new List<Entity>() { e}));
});
}
public void UpdateShowEntities()
//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()
{
foreach(Entity en in GetEntityExcludingChar())
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 (en.Position.Distance(GetOwner().position) < 100)
if(e.Position.Distance(GetOwner().position) > 300 && sceneNumId != 87)
{
if (!en.spawned)
{
SpawnEntity(en);
}
continue;
}
else
if(e.spawned==false)
{
/*if (en.spawned)
if (!e.defaultHide)
{
en.spawned = false;
GetOwner().Send(new PacketScObjectLeaveView(GetOwner(), new List<ulong>() { en.guid }));
en.Position=en.BornPos;
en.Rotation = en.Rotation;
}*/
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));
}
}
}
@ -427,8 +459,15 @@ namespace Campofinale.Game
{
return Server.clients.Find(c => c.roleId == ownerId);
}
public void SpawnEnemy(ulong v)
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);
@ -438,11 +477,46 @@ namespace Campofinale.Game
{
type = en.entityType,
belongLevelScriptId = en.belongLevelScriptId,
levelLogicId = en.levelLogicId
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,5 +1,6 @@
using Campofinale.Game;
using HttpServerLite;
using Newtonsoft.Json;
namespace Campofinale.Http
{
@ -63,11 +64,46 @@ 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";
@ -122,7 +158,19 @@ namespace Campofinale.Http
await ctx.Response.SendAsync(resp);
}
[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 = "{\"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/gameBulletin/version")]
public static async Task Version(HttpContext ctx)
{
@ -144,7 +192,7 @@ namespace Campofinale.Http
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\":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 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")
{
@ -152,7 +200,6 @@ namespace Campofinale.Http
}
ctx.Response.StatusCode = 200;
//ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
@ -241,7 +288,32 @@ 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)
{
string fileId = ctx.Request.Url.Elements.LastOrDefault();

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,5 +1,9 @@
using Campofinale.Database;
using HttpServerLite;
using Newtonsoft.Json;
using System.Diagnostics;
using System.Text;
using System.Text.Json;
using static Campofinale.Game.Gacha.GachaManager;
using static Campofinale.Http.Dispatch;
@ -14,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)
{
@ -42,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);
@ -66,7 +77,6 @@ namespace Campofinale.Http
}
ctx.Response.StatusCode = 200;
//ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
@ -87,7 +97,7 @@ namespace Campofinale.Http
if (account != null)
{
/*
* {"data":{"hgId":"1326618825955","phone":"153****5243","email":null,"identityNum":"5002**********1619","identityName":"金*","isMinor":false,"isLatestUserAgreement":true},"msg":"OK","status":0,"type":"A"}
* {"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\"}";
}
@ -100,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;
@ -128,26 +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\": { \"token\": \"" + account.token + "\", \"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
@ -182,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;
@ -203,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 = "";
@ -246,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)
@ -267,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

@ -165,6 +165,7 @@ 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");
@ -193,5 +194,27 @@ namespace Campofinale.Network
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

@ -47,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)
{
if (s_notifyReqGroup.TryGetValue(cmdId, out var handler))
await Task.Run(() =>
{
handler.Item2.Invoke(session, ((int)cmdId), packet);
}
else
{
if (!Server.hideLog.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))})");
}
if (s_notifyReqGroup.TryGetValue(cmdId, out var handler))
{
handler.Item2.Invoke(session, ((int)cmdId), packet);
}
else
{
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,4 +1,4 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Game.Entities;
using Campofinale.Network;
using Campofinale.Protocol;
@ -19,6 +19,7 @@ namespace Campofinale.Packets.Cs
{
case BattleActionOperateType.BattleOpEntityValueModify:
OnEntityValueModify(session, data);
break;
case BattleActionOperateType.BattleOpSkillStartCast:
@ -34,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;
}
}
@ -73,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;
}
}
@ -106,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)
{
@ -140,7 +139,7 @@ namespace Campofinale.Packets.Cs
BattleInfo = new()
{
Hp = character.curHp,
Ultimatesp = character.ultimateSp+1
Ultimatesp = character.ultimateSp
},
Objid = character.guid,
};
@ -154,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

@ -16,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

@ -14,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,4 +1,4 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Protocol;

View File

@ -1,4 +1,4 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Protocol;

View File

@ -1,4 +1,4 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Protocol;

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,4 +1,4 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Protocol;

View File

@ -1,4 +1,4 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Protocol;

View File

@ -1,6 +1,7 @@
using BeyondTools.VFS.Crypto;
using Campofinale.Database;
using Campofinale.Game;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
@ -16,11 +17,43 @@ namespace Campofinale.Packets.Cs
public static void HandleCsSetGender(Player session, CsMsgId cmdId, Packet packet)
{
CsSetGender req = packet.DecodeBody<CsSetGender>();
if(session.chars.Count < 2)
{
if (req.Gender == Gender.GenMale)
{
session.AddCharacter("chr_0002_endminm", true);
session.RemoveCharacter("chr_0003_endminf");
}
else
{
session.AddCharacter("chr_0003_endminf", true);
session.RemoveCharacter("chr_0002_endminm");
}
session.teamIndex = 0;
session.teams[0].leader = session.chars[0].guid;
session.teams[0].members = new() { session.chars[0].guid };
ScCharBagSetTeam setTeam = new()
{
CharTeam = { session.teams[0].members },
LeaderId = session.teams[0].leader,
ScopeName = 1,
TeamIndex = 0,
TeamType = CharBagTeamType.Main,
};
session.Send(ScMsgId.ScCharBagSetTeam, setTeam);
session.Send(new PacketScCharBagSetCurrTeamIndex(session));
session.Send(new PacketScSelfSceneInfo(session,SelfInfoReasonType.SlrChangeTeam));
}
ScSetGender rsp = new()
{
Gender = req.Gender,
};
session.gender = rsp.Gender;
session.Send(ScMsgId.ScSetGender, rsp);
}
@ -39,6 +72,16 @@ namespace Campofinale.Packets.Cs
return;
}
Account account = DatabaseManager.db.GetAccountByTokenGrant(req.Token);
if (account==null)
{
session.Send(ScMsgId.ScNtfErrorCode, new ScNtfErrorCode()
{
Details = "Auth Error",
ErrorCode = (int)CODE.ErrLoginProcessLogin,
});
session.Disconnect();
return;
}
ScLogin rsp = new()
{
IsEnc = false,
@ -95,29 +138,11 @@ namespace Campofinale.Packets.Cs
return;
}
session.Send(new PacketScSyncBaseData(session));
ScItemBagCommonSync common = new()
session.Send(ScMsgId.ScSceneClientIdInfo, new ScSceneClientIdInfo()
{
LostAndFound = new()
{
InstList =
{
new ScdItemGrid()
{
GridIndex=0,
Count=1,
Id="item_port_power_pole_2",
Inst = new()
{
InstId=300000000000,
},
}
}
},
};
session.Send(ScMsgId.ScItemBagCommonSync, common);
RoleIdx=6,
LastMaxIdx=session.random.v
});
session.Send(new PacketScItemBagScopeSync(session, ItemValuableDepotType.Weapon));
session.Send(new PacketScItemBagScopeSync(session, ItemValuableDepotType.WeaponGem));
session.Send(new PacketScItemBagScopeSync(session, ItemValuableDepotType.Equip));
@ -126,132 +151,7 @@ namespace Campofinale.Packets.Cs
session.Send(new PacketScItemBagScopeSync(session, ItemValuableDepotType.SpecialItem));
session.Send(new PacketScSyncAllMail(session));
session.Send(new PacketScSceneCollectionSync(session));
string json1 = File.ReadAllText("44_ScSyncAllMission.json");
ScSyncAllMission m = Newtonsoft.Json.JsonConvert.DeserializeObject<ScSyncAllMission>(json1);
m.TrackMissionId = "";
//Disabled the hardcoded one and enable the missionSystem one
//session.Send(ScMsgId.ScSyncAllMission, session.missionSystem.ToProto());
session.Send(ScMsgId.ScSyncAllMission, m);
/*ession.Send(ScMsgId.ScSyncAllMission, new ScSyncAllMission()
{
NewMissionTags =
{
},
Missions =
{
{"e0m0", new Mission()
{
MissionId="e0m0",
MissionState=(int)MissionState.Processing,
SucceedId=-1,
Properties =
{
{1,new DynamicParameter()
{
RealType=1,
ValueType=1,
ValueBoolList =
{
false
}
} }
}
} }
},
TrackMissionId = "e0m0",
CurQuests =
{
{"e0m0_q#1", new Quest()
{
QuestId="e0m0_q#1",
QuestState=(int)QuestState.Processing,
QuestObjectives =
{
new QuestObjective()
{
ConditionId="f6415b84",
IsComplete=false
}
}
} },
{"e0m0_q#2", new Quest()
{
QuestId="e0m0_q#2",
QuestState=(int)QuestState.Available,
QuestObjectives =
{
new QuestObjective()
{
ConditionId="81736ca7",
IsComplete=false,
}
}
} },
{"e0m0_q#3", new Quest()
{
QuestId="e0m0_q#3",
QuestState=(int)QuestState.Available,
QuestObjectives =
{
}
} },
{"e0m0_q#4", new Quest()
{
QuestId="e0m0_q#4",
QuestState=(int)QuestState.Available,
QuestObjectives =
{
}
} },
{"e0m0_q#5", new Quest()
{
QuestId="e0m0_q#5",
QuestState=(int)QuestState.Available,
QuestObjectives =
{
}
} },
{"e0m0_q#6", new Quest()
{
QuestId="e0m0_q#6",
QuestState=(int)QuestState.Available,
QuestObjectives =
{
}
} },
{"e0m0_q#7", new Quest()
{
QuestId="e0m0_q#7",
QuestState=(int)QuestState.Available,
QuestObjectives =
{
}
} },
{"e0m0_q#8", new Quest()
{
QuestId="e0m0_q#8",
QuestState=(int)QuestState.Available,
QuestObjectives =
{
}
} }
}
});*/
session.Send(new PacketScSyncAllMission(session));
session.Send(new PacketScGachaSync(session));
ScSettlementSyncAll settlements = new ScSettlementSyncAll()
{
@ -311,8 +211,10 @@ namespace Campofinale.Packets.Cs
session.EnterScene();
session.Initialized = true;
session.Update();
session.adventureBookManager.data.dailyLogin++;
session.adventureBookManager.TaskUpdate(ConditionType.CheckStatisticVal, null);
}
static byte[] GenerateRandomBytes(int length)
{

View File

@ -30,6 +30,7 @@ namespace Campofinale.Packets.Cs
ScSceneInteractSpInteractive rsp = new()
{
ObjId = req.ObjId,
};
session.Send(ScMsgId.ScSceneInteractSpInteractive, rsp);
}

View File

@ -11,8 +11,11 @@ namespace Campofinale.Packets.Cs
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsSceneInteractiveEventTrigger req = packet.DecodeBody<CsSceneInteractiveEventTrigger>();
ScSceneInteractiveEventTrigger rsp = new()
{
};
session.Send(ScMsgId.ScSceneInteractiveEventTrigger, rsp,packet.csHead.UpSeqid);
EntityInteractive entity = (EntityInteractive)session.sceneManager.GetEntity(req.Id);
if (entity != null)
{
@ -20,17 +23,14 @@ namespace Campofinale.Packets.Cs
{
}
else
ScSceneTriggerClientInteractiveEvent tr = new()
{
ScSceneTriggerClientInteractiveEvent tr = new()
{
EventName = req.EventName,
Id = req.Id,
SceneNumId = req.SceneNumId,
};
session.Send(ScMsgId.ScSceneTriggerClientInteractiveEvent, tr);
}
EventName = req.EventName,
Id = req.Id,
SceneNumId = req.SceneNumId,
};
session.Send(ScMsgId.ScSceneTriggerClientInteractiveEvent, tr);
}
}

View File

@ -13,16 +13,11 @@ namespace Campofinale.Packets.Cs
{
CsSceneLoadFinish req = packet.DecodeBody<CsSceneLoadFinish>();
session.curSceneNumId=req.SceneNumId;
session.Send(new PacketScSelfSceneInfo(session, SelfInfoReasonType.SlrEnterScene));
session.sceneManager.LoadCurrentTeamEntities();
session.sceneManager.LoadCurrent();
session.LoadFinish = true;
session.Send(ScMsgId.ScSceneClientIdInfo, new ScSceneClientIdInfo()
{
RoleIdx = (uint)session.roleId,
LastMaxIdx = session.random.usedGuids.Max()
});
if (session.curSceneNumId == 98)
{
session.Send(new PacketScSyncGameMode(session, "spaceship"));
@ -41,7 +36,7 @@ namespace Campofinale.Packets.Cs
}
}
session.LoadFinish = true;
session.sceneLoadState = Player.SceneLoadState.OK;
}
}
}

View File

@ -0,0 +1,24 @@
using Campofinale.Network;
using Campofinale.Protocol;
namespace Campofinale.Packets.Cs
{
public class HandleCsSceneMonsterSpawnerBeginWave
{
[Server.Handler(CsMsgId.CsSceneMonsterSpawnerBeginWave)]
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsSceneMonsterSpawnerBeginWave req = packet.DecodeBody<CsSceneMonsterSpawnerBeginWave>();
session.sceneManager.GetCurScene().SpawnWaveEnemy(req.SpawnerId, req.WaveId);
session.Send(ScMsgId.ScSceneMonsterSpawnerBeginWave, new ScSceneMonsterSpawnerBeginWave()
{
SceneNumId=req.SceneNumId,
SpawnerId=req.SpawnerId,
WaveId=req.WaveId,
});
}
}
}

View File

@ -10,9 +10,8 @@ namespace Campofinale.Packets.Cs
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsSceneMoveStateSet req = packet.DecodeBody<CsSceneMoveStateSet>();
//req.
}
}

View File

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

View File

@ -10,18 +10,10 @@ namespace Campofinale.Packets.Cs
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsSceneSetLastSafeZone req = packet.DecodeBody<CsSceneSetLastSafeZone>();
//TODO understand how to work
if (req.SceneNumId != session.curSceneNumId)
/*if (req.SceneNumId != session.curSceneNumId)
{
//session.sceneManager.UnloadCurrent(true);
session.curSceneNumId = req.SceneNumId;
Logger.Print("Cur Scene id changed by SetLastSafeZone");
//session.sceneManager.LoadCurrent();
//session.EnterScene(req.SceneNumId,new Vector3f(req.Position),new Vector3f(req.Rotation));
}
session.SeamlessEnterScene(req.SceneNumId);
}*/
}
}

View File

@ -1,10 +1,12 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Game.Entities;
using Campofinale.Network;
using Campofinale.Protocol;
using Campofinale.Resource;
using Campofinale.Resource.Table;
using Campofinale.Resource.Json;
using Pastel;
using System.Net.Sockets;
using static Campofinale.Resource.ResourceManager.LevelScene.LevelData;
namespace Campofinale.Packets.Cs
{
@ -14,19 +16,44 @@ namespace Campofinale.Packets.Cs
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsSceneSetLevelScriptActive req = packet.DecodeBody<CsSceneSetLevelScriptActive>();
if (req.IsActive)
LevelScriptData data = ResourceManager.GetLevelData(session.curSceneNumId).levelData.levelScripts.Find(s=>s.scriptId==req.ScriptId);
if (data != null)
if (data.refGameId != null && session.currentDungeon != null)
{
if (session.currentDungeon.table.dungeonId != data.refGameId)
{
return;
}
}
var sceneScript = session.sceneManager.GetCurScene().scripts.Find(s => s.scriptId == req.ScriptId);
if (sceneScript != null)
{
if (req.IsActive)
{
sceneScript.state = 3;
}
else
{
sceneScript.state = 2;
}
ScSceneLevelScriptStateNotify rsp = new ScSceneLevelScriptStateNotify()
{
SceneNumId = req.SceneNumId,
ScriptId = req.ScriptId,
State = 3
State = sceneScript.state
};
if (!session.sceneManager.GetCurScene().activeScripts.Contains(req.ScriptId))
{
session.sceneManager.GetCurScene().activeScripts.Add(req.ScriptId);
session.sceneManager.GetCurScene().UpdateShowEntities();
}
session.Send(ScMsgId.ScSceneLevelScriptStateNotify, rsp);
}
}
@ -34,22 +61,43 @@ namespace Campofinale.Packets.Cs
public static void HandleCsSceneSetLevelScriptStart(Player session, CsMsgId cmdId, Packet packet)
{
CsSceneSetLevelScriptStart req = packet.DecodeBody<CsSceneSetLevelScriptStart>();
if (req.IsStart)
LevelScriptData data = ResourceManager.GetLevelData(session.curSceneNumId).levelData.levelScripts.Find(s => s.scriptId == req.ScriptId);
if(data!=null)
if (data.refGameId != null && session.currentDungeon != null)
{
if (session.currentDungeon.table.dungeonId != data.refGameId)
{
return;
}
}
var sceneScript = session.sceneManager.GetCurScene().scripts.Find(s => s.scriptId == req.ScriptId);
if (sceneScript != null)
{
if (req.IsStart)
{
sceneScript.state = 4;
}
else
{
sceneScript.state = 3;
}
ScSceneLevelScriptStateNotify rsp = new ScSceneLevelScriptStateNotify()
{
SceneNumId = req.SceneNumId,
ScriptId = req.ScriptId,
State = 4
State = sceneScript.state
};
session.Send(ScMsgId.ScSceneLevelScriptStateNotify, rsp);
}
}
public static void ExecuteEventAction(Player player, ScriptAction action)
public static void ExecuteEventAction(Player player, ScriptAction action, CsSceneLevelScriptEventTrigger req)
{
switch (action.action)
{
@ -60,7 +108,119 @@ namespace Campofinale.Packets.Cs
player.missionSystem.ProcessQuest(action.valueStr[0]);
break;
case ScriptActionType.SpawnEnemy:
player.sceneManager.GetCurScene().SpawnEnemy(action.valueUlong[0]);
foreach (ulong id in action.valueUlong)
{
player.sceneManager.GetCurScene().SpawnEnemy(id,true);
}
break;
case ScriptActionType.SpawnEnemyByScriptId:
foreach(ulong id in action.valueUlong)
{
player.sceneManager.GetCurScene().SpawnEnemyByScriptId(id);
}
break;
case ScriptActionType.UnlockSystem:
UnlockSystemType type = (UnlockSystemType)Enum.Parse(typeof(UnlockSystemType), action.valueStr[0]);
player.UnlockSystem(type);
break;
case ScriptActionType.EnterScene:
player.EnterScene((int)action.valueUlong[0]);
break;
case ScriptActionType.CompleteMission:
player.missionSystem.CompleteMission(action.valueStr[0]);
break;
case ScriptActionType.AddMission:
player.missionSystem.AddMission(action.valueStr[0],MissionState.Processing,true);
if(action.valueUlong !=null)
if(action.valueUlong.Length > 0)
{
player.missionSystem.TrackMission(action.valueStr[0]);
}
break;
case ScriptActionType.StartSpawner:
ScSceneMonsterSpawnerStart start = new()
{
SceneNumId = player.curSceneNumId,
SpawnerId = action.valueUlong[0],
};
player.Send(ScMsgId.ScSceneMonsterSpawnerStart,start);
break;
case ScriptActionType.AddCharacter:
Character chara =player.AddCharacter(action.valueStr[0],(int) action.valueUlong[0],true);
player.AddToTeam(player.teamIndex, chara.guid);
break;
case ScriptActionType.ChangeScriptPropertyBool:
int i = 0;
ScSceneUpdateLevelScriptProperty update1 = new()
{
SceneNumId = req.SceneNumId,
ScriptId = req.ScriptId,
};
foreach (string keyId in action.valueStr)
{
long val = (long)action.valueUlong[i];
LevelScriptData levelscript = ResourceManager.GetLevelData(player.curSceneNumId).levelData.levelScripts.Find(l => l.scriptId == req.ScriptId);
if (levelscript != null)
{
int key = levelscript.GetPropertyId(keyId, new List<int>());
ParamKeyValue v = new()
{
key = keyId,
value = new ParamKeyValue.ParamValue()
{
type = ParamRealType.Bool,
valueArray = new[]
{
new ParamKeyValue.ParamValueAtom()
{
valueBit64=val,
}
}
}
};
update1.Properties.Add(key, v.ToProto());
}
i++;
}
player.Send(ScMsgId.ScSceneUpdateLevelScriptProperty, update1);
break;
case ScriptActionType.StartScript:
foreach (ulong id in action.valueUlong)
{
ScSceneLevelScriptStateNotify rsp = new ScSceneLevelScriptStateNotify()
{
SceneNumId = req.SceneNumId,
ScriptId = id,
State = 4
};
player.Send(ScMsgId.ScSceneLevelScriptStateNotify, rsp);
}
break;
case ScriptActionType.CallClientEvent:
foreach(string id in action.valueStr)
{
LevelScriptData levelscript = ResourceManager.GetLevelData(player.curSceneNumId).levelData.levelScripts.Find(l => l.actionMap.dataMap.headerList.Any(h=>h._eventKey.constValue==id));
ScSceneTriggerClientLevelScriptEvent trigger = new()
{
EventName = id,
SceneNumId = req.SceneNumId,
ScriptId = levelscript== null ? req.ScriptId : levelscript.scriptId,
};
player.Send(ScMsgId.ScSceneTriggerClientLevelScriptEvent, trigger);
}
break;
default:
Logger.PrintWarn("Script Action not implemented");
@ -73,14 +233,14 @@ namespace Campofinale.Packets.Cs
CsSceneLevelScriptEventTrigger req = packet.DecodeBody<CsSceneLevelScriptEventTrigger>();
Logger.Print(req.Properties.ToString());
if (ResourceManager.levelScriptsEvents.TryGetValue(req.EventName, out LevelScriptEvent levelScriptEvent))
{
Logger.Print($"Event {req.EventName.Pastel(ConsoleColor.Yellow)} Executed.");
Logger.Print($"{levelScriptEvent.comment}");
levelScriptEvent.actions.ForEach(a =>
{
ExecuteEventAction(session, a);
ExecuteEventAction(session, a,req);
});
}
else
@ -90,84 +250,6 @@ namespace Campofinale.Packets.Cs
Logger.PrintWarn($" ScriptID: {req.ScriptId.ToString().Pastel(ConsoleColor.White)} ");
Logger.PrintWarn($"]");
}
/*if(req.EventName== "#8777e316")
{
session.Send(ScMsgId.ScQuestStateUpdate, new ScQuestStateUpdate()
{
QuestId = "e0m0_q#1",
QuestState = (int)QuestState.Completed,
});
session.Send(ScMsgId.ScQuestStateUpdate, new ScQuestStateUpdate()
{
QuestId = "e0m0_q#2",
QuestState = (int)QuestState.Processing,
});
}
if(req.EventName== "#6ea2690d")
{
session.Send(ScMsgId.ScQuestStateUpdate, new ScQuestStateUpdate()
{
QuestId = "e0m0_q#2",
QuestState = (int)QuestState.Completed,
});
session.Send(ScMsgId.ScQuestStateUpdate, new ScQuestStateUpdate()
{
QuestId = "e0m0_q#3",
QuestState = (int)QuestState.Processing,
});
}
if (req.EventName == "#bb79de30")
{
session.Send(ScMsgId.ScQuestStateUpdate, new ScQuestStateUpdate()
{
QuestId = "e0m0_q#3",
QuestState = (int)QuestState.Completed,
});
session.Send(ScMsgId.ScQuestStateUpdate, new ScQuestStateUpdate()
{
QuestId = "e0m0_q#4",
QuestState = (int)QuestState.Processing,
});
}
if (req.EventName == "#4c76ec3c")
{
session.Send(ScMsgId.ScQuestStateUpdate, new ScQuestStateUpdate()
{
QuestId = "e0m0_q#4",
QuestState = (int)QuestState.Completed,
});
session.Send(ScMsgId.ScQuestStateUpdate, new ScQuestStateUpdate()
{
QuestId = "e0m0_q#5",
QuestState = (int)QuestState.Processing,
});
}
if (req.EventName == "#251df3ad")
{
session.Send(ScMsgId.ScQuestStateUpdate, new ScQuestStateUpdate()
{
QuestId = "e0m0_q#5",
QuestState = (int)QuestState.Completed,
});
session.Send(ScMsgId.ScQuestStateUpdate, new ScQuestStateUpdate()
{
QuestId = "e0m0_q#6",
QuestState = (int)QuestState.Processing,
});
}
if (req.EventName == "#e6ac322b")
{
session.Send(ScMsgId.ScQuestStateUpdate, new ScQuestStateUpdate()
{
QuestId = "e0m0_q#6",
QuestState = (int)QuestState.Completed,
});
session.Send(ScMsgId.ScQuestStateUpdate, new ScQuestStateUpdate()
{
QuestId = "e0m0_q#7",
QuestState = (int)QuestState.Processing,
});
}*/
ScSceneUpdateLevelScriptProperty update1 = new()
{
@ -175,23 +257,28 @@ namespace Campofinale.Packets.Cs
ScriptId = req.ScriptId,
};
LevelScriptData levelscript= ResourceManager.GetLevelData(session.curSceneNumId).levelData.levelScripts.Find(l=>l.scriptId == req.ScriptId);
var sceneScript = session.sceneManager.GetCurScene().scripts.Find(s => s.scriptId == req.ScriptId);
if (levelscript != null && sceneScript != null) {
foreach (var item in req.Properties)
{
int key = levelscript.GetPropertyId(item.Key, new List<int>());
sceneScript.properties[item.Key] = new ScriptProperty(item.Value);
update1.Properties.Add(key, item.Value);
}
}
session.Send(ScMsgId.ScSceneUpdateLevelScriptProperty, update1);
ScSceneTriggerClientLevelScriptEvent trigger = new()
{
EventName = req.EventName,
SceneNumId = req.SceneNumId,
ScriptId = req.ScriptId,
};
session.Send(ScMsgId.ScSceneTriggerClientLevelScriptEvent, trigger);
ScSceneUpdateLevelScriptProperty update2 = new()
/*ScSceneUpdateLevelScriptProperty update2 = new()
{
SceneNumId = req.SceneNumId,
ScriptId = req.ScriptId,
};
session.Send(ScMsgId.ScSceneUpdateLevelScriptProperty, update2);
session.Send(ScMsgId.ScSceneUpdateLevelScriptProperty, update2);*/
ScSceneLevelScriptEventTrigger rsp = new ScSceneLevelScriptEventTrigger()
{

View File

@ -1,5 +1,6 @@
using Campofinale.Network;
using Campofinale.Protocol;
using Campofinale.Utils;
namespace Campofinale.Packets.Cs
{
@ -14,9 +15,21 @@ namespace Campofinale.Packets.Cs
if (session.curSceneNumId != req.SceneNumId)
{
session.EnterScene(req.SceneNumId, new Resource.ResourceManager.Vector3f(req.Position), new Resource.ResourceManager.Vector3f(req.Rotation));
/* ScSceneTeleport t = new()
{
TeleportReason = req.TeleportReason,
PassThroughData = req.PassThroughData,
Position = req.Position,
Rotation = req.Rotation,
SceneNumId = req.SceneNumId,
};
session.Send(ScMsgId.ScSceneTeleport, t);*/
}
else
{
uint unixTimestamp = (uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var generator = new SnowflakeIdGenerator(machineId: 1);
long id = generator.GenerateId();
ScSceneTeleport t = new()
{
TeleportReason = req.TeleportReason,
@ -24,6 +37,8 @@ namespace Campofinale.Packets.Cs
Position = req.Position,
Rotation = req.Rotation,
SceneNumId = req.SceneNumId,
ServerTime = unixTimestamp,
TpUuid= (ulong)id
};
session.curSceneNumId = t.SceneNumId;
session.Send(ScMsgId.ScSceneTeleport, t);

View File

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

View File

@ -0,0 +1,19 @@
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
namespace Campofinale.Packets.Cs
{
public class HandleCsTakeAdventureTaskReward
{
[Server.Handler(CsMsgId.CsTakeAdventureTaskReward)]
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsTakeAdventureTaskReward req = packet.DecodeBody<CsTakeAdventureTaskReward>();
session.adventureBookManager.ClaimTask(req.TaskId);
session.Send(new PacketScAdventureBookSync(session), packet.csHead.UpSeqid);
}
}
}

View File

@ -0,0 +1,20 @@
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Campofinale.Resource;
namespace Campofinale.Packets.Cs
{
public class HandleCsTakeAllAdventureTaskReward
{
[Server.Handler(CsMsgId.CsTakeAllAdventureTaskReward)]
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsTakeAllAdventureTaskReward req = packet.DecodeBody<CsTakeAllAdventureTaskReward>();
session.adventureBookManager.ClaimTasks((AdventureTaskType)req.TaskType);
session.Send(new PacketScAdventureBookSync(session), packet.csHead.UpSeqid);
}
}
}

View File

@ -10,11 +10,12 @@ namespace Campofinale.Packets.Cs
{
CsTrackMission req = packet.DecodeBody<CsTrackMission>();
session.missionSystem.curMission = req.MissionId;
ScTrackMissionChange rsp = new()
{
MissionId = req.MissionId
};
session.Send(ScMsgId.ScTrackMissionChange, rsp);
session.Send(ScMsgId.ScTrackMissionChange, rsp,packet.csHead.UpSeqid);
}
}
}

View File

@ -1,4 +1,4 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Protocol;

View File

@ -26,6 +26,7 @@ namespace Campofinale.Packets.Sc
{
LoginDays=1,
RewardDays=16,
}
}
}

View File

@ -1,6 +1,7 @@
using Campofinale.Network;
using Campofinale.Protocol;
using Campofinale.Resource;
using static Campofinale.Game.Adventure.AdventureBookManager;
namespace Campofinale.Packets.Sc
{
@ -8,19 +9,12 @@ namespace Campofinale.Packets.Sc
{
public PacketScAdventureBookSync(Player player) {
ScAdventureBookSync proto = new ScAdventureBookSync() {
AdventureBookStage=1,
DailyActivation=100,
AdventureBookStage=player.adventureBookManager.data.adventureBookStage,
DailyActivation=player.adventureBookManager.data.dailyActivation,
};
foreach(var i in ResourceManager.adventureTaskTable)
foreach (GameAdventureTask task in player.adventureBookManager.data.tasks)
{
if (i.Value.adventureBookStage == 1)
{
proto.Tasks.Add(new AdventureTask()
{
TaskId = i.Value.adventureTaskId,
State = 1
});
}
proto.Tasks.Add(task.ToProto());
}
SetData(ScMsgId.ScAdventureBookSync, proto);
}

View File

@ -1,4 +1,4 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Protocol;

View File

@ -1,4 +1,4 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Protocol;

View File

@ -0,0 +1,24 @@
using Campofinale.Game;
using Campofinale.Network;
using Campofinale.Protocol;
namespace Campofinale.Packets.Sc
{
public class PacketScCharBagSetTeam : Packet
{
public PacketScCharBagSetTeam(Player client, Team team, int index) {
ScCharBagSetTeam proto = new ScCharBagSetTeam()
{
CharTeam = {team.members },
LeaderId = team.leader,
ScopeName = 1,
TeamIndex = index,
TeamType = CharBagTeamType.Main,
};
SetData(ScMsgId.ScCharBagSetTeam, proto);
}
}
}

View File

@ -1,4 +1,4 @@
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Network;
using Campofinale.Protocol;

View File

@ -19,7 +19,7 @@ namespace Campofinale.Packets.Sc
SceneNumId = sceneNumId,
};
SetData(ScMsgId.ScEnterSceneNotify, proto);
}

View File

@ -0,0 +1,37 @@
using Campofinale.Game.Factory;
using Campofinale.Network;
using Campofinale.Protocol;
namespace Campofinale.Packets.Sc
{
public class PacketScFactoryModifyChapterNodes : Packet
{
public PacketScFactoryModifyChapterNodes(Player client,string chapterId,FactoryNode node) {
ScFactoryModifyChapterNodes edit = new()
{
ChapterId = chapterId,
Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds()/1000,
Nodes =
{
node.ToProto()
}
};
SetData(ScMsgId.ScFactoryModifyChapterNodes, edit);
}
public PacketScFactoryModifyChapterNodes(Player client, string chapterId, uint nodeId)
{
ScFactoryModifyChapterNodes edit = new()
{
ChapterId = chapterId,
Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds() / 1000,
RemoveNodes =
{
nodeId
}
};
SetData(ScMsgId.ScFactoryModifyChapterNodes, edit);
}
}
}

View File

@ -6,23 +6,50 @@ namespace Campofinale.Packets.Sc
public class PacketScFactoryOpRet : Packet
{
public PacketScFactoryOpRet(Player client, uint nodeId,FactoryOpType type) {
public PacketScFactoryOpRet(Player client, uint val,CsFactoryOp op) {
ScFactoryOpRet proto = new ScFactoryOpRet()
{
RetCode=FactoryOpRetCode.Ok,
OpType=type,
OpType=op.OpType,
};
if(type == FactoryOpType.Place)
if(op.OpType == FactoryOpType.Place)
{
proto.Place = new()
{
NodeId = nodeId
NodeId = val
};
proto.Index = "CHANNLE_BUILDING";
}
if (op.OpType == FactoryOpType.MoveNode)
{
proto.MoveNode = new()
{
};
}
if (op.OpType == FactoryOpType.AddConnection)
{
proto.AddConnection = new()
{
Index = val,
};
}
if (op.OpType == FactoryOpType.Dismantle)
{
proto.Dismantle = new()
{
};
}
if (op.OpType == FactoryOpType.SetTravelPoleDefaultNext)
{
proto.SetTravelPoleDefaultNext = new()
{
};
}
proto.Index=op.Index;
SetData(ScMsgId.ScFactoryOpRet, proto);
}

View File

@ -12,7 +12,7 @@ namespace Campofinale.Packets.Sc
public PacketScFactorySyncChapter(Player client, string chapterId) {
string json = File.ReadAllText("ScFactorySyncChapter.json");
/*string json = File.ReadAllText("ScFactorySyncChapter.json");
//ScFactorySyncChapter chapter = Newtonsoft.Json.JsonConvert.DeserializeObject<ScFactorySyncChapter>(json);
ScFactorySyncChapter chapter = new()
@ -61,7 +61,7 @@ namespace Campofinale.Packets.Sc
}
}
}*/
}
},
Blackboard = new()
{
@ -119,7 +119,7 @@ namespace Campofinale.Packets.Sc
{
},
});*/
});
LevelGradeInfo sceneGrade = ResourceManager.levelGradeTable[levelGroup].grades[0];
chapter.Blackboard.Power.PowerGen += sceneGrade.bandwidth;
chapter.Blackboard.Power.PowerSaveMax += sceneGrade.bandwidth;
@ -185,9 +185,9 @@ namespace Campofinale.Packets.Sc
foreach(FactoryNode node in client.factoryManager.GetChapter(chapterId).nodes)
{
chapter.Nodes.Add(node.ToProto());
}
}*/
//Logger.Print(Newtonsoft.Json.JsonConvert.SerializeObject(chapter,Newtonsoft.Json.Formatting.Indented));
SetData(ScMsgId.ScFactorySyncChapter, chapter);
SetData(ScMsgId.ScFactorySyncChapter, client.factoryManager.GetChapter(chapterId).ToProto());
}
}

View File

@ -16,7 +16,8 @@ namespace Campofinale.Packets.Sc
SummonList =
{
}
},
},
HasExtraObject = entities.Count > 1

View File

@ -59,7 +59,11 @@ namespace Campofinale.Packets.Sc
sceneInfo.Detail.CharList.Add(session.chars.Find(c => c.guid == m).ToSceneProto());
});
//Levelscripts here?
if (infoReason == SelfInfoReasonType.SlrSeamlesslyEnterScene)
{
sceneInfo.TeamInfo = null;
}
if(infoReason!= SelfInfoReasonType.SlrChangeTeam)
ResourceManager.GetLevelData(session.curSceneNumId).levelData.levelScripts.ForEach(l =>
{
LevelScriptInfo script = new LevelScriptInfo()
@ -69,13 +73,42 @@ namespace Campofinale.Packets.Sc
State = 2,
};
int i = 0;
foreach (var item in l.properties)
var sceneScript=session.sceneManager.GetCurScene().scripts.Find(s => s.scriptId == l.scriptId);
if (sceneScript == null)
{
sceneScript = new()
{
scriptId = l.scriptId,
state = 2
};
l.properties.ForEach(p =>
{
if(!sceneScript.properties.ContainsKey(p.key))
sceneScript.properties.Add(p.key,p.ToScriptProperty());
});
session.sceneManager.GetCurScene().scripts.Add(sceneScript);
}
if (Server.config.serverOptions.disableLevelscripts)
{
script.State = 1;
}
else
{
script.State = sceneScript.state;
}
int i = 0;
foreach (var item in sceneScript.properties)
{
if(item.Value != null)
{
DynamicParameter p = item.Value.ToProto();
if (p != null)
script.Properties.Add(l.GetPropertyId(item.Key, script.Properties.Keys.ToList()), p);
}
DynamicParameter p=item.ToProto();
if (p != null)
script.Properties.Add(l.GetPropertyId(item.key,script.Properties.Keys.ToList()), p);
}
sceneInfo.LevelScripts.Add(script);
});

View File

@ -0,0 +1,16 @@
using Campofinale.Network;
using Campofinale.Protocol;
namespace Campofinale.Packets.Sc
{
public class PacketScSyncAllMission : Packet
{
public PacketScSyncAllMission(Player client) {
SetData(ScMsgId.ScSyncAllMission, client.missionSystem.ToProto());
}
}
}

View File

@ -3,7 +3,7 @@ using Campofinale.Protocol;
using Google.Protobuf;
using System.Net.Sockets;
using Campofinale.Packets.Sc;
using Campofinale.Game.Character;
using Campofinale.Game.Char;
using Campofinale.Resource;
using Campofinale.Game.Inventory;
using static Campofinale.Resource.ResourceManager;
@ -16,6 +16,8 @@ using Campofinale.Game.Factory;
using Campofinale.Game.MissionSys;
using Pastel;
using System.Drawing;
using Campofinale.Game.Adventure;
using static Campofinale.Player;
namespace Campofinale
@ -81,8 +83,8 @@ namespace Campofinale
//Data
public string accountId = "";
public string nickname = "Endministrator";
public ulong roleId= 1;
public Gender gender=Gender.GenFemale;
public ulong roleId = 1;
public Gender gender = Gender.GenFemale;
public uint level = 20;
public uint xp = 0;
//
@ -98,14 +100,16 @@ namespace Campofinale
public BitsetManager bitsetManager;
public FactoryManager factoryManager;
public MissionSystem missionSystem;
public AdventureBookManager adventureBookManager;
public int teamIndex = 0;
public List<Team> teams= new List<Team>();
public List<Team> teams = new List<Team>();
public List<Mail> mails = new List<Mail>();
public List<int> unlockedSystems = new();
public List<ulong> noSpawnAnymore = new();
public long maxDashEnergy = 250;
public uint curStamina = 10;
public long nextRecoverTime = 0;
public long nextDailyReset = 0;
public Dungeon currentDungeon;
public PlayerSafeZoneInfo savedSaveZone;
@ -128,6 +132,7 @@ namespace Campofinale
spaceshipManager = new(this);
factoryManager = new(this);
missionSystem = new(this);
adventureBookManager = new(this);
receivorThread = new Thread(new ThreadStart(Receive));
}
@ -168,14 +173,16 @@ namespace Campofinale
{
sceneManager.scenes = data.scenes;
}
nextDailyReset = data.nextDailyReset;
bitsetManager.Load(data.bitsets);
savedSaveZone = data.savedSafeZone;
if(Server.config.serverOptions.missionsEnabled) missionSystem.Load();
}
else
{
Initialize(); //only if no account found
}
missionSystem.Load();
adventureBookManager.Load();
sceneManager.Load();
factoryManager.Load();
return (data != null);
@ -202,39 +209,99 @@ namespace Campofinale
{
return chars.Find(c => c.id==templateId);
}
/// <summary>
/// Add a character with template id if not present in the chars list *Added in 1.1.6*
/// </summary>
/// <param name="id"></param>
public Character AddCharacter(string id, bool notify = false)
{
Character chara = GetCharacter(id);
if (chara == null)
{
chara = new Character(roleId, id, 1);
chars.Add(chara);
if (notify)
{
Send(new PacketScCharBagAddChar(this,chara));
}
}
return chara;
}
/// <summary>
/// Add a character with template id and level if not present in the chars list *Added in 1.1.6*
/// </summary>
/// <param name="id"></param>
public Character AddCharacter(string id, int level, bool notify = false)
{
Character chara = GetCharacter(id);
if (chara == null)
{
chara = new Character(roleId, id, level);
chars.Add(chara);
if (notify)
{
Send(new PacketScCharBagAddChar(this, chara));
}
}
return chara;
}
/// <summary>
/// Remove a character using template id *Added in 1.1.6*
/// </summary>
/// <param name="id"></param>
public void RemoveCharacter(string id)
{
Character chara = GetCharacter(id);
if (chara == null)
{
return;
}
chars.Remove(chara);
Send(new PacketScCharBagDelChar(this,chara));
}
public void ReplaceCharacter(string id, string newId)
{
Character chara = GetCharacter(id);
if (chara == null)
{
return;
}
chara.id = newId;
Send(new PacketScSyncCharBagInfo(this));
}
public void Initialize()
{
if (Server.config.serverOptions.defaultCharacters.giveAllCharacters)
if (Server.config.serverOptions.missionsEnabled)
{
foreach (var item in ResourceManager.characterTable)
{
chars.Add(new Character(roleId, item.Key, Server.config.serverOptions.defaultCharacters.defaultLevel));
}
chars.Add(new Character(roleId, "chr_0002_endminm", 1));
missionSystem.AddMission("e0m0", MissionState.Processing);
}
else
{
foreach (var item in Server.config.serverOptions.defaultCharacters.characters)
foreach (var item in ResourceManager.characterTable)
{
chars.Add(new Character(roleId, item, Server.config.serverOptions.defaultCharacters.defaultLevel));
chars.Add(new Character(roleId, item.Key, 1));
}
UnlockImportantSystems();
}
if (Server.config.serverOptions.giveAllItems)
{
foreach (var item in itemTable)
{
if (item.Value.GetStorage() != ItemStorageSpace.BagAndFactoryDepot)
{
if (item.Value.maxStackCount == -1)
{
inventoryManager.items.Add(new Item(roleId, item.Value.id, 10000000));
}
else
{
inventoryManager.items.Add(new Item(roleId, item.Value.id, item.Value.maxStackCount));
}
}
}
}
foreach(var item in itemTable)
{
if(item.Value.GetStorage()!= ItemStorageSpace.BagAndFactoryDepot)
{
if (item.Value.maxStackCount == -1)
{
inventoryManager.items.Add(new Item(roleId, item.Value.id, 10000000));
}
else
{
inventoryManager.items.Add(new Item(roleId, item.Value.id, item.Value.maxStackCount));
}
}
}
teams.Add(new Team()
{
leader = chars[0].guid,
@ -262,8 +329,8 @@ namespace Campofinale
}
});*/
UnlockImportantSystems();
spaceshipManager.Load();
}
public void UnlockImportantSystems()
@ -283,7 +350,7 @@ namespace Campofinale
{
//sceneManager.UnloadCurrent(false);
//sceneManager.LoadCurrent();
LoadFinish = false;
sceneLoadState = SceneLoadState.Loading;
Send(new PacketScEnterSceneNotify(this, curSceneNumId));
}
if (savedSaveZone == null || savedSaveZone.sceneNumId == 0)
@ -296,7 +363,14 @@ namespace Campofinale
};
}
}
public bool LoadFinish = true;
public enum SceneLoadState
{
OK=0,
Loading=1,
}
public SceneLoadState sceneLoadState=0;
// public bool LoadFinish = true;
public void EnterScene(int sceneNumId, Vector3f pos, Vector3f rot, PassThroughData passThroughData = null)
{
// if (!LoadFinish) return;
@ -315,7 +389,7 @@ namespace Campofinale
curSceneNumId = sceneNumId;
position = pos;
rotation = rot;
LoadFinish = false;
sceneLoadState = SceneLoadState.Loading;
Send(new PacketScEnterSceneNotify(this, sceneNumId, pos, passThroughData));
//sceneManager.LoadCurrent();
}
@ -324,6 +398,37 @@ namespace Campofinale
Logger.PrintError($"Scene {sceneNumId} not found");
}
}
/// <summary>
/// Seamless Crossing scene is not working, self scene info is not modifying the current scene num id in the client...
/// </summary>
/// <param name="sceneNumId"></param>
public void SeamlessEnterScene(int sceneNumId)
{
if(curSceneNumId != sceneNumId && sceneLoadState == SceneLoadState.OK)
{
sceneLoadState=SceneLoadState.Loading;
curSceneNumId = sceneNumId;
Send(new PacketScSelfSceneInfo(this, SelfInfoReasonType.SlrSeamlesslyEnterScene));
ScFactoryModifyChapterScene modify = new()
{
ChapterId=GetCurrentChapter(),
SceneId=sceneNumId,
Tms=DateTime.UtcNow.ToUnixTimestampMilliseconds()
};
Send(ScMsgId.ScFactoryModifyChapterScene, modify);
ScSceneCrossSceneStatus cross = new()
{
ObjId = teams[teamIndex].leader,
SceneNumId = curSceneNumId
};
Send(ScMsgId.ScSceneCrossSceneStatus, cross);
sceneManager.LoadCurrentTeamEntities();
sceneManager.LoadCurrent();
sceneLoadState = SceneLoadState.OK;
}
}
public void EnterScene(int sceneNumId)
{
if(GetLevelData(sceneNumId) != null)
@ -344,7 +449,7 @@ namespace Campofinale
position = GetLevelData(sceneNumId).playerInitPos;
rotation = GetLevelData(sceneNumId).playerInitRot;
// sceneManager.LoadCurrent();
LoadFinish = false;
sceneLoadState = SceneLoadState.Loading;
Send(new PacketScEnterSceneNotify(this, sceneNumId));
}
@ -375,7 +480,7 @@ namespace Campofinale
{
Send(Packet.EncodePacket((int)id, mes, seq, totalPackCount, currentPackIndex));
}
public void Send(Packet packet)
public async void Send(Packet packet)
{
byte[] datas = packet.set_body.ToByteArray();
int maxChunkSize = 65535;
@ -402,11 +507,11 @@ namespace Campofinale
Send(Packet.EncodePacket(packet.cmdId, data, seqNext, (uint)chunks.Count, (uint)i));
}
}
public void Send(byte[] data)
public async void Send(byte[] data)
{
try
{
socket.Send(data);
await socket.SendAsync(data);
}
catch (Exception e)
{
@ -511,12 +616,16 @@ namespace Campofinale
DatabaseManager.db.SavePlayerData(this);
inventoryManager.Save();
spaceshipManager.Save();
adventureBookManager.Save();
factoryManager.Save();
if(Server.config.serverOptions.missionsEnabled) missionSystem.Save();
SaveCharacters();
SaveMails();
}
public void AddStamina(uint stamina)
{
curStamina += stamina;
if(curStamina > maxStamina)
{
@ -533,7 +642,14 @@ namespace Campofinale
nextRecoverTime= DateTime.UtcNow.AddMinutes(7).ToUnixTimestampMilliseconds();
AddStamina(1);
}
if(LoadFinish)
if(curtimestamp >= nextDailyReset && adventureBookManager.data!=null)
{
nextDailyReset = DateTime.UtcNow.GetNextDailyReset().ToUnixTimestampMilliseconds();
adventureBookManager.DailyReset();
if (Initialized)
this.Send(new PacketScAdventureBookSync(this));
}
if(sceneLoadState==0)
sceneManager.Update();
factoryManager.Update();
}
@ -563,30 +679,13 @@ namespace Campofinale
table = ResourceManager.dungeonTable[dungeonId],
};
this.currentDungeon = dungeon;
ScEnterDungeon enter = new()
{
DungeonId = dungeonId,
SceneId = dungeon.table.sceneId,
};
Send(new PacketScSyncAllUnlock(this));
EnterScene(GetSceneNumIdFromLevelData(dungeon.table.sceneId));
Send(ScMsgId.ScEnterDungeon, enter);
dungeon.Enter();
}
public void LeaveDungeon(CsLeaveDungeon req)
{
ScLeaveDungeon rsp = new()
{
DungeonId = req.DungeonId,
};
Send(ScMsgId.ScLeaveDungeon, rsp);
Dungeon dungeon = currentDungeon;
currentDungeon = null;
EnterScene(dungeon.prevPlayerSceneNumId, dungeon.prevPlayerPos, dungeon.prevPlayerRot);
if(currentDungeon!=null)
currentDungeon.Leave();
}
public string GetCurrentChapter()
@ -636,5 +735,29 @@ namespace Campofinale
}
}
/// <summary>
/// Unlock a system
/// </summary>
/// <param name="none"></param>
public void UnlockSystem(UnlockSystemType t)
{
unlockedSystems.Add((int)t);
Send(ScMsgId.ScUnlockSystem, new ScUnlockSystem()
{
UnlockSystemType = (int)t
});
}
public void AddToTeam(int index, ulong guid)
{
if (teams[index].members.Count < 4)
{
teams[index].members.Add(guid);
Send(new PacketScCharBagSetTeam(this, teams[index], index));
if(index==this.teamIndex)
Send(new PacketScSelfSceneInfo(this, Resource.SelfInfoReasonType.SlrChangeTeam));
}
}
}
}

View File

@ -1,19 +1,84 @@
using Campofinale;
using Newtonsoft.Json;
using System.Net.Sockets;
using System.Net;
using Campofinale.Network;
using Campofinale.Protocol;
using Google.Protobuf;
using Pastel;
using System.Drawing;
class Program
{
static void Main(string[] args)
{
StartServer(args);
StartServer(args);
//FakeClientTester();
}
public static byte[] ConcatenateByteArrays(byte[] array1, byte[] array2)
{
return array1.Concat(array2).ToArray();
}
private static void FakeClientTester()
{
//
string serverIp = "beyond-cn.hypergryph.com";
int serverPort = 30000;
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress[] addresses = Dns.GetHostAddresses(serverIp);
IPAddress ipAddress = addresses[0];
socket.Connect(new IPEndPoint(ipAddress, serverPort));
socket.Send(Packet.EncodePacket((int)CsMsgId.CsLogin,new CsLogin() { ClientVersion="0.5.5",Uid= "", Token= "", Env=EnvType.Prod,PlatformId=ClientPlatformType.Windows,Area=AreaType.Oversea,ClientResVersion="", LoginToken= "" }.ToByteArray()));
while (true)
{
byte[] buffer = new byte[3];
int length = socket.Receive(buffer);
if (length == 3)
{
Packet packet = null;
byte headLength = Packet.GetByte(buffer, 0);
ushort bodyLength = Packet.GetUInt16(buffer, 1);
byte[] moreData = new byte[bodyLength + headLength];
while (socket.Available < moreData.Length)
{
}
int mLength = socket.Receive(moreData);
if (mLength == moreData.Length)
{
buffer = ConcatenateByteArrays(buffer, moreData);
packet = Packet.Read(buffer);
switch ((ScMsgId)packet.cmdId)
{
case ScMsgId.ScLogin:
ScLogin p1 = ScLogin.Parser.ParseFrom(packet.finishedBody);
Console.WriteLine(JsonConvert.SerializeObject(p1));
break;
case ScMsgId.ScNtfErrorCode:
ScNtfErrorCode p2 = ScNtfErrorCode.Parser.ParseFrom(packet.finishedBody);
Console.WriteLine(JsonConvert.SerializeObject(p2));
break;
default:
string base64 = Convert.ToBase64String(packet.finishedBody);
Console.WriteLine($"{(ScMsgId)packet.cmdId}: {base64}");
break;
}
}
}
}
}
private static void StartServer(string[] args)
{
Console.Title = "Initializing...";
//bool disableLogs = args.Length > 0 && args[0].ToLower() == "nologs";
ConfigFile config = new ConfigFile();
if (File.Exists("server_config.json"))
{
@ -27,7 +92,7 @@ class Program
}).Start();
AppDomain.CurrentDomain.ProcessExit += (_, _) =>
{
Console.WriteLine("Shutting down...");
Logger.Print("Shutting down...");
Server.Shutdown();
};

View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Resource.Dynamic
{
public class SpawnerConfig
{
public string configId;
public Dictionary<string, SpawnerWave> waveMap = new();
public List<EnemyLibraryData> enemyLibrary = new();
public SpawnerConfig() { }
public class EnemyLibraryData
{
public string key;
public string enemyId;
public int enemyLevel;
}
public class SpawnerWave
{
public int waveId;
public bool repeatable;
public int waveModeKillCount;
public Dictionary<string, WaveGroup> groupMap = new();
}
public class WaveGroup
{
public int groupId;
public int groupMode;
public int groupModeKillCount;
public float timestamp;
public Dictionary<string, GroupAction> actionMap = new();
}
public class GroupAction
{
[JsonPropertyName("$type")]
public string type;
public int actionId;
public float timestamp;
public string libraryKey;
public int spawnCount;
public float spawnInterval;
public Vector3f position;
public Vector3f rotation;
public float randomizeRadius;
public int routeId;
}
}
}

View File

@ -1,6 +1,6 @@
namespace Campofinale.Resource
{
public enum MissionState : int// TypeDefIndex: 33630
public enum MissionState
{
None = 0,
Available = 1,
@ -17,6 +17,193 @@
Completed = 3,
Failed = 4,
}
public enum AdventureTaskState
{
None = 0,
Processing = 1,
Completed = 2,
Rewarded = 3
}
public enum ConditionType
{
Combined = 0,
NumberOfKills = 1,
TotalOfKills = 2,
MissionGroupComplete = 3,
MissionAvailable = 4,
MissionProcessing = 5,
MissionCompleted = 6,
MissionAction = 7,
ReachDestination = 8,
NumOfProduceItems = 9,
TotalOfProduceItems = 10,
GuideFinish = 11,
RepairBuilding = 12,
TotalOfOrder = 13,
BlocLevel = 14,
BlocExpFull = 15,
CanChangeGold = 16,
CharMaxLevel = 17,
QuestStateEqual = 18,
MissionStateEqual = 19,
CheckMissionSucceedId = 20,
ItemBagHasItem = 106,
PlayerHasItem = 107,
CastSkill = 108,
DepotHasItem = 109,
CheckGetEnoughItem = 110,
CheckGetEnoughItemInBag = 111,
CheckGetEnoughItemInDepot = 112,
FacBuildingConnected = 501,
FacBuildingUpgrade = 502,
FacBuildingAdded = 503,
FacBuildingWorking = 504,
FacRepairBuilding = 505,
FacProducePowerReach = 511,
FacProductivityReach = 512,
KillSpecificEnemy = 1000,
CheckBaseAndPoleConnected = 1001,
CheckBaseAndMinerRunning = 1002,
CheckTotalMinerRunning = 1003,
CheckInteract = 1004,
OnInteract = 1005,
CheckInteractiveBool = 1006,
CheckPlayerInMap = 1007,
CheckInteractiveInt = 1008,
SceneCollectionProgress = 2000,
CompareProperty = 4000,
PlusThenCompareTargetInteractiveProperty = 4001,
CheckTriggerSpecificInteractiveEvent = 4002,
CheckClientObjectiveCommon = 4003,
CompareTargetInteractiveProperty = 4004,
HasItemCount = 4501,
DungeonKeptTime = 4502,
CheckDoodadIsPickable = 5000,
CheckDoodadIsBreakable = 5001,
CheckInteractiveDestroyed = 5002,
CheckUnlockTech = 5003,
CheckRepairBuilding = 5004,
CheckStorageBoxHasEnoughItem = 5005,
CheckBuildingConnected = 5006,
CheckBuildingStateInArea = 5007,
CheckBuildingConnectedAsMA2SB = 5008,
CheckUnlockMultipleTech = 5009,
DoFacTradeCashAnyOrder = 5010,
CheckSceneAreaUnlocked = 5011,
CheckUnlockTechPackage = 5012,
CheckUnlockTechLayer = 5013,
FacBuildingCountInScene = 5014,
FacBuildingProducingCountInScene = 5015,
FacProducingFormulaCountInScene = 5016,
FacStatisticItemGenRate = 5017,
FacStatisticItemGen = 5018,
FacPowerCostSum = 5019,
FacBoxConveyorLengthSum = 5020,
FacStorageBoxHasItems = 5021,
CheckSpaceshipRoomLevel = 5022,
CheckAdventureLevel = 5023,
CheckShopNothingToBuy = 5024,
CheckLiquidInBag = 5025,
SettlementCheckExpEnoughToLevelup = 5026,
CheckBuildingConnectedSpecify = 5027,
CheckSpaceshipRoomUnlock = 5028,
CheckSpaceshipRoomBuilt = 5029,
CheckSpaceshipRoomStationCount = 5030,
CheckPassGameMechanicsId = 5031,
FacBuildingFluidContainerHasItem = 5032,
CheckFacSoilHarvest = 5033,
CheckFacBuildingState = 5034,
FacBattleBuildingCurEnergy = 5035,
CheckSpaceshipGrowCabinHarvest = 5036,
CheckGameInstCompletionStatus = 5037,
CheckItemGot = 5038,
CheckBuildingConnectedExist = 5039,
CheckFacSoilPlacedInPanel = 5040,
CheckWeaponGachaPoolIsOpen = 5041,
CheckShopGoodsIsSoldOut = 5042,
CheckPassedGameMechanicsNum = 5044,
CheckSettlementLevelSum = 5045,
CheckInteractiveLock = 5244,
CheckRichContentReadingDone = 5245,
CheckInteractiveSubmitSuccess = 5246,
CheckInteractiveNextAvailableTime = 5247,
CheckMonsterSpawnerComplete = 5248,
CheckItemBagCanPutIn = 5249,
CheckFluidVolume = 5250,
CheckGreaterWeapeonStageNum = 5251,
CheckRoleCreateTime = 5252,
CheckSceneGrade = 5253,
CheckUnlockGroupTechNum = 5254,
CheckCharSkillLevel = 5255,
CheckCharUnlockBreakTalentId = 5256,
CheckFactoryBlackBoxStateNum = 5257,
CheckDungeonTypePassNum = 5258,
CheckEquipTierLevelNumCharNum = 5259,
CheckInteractiveIsActivable = 5260,
CheckInteractiveIsActived = 5261,
CheckSceneScope = 5262,
CheckGameInstStartDuration = 5263,
CheckPlayerInDungeon = 5264,
CheckCharUnlock = 5265,
CheckCharFavorability = 5266,
CheckEtherSubmitCount = 5267,
CheckTDStart = 5600,
CheckTDSettlement = 5601,
CheckPanelOpen = 6000,
CheckQuestSubmitItem = 6001,
CheckLevelScriptProperty = 6002,
CheckRepeatableTalkFinish = 6003,
KillEnemyIdList = 6004,
CheckCompletedBlocMissionNum = 6005,
CheckSceneCollectionNum = 6006,
CheckPRTSCollectionUnlock = 6007,
CheckCostStamina = 6008,
CheckTmpShopAlreadyBuyCount = 6009,
CheckInPowerMinerCount = 6010,
CheckTimestamp = 6011,
CheckMissionProperty = 6012,
CheckProperty = 6015,
CheckClientGameVar = 6016,
CheckServerGameVar = 6017,
CheckPlayerHasEnoughItemList = 6018,
CheckMiniGameCompletedCount = 6019,
CheckMonsterKilledNum = 6020,
CheckTerminalReadingDone = 6021,
CheckScriptTaskStateEqual = 6022,
CheckFactoryBlackBoxState = 6023,
CheckTeamMemberNumberEven = 6024,
CheckDaysNumAfterMissionComplete = 6025,
CheckTimelineFinish = 6026,
CheckFmvFinish = 6027,
CheckRemoteCommFinish = 6028,
CheckTalkFinish = 6029,
CheckPrtsInvestigateFinish = 6030,
CheckSNSDialogComplete = 6500,
CheckSNSDialogContent = 6501,
CheckGreaterCharLevelNum = 6502,
CheckGreaterWeapeonLevelNum = 6503,
CheckGreaterCharStageNum = 6504,
CheckGreaterCharPotentialNum = 6505,
CheckGreaterSettlementLevelNum = 6506,
CheckStatisticVal = 6507,
ClientOnly = 9999,
SystemUnlocked = 10000,
None = 2147483647
}
public enum AdventureTaskType
{
None = 0,
Daily = 1,
AdventureBook = 2
}
public enum LevelScriptState
{
None = 0,
Disabled = 1,
Enabled = 2,
Active = 3,
Running = 4
}
public enum InteractiveComponentType
{
TriggerObserver = 0,
@ -350,13 +537,6 @@
KeyStepFinish = 2,
Completed = 3
}
public enum AdventureTaskState // TypeDefIndex: 33702
{
None = 0,
Processing = 1,
Completed = 2,
Rewarded = 3
}
public enum EntryState // TypeDefIndex: 24402
{
Empty = 0,
@ -365,12 +545,6 @@
LevelLoaded = 3,
Invalid = 4
}
public enum AdventureTaskType // TypeDefIndex: 33687
{
None = 0,
Daily = 1,
AdventureBook = 2
}
public enum ItemStorageSpace // TypeDefIndex: 33575
{
None = 0,

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Resource.Json
{
[TableCfgType("Data/Conditions.json", LoadPriority.LOW)]
public class ConditionData
{
public List<string> args = new();
public string Get(int index)
{
return args[index];
}
public int ToInt(int index)
{
return int.Parse(args[index]);
}
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Resource.Json
{
public class LevelScriptEvent
{
public string eventName;
public string comment;
public List<ScriptAction> actions;
}
public class ScriptAction
{
public ScriptActionType action;
public string[] valueStr = new string[0];
public ulong[] valueUlong = new ulong[0];
}
public enum ScriptActionType
{
None = 0,
CompleteQuest = 1,
ProcessQuest = 2,
SpawnEnemy = 3,
UnlockSystem = 4,
EnterScene = 5,
AddMission = 6,
CompleteMission = 7,
SpawnEnemyByScriptId = 8,
CallClientEvent = 9,
StartScript = 10,
ChangeScriptPropertyBool = 11,
StartSpawner = 12,
AddCharacter = 13
}
}

View File

@ -1,6 +1,11 @@
using Campofinale.Resource.Table;
using Campofinale.Resource.Dynamic;
using Campofinale.Resource.Json;
using Campofinale.Resource.Table;
using Newtonsoft.Json;
using System.Numerics;
using System;
using static Campofinale.Resource.ResourceManager.LevelScene;
using static Campofinale.Resource.ResourceManager.LevelScene.LevelData;
namespace Campofinale.Resource
{
@ -52,6 +57,7 @@ namespace Campofinale.Resource
public static Dictionary<string, GachaWeaponPoolTable> gachaWeaponPoolTable = new();
//
public static Dictionary<string, EnemyTable> enemyTable = new();
public static Dictionary<string, WikiEnemyDropTable> wikiEnemyDropTable = new();
public static Dictionary<string, EquipTable> equipTable = new();
public static Dictionary<string, EquipSuitTable> equipSuitTable = new();
public static Dictionary<string, SpaceShipCharBehaviourTable> spaceShipCharBehaviourTable = new();
@ -68,12 +74,14 @@ namespace Campofinale.Resource
public static Dictionary<int, ItemTypeTable> itemTypeTable = new(); //
public static Dictionary<string, SNSChatTable> snsChatTable = new();//
public static Dictionary<string, GiftItemTable> giftItemTable = new();
public static Dictionary<string, InteractiveFacWrapperTable> interactiveFacWrapperTable = new();
public static List<MissionDataTable> missionDataTable = new();
public static InteractiveTable interactiveTable = new(); //
public static List<LevelScene> levelDatas = new();
public static List<InteractiveData> interactiveData = new();
public static List<InteractiveData> interactiveData = new();
public static List<SpawnerConfig> spawnerConfigs = new();
public static Dictionary<string,ConditionData> conditions=new();
public static int GetSceneNumIdFromLevelData(string name)
{
if (levelDatas.Find(a => a.id == name) == null) return 0;
@ -102,9 +110,9 @@ namespace Campofinale.Resource
public static void Init()
{
Logger.Print("Loading TableCfg resources");
// TODO: move all tables to the folder
sceneAreaTable=JsonConvert.DeserializeObject<Dictionary<string, SceneAreaTable>>(ReadJsonFile("TableCfg/SceneAreaTable.json"));
strIdNumTable = JsonConvert.DeserializeObject<StrIdNumTable>(ReadJsonFile("TableCfg/StrIdNumTable.json"));
characterTable = JsonConvert.DeserializeObject<Dictionary<string, CharacterTable>>(ReadJsonFile("TableCfg/CharacterTable.json"));
systemJumpTable = JsonConvert.DeserializeObject<Dictionary<string, SystemJumpTable>>(ReadJsonFile("TableCfg/SystemJumpTable.json"));
settlementBasicDataTable = JsonConvert.DeserializeObject<Dictionary<string, SettlementBasicDataTable>>(ReadJsonFile("TableCfg/SettlementBasicDataTable.json"));
blocMissionTable = JsonConvert.DeserializeObject<Dictionary<string, BlocMissionTable>>(ReadJsonFile("TableCfg/BlocMissionTable.json"));
@ -135,22 +143,21 @@ namespace Campofinale.Resource
spaceshipRoomInsTable = JsonConvert.DeserializeObject<Dictionary<string, SpaceshipRoomInsTable>>(ReadJsonFile("TableCfg/SpaceshipRoomInsTable.json"));
dungeonTable = JsonConvert.DeserializeObject<Dictionary<string, DungeonTable>>(ReadJsonFile("TableCfg/DungeonTable.json"));
equipSuitTable = JsonConvert.DeserializeObject<Dictionary<string, EquipSuitTable>>(ReadJsonFile("TableCfg/EquipSuitTable.json"));
levelGradeTable = JsonConvert.DeserializeObject<Dictionary<string, LevelGradeTable>>(ReadJsonFile("TableCfg/LevelGradeTable.json"));
levelShortIdTable = JsonConvert.DeserializeObject<Dictionary<string, LevelShortIdTable>>(ReadJsonFile("DynamicAssets/gamedata/gameplayconfig/jsoncfg/LevelShortIdTable.json"));
rewardTable = JsonConvert.DeserializeObject<Dictionary<string, RewardTable>>(ReadJsonFile("TableCfg/RewardTable.json"));
adventureTaskTable = JsonConvert.DeserializeObject<Dictionary<string, AdventureTaskTable>>(ReadJsonFile("TableCfg/AdventureTaskTable.json"));
factoryBuildingTable = JsonConvert.DeserializeObject<Dictionary<string, FactoryBuildingTable>>(ReadJsonFile("TableCfg/FactoryBuildingTable.json"));
facSTTNodeTable = JsonConvert.DeserializeObject<Dictionary<string, FacSTTNodeTable>>(ReadJsonFile("TableCfg/FacSTTNodeTable.json"));
facSTTLayerTable = JsonConvert.DeserializeObject<Dictionary<string, FacSTTLayerTable>>(ReadJsonFile("TableCfg/FacSTTLayerTable.json"));
itemTypeTable = JsonConvert.DeserializeObject<Dictionary<int, ItemTypeTable>>(ReadJsonFile("TableCfg/ItemTypeTable.json"));
interactiveTable = JsonConvert.DeserializeObject<InteractiveTable>(ReadJsonFile("Json/Interactive/InteractiveTable.json"));
LoadInteractiveData();
LoadLevelDatas();
LoadScriptsEvent();
LoadSpawners();
ResourceLoader.LoadTableCfg();
if (missingResources)
{
Logger.PrintWarn("Missing some resources. The gameserver will probably crash.");
Logger.PrintWarn("Some Resources are Missing. The Game server may not work properly.");
}
}
public static List<int> GetAllShortIds()
@ -220,6 +227,7 @@ namespace Campofinale.Resource
foreach (string json in jsonFiles)
{
InteractiveData data = JsonConvert.DeserializeObject<InteractiveData>(ReadJsonFile(json));
if (data != null)
{
interactiveData.Add(data);
@ -232,6 +240,60 @@ namespace Campofinale.Resource
Logger.PrintError($"Error occured when loading InteractiveData: " + e.Message);
}
}
public static void LoadScriptsEvent()
{
Logger.Print("Loading ScriptsEvents");
string directoryPath = @"Json/ScriptEvents";
try
{
string[] jsonFiles = Directory.GetFiles(directoryPath, "*.json", SearchOption.AllDirectories);
foreach (string json in jsonFiles)
{
Dictionary<string, LevelScriptEvent> events = JsonConvert.DeserializeObject<Dictionary<string, LevelScriptEvent>>(ReadJsonFile(json));
foreach (KeyValuePair<string, LevelScriptEvent> e in events)
{
if (levelScriptsEvents.ContainsKey(e.Key))
{
Logger.PrintWarn($"{e.Key} already added, skipping the one in {json}");
}
else
{
levelScriptsEvents.Add(e.Key, e.Value);
}
}
}
Logger.Print($"Loaded {levelScriptsEvents.Count} ScriptsEvents");
}
catch (Exception e)
{
Logger.PrintWarn($"No ScriptsEvents folder found in Json.");
}
}
public static void LoadSpawners()
{
Logger.Print("Loading Spawners");
string directoryPath = @"DynamicAssets\gamedata\spawnerconfig";
try
{
string[] jsonFiles = Directory.GetFiles(directoryPath, "*.json", SearchOption.AllDirectories);
foreach (string json in jsonFiles)
{
SpawnerConfig spawner = JsonConvert.DeserializeObject<SpawnerConfig>(ReadJsonFile(json));
spawnerConfigs.Add(spawner);
}
Logger.Print($"Loaded {spawnerConfigs.Count} Spawners");
}
catch (Exception e)
{
Logger.PrintError($"Error occured when loading SpawnerConfigs: " + e.Message);
}
}
public static void LoadLevelDatas()
{
@ -260,7 +322,7 @@ namespace Campofinale.Resource
catch (Exception ex)
{
//Logger.PrintError(ex.Message);
Logger.PrintWarn("Missing levelData natural spawns file for scene " + data.mapIdStr + " path: " + path);
Logger.PrintWarn("Missing LevelData natural spawns file for scene " + data.mapIdStr + " path: " + path);
}
}
@ -280,7 +342,8 @@ namespace Campofinale.Resource
public class InteractiveData
{
public string id;
public Dictionary<string, int> propertyKeyToIdMap;
public Dictionary<string, int> propertyKeyToIdMap = new();
public List<ParamKeyValue> saveProperties = new();
}
public class FactoryBuildingTable
{
@ -351,13 +414,13 @@ namespace Campofinale.Resource
public int adventureBookStage;
public string adventureTaskId;
public string conditionId;
public int conditionType;
public ConditionType conditionType;
public string jumpSystemId;
public int progressToCompare;
public string rewardId;
public int sortId;
public TaskDescription taskDesc;
public int taskType;
public AdventureTaskType taskType;
}
public class TaskDescription
{
@ -480,6 +543,8 @@ namespace Campofinale.Resource
public List<string> levelDataPaths;
[JsonIgnore]
public LevelData levelData;
//public List<LevelData> levelDataList;
public class LevelData
{
public string sceneId="";
@ -490,6 +555,8 @@ namespace Campofinale.Resource
public List<LevelScriptData> levelScripts = new();
public List<WorldWayPointSets> worldWayPointSets = new();
public List<LevelFactoryRegionData> factoryRegions = new();
public List<LevelSpawnerData> spawners = new();
public LevelFunctionAreaData functionArea = new();
public void Merge(LevelData other)
{
this.sceneId = other.sceneId;
@ -500,6 +567,8 @@ namespace Campofinale.Resource
this.levelScripts.AddRange(other.levelScripts);
this.worldWayPointSets.AddRange(other.worldWayPointSets);
this.factoryRegions.AddRange(other.factoryRegions);
this.spawners.AddRange(other.spawners);
this.functionArea.ranges.AddRange(other.functionArea.ranges);
}
public class WorldWayPointSets
@ -507,11 +576,39 @@ namespace Campofinale.Resource
public int id;
public Dictionary<string, int> pointIdToIndex = new();
}
public class LevelFunctionAreaData
{
public List<LevelFunctionRangeData> ranges = new();
public class LevelFunctionRangeData
{
public Vector3f m_center = new();
public Vector3f m_size = new();
public bool IsObjectInside(Vector3f position)
{
Vector3f halfSize = m_size * 0.5f;
return Math.Abs(position.x - m_center.x) <= halfSize.x &&
Math.Abs(position.y - m_center.y) <= halfSize.y &&
Math.Abs(position.z - m_center.z) <= halfSize.z;
}
}
}
public class LevelSpawnerData
{
public ulong spawnerId;
public string configId;
public ulong belongLevelScriptId;
}
public class LevelScriptData
{
public ulong scriptId;
public List<ParamKeyValue> properties;
public Dictionary<int, string> propertyIdToKeyMap;
public string refGameId;
public List<ParamKeyValue> properties = new();
public Dictionary<int, string> propertyIdToKeyMap = new();
public ScriptActionMap actionMap = new();
public int GetPropertyId(string key, List<int> toExclude)
@ -525,6 +622,28 @@ namespace Campofinale.Resource
}
return 0;
}
public class ScriptActionMap
{
public ActionDataMap dataMap = new();
public class ScriptHeader
{
public string _uid = "";
public EventKey _eventKey = new();
public class EventKey
{
public string constValue ="";
}
}
public class ActionDataMap
{
public List<ScriptHeader> headerList = new();
}
}
}
public class LevelFactoryRegionData
{
@ -588,6 +707,42 @@ namespace Campofinale.Resource
public List<ParamKeyValue> properties;
public Dictionary<InteractiveComponentType, List<ParamKeyValue>> componentProperties = new();
}
public class ScriptProperty
{
public int RealType;
public int ValueType;
public List<string> ValueStringList = new();
public List<float> ValueFloatList = new();
public List<long> ValueIntList = new();
public List<bool> ValueBoolList = new();
public ScriptProperty()
{
}
public ScriptProperty(DynamicParameter p)
{
this.RealType = p.RealType;
this.ValueType = p.ValueType;
this.ValueBoolList.AddRange(p.ValueBoolList.ToList());
this.ValueFloatList.AddRange(p.ValueFloatList.ToList());
this.ValueIntList.AddRange(p.ValueIntList.ToList());
this.ValueStringList.AddRange(p.ValueStringList.ToList());
}
public DynamicParameter ToProto()
{
return new DynamicParameter()
{
RealType = RealType,
ValueType = ValueType,
ValueStringList = { ValueStringList },
ValueBoolList = { ValueBoolList },
ValueFloatList = { ValueFloatList },
ValueIntList = { ValueIntList },
};
}
}
public class ParamKeyValue
{
public string key;
@ -665,6 +820,10 @@ namespace Campofinale.Resource
param.ValueIntList.Add(val.valueBit64);
param.ValueType = (int)ParamValueType.Int;
break;
case ParamRealType.UInt:
param.ValueIntList.Add(val.valueBit64);
param.ValueType = (int)ParamValueType.Int;
break;
case ParamRealType.WaterVolumePtr:
param.ValueIntList.Add(val.valueBit64);
param.ValueType = (int)ParamValueType.Int;
@ -677,6 +836,98 @@ namespace Campofinale.Resource
return param;
}
public ScriptProperty ToScriptProperty()
{
ScriptProperty param = new()
{
RealType = (int)value.type,
ValueType = (int)value.type,
};
foreach (var val in value.valueArray)
{
switch (value.type)
{
case ParamRealType.LangKey:
param.ValueStringList.Add(val.valueString);
param.ValueType = (int)ParamValueType.String;
break;
case ParamRealType.LangKeyList:
param.ValueStringList.Add(val.valueString);
param.ValueType = (int)ParamValueType.StringList;
break;
case ParamRealType.String:
param.ValueStringList.Add(val.valueString);
param.ValueType = (int)ParamValueType.String;
break;
case ParamRealType.StringList:
param.ValueStringList.Add(val.valueString);
param.ValueType = (int)ParamValueType.StringList;
break;
case ParamRealType.Vector3:
param.ValueFloatList.Add(val.ToFloat());
param.ValueType = (int)ParamValueType.FloatList;
break;
case ParamRealType.Float:
param.ValueFloatList.Add(val.ToFloat());
param.ValueType = (int)ParamValueType.Float;
break;
case ParamRealType.FloatList:
param.ValueFloatList.Add(val.ToFloat());
param.ValueType = (int)ParamValueType.FloatList;
break;
case ParamRealType.Int:
param.ValueIntList.Add(val.valueBit64);
param.ValueType = (int)ParamValueType.Int;
break;
case ParamRealType.IntList:
param.ValueIntList.Add(val.valueBit64);
param.ValueType = (int)ParamValueType.IntList;
break;
case ParamRealType.Bool:
param.ValueBoolList.Add(val.valueBit64 == 1);
param.ValueType = (int)ParamValueType.Bool;
break;
case ParamRealType.Vector3List:
param.ValueFloatList.Add(val.ToFloat());
param.ValueType = (int)ParamValueType.FloatList;
break;
case ParamRealType.BoolList:
param.ValueBoolList.Add(val.valueBit64 == 1);
param.ValueType = (int)ParamValueType.BoolList;
break;
case ParamRealType.EntityPtr:
param.ValueIntList.Add(val.valueBit64);
param.ValueType = (int)ParamValueType.Int;
break;
case ParamRealType.EntityPtrList:
param.ValueIntList.Add(val.valueBit64);
param.ValueType = (int)ParamValueType.Int;
break;
case ParamRealType.UInt64:
param.ValueIntList.Add(val.valueBit64);
param.ValueType = (int)ParamValueType.Int;
break;
case ParamRealType.WaterVolumePtr:
param.ValueIntList.Add(val.valueBit64);
param.ValueType = (int)ParamValueType.Int;
break;
default:
return null;
break;
}
}
return param;
}
public void Update(DynamicParameter value)
{
foreach (var item in value.ValueBoolList)
{
}
}
public class ParamValue
{
@ -732,6 +983,14 @@ namespace Campofinale.Resource
public Vector3f()
{
}
public static Vector3f operator *(Vector3f v, float scalar)
{
return new Vector3f(v.x * scalar, v.y * scalar, v.z * scalar);
}
public static Vector3f operator +(Vector3f v, Vector3f v2)
{
return new Vector3f(v.x + v2.x, v.y + v2.y, v.z + v2.z);
}
public Vector3f(float x, float y, float z)
{
@ -757,6 +1016,13 @@ namespace Campofinale.Resource
float dz = z - other.z;
return MathF.Sqrt(dx * dx + dy * dy + dz * dz);
}
public float DistanceXZ(Vector3f other)
{
float dx = x - other.x;
float dy = 0;
float dz = z - other.z;
return MathF.Sqrt(dx * dx + dy * dy + dz * dz);
}
public ScdVec3Int ToProtoScd()
{
return new ScdVec3Int()

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Resource
{
public enum ServerEventExec
{
UpdateTasks=0
}
}

View File

@ -0,0 +1,8 @@
namespace Campofinale.Resource.Table
{
[TableCfgType("TableCfg/InteractiveFacWrapperTable.json", LoadPriority.LOW)]
public class InteractiveFacWrapperTable
{
public string interactiveTemplateId;
}
}

View File

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Resource.Table
{
[TableCfgType("Json/LevelScriptEvents.json", LoadPriority.LOW)]
public class LevelScriptEvent : TableCfgResource
{
public string eventName;
public string comment;
public List<ScriptAction> actions;
}
public class ScriptAction
{
public ScriptActionType action;
public string[] valueStr;
public ulong[] valueUlong;
}
public enum ScriptActionType
{
None = 0,
CompleteQuest = 1,
ProcessQuest = 2,
SpawnEnemy = 3
}
}

View File

@ -0,0 +1,8 @@
namespace Campofinale.Resource.Table
{
[TableCfgType("TableCfg/WikiEnemyDropTable.json", LoadPriority.LOW)]
public class WikiEnemyDropTable
{
public List<string> dropItemIds = new();
}
}

View File

@ -21,6 +21,17 @@ namespace Campofinale
{
return (long)(dateTime - UnixEpoch).TotalMilliseconds;
}
public static DateTime GetNextDailyReset(this DateTime dateTime)
{
DateTime now = DateTime.UtcNow;
DateTime todayReset = new DateTime(now.Year, now.Month, now.Day, 6, 0, 0, DateTimeKind.Utc);
// Se siamo già passati oltre le 6:00 AM di oggi, ritorna le 6:00 AM di domani
if (now >= todayReset)
return todayReset.AddDays(1);
else
return todayReset;
}
}
public class Server
{
@ -48,20 +59,15 @@ namespace Campofinale
public delegate void HandlerDelegate(Player sender, string command, string[] args, Player target);
}
public static List<Player> clients = new List<Player>();
public static string ServerVersion = "1.1.5";
public static string ServerVersion = "1.1.6";
public static bool Initialized = false;
public static bool showLogs = true;
public static bool showWarningLogs = true;
public static bool showBodyLogs = false;
public static Dispatch dispatch;
public static ResourceManager resourceManager;
public static ConfigFile config;
public static Dispatch? dispatch;
public static ConfigFile? config;
public static List<CsMsgId> csMessageToHide = new() { CsMsgId.CsMoveObjectMove, CsMsgId.CsBattleOp,CsMsgId.CsPing };
public static List<ScMsgId> scMessageToHide = new() { ScMsgId.ScMoveObjectMove, ScMsgId.ScPing };
public static ResourceManager GetResources()
{
return resourceManager;
}
public static List<ScMsgId> scMessageToHide = new() { ScMsgId.ScMoveObjectMove, ScMsgId.ScPing,ScMsgId.ScObjectEnterView };
public void Start(ConfigFile config)
{
{
@ -179,7 +185,6 @@ namespace Campofinale
dispatch = new Dispatch();
dispatch.Start();
}
public static CsMsgId[] hideLog = [];
public static string ColoredText(string text, string color)
{

View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Utils
{
public class SnowflakeIdGenerator
{
private static readonly DateTime Epoch = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private readonly int _machineId; // es. 031 (5 bit)
private int _sequence = 0;
private long _lastTimestamp = -1L;
private readonly object _lock = new object();
public SnowflakeIdGenerator(int machineId)
{
_machineId = machineId & 0x1F; // 5 bit
}
public long GenerateId()
{
lock (_lock)
{
long timestamp = GetCurrentTimestamp();
if (timestamp == _lastTimestamp)
{
_sequence = (_sequence + 1) & 0xFFF; // 12 bit
if (_sequence == 0)
{
// Attendi il prossimo millisecondo
while ((timestamp = GetCurrentTimestamp()) <= _lastTimestamp) ;
}
}
else
{
_sequence = 0;
}
_lastTimestamp = timestamp;
return ((timestamp << 22) | ((long)_machineId << 12) | (long)_sequence);
}
}
private long GetCurrentTimestamp()
{
return (long)(DateTime.UtcNow - Epoch).TotalMilliseconds;
}
}
}

229
Dotfuscator1.xml Normal file
View File

@ -0,0 +1,229 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!--This config file was generated by Dotfuscator. Please use the Dotfuscator Config Editor to modify.-->
<!DOCTYPE dotfuscator SYSTEM "http://www.preemptive.com/dotfuscator/dtd/dotfuscator_v2.5.dtd">
<dotfuscator version="2.3">
<global>
<option>debugauto</option>
</global>
<input>
<loadpaths />
<asmlist>
<package refid="75fb581d-504b-40a3-8b1a-b1ac03b08930">
<file dir="C:\Users\Alessandro\source\repos\Campofinale\Campofinale\bin\Release" name="net8.0" />
<asmlist>
<inputassembly refid="604ebecb-0504-454e-ad08-34eda9a04774">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="Campofinale.dll" />
</inputassembly>
<inputassembly refid="3ae7d7b1-7703-4c9d-b40f-15d33288f11a">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="Campofinale.Protocol.dll" />
</inputassembly>
<inputassembly refid="08e7eb08-20c7-4681-a00a-838c9388cfe8">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="CavemanTcp.dll" />
</inputassembly>
<inputassembly refid="75176245-be9c-450b-b68a-878bff8bf51a">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="CsvHelper.dll" />
</inputassembly>
<inputassembly refid="16c2e47d-0170-4a33-bc31-1d97d021bb5d">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="DnsClient.dll" />
</inputassembly>
<inputassembly refid="ba0d0ec2-a7da-4b55-9409-e2fb34ed45f2">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="Google.Protobuf.dll" />
</inputassembly>
<inputassembly refid="df591eb9-0816-47c5-a869-3ac41b3611c4">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="HttpServerLite.dll" />
</inputassembly>
<inputassembly refid="56b0c337-902f-4a99-b0f9-c78a8989d37a">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="IpMatcher.dll" />
</inputassembly>
<inputassembly refid="2c1d4661-b740-491b-a9c7-0ab81f686612">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="KeraLua.dll" />
</inputassembly>
<inputassembly refid="794877c9-4ede-4a5d-826e-634289672ee2">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="Microsoft.Extensions.Logging.Abstractions.dll" />
</inputassembly>
<inputassembly refid="164f6b24-38c1-4a23-9c04-bbdef42b8f98">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="MongoDB.Bson.dll" />
</inputassembly>
<inputassembly refid="c99724b1-c389-4524-afb2-eb102c333d4a">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="MongoDB.Driver.dll" />
</inputassembly>
<inputassembly refid="7d96e1ea-bbf7-43b1-a538-41493fb3871c">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="Newtonsoft.Json.dll" />
</inputassembly>
<inputassembly refid="17cea055-f817-486d-aa3a-1e1afbe52764">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="NLua.dll" />
</inputassembly>
<inputassembly refid="c5299b3b-de5c-4470-b57f-70b04e714b9b">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="Pastel.dll" />
</inputassembly>
<inputassembly refid="04df18de-2ea9-4bf6-96e6-1a52d414729a">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="RegexMatcher.dll" />
</inputassembly>
<inputassembly refid="489010cf-b982-47d2-aebb-b2ccaf6e3f57">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="SharpCompress.dll" />
</inputassembly>
<inputassembly refid="8b2b943b-7677-4533-a1e5-15edfa90bd84">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="Snappier.dll" />
</inputassembly>
<inputassembly refid="3fed8738-cc79-4768-94e9-209f629f5a4d">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="SQLite-net.dll" />
</inputassembly>
<inputassembly refid="f91f7184-71b8-45b9-a8ed-eb565daff3f5">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="SQLiteNetExtensions.dll" />
</inputassembly>
<inputassembly refid="e923d72d-35da-435a-aa9a-2d540caff040">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="SQLitePCLRaw.batteries_v2.dll" />
</inputassembly>
<inputassembly refid="bbd50d8d-d78c-404f-8120-5b611a3714c4">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="SQLitePCLRaw.core.dll" />
</inputassembly>
<inputassembly refid="492c3d97-8768-4ac6-aa9b-0f85acc706cd">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="SQLitePCLRaw.provider.e_sqlite3.dll" />
</inputassembly>
<inputassembly refid="77f2e352-f3ad-4fe8-b924-9e27f1184e1a">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="Timestamps.dll" />
</inputassembly>
<inputassembly refid="222ebd59-927a-46a3-bdef-e6f61e3fd73f">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="UrlMatcher.dll" />
</inputassembly>
<inputassembly refid="668764f1-b4c4-40ba-8631-24e31fcacc2a">
<option>honoroas</option>
<option>stripoa</option>
<option>library</option>
<option>transformxaml</option>
<file dir="" name="ZstdSharp.dll" />
</inputassembly>
</asmlist>
</package>
</asmlist>
</input>
<output>
<file dir="${configdir}/Dotfuscated" />
</output>
<renaming>
<option>xmlserialization</option>
<excludelist>
<namespace name="Campofinale.Resource" regex="true" />
<type name="ConfigFile" regex="true" />
</excludelist>
<mapping>
<mapoutput overwrite="false">
<file dir="" name="${configdir}/Dotfuscated/Map.xml" />
</mapoutput>
</mapping>
<referencerulelist>
<referencerule rulekey="{6655B10A-FD58-462d-8D4F-5B1316DFF0FF}" />
<referencerule rulekey="{7D9C8B02-2383-420f-8740-A9760394C2C1}" />
<referencerule rulekey="{229FD6F8-5BCC-427b-8F72-A7A413ECDF1A}" />
<referencerule rulekey="{2B7E7C8C-A39A-4db8-9DFC-6AFD38509061}" />
<referencerule rulekey="{494EA3BA-B947-44B5-BEE8-A11CC85AAF9B}" />
<referencerule rulekey="{89769974-93E9-4e71-8D92-BE70E855ACFC}" />
<referencerule rulekey="{4D81E604-A545-4631-8B6D-C3735F793F80}" />
<referencerule rulekey="{62bd3899-7d53-4336-8ca2-4e5dbae187d5}" />
</referencerulelist>
</renaming>
<sos />
<smartobfuscation>
<smartobfuscationreport verbosity="all" overwrite="false" />
</smartobfuscation>
</dotfuscator>