Removed NioTSO client and server

- NioTSO client isn't needed because we're using RayLib
- Added FreeSO's API server to handle most backend operations
This commit is contained in:
Tony Bark 2024-05-01 02:55:43 -04:00
parent f12ba1502b
commit 22191ce648
591 changed files with 53264 additions and 3362 deletions

View file

@ -0,0 +1,19 @@
using Mina.Core.Buffer;
using FSO.Common.Serialization;
namespace FSO.Server.Protocol.Electron
{
public abstract class AbstractElectronPacket : IElectronPacket
{
public static IoBuffer Allocate(int size)
{
IoBuffer buffer = IoBuffer.Allocate(size);
buffer.Order = ByteOrder.BigEndian;
return buffer;
}
public abstract ElectronPacketType GetPacketType();
public abstract void Deserialize(IoBuffer input, ISerializationContext context);
public abstract void Serialize(IoBuffer output, ISerializationContext context);
}
}

View file

@ -0,0 +1,51 @@
using System;
namespace FSO.Server.Protocol.Electron
{
public enum ElectronPacketType : ushort
{
CreateASimResponse = 1,
PurchaseLotRequest,
PurchaseLotResponse,
InstantMessage,
FindLotRequest,
FindLotResponse,
FSOVMTickBroadcast,
FSOVMDirectToClient,
FSOVMCommand,
FindAvatarRequest,
FindAvatarResponse,
ChangeRoommateRequest,
KeepAlive,
ChangeRoommateResponse,
ModerationRequest,
FSOVMProtocolMessage,
AvatarRetireRequest,
MailRequest,
MailResponse,
NhoodRequest,
NhoodResponse,
NhoodCandidateList,
BulletinRequest,
BulletinResponse,
GlobalTuningUpdate,
Unknown = 0xFFFF
}
public static class ElectronPacketTypeUtils
{
public static ElectronPacketType FromPacketCode(ushort code)
{
var result = (ElectronPacketType)code;
if (Enum.IsDefined(typeof(ElectronPacketType), result))
return result;
else
return ElectronPacketType.Unknown;
}
public static ushort GetPacketCode(this ElectronPacketType type)
{
return (ushort)type;
}
}
}

View file

@ -0,0 +1,60 @@
using FSO.Server.Protocol.Electron.Packets;
using System;
using System.Collections.Generic;
namespace FSO.Server.Protocol.Electron
{
public class ElectronPackets
{
public static Dictionary<ushort, Type> ELECTRON_PACKET_BY_TYPEID;
public static Type[] ELECTRON_PACKETS = new Type[] {
typeof(CreateASimResponse),
typeof(PurchaseLotRequest),
typeof(PurchaseLotResponse),
typeof(InstantMessage),
typeof(FindLotRequest),
typeof(FindLotResponse),
typeof(FSOVMTickBroadcast),
typeof(FSOVMDirectToClient),
typeof(FSOVMCommand),
typeof(FindAvatarRequest),
typeof(FindAvatarResponse),
typeof(ChangeRoommateRequest),
typeof(KeepAlive),
typeof(ChangeRoommateResponse),
typeof(ModerationRequest),
typeof(FSOVMProtocolMessage),
typeof(AvatarRetireRequest),
typeof(MailRequest),
typeof(MailResponse),
typeof(NhoodRequest),
typeof(NhoodResponse),
typeof(NhoodCandidateList),
typeof(BulletinRequest),
typeof(BulletinResponse),
typeof(GlobalTuningUpdate)
};
static ElectronPackets()
{
ELECTRON_PACKET_BY_TYPEID = new Dictionary<ushort, Type>();
foreach (Type packetType in ELECTRON_PACKETS)
{
IElectronPacket packet = (IElectronPacket)Activator.CreateInstance(packetType);
ELECTRON_PACKET_BY_TYPEID.Add(packet.GetPacketType().GetPacketCode(), packetType);
}
}
public static Type GetByPacketCode(ushort code)
{
if (ELECTRON_PACKET_BY_TYPEID.ContainsKey(code))
{
return ELECTRON_PACKET_BY_TYPEID[code];
}
else
{
return null;
}
}
}
}

View file

@ -0,0 +1,9 @@
using FSO.Common.Serialization;
namespace FSO.Server.Protocol.Electron
{
public interface IElectronPacket : IoBufferDeserializable, IoBufferSerializable
{
ElectronPacketType GetPacketType();
}
}

View file

@ -0,0 +1,33 @@
namespace FSO.Server.Protocol.Electron.Model
{
public enum ChangeRoommateResponseStatus : byte
{
INVITE_SUCCESS = 0,
//invite codes
ROOMIE_ELSEWHERE = 1,
TOO_MANY_ROOMMATES = 2,
OTHER_INVITE_PENDING = 3,
//shared
YOU_ARE_NOT_OWNER = 4, //everything but move out
//kick or move out
YOU_ARE_NOT_ROOMMATE = 5,
LOT_MUST_BE_CLOSED = 6, //move out of lot with 1 roommate
//invite response
LOT_DOESNT_EXIST = 7,
NO_INVITE_PENDING = 8,
ACCEPT_SUCCESS = 9,
DECLINE_SUCCESS = 10,
KICK_SUCCESS = 11,
SELFKICK_SUCCESS = 12,
ROOMMATE_LEFT = 13,
GOT_KICKED = 14,
UNKNOWN = 255
}
}

View file

@ -0,0 +1,11 @@
namespace FSO.Server.Protocol.Electron.Model
{
public enum ChangeRoommateType : byte
{
INVITE = 0,
KICK = 1,
ACCEPT = 2,
DECLINE = 3,
POLL = 4
}
}

View file

@ -0,0 +1,11 @@
namespace FSO.Server.Protocol.Electron.Model
{
public enum FindAvatarResponseStatus
{
FOUND,
IGNORING_THEM,
IGNORING_YOU,
NOT_ON_LOT,
PRIVACY_ENABLED,
}
}

View file

@ -0,0 +1,14 @@
namespace FSO.Server.Protocol.Electron.Model
{
public enum FindLotResponseStatus
{
FOUND,
NO_SUCH_LOT,
NOT_OPEN,
NOT_PERMITTED_TO_OPEN,
CLAIM_FAILED,
NO_CAPACITY,
NO_ADMIT,
UNKNOWN_ERROR
}
}

View file

@ -0,0 +1,8 @@
namespace FSO.Server.Protocol.Electron.Model
{
public interface IActionRequest
{
object OType { get; }
bool NeedsValidation { get; }
}
}

View file

@ -0,0 +1,8 @@
namespace FSO.Server.Protocol.Electron.Model
{
public interface IActionResponse
{
bool Success { get; }
object OCode { get; }
}
}

View file

@ -0,0 +1,9 @@
namespace FSO.Server.Protocol.Electron.Model
{
public enum ModerationRequestType
{
IPBAN_USER,
BAN_USER,
KICK_USER
}
}

View file

@ -0,0 +1,23 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class AvatarRetireRequest : AbstractElectronPacket
{
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
input.GetUInt32();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.AvatarRetireRequest;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutUInt32(0);
}
}
}

View file

@ -0,0 +1,69 @@
using FSO.Common.Serialization;
using FSO.Server.Protocol.Electron.Model;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class BulletinRequest : AbstractElectronPacket, IActionRequest
{
public BulletinRequestType Type;
public uint TargetNHood; //the bulletin board to use
//post message
public string Title = "";
public string Message = "";
public uint LotID; //0 if empty - optionally reference a lot in this bulletin post
//post message, delete message, promote message
public uint Value; //bulletin type if post, bulletin ID otherwise.
public object OType => Type;
public bool NeedsValidation => false; //the CAN POST items are one off requests, rather than a state machine.
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
Type = input.GetEnum<BulletinRequestType>();
TargetNHood = input.GetUInt32();
if (Type == BulletinRequestType.POST_MESSAGE || Type == BulletinRequestType.POST_SYSTEM_MESSAGE)
{
Title = input.GetPascalString();
Message = input.GetPascalString();
LotID = input.GetUInt32();
}
Value = input.GetUInt32();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.BulletinRequest;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum(Type);
output.PutUInt32(TargetNHood);
if (Type == BulletinRequestType.POST_MESSAGE || Type == BulletinRequestType.POST_SYSTEM_MESSAGE)
{
output.PutPascalString(Title);
output.PutPascalString(Message);
output.PutUInt32(LotID);
}
output.PutUInt32(Value);
}
}
public enum BulletinRequestType : byte
{
GET_MESSAGES = 0,
POST_MESSAGE,
PROMOTE_MESSAGE, //mayor/admin only.
CAN_POST_MESSAGE,
CAN_POST_SYSTEM_MESSAGE,
//admin
POST_SYSTEM_MESSAGE,
DELETE_MESSAGE,
}
}

View file

@ -0,0 +1,90 @@
using FSO.Common.Serialization;
using FSO.Files.Formats.tsodata;
using FSO.Server.Protocol.Electron.Model;
using Mina.Core.Buffer;
using System.IO;
namespace FSO.Server.Protocol.Electron.Packets
{
public class BulletinResponse : AbstractElectronPacket, IActionResponse
{
public BulletinResponseType Type;
public BulletinItem[] Messages = new BulletinItem[0];
public string Message;
public uint BanEndDate;
public bool Success => Type == BulletinResponseType.SUCCESS || Type == BulletinResponseType.SEND_SUCCESS || Type == BulletinResponseType.MESSAGES;
public object OCode => Type;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
Type = input.GetEnum<BulletinResponseType>();
var numMessages = input.GetInt32();
Messages = new BulletinItem[numMessages];
for (int j = 0; j < numMessages; j++)
{
var length = input.GetInt32();
var dat = new byte[length];
for (int i = 0; i < length; i++)
{
dat[i] = input.Get();
}
using (var str = new MemoryStream(dat))
{
Messages[j] = new BulletinItem(str);
}
}
Message = input.GetPascalVLCString();
BanEndDate = input.GetUInt32();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.BulletinResponse;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum(Type);
output.PutInt32(Messages.Length);
foreach (var msg in Messages)
{
byte[] dat;
using (var str = new MemoryStream())
{
msg.Save(str);
dat = str.ToArray();
}
output.PutInt32(dat.Length);
foreach (var b in dat)
output.Put(b);
}
output.PutPascalVLCString(Message);
output.PutUInt32(BanEndDate);
}
}
public enum BulletinResponseType
{
MESSAGES,
SEND_SUCCESS, //returns message you sent, with dbid
SUCCESS,
SEND_FAIL_NON_RESIDENT,
SEND_FAIL_BAD_PERMISSION,
SEND_FAIL_INVALID_LOT,
SEND_FAIL_INVALID_MESSAGE,
SEND_FAIL_INVALID_TITLE,
SEND_FAIL_GAMEPLAY_BAN,
SEND_FAIL_TOO_FREQUENT,
SEND_FAIL_JUST_MOVED,
FAIL_MESSAGE_DOESNT_EXIST,
FAIL_NOT_MAYOR,
FAIL_CANT_DELETE,
FAIL_ALREADY_PROMOTED,
FAIL_BAD_PERMISSION,
CANCEL = 0xFE,
FAIL_UNKNOWN = 0xFF
}
}

View file

@ -0,0 +1,32 @@
using FSO.Common.Serialization;
using FSO.Server.Protocol.Electron.Model;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class ChangeRoommateRequest : AbstractElectronPacket
{
public ChangeRoommateType Type;
public uint AvatarId;
public uint LotLocation;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
Type = input.GetEnum<ChangeRoommateType>();
AvatarId = input.GetUInt32();
LotLocation = input.GetUInt32();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.ChangeRoommateRequest;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum(Type);
output.PutUInt32(AvatarId);
output.PutUInt32(LotLocation);
}
}
}

View file

@ -0,0 +1,29 @@
using FSO.Common.Serialization;
using FSO.Server.Protocol.Electron.Model;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class ChangeRoommateResponse : AbstractElectronPacket
{
public ChangeRoommateResponseStatus Type;
public uint Extra;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
Type = input.GetEnum<ChangeRoommateResponseStatus>();
Extra = input.GetUInt32();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.ChangeRoommateResponse;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum(Type);
output.PutUInt32(Extra);
}
}
}

View file

@ -0,0 +1,47 @@
using Mina.Core.Buffer;
using FSO.Common.Serialization;
namespace FSO.Server.Protocol.Electron.Packets
{
public class CreateASimResponse : AbstractElectronPacket
{
public CreateASimStatus Status { get; set; }
public CreateASimFailureReason Reason { get; set; } = CreateASimFailureReason.NONE;
public uint NewAvatarId { get; set; }
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.CreateASimResponse;
}
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
Status = input.GetEnum<CreateASimStatus>();
Reason = input.GetEnum<CreateASimFailureReason>();
NewAvatarId = input.GetUInt32();
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum<CreateASimStatus>(Status);
output.PutEnum<CreateASimFailureReason>(Reason);
output.PutUInt32(NewAvatarId);
}
}
public enum CreateASimStatus
{
SUCCESS = 0x01,
FAILED = 0x02
}
public enum CreateASimFailureReason
{
NONE = 0x00,
NAME_TAKEN = 0x01,
NAME_VALIDATION_ERROR = 0x02,
DESC_VALIDATION_ERROR = 0x03,
BODY_VALIDATION_ERROR = 0x04,
HEAD_VALIDATION_ERROR = 0x05
}
}

View file

@ -0,0 +1,28 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class FSOVMCommand : AbstractElectronPacket
{
public byte[] Data;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
var dataLen = input.GetInt32(); //TODO: limits? 4MB is probably reasonable.
Data = new byte[dataLen];
input.Get(Data, 0, dataLen);
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.FSOVMCommand;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutInt32(Data.Length);
output.Put(Data, 0, Data.Length);
}
}
}

View file

@ -0,0 +1,28 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class FSOVMDirectToClient : AbstractElectronPacket
{
public byte[] Data;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
var dataLen = input.GetInt32(); //TODO: limits? 4MB is probably reasonable.
Data = new byte[dataLen];
input.Get(Data, 0, dataLen);
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.FSOVMDirectToClient;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutInt32(Data.Length);
output.Put(Data, 0, Data.Length);
}
}
}

View file

@ -0,0 +1,43 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class FSOVMProtocolMessage : AbstractElectronPacket
{
public bool UseCst;
public string Title;
public string Message;
public FSOVMProtocolMessage()
{
}
public FSOVMProtocolMessage(bool cst, string title, string body)
{
UseCst = cst;
Title = title;
Message = body;
}
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
UseCst = input.GetBool();
Title = input.GetPascalVLCString();
Message = input.GetPascalVLCString();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.FSOVMProtocolMessage;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutBool(UseCst);
output.PutPascalVLCString(Title);
output.PutPascalVLCString(Message);
}
}
}

View file

@ -0,0 +1,28 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class FSOVMTickBroadcast : AbstractElectronPacket
{
public byte[] Data;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
var dataLen = input.GetInt32(); //TODO: limits? 4MB is probably reasonable.
Data = new byte[dataLen];
input.Get(Data, 0, dataLen);
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.FSOVMTickBroadcast;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutInt32(Data.Length);
output.Put(Data, 0, Data.Length);
}
}
}

View file

@ -0,0 +1,25 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class FindAvatarRequest : AbstractElectronPacket
{
public uint AvatarId;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
AvatarId = input.GetUInt32();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.FindAvatarRequest;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutUInt32(AvatarId);
}
}
}

View file

@ -0,0 +1,32 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
using FSO.Server.Protocol.Electron.Model;
namespace FSO.Server.Protocol.Electron.Packets
{
public class FindAvatarResponse : AbstractElectronPacket
{
public uint AvatarId;
public FindAvatarResponseStatus Status;
public uint LotId; //0 if status is not FOUND.
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
AvatarId = input.GetUInt32();
Status = input.GetEnum<FindAvatarResponseStatus>();
LotId = input.GetUInt32();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.FindAvatarResponse;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutUInt32(AvatarId);
output.PutEnum(Status);
output.PutUInt32(LotId);
}
}
}

View file

@ -0,0 +1,28 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class FindLotRequest : AbstractElectronPacket
{
public uint LotId;
public bool OpenIfClosed;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
LotId = input.GetUInt32();
OpenIfClosed = input.GetBool();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.FindLotRequest;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutUInt32(LotId);
output.PutBool(OpenIfClosed);
}
}
}

View file

@ -0,0 +1,38 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
using FSO.Server.Protocol.Electron.Model;
namespace FSO.Server.Protocol.Electron.Packets
{
public class FindLotResponse : AbstractElectronPacket
{
public FindLotResponseStatus Status;
public uint LotId;
public string LotServerTicket;
public string Address;
public string User;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
Status = input.GetEnum<FindLotResponseStatus>();
LotId = input.GetUInt32();
LotServerTicket = input.GetPascalVLCString();
Address = input.GetPascalVLCString();
User = input.GetPascalVLCString();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.FindLotResponse;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum(Status);
output.PutUInt32(LotId);
output.PutPascalVLCString(LotServerTicket);
output.PutPascalVLCString(Address);
output.PutPascalVLCString(User);
}
}
}

View file

@ -0,0 +1,54 @@
using FSO.Common.Model;
using FSO.Common.Serialization;
using Mina.Core.Buffer;
using System;
using System.IO;
namespace FSO.Server.Protocol.Electron.Packets
{
public class GlobalTuningUpdate : AbstractElectronPacket
{
public DynamicTuning Tuning;
public byte[] ObjectUpgrades;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
var dataLen = input.GetInt32();
if (dataLen > 4000000 || dataLen > input.Remaining) throw new Exception("Tuning too long");
var data = new byte[dataLen];
input.Get(data, 0, dataLen);
using (var mem = new MemoryStream(data))
{
using (var reader = new BinaryReader(mem))
{
Tuning = new DynamicTuning(reader);
}
}
var upgLen = input.GetInt32();
if (upgLen > 10000000 || upgLen > input.Remaining) throw new Exception("Upgrades too long");
ObjectUpgrades = new byte[upgLen];
input.Get(ObjectUpgrades, 0, upgLen);
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.GlobalTuningUpdate;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
using (var mem = new MemoryStream())
{
using (var writer = new BinaryWriter(mem))
{
Tuning.SerializeInto(writer);
var result = mem.ToArray();
output.PutInt32(result.Length);
output.Put(result, 0, result.Length);
}
}
output.PutInt32(ObjectUpgrades.Length);
output.Put(ObjectUpgrades, 0, ObjectUpgrades.Length);
}
}
}

View file

@ -0,0 +1,63 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
using FSO.Common.Enum;
namespace FSO.Server.Protocol.Electron.Packets
{
public class InstantMessage : AbstractElectronPacket
{
public UserReferenceType FromType;
public uint From;
public uint To;
public InstantMessageType Type;
public string Message;
public string AckID;
public InstantMessageFailureReason Reason = InstantMessageFailureReason.NONE;
public uint Color;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
FromType = input.GetEnum<UserReferenceType>();
From = input.GetUInt32();
To = input.GetUInt32();
Type = input.GetEnum<InstantMessageType>();
Message = input.GetPascalVLCString();
AckID = input.GetPascalVLCString();
Reason = input.GetEnum<InstantMessageFailureReason>();
Color = input.GetUInt32();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.InstantMessage;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum(FromType);
output.PutUInt32(From);
output.PutUInt32(To);
output.PutEnum(Type);
output.PutPascalVLCString(Message);
output.PutPascalVLCString(AckID);
output.PutEnum(Reason);
output.PutUInt32(Color);
}
}
public enum InstantMessageType
{
MESSAGE,
SUCCESS_ACK,
FAILURE_ACK
}
public enum InstantMessageFailureReason
{
NONE,
THEY_ARE_OFFLINE,
THEY_ARE_IGNORING_YOU,
YOU_ARE_IGNORING_THEM,
MESSAGE_QUEUE_FULL
}
}

View file

@ -0,0 +1,23 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class KeepAlive : AbstractElectronPacket
{
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.KeepAlive;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
}
}
}

View file

@ -0,0 +1,70 @@
using FSO.Common.Serialization;
using FSO.Files.Formats.tsodata;
using Mina.Core.Buffer;
using System.IO;
namespace FSO.Server.Protocol.Electron.Packets
{
public class MailRequest : AbstractElectronPacket
{
public MailRequestType Type;
public long TimestampID;
public MessageItem Item;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
Type = input.GetEnum<MailRequestType>();
if (Type == MailRequestType.SEND) {
var length = input.GetInt32();
var dat = new byte[length];
for (int i=0; i<length; i++)
{
dat[i] = input.Get();
}
using (var str = new MemoryStream(dat))
{
Item = new MessageItem(str);
}
} else
{
TimestampID = input.GetInt64();
}
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.MailRequest;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum(Type);
if (Type == MailRequestType.SEND)
{
byte[] dat;
if (Item == null) dat = new byte[0];
else
{
using (var str = new MemoryStream())
{
Item.Save(str);
dat = str.ToArray();
}
}
output.PutInt32(dat.Length);
foreach (var b in dat)
output.Put(b);
} else
output.PutInt64(TimestampID);
}
}
public enum MailRequestType : byte
{
POLL_INBOX,
SEND,
DELETE
}
}

View file

@ -0,0 +1,69 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
using FSO.Files.Formats.tsodata;
using System.IO;
namespace FSO.Server.Protocol.Electron.Packets
{
public class MailResponse : AbstractElectronPacket
{
public MailResponseType Type;
public MessageItem[] Messages = new MessageItem[0];
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
Type = input.GetEnum<MailResponseType>();
var numMessages = input.GetInt32();
Messages = new MessageItem[numMessages];
for (int j = 0; j < numMessages; j++)
{
var length = input.GetInt32();
var dat = new byte[length];
for (int i = 0; i < length; i++)
{
dat[i] = input.Get();
}
using (var str = new MemoryStream(dat))
{
Messages[j] = new MessageItem(str);
}
}
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.MailResponse;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum(Type);
output.PutInt32(Messages.Length);
foreach (var msg in Messages)
{
byte[] dat;
using (var str = new MemoryStream())
{
msg.Save(str);
dat = str.ToArray();
}
output.PutInt32(dat.Length);
foreach (var b in dat)
output.Put(b);
}
}
}
public enum MailResponseType
{
POLL_RESPONSE,
NEW_MAIL,
SEND_IGNORING_YOU,
SEND_IGNORING_THEM,
SEND_THROTTLED,
SEND_THROTTLED_DAILY,
SEND_FAILED,
SEND_SUCCESS //returns the message you sent, with its db id
}
}

View file

@ -0,0 +1,29 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
using FSO.Server.Protocol.Electron.Model;
namespace FSO.Server.Protocol.Electron.Packets
{
public class ModerationRequest : AbstractElectronPacket
{
public ModerationRequestType Type;
public uint EntityId;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
Type = input.GetEnum<ModerationRequestType>();
EntityId = input.GetUInt32();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.ModerationRequest;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum(Type);
output.PutUInt32(EntityId);
}
}
}

View file

@ -0,0 +1,76 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
using System.Collections.Generic;
namespace FSO.Server.Protocol.Electron.Packets
{
public class NhoodCandidateList : AbstractElectronPacket
{
public bool NominationMode;
public List<NhoodCandidate> Candidates;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
NominationMode = input.GetBool();
int candCount = input.GetInt32();
Candidates = new List<NhoodCandidate>();
for (int i=0; i<candCount; i++)
{
var candidate = new NhoodCandidate()
{
ID = input.GetUInt32(),
Name = input.GetPascalVLCString(),
Rating = input.GetUInt32()
};
if (!NominationMode)
{
candidate.LastNhoodName = input.GetPascalVLCString();
candidate.LastNhoodID = input.GetUInt32();
candidate.TermNumber = input.GetUInt32();
candidate.Message = input.GetPascalVLCString();
}
Candidates.Add(candidate);
}
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.NhoodCandidateList;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutBool(NominationMode);
output.PutInt32(Candidates.Count);
foreach (var candidate in Candidates)
{
output.PutUInt32(candidate.ID);
output.PutPascalVLCString(candidate.Name);
output.PutUInt32(candidate.Rating);
if (!NominationMode)
{
output.PutPascalVLCString(candidate.LastNhoodName);
output.PutUInt32(candidate.LastNhoodID);
output.PutUInt32(candidate.TermNumber);
output.PutPascalVLCString(candidate.Message);
}
}
}
}
public class NhoodCandidate
{
public uint ID;
public string Name;
public uint Rating;
public string LastNhoodName = "";
public uint LastNhoodID;
public uint TermNumber;
public string Message = "";
}
}

View file

@ -0,0 +1,71 @@
using FSO.Common.Serialization;
using FSO.Server.Protocol.Electron.Model;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class NhoodRequest : AbstractElectronPacket, IActionRequest
{
public NhoodRequestType Type;
public uint TargetAvatar; //vote, nominate, rate, delete rate, force mayor, gameplay ban, add candidate, remove candidate
public uint TargetNHood; //vote, nominate, add candidate, remove candidate
public object OType => Type;
public bool NeedsValidation =>
Type == NhoodRequestType.CAN_NOMINATE || Type == NhoodRequestType.CAN_RATE
|| Type == NhoodRequestType.CAN_RUN || Type == NhoodRequestType.CAN_VOTE || Type == NhoodRequestType.CAN_FREE_VOTE;
public string Message = ""; //bulletin, rate
public uint Value; //rate (stars), nomination_run (accept if >0)
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
Type = input.GetEnum<NhoodRequestType>();
TargetAvatar = input.GetUInt32();
TargetNHood = input.GetUInt32();
Message = input.GetPascalString();
Value = input.GetUInt32();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.NhoodRequest;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum(Type);
output.PutUInt32(TargetAvatar);
output.PutUInt32(TargetNHood);
output.PutPascalString(Message);
output.PutUInt32(Value);
}
}
public enum NhoodRequestType : byte
{
VOTE = 0,
CAN_VOTE,
NOMINATE,
CAN_NOMINATE,
RATE,
CAN_RATE,
NOMINATION_RUN,
CAN_RUN,
CAN_FREE_VOTE,
FREE_VOTE,
//moderator commands
DELETE_RATE,
FORCE_MAYOR,
REMOVE_CANDIDATE,
ADD_CANDIDATE,
TEST_ELECTION, //nhood id, avatar id = state (over/nomination/election), value = end date in x days
PRETEND_DATE, //run the daily nhood task as if it's (value) date. (Epoch value)
NHOOD_GAMEPLAY_BAN
}
}

View file

@ -0,0 +1,81 @@
using FSO.Common.Serialization;
using FSO.Server.Protocol.Electron.Model;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class NhoodResponse : AbstractElectronPacket, IActionResponse
{
public NhoodResponseCode Code;
public uint BanEndDate;
public string Message = "";
public bool Success => Code == NhoodResponseCode.SUCCESS;
public object OCode => Code;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
Code = input.GetEnum<NhoodResponseCode>();
BanEndDate = input.GetUInt32();
Message = input.GetPascalVLCString();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.NhoodResponse;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum(Code);
output.PutUInt32(BanEndDate);
output.PutPascalVLCString(Message);
}
}
public enum NhoodResponseCode : byte
{
SUCCESS = 0x00,
//nominate/vote
NOT_IN_NHOOD = 0x01,
ELECTION_OVER = 0x02,
CANDIDATE_NOT_IN_NHOOD = 0x03,
CANDIDATE_NOT_NOMINATED = 0x04,
ALREADY_VOTED = 0x05,
ALREADY_VOTED_SAME_IP = 0x06,
BAD_STATE = 0x07,
//rate
NOT_YOUR_MAYOR = 0x08,
INVALID_RATING = 0x09,
CANT_RATE_AVATAR = 0x0A,
//accept or decline a nomination
NOBODY_NOMINATED_YOU_IDIOT = 0x0B,
ALREADY_RUNNING = 0x0C,
BAD_COMMENT = 0x0D,
//moderator actions
NOT_MODERATOR = 0x0E,
INVALID_AVATAR = 0x0F,
INVALID_NHOOD = 0x10,
//shared
NHOOD_GAMEPLAY_BAN = 0x11,
CANDIDATE_MOVED_RECENTLY = 0x12,
YOU_MOVED_RECENTLY = 0x13,
CANDIDATE_NHOOD_GAMEPLAY_BAN = 0x14,
MISSING_ENTITY = 0x15, //missing someone
//free vote
NHOOD_NO_ELECTION = 0x16,
ALREADY_ENROLLED_FOR_FREE_VOTE = 0x17,
FREE_VOTE_ALREADY_ELIGIBLE = 0x18,
FREE_VOTE_MOVE_DATE = 0x19,
FREE_VOTE_ELECTION_OVER = 0x1A,
CANCEL = 0xFE,
UNKNOWN_ERROR = 0xFF
};
}

View file

@ -0,0 +1,37 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class PurchaseLotRequest : AbstractElectronPacket
{
public ushort LotLocation_X;
public ushort LotLocation_Y;
public string Name;
public bool StartFresh;
public bool MayorMode;
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
LotLocation_X = input.GetUInt16();
LotLocation_Y = input.GetUInt16();
Name = input.GetPascalString();
StartFresh = input.GetBool();
MayorMode = input.GetBool();
}
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.PurchaseLotRequest;
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutUInt16(LotLocation_X);
output.PutUInt16(LotLocation_Y);
output.PutPascalString(Name);
output.PutBool(StartFresh);
output.PutBool(MayorMode);
}
}
}

View file

@ -0,0 +1,60 @@
using FSO.Common.Serialization;
using Mina.Core.Buffer;
namespace FSO.Server.Protocol.Electron.Packets
{
public class PurchaseLotResponse : AbstractElectronPacket
{
public PurchaseLotStatus Status { get; set; }
public PurchaseLotFailureReason Reason { get; set; } = PurchaseLotFailureReason.NONE;
public uint NewLotId { get; set; }
public int NewFunds { get; set; }
public override ElectronPacketType GetPacketType()
{
return ElectronPacketType.PurchaseLotResponse;
}
public override void Deserialize(IoBuffer input, ISerializationContext context)
{
Status = input.GetEnum<PurchaseLotStatus>();
Reason = input.GetEnum<PurchaseLotFailureReason>();
NewLotId = input.GetUInt32();
NewFunds = input.GetInt32();
}
public override void Serialize(IoBuffer output, ISerializationContext context)
{
output.PutEnum<PurchaseLotStatus>(Status);
output.PutEnum<PurchaseLotFailureReason>(Reason);
output.PutUInt32(NewLotId);
output.PutInt32(NewFunds);
}
}
public enum PurchaseLotStatus
{
SUCCESS = 0x01,
FAILED = 0x02
}
public enum PurchaseLotFailureReason
{
NONE = 0x00,
NAME_TAKEN = 0x01,
NAME_VALIDATION_ERROR = 0x02,
INSUFFICIENT_FUNDS = 0x03,
LOT_TAKEN = 0x04,
LOT_NOT_PURCHASABLE = 0x05,
IN_LOT_CANT_EVICT = 0x06,
NOT_OFFLINE_FOR_MOVE = 0x07,
LOCATION_TAKEN = 0x08,
NHOOD_RESERVED = 0x09,
TH_NOT_MAYOR = 0x80,
TH_INCORRECT_NHOOD = 0x81,
UNKNOWN = 0xFF
}
}