Compare commits

..

No commits in common. "development" and "master" have entirely different histories.

50 changed files with 196 additions and 1120 deletions

View File

@ -28,12 +28,15 @@ public static class CommandAdd
case "item":
Item item=target.inventoryManager.AddItem(args[1], int.Parse(args[2]));
message = $"Item {args[1]} was added to {target.nickname}";
target.Send(new PacketScItemBagScopeModify(target, item));
break;
case "weapon":
Item wep = target.inventoryManager.AddWeapon(args[1], Convert.ToUInt64(args[2]));
message = $"Weapon {args[1]} was added to {target.nickname}";
target.Send(new PacketScItemBagScopeModify(target, wep));
break;
case "char":
@ -74,7 +77,7 @@ public static class CommandAdd
return;
}
target.inventoryManager.Save();
CommandManager.SendMessage(sender, $"{message}.");
}
catch (Exception err)

View File

@ -61,7 +61,7 @@ namespace Campofinale.Game.Character
}
int updatedItemCount = 0;
foreach (var item in target.inventoryManager.items.items)
foreach (var item in target.inventoryManager.items)
{
if (item.id.StartsWith("wpn_"))
{

View File

@ -19,6 +19,11 @@ namespace Campofinale.Commands.Handlers
return;
}
for (int i=0; i < args.Length; i++)
{
args[i] = Uri.UnescapeDataString(args[i]);
}
target.nickname = string.Join(" ", args);
target.Save();
target.Send(new PacketScSetName(target, target.nickname));

View File

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

View File

@ -1,5 +1,4 @@
using Newtonsoft.Json;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -15,28 +14,21 @@ namespace Campofinale
public ServerOptions serverOptions = new();
public LogSettings logOptions = new();
}
public class ServerOptions
public struct ServerOptions
{
public int defaultSceneNumId = 98;
public int maxPlayers = 20;
public CharactersOptions defaultCharacters = new();
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
public struct LogSettings
{
public bool packets;
public bool debugPrint=false;
@ -45,7 +37,7 @@ namespace Campofinale
{
}
}
public class GameserverSettings
public struct GameserverSettings
{
public string bindAddress = "127.0.0.1";
public int bindPort = 30000;
@ -55,9 +47,10 @@ namespace Campofinale
{
}
}
public class DispatchServerSettings
public struct DispatchServerSettings
{
public string bindAddress = "127.0.0.1";
public int bindPort = 5000;
public string accessAddress = "127.0.0.1";
public int accessPort = 5000;
@ -67,7 +60,7 @@ namespace Campofinale
}
}
public class MongoDatabaseSettings
public struct MongoDatabaseSettings
{
public string uri = "mongodb://localhost:27017";
public string collection = "Campofinale";

View File

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

View File

@ -42,8 +42,6 @@ namespace Campofinale.Database
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 Account
{
@ -143,9 +141,7 @@ namespace Campofinale.Database
noSpawnAnymore = player.noSpawnAnymore,
scenes=player.sceneManager.scenes,
bitsets=player.bitsetManager.bitsets,
savedSafeZone = player.savedSaveZone,
gender=player.gender,
bag=player.inventoryManager.items.bag
savedSafeZone = player.savedSaveZone
};
UpsertPlayerData(data);
}

View File

@ -9,7 +9,6 @@ using MongoDB.Bson.IO;
using MongoDB.Bson;
using System.Reflection;
using static Campofinale.Game.Factory.FactoryNode;
using Campofinale.Game.Inventory;
namespace Campofinale.Database
{
@ -69,8 +68,6 @@ namespace Campofinale.Database
{
BsonSerializer.RegisterSerializer(typeof(Dictionary<int, ulong>), new CustomDictionarySerializer<int, ulong>());
BsonSerializer.RegisterSerializer(typeof(Dictionary<int, List<int>>), new CustomDictionarySerializer<int, List<int>>());
BsonSerializer.RegisterSerializer(typeof(Dictionary<int, Item>), new CustomDictionarySerializer<int, Item>());
RegisterSubclasses<FComponent>();
Logger.Print("Connecting to MongoDB...");
try

View File

@ -149,11 +149,6 @@ namespace Campofinale.Game.Character
guid = GetOwner().random.Next();
this.weaponGuid = GetOwner().inventoryManager.AddWeapon(ResourceManager.charGrowthTable[id].defaultWeaponId, 1).guid;
this.curHp = CalcAttributes()[AttributeType.MaxHp].val;
if (level < 20) breakNode = "";
if (level >= 20 && level <= 40) breakNode = "charBreak20";
if (level > 40 && level <= 60) breakNode = "charBreak40";
if (level > 60 && level <= 70) breakNode = "charBreak60";
if (level > 70) breakNode = "charBreak70";
}
public int GetSkillMaxLevel()
{

View File

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

View File

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

View File

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

View File

@ -48,10 +48,6 @@ namespace Campofinale.Game.Inventory
this.level = level;
guid = GetOwner().random.Next();
}
public ItemStorageSpace StorageSpace()
{
return ResourceManager.itemTypeTable[GetItemTable().type].storageSpace;
}
public ulong GetDefaultLevel()
{
switch (ItemType)
@ -72,15 +68,10 @@ namespace Campofinale.Game.Inventory
}
public ItemValuableDepotType ItemType
{
get
{
get{
return ResourceManager.GetItemTable(id).valuableTabType;
}
}
public ItemTable GetItemTable()
{
return ResourceManager.GetItemTable(id);
}
public virtual ScdItemGrid ToProto()
{
try

View File

@ -379,15 +379,7 @@ namespace Campofinale.Game
if (!en.spawned)
{
en.spawned = true;
try
{
GetOwner().Send(new PacketScObjectEnterView(GetOwner(), new List<Entity>() { en }));
}
catch(Exception e)
{
}
GetOwner().Send(new PacketScObjectEnterView(GetOwner(), new List<Entity>() { en }));
}
}
else

View File

@ -46,7 +46,6 @@ namespace Campofinale.Game.Spaceship
IsWorking = isWorking,
PhysicalStrength = physicalStrength,
StationedRoomId = stationedRoomId,
Skills =
{
new ScdSpaceshipCharSkill()

View File

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

View File

@ -65,17 +65,7 @@ namespace Campofinale.Http
await data(ctx);
}
[StaticRoute(HttpServerLite.HttpMethod.GET, "/serverStatus")]
public static async Task serverStatus(HttpContext ctx)
{
string resp = "{\"maxPlayers\":" + Server.config.serverOptions.maxPlayers + ", \"players\":" + Server.clients.Count + ", \"status\":\"Online\", \"gameVersion\": \"" + GameConstants.GAME_VERSION + "\", \"serverVersion\": \"" + Server.ServerVersion + "\"}";
ctx.Response.StatusCode = 200;
ctx.Response.ContentLength = resp.Length;
ctx.Response.ContentType = "application/json";
await ctx.Response.SendAsync(resp);
}
[StaticRoute(HttpServerLite.HttpMethod.POST, "/u8/pay/getAllProductList")]
public static async Task getAllProductList(HttpContext ctx)
{

View File

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

View File

@ -20,10 +20,6 @@ public static class Logger
var method = frame?.GetMethod();
return method?.DeclaringType?.Name ?? "Server";
}
/// <summary>
/// Print a text in the console
/// </summary>
/// <param name="text"></param>
public static void Print(string text)
{
string className = GetCallingClassName();
@ -31,10 +27,6 @@ public static class Logger
string prefix = "<" + "INFO".Pastel("03fcce") + $":{className.Pastel("999")}>";
Console.WriteLine($"{prefix} " + text);
}
/// <summary>
/// Print a text in the console as Error
/// </summary>
/// <param name="text"></param>
public static void PrintError(string text)
{
string className = GetCallingClassName();
@ -42,10 +34,6 @@ public static class Logger
string prefix = "<" + "ERROR".Pastel("eb4034") + $":{className.Pastel("999")}>";
Console.WriteLine($"{prefix} " + text.Pastel("917e7e"));
}
/// <summary>
/// Print a text in the console as a Warn
/// </summary>
/// <param name="text"></param>
public static void PrintWarn(string text)
{
string className = GetCallingClassName();
@ -66,10 +54,7 @@ public static class Logger
Logger.hideLogs = hideLogs;
logWriter = new StreamWriter("latest.log", false);
}
/// <summary>
/// Log a message
/// </summary>
/// <param name="message"></param>
public static void Log(string message)
{
if (!hideLogs)

View File

@ -61,11 +61,6 @@ namespace Campofinale.Network
byte networkValue = buf[index];
return networkValue;
}
/// <summary>
/// Parse the body using a specific IMessage proto class
/// </summary>
/// <typeparam name="TBody"></typeparam>
/// <returns></returns>
public TBody DecodeBody<TBody>() where TBody : IMessage<TBody>, new()
{
return new MessageParser<TBody>(() => new()).ParseFrom(finishedBody);
@ -81,10 +76,35 @@ namespace Campofinale.Network
Buffer.BlockCopy(source, 0, destination, offset, source.Length);
}
public static byte[] ToByteArray(IntPtr ptr, int length)
{
if (ptr == IntPtr.Zero)
{
throw new ArgumentException("Pointer cannot be null", nameof(ptr));
}
byte[] byteArray = new byte[length];
Marshal.Copy(ptr, byteArray, 0, length);
return byteArray;
}
public static IntPtr ByteArrayToIntPtr(byte[] data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
// Allocate unmanaged memory
IntPtr ptr = Marshal.AllocHGlobal(data.Length);
// Copy the byte array to the unmanaged memory
Marshal.Copy(data, 0, ptr, data.Length);
return ptr;
}
public static byte[] EncryptWithPublicKey(byte[] data, string publicKey)
{
// Crea un oggetto RSA
using (RSA rsa = RSA.Create())
{
publicKey = publicKey.Replace("-----BEGIN PUBLIC KEY-----", "");
publicKey = publicKey.Replace("\r", "");
publicKey = publicKey.Replace("\n", "");
@ -92,44 +112,24 @@ namespace Campofinale.Network
publicKey = publicKey.Trim();
Logger.Print(publicKey);
byte[] publicKey_ = Convert.FromBase64String(publicKey);
// Importa la chiave pubblica
rsa.ImportSubjectPublicKeyInfo(publicKey_, out _);
// Crittografa i dati
return rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
}
}
/// <summary>
/// Set the data of the packet with the Message Id and the body
/// </summary>
/// <param name="msgId"></param>
/// <param name="body">The proto message</param>
/// <returns>The current Packet</returns>
public Packet SetData(ScMsgId msgId, IMessage body)
{
set_body = body;
cmdId = (int)msgId;
return this;
}
/// <summary>
/// Encode the packet using the Packet class
/// </summary>
/// <param name="packet">The packet</param>
/// <param name="seq">the sequence id</param>
/// <param name="totalPackCount">the pack count</param>
/// <param name="currentPackIndex"></param>
/// <returns></returns>
public static byte[] EncodePacket(Packet packet,ulong seq = 0, uint totalPackCount = 1, uint currentPackIndex = 0)
{
return EncodePacket(packet.cmdId,packet.set_body,seq, totalPackCount, currentPackIndex);
}
public static ulong seqNext = 1;
/// <summary>
/// Encode the packet using the msgId and the body
/// </summary>
/// <param name="msgId"></param>
/// <param name="body"></param>
/// <param name="seqNext_"></param>
/// <param name="totalPackCount"></param>
/// <param name="currentPackIndex"></param>
/// <returns></returns>
public static byte[] EncodePacket(int msgId, IMessage body, ulong seqNext_ = 0, uint totalPackCount=1,uint currentPackIndex=0)
{
if (seqNext_ == 0)
@ -149,15 +149,6 @@ namespace Campofinale.Network
return data;
}
/// <summary>
/// Encode the packet with msgId and body as byte array
/// </summary>
/// <param name="msgId"></param>
/// <param name="body"></param>
/// <param name="seqNext_"></param>
/// <param name="totalPackCount"></param>
/// <param name="currentPackIndex"></param>
/// <returns></returns>
public static byte[] EncodePacket(int msgId, byte[] body, ulong seqNext_ = 0, uint totalPackCount = 1, uint currentPackIndex = 0)
{
if (seqNext_ == 0)
@ -181,12 +172,6 @@ namespace Campofinale.Network
return data;
}
/// <summary>
/// Read the byteArray as a valid packet
/// </summary>
/// <param name="client"></param>
/// <param name="byteArray"></param>
/// <returns>The decoded packet</returns>
public static Packet Read(Player client,byte[] byteArray)
{
byte headLength = GetByte(byteArray, 0);

View File

@ -26,7 +26,6 @@ namespace Campofinale.Packets.Cs
if (character != null)
{
character.potential=req.Level;
//TODO consume Item ID
ScCharPotentialUnlock unlock = new()

View File

@ -1,27 +0,0 @@
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{
public class HandleCsItemBagAbandonInBag
{
[Server.Handler(CsMsgId.CsItemBagAbandonInBag)]
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsItemBagAbandonInBag req = packet.DecodeBody<CsItemBagAbandonInBag>();
session.inventoryManager.DropItemsBag(req);
}
}
}

View File

@ -1,27 +0,0 @@
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{
public class HandleCsItemBagMoveInBag
{
[Server.Handler(CsMsgId.CsItemBagMoveInBag)]
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsItemBagMoveInBag req = packet.DecodeBody<CsItemBagMoveInBag>();
session.inventoryManager.items.MoveBagItem(req.FromGrid, req.ToGrid);
}
}
}

View File

@ -65,18 +65,9 @@ namespace Campofinale.Packets.Cs
session.Disconnect();
return;
}
bool exist=session.Load(account.id);
session.Load(account.id);
rsp.Uid = ""+session.accountId;
if (!exist)
{
rsp.IsFirstLogin = true;
//session.gender = Gender.GenInvalid;
//session.Send(ScMsgId.ScLogin, rsp);
//session.Send(new PacketScSyncBaseData(session));
//return;
}
session.Send(ScMsgId.ScLogin, rsp);
}
@ -241,7 +232,7 @@ namespace Campofinale.Packets.Cs
session.Send(new PacketScSpaceshipSync(session));
session.Send(new PacketScSyncFullDungeonStatus(session));
session.Send(new PacketScActivitySync(session));
session.Send(new PacketScSnsGetChatList(session));
session.Send(ScMsgId.ScSyncFullDataEnd, new ScSyncFullDataEnd());
session.EnterScene();
session.Initialized = true;

View File

@ -1,28 +0,0 @@
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Campofinale.Packets.Cs
{
public class HandleCsSpaceshipPresentGiftToChar
{
[Server.Handler(CsMsgId.CsSpaceshipPresentGiftToChar)]
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsSpaceshipPresentGiftToChar req = packet.DecodeBody<CsSpaceshipPresentGiftToChar>();
session.spaceshipManager.GiftToChar(req);
}
}
}

View File

@ -15,11 +15,6 @@ namespace Campofinale.Packets.Sc
public PacketScItemBagScopeModify(Player client, Item item) {
if (item == null)
{
SetData(ScMsgId.ScItemBagScopeModify, new ScItemBagScopeModify());
return;
}
ScItemBagScopeModify proto = new ScItemBagScopeModify()
{
Depot =

View File

@ -19,10 +19,10 @@ namespace Campofinale.Packets.Sc
{
Bag = new()
{
GridLimit = client.inventoryManager.items.maxBagSize,
GridLimit = 30,
Grids =
{
/*new ScdItemGrid()
new ScdItemGrid()
{
GridIndex=0,
Count=1,
@ -79,7 +79,7 @@ namespace Campofinale.Packets.Sc
InstId=300000000004,
},
}*/
}
}
},
FactoryDepot =
@ -114,18 +114,7 @@ namespace Campofinale.Packets.Sc
proto.Bag = null;
}
proto.Depot.Add(i, new ScdItemDepot());
if(proto.Bag!=null)
foreach (var item in client.inventoryManager.items.bag)
{
proto.Bag.Grids.Add(new ScdItemGrid()
{
Count=item.Value.amount,
GridIndex=item.Key,
Id=item.Value.id,
Inst=item.Value.ToProto().Inst,
});
}
List<Item> items = client.inventoryManager.items.items.FindAll(item => item.ItemType == (ItemValuableDepotType)i);
List<Item> items = client.inventoryManager.items.FindAll(item => item.ItemType == (ItemValuableDepotType)i);
items.ForEach(item =>
{
if (item.InstanceType())

View File

@ -74,7 +74,7 @@ namespace Campofinale.Packets.Sc
ScriptId = l.scriptId,
IsDone = false,
State = 1,
};
int i = 0;
foreach (var item in l.properties)

View File

@ -1,33 +0,0 @@
using Campofinale.Network;
using Campofinale.Protocol;
using Campofinale.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Packets.Sc
{
public class PacketScSnsGetChatList : Packet
{
public PacketScSnsGetChatList(Player player) {
ScSnsGetChatList proto = new ScSnsGetChatList() {
};
foreach (var chat in ResourceManager.snsChatTable)
{
var chatInfo = new SnsChatInfo()
{
ChatId = chat.Value.chatId,
ChatType = chat.Value.chatType,
Timestamp = DateTime.UtcNow.ToUnixTimestampMilliseconds(),
};
proto.ChatList.Add(chatInfo);
}
SetData(ScMsgId.ScSnsGetChatList, proto);
}
}
}

View File

@ -20,7 +20,7 @@ namespace Campofinale.Packets.Sc
Level = client.level,
Exp=client.xp,
RoleName = client.nickname,
Gender = client.gender,
Gender = Gender.GenFemale,
ShortId="1",
};

View File

@ -89,7 +89,6 @@ namespace Campofinale
public string accountId = "";
public string nickname = "Endministrator";
public ulong roleId= 1;
public Gender gender=Gender.GenFemale;
public uint level = 20;
public uint xp = 0;
//
@ -140,7 +139,7 @@ namespace Campofinale
{
return chars.FindAll(c=> teams[teamIndex].members.Contains(c.guid));
}
public bool Load(string accountId)
public void Load(string accountId)
{
this.accountId = accountId;
PlayerData data = DatabaseManager.db.GetPlayerById(this.accountId);
@ -162,12 +161,9 @@ namespace Campofinale
maxDashEnergy = data.maxDashEnergy;
curStamina = data.curStamina;
nextRecoverTime=data.nextRecoverTime;
if (data.gender > 0) gender = data.gender;
LoadCharacters();
mails = DatabaseManager.db.LoadMails(roleId);
inventoryManager.Load();
if (data.bag != null) inventoryManager.items.bag = data.bag;
spaceshipManager.Load();
if (data.scenes != null)
{
@ -182,61 +178,37 @@ namespace Campofinale
}
sceneManager.Load();
factoryManager.Load();
return (data != null);
}
public void LoadCharacters()
{
chars = DatabaseManager.db.LoadCharacters(roleId);
}
/// <summary>
/// Get the character using the guid *Added in 1.0.7*
/// </summary>
/// <param name="guid"></param>
/// <returns></returns>
//Added in 1.0.7
public Character GetCharacter(ulong guid)
{
return chars.Find(c => c.guid == guid);
}
/// <summary>
/// Get the character using the template id
/// </summary>
/// <param name="templateId"></param>
/// <returns>Character</returns>
public Character GetCharacter(string templateId)
{
return chars.Find(c => c.id==templateId);
}
public void Initialize()
{
if (Server.config.serverOptions.defaultCharacters.giveAllCharacters)
foreach (var item in ResourceManager.characterTable)
{
foreach (var item in ResourceManager.characterTable)
{
chars.Add(new Character(roleId, item.Key, Server.config.serverOptions.defaultCharacters.defaultLevel));
}
chars.Add(new Character(roleId,item.Key,20));
}
else
{
foreach (var item in Server.config.serverOptions.defaultCharacters.characters)
{
chars.Add(new Character(roleId, item, Server.config.serverOptions.defaultCharacters.defaultLevel));
}
}
foreach(var item in itemTable)
{
if(item.Value.GetStorage()!= ItemStorageSpace.BagAndFactoryDepot)
if(item.Value.maxStackCount == -1)
{
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));
}
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()

View File

@ -1,100 +0,0 @@
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Resource
{
public class ResourceLoader
{
/// <summary>
/// Load table cfg automatically inside ResourceManager fields
/// </summary>
public static void LoadTableCfg()
{
var tableCfgTypes = GetAllTableCfgTypes();
foreach (var type in tableCfgTypes)
{
var attr = type.GetCustomAttribute<TableCfgTypeAttribute>();
string json = ResourceManager.ReadJsonFile(attr.Name);
FieldInfo field = GetResourceField(type);
if (field != null && json.Length > 0)
{
object deserializedData = DeserializeJson(json, field.FieldType, type);
field.SetValue(null, deserializedData);
//Logger.Print($"Loaded {attr.Name} into {field.Name}");
}
}
}
private static object DeserializeJson(string json, Type fieldType, Type valueType)
{
if (fieldType.IsGenericType)
{
var genericTypeDef = fieldType.GetGenericTypeDefinition();
if (genericTypeDef == typeof(Dictionary<,>))
{
var keyType = fieldType.GetGenericArguments()[0];
var valType = fieldType.GetGenericArguments()[1];
return JsonConvert.DeserializeObject(json, typeof(Dictionary<,>).MakeGenericType(keyType, valType));
}
else if (genericTypeDef == typeof(List<>))
{
return JsonConvert.DeserializeObject(json, typeof(List<>).MakeGenericType(valueType));
}
}
return JsonConvert.DeserializeObject(json, valueType);
}
public static List<Type> GetAllTableCfgTypes()
{
return Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.IsClass && !t.IsAbstract && t.GetCustomAttribute<TableCfgTypeAttribute>() != null)
.ToList();
}
public static FieldInfo GetResourceField(Type type)
{
var resourceManagerType = typeof(ResourceManager);
var fields = resourceManagerType.GetFields(BindingFlags.Public | BindingFlags.Static);
foreach (var field in fields)
{
var fieldType = field.FieldType;
if (fieldType.IsGenericType)
{
var genericTypeDef = fieldType.GetGenericTypeDefinition();
if (genericTypeDef == typeof(Dictionary<,>))
{
var valueType = fieldType.GetGenericArguments()[1];
if (valueType == type)
{
return field;
}
}
else if (genericTypeDef == typeof(List<>) && fieldType.GetGenericArguments()[0] == type)
{
return field;
}
}
else
{
if (fieldType == type)
{
return field;
}
}
}
return null;
}
}
}

View File

@ -28,19 +28,19 @@ namespace Campofinale.Resource
public class ResourceManager
{
public static Dictionary<string, SceneAreaTable> sceneAreaTable = new();
public static StrIdNumTable strIdNumTable = new StrIdNumTable();//
public static Dictionary<string, CharacterTable> characterTable = new(); //
public static Dictionary<string, SystemJumpTable> systemJumpTable = new(); //
public static StrIdNumTable strIdNumTable = new StrIdNumTable();
public static Dictionary<string, CharacterTable> characterTable = new();
public static Dictionary<string, SystemJumpTable> systemJumpTable = new();
public static Dictionary<string, SettlementBasicDataTable> settlementBasicDataTable = new();
public static Dictionary<string, BlocMissionTable> blocMissionTable = new();
public static MissionAreaTable missionAreaTable = new(); //
public static MissionAreaTable missionAreaTable = new();
public static Dictionary<string, DialogTextTable> dialogTextTable = new();
public static Dictionary<string, GameSystemConfigTable> gameSystemConfigTable = new();
public static Dictionary<string, WikiGroupTable> wikiGroupTable = new();
public static Dictionary<string, object> blocUnlockTable = new();
public static Dictionary<string, GameMechanicTable> gameMechanicTable = new();
public static Dictionary<string, WeaponBasicTable> weaponBasicTable= new();
public static Dictionary<string, BlocDataTable> blocDataTable = new(); //
public static Dictionary<string, BlocDataTable> blocDataTable = new();
public static Dictionary<string, ItemTable> itemTable = new();
public static Dictionary<string, DomainDataTable> domainDataTable = new();
public static Dictionary<string, CollectionTable> collectionTable = new();
@ -59,18 +59,15 @@ namespace Campofinale.Resource
public static Dictionary<string, SpaceShipCharBehaviourTable> spaceShipCharBehaviourTable = new();
public static Dictionary<string, SpaceshipRoomInsTable> spaceshipRoomInsTable = new();
public static Dictionary<string, DungeonTable> dungeonTable = new();
public static Dictionary<string, LevelGradeTable> levelGradeTable = new(); //
public static Dictionary<string, LevelGradeTable> levelGradeTable = new();
public static Dictionary<string, RewardTable> rewardTable = new();
public static Dictionary<string, AdventureTaskTable> adventureTaskTable = new();
public static DialogIdTable dialogIdTable = new();//
public static StrIdNumTable dialogIdTable = new();
public static Dictionary<string, LevelShortIdTable> levelShortIdTable = new();
public static Dictionary<string, FactoryBuildingTable> factoryBuildingTable = new();
public static Dictionary<string, FacSTTNodeTable> facSTTNodeTable = new();
public static Dictionary<string, FacSTTLayerTable> facSTTLayerTable = new();
public static Dictionary<int, ItemTypeTable> itemTypeTable = new(); //
public static Dictionary<string, SNSChatTable> snsChatTable = new();//
public static Dictionary<string, GiftItemTable> giftItemTable = new();
public static InteractiveTable interactiveTable = new(); //
public static InteractiveTable interactiveTable = new();
public static List<LevelScene> levelDatas = new();
public static List<InteractiveData> interactiveData = new();
@ -80,11 +77,6 @@ namespace Campofinale.Resource
return levelDatas.Find(a => a.id == name).idNum;
}
public static bool missingResources = false;
/// <summary>
/// Utility method for read a json file
/// </summary>
/// <param name="path">The file path</param>
/// <returns>Return the file content if the file exist, else it return an empty string</returns>
public static string ReadJsonFile(string path)
{
try
@ -111,7 +103,7 @@ namespace Campofinale.Resource
dialogTextTable = JsonConvert.DeserializeObject<Dictionary<string, DialogTextTable>>(ReadJsonFile("TableCfg/DialogTextTable.json"));
gameSystemConfigTable = JsonConvert.DeserializeObject<Dictionary<string, GameSystemConfigTable>>(ReadJsonFile("TableCfg/GameSystemConfigTable.json"));
wikiGroupTable = JsonConvert.DeserializeObject<Dictionary<string, WikiGroupTable>>(ReadJsonFile("TableCfg/WikiGroupTable.json"));
dialogIdTable = JsonConvert.DeserializeObject<DialogIdTable>(ReadJsonFile("Json/GameplayConfig/DialogIdTable.json"));
dialogIdTable = JsonConvert.DeserializeObject<StrIdNumTable>(ReadJsonFile("Json/GameplayConfig/DialogIdTable.json"));
blocUnlockTable = JsonConvert.DeserializeObject<Dictionary<string, object>>(ReadJsonFile("TableCfg/BlocUnlockTable.json"));
gameMechanicTable= JsonConvert.DeserializeObject<Dictionary<string, GameMechanicTable>>(ReadJsonFile("TableCfg/GameMechanicTable.json"));
weaponBasicTable = JsonConvert.DeserializeObject<Dictionary<string, WeaponBasicTable>>(ReadJsonFile("TableCfg/WeaponBasicTable.json"));
@ -142,12 +134,10 @@ namespace Campofinale.Resource
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();
ResourceLoader.LoadTableCfg();
LoadLevelDatas();
if (missingResources)
{
Logger.PrintWarn("Missing some resources. The gameserver will probably crash.");
@ -416,7 +406,15 @@ namespace Campofinale.Resource
{
public List<WikiGroup> list;
}
public class InteractiveTable
{
public Dictionary<string, InteractiveTemplate> interactiveDataDict = new();
public class InteractiveTemplate
{
public string templateId;
}
}
public class WikiGroup
{
public string groupId;
@ -785,6 +783,19 @@ namespace Campofinale.Resource
public string settlementId;
public string domainId;
}
public class StrIdNumTable
{
public StrIdDic skill_group_id;
public StrIdDic item_id;
public Dictionary<string, int> dialogStrToNum;
public StrIdDic chapter_map_id;
public StrIdDic char_voice_id;
public StrIdDic char_doc_id;
public StrIdDic area_id;
public StrIdDic map_mark_temp_id;
public StrIdDic wiki_id;
public StrIdDic client_game_var_string_id;
}
public class GachaCharPoolTable
{
public string id;
@ -812,7 +823,10 @@ namespace Campofinale.Resource
{
}
public class SystemJumpTable
{
public int bindSystem;
}
public class StrIdDic
{
public Dictionary<string, int> dic;
@ -829,7 +843,6 @@ namespace Campofinale.Resource
public string enemyId;
public string templateId;
}
public class ItemTable
{
public ItemValuableDepotType valuableTabType;
@ -837,12 +850,6 @@ namespace Campofinale.Resource
public int maxStackCount;
public bool backpackCanDiscard;
public string modelKey;
public int type;
public ItemStorageSpace GetStorage()
{
return ResourceManager.itemTypeTable[type].storageSpace;
}
}
public class WeaponBasicTable
{
@ -901,7 +908,15 @@ namespace Campofinale.Resource
public string id;
public int count;
}
public class CharacterTable
{
public List<Attributes> attributes;
public string charId;
public int weaponType;
public string engName;
public int rarity;
}
public class Attributes
{
public int breakStage;

View File

@ -6,8 +6,7 @@ using System.Threading.Tasks;
namespace Campofinale.Resource.Table
{
[TableCfgType("TableCfg/BlocDataTable.json", LoadPriority.LOW)]
public class BlocDataTable : TableCfgResource
public class BlocDataTable
{
public string blocId;
}

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Resource.Table
{
[TableCfgType("TableCfg/CharacterTable.json", LoadPriority.LOW)]
public class CharacterTable : TableCfgResource
{
public List<Attributes> attributes;
public string charId;
public int weaponType;
public string engName;
public int rarity;
}
}

View File

@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Resource.Table
{
[TableCfgType("Json/GameplayConfig/DialogIdTable.json", LoadPriority.LOW)]
public class DialogIdTable : StrIdNumTable
{
}
}

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Resource.Table
{
[TableCfgType("TableCfg/GiftItemTable.json", LoadPriority.LOW)]
public class GiftItemTable
{
public int favorablePoint;
public string id;
}
}

View File

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Resource.Table
{
[TableCfgType("Json/Interactive/InteractiveTable.json", LoadPriority.LOW)]
public class InteractiveTable : TableCfgResource
{
public Dictionary<string, InteractiveTemplate> interactiveDataDict = new();
public class InteractiveTemplate
{
public string templateId;
}
}
}

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Resource.Table
{
[TableCfgType("TableCfg/ItemTypeTable.json", LoadPriority.LOW)]
public class ItemTypeTable
{
public int itemType;
public ItemStorageSpace storageSpace;
}
}

View File

@ -6,8 +6,7 @@ using System.Threading.Tasks;
namespace Campofinale.Resource.Table
{
[TableCfgType("TableCfg/LevelGradeTable.json", LoadPriority.LOW)]
public class LevelGradeTable : TableCfgResource
public class LevelGradeTable
{
public string name;
public List<LevelGradeInfo> grades;

View File

@ -6,8 +6,7 @@ using System.Threading.Tasks;
namespace Campofinale.Resource.Table
{
[TableCfgType("Json/GameplayConfig/MissionAreaTable.json", LoadPriority.LOW)]
public class MissionAreaTable : TableCfgResource
public class MissionAreaTable
{
public Dictionary<string, Dictionary<string, object>> m_areas;
}

View File

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Resource.Table
{
[TableCfgType("TableCfg/SNSChatTable.json", LoadPriority.LOW)]
public class SNSChatTable
{
public string chatId;
public int chatType;
public int tagType;
}
}

View File

@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Resource.Table
{
[TableCfgType("TableCfg/StrIdNumTable.json", LoadPriority.LOW)]
public class StrIdNumTable : TableCfgResource
{
public StrIdDic skill_group_id;
public StrIdDic item_id;
public Dictionary<string, int> dialogStrToNum;
public StrIdDic chapter_map_id;
public StrIdDic char_voice_id;
public StrIdDic char_doc_id;
public StrIdDic area_id;
public StrIdDic map_mark_temp_id;
public StrIdDic wiki_id;
public StrIdDic client_game_var_string_id;
}
}

View File

@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Resource.Table
{
[TableCfgType("TableCfg/SystemJumpTable.json", LoadPriority.LOW)]
public class SystemJumpTable
{
public int bindSystem;
}
}

View File

@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Resource
{
public abstract class TableCfgResource
{
/// <summary>
/// Not implemented yet
/// </summary>
public void OnLoad()
{
}
}
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class TableCfgTypeAttribute : Attribute
{
/// <summary>
/// Path of the Resource
/// </summary>
public string Name { get; }
/// <summary>
/// Priority of load (still not implemented)
/// </summary>
public LoadPriority Priority { get; }
public TableCfgTypeAttribute(string name, LoadPriority priority)
{
Name = name;
Priority = priority;
}
}
public enum LoadPriority
{
HIGH,
MEDIUM,
LOW
}
}

View File

@ -1,9 +1,9 @@
# Campofinale
[EN](README.md) | [IT](docs/README_it-IT.md) | [RU](docs/README_ru-RU.md) | [CN](docs/README_zh-CN.md) | [NL](docs/README_nl-NL.md)
Campofinale is a experimental server implementation for a certain factory building game.
![Logo]()
> **NOTICE: Our old Discord server was raided (all members were removed), please rejoin our community using this new invite link: https://discord.gg/YZGYtAxeZk**
Campofinale is a experimental server implementation for a certain factory building game.
## Current Features
@ -23,14 +23,11 @@ The list of all characters is [here](docs/CharactersTable.md).<br>
The list of all items is [here](docs/ItemsTable.md).<br>
If you want to open the in-game console, go to `Settings -> Platform & Account -> Account Settings (Access Account button)`. To view available commands, type `help`.
## Tutorial
New tutorial will be added in the next days on the wiki, in the meanwhile you can ask help in the Discord server
## Discord for support
If you want to discuss, ask for support or help with this project, join our [Discord Server](https://discord.gg/YZGYtAxeZk)!
If you want to discuss, ask for support or help with this project, join our [Discord Server](https://discord.gg/gPvqhfdMU6)!
## Note
This project is developed independently, and all rights to the original game assets and intellectual property belong to their respective owners.
This project is developed independently, and all rights to the original game assets and intellectual property belong to their respective owners.

View File

@ -24,5 +24,5 @@
| idlist | 显示所有角色(chars)、敌人(enemies)和场景(scenes)的id | `<chars\|enemies\|scenes>` | 否 | idlist `<chars\|enemies\|scenes>` | idlist chars |
---
> [!WARNING]
> [!WARNING]警告
> `level` 指令: 如果你没有指定具体的`id`字段, 那么等级变化将会被应用在**所有**武器和干员身上

View File

@ -25,7 +25,7 @@
| eny_0059_erhound | Blighted Tuskbeast| 侵蚀牙兽 |
| eny_0060_lbmad | Blighted Klaw| 侵蚀爪牙 |
| eny_0061_palecore | Marble Agellomoirai| 白垩界卫一阶段 |
| eny_0062_paletent | Marble Appendage| 白垩附肢 |
| eny_0062_paletent | Marble Appendage| 白垩界卫一阶段触手 |
| eny_0063_agmelee2 | Ram α | 大角天使α |
| eny_0064_agrange2 | Sting α | 针刺天使α |
| eny_0065_lbmob2 | Elite Raider | 精锐劫掠者 |

View File

@ -1,32 +0,0 @@
# Campofinale
[EN](/README.md) | [IT](./README_it-IT.md) | [RU](./README_ru-RU.md) | [CN](./README_zh-CN.md) | [NL](./README_nl-NL.md)
Campofinale - экспериментальная реализация сервера для кое-какой игры по постройке фабрик.
> **Внимание: наш старый Discord сервер был подвергнут крашу (все участники были выгнаны), поэтому настоятельно просим вас присоединиться заново по этой ссылке: https://discord.gg/eGGXymVd4K**
## Текущие возможности
* Переключение персонажей;
* Переключение отрядов;
* Переключение сцен;
* Сохранение данных с помощью MongoDB;
* Система боёвки;
## Дополнительно
Описание всех команд сервера вы можете найти [здесь](./CommandList/commands_ru-RU.md).<br>
Список всех сцен находится [тут](./LevelsTable.md).<br>
Список всех врагов - [тут](./EnemiesTable.md).<br>
Список всех персонажей - [тут](./CharactersTable.md).<br>
Список всех предметов - [тут](./ItemsTable.md).<br>
Вы можете открыть внутриигровую консоль, перейдя во вкладку `Settings -> Platform & Account -> Account Settings (кнопка Access Account)`. Чтобы просмотреть доступные команды, пропишите `help`.
## Discord поддержка
Если вы хотите обсудить проект или помочь в его разработке, присоединяйтесь к нашему [Discord серверу](https://discord.gg/eGGXymVd4K)!
## Примечание
Этот проект разрабатывается независимо от чего-либо, все права на ассеты из оригинальной игры и вся интеллектуальная собственность принадлежит их правообладателям.

View File

@ -1,43 +0,0 @@
# Campofinale
[EN](../README.md) | [IT](./README_it-IT.md) | [RU](./README_ru-RU.md) | [CN](./README_zh-CN.md) | [NL](./README_nl-NL.md)
![Logo]()
Campofinale 是为某个工厂建造游戏提供的实验性本地服务器实现
> **我们的旧 Discord 服务器遭到了袭击(攻击者踢走了所有成员),请使用以下新邀请链接重新加入我们的社区:[https://discord.gg/eGGXymVd4K](https://discord.gg/eGGXymVd4K)**
## 当前功能
* 登录
* 切换角色
* 切换配队
* 场景切换
* 通过MongoDB保存存档
* 战斗系统
## 补充信息
您可以在[这里](./CommandList/commands_zh-CN.md)找到所有服务端指令的详细说明。
所有场景的列表[在此](./LevelsTable.md)。
所有敌人的列表[在此](./EnemiesTable.md)。
所有干员的列表[在此](./CharactersTable.md)。
所有物品的列表[在此](./ItemsTable_zh-CN.md)。
如果你想使用游戏内控制台,请前往 `设置 → 平台与账号 → 账号设置("点击前往"`。要查看可用命令,请输入 `help`
## 教程
新的教程将会在几天后添加到Wiki上目前您可以在Discord服务器上寻求帮助
## 在Discord上寻求帮助
如果你想讨论、寻求帮助或者协助我们完善和改进此项目,请加入我们的[Discord服务器](https://discord.gg/eGGXymVd4K)!
## 附录
本项目为独立开发,所有原始游戏资产和知识产权均归其各自所有者所有