This commit is contained in:
Aria 2025-03-21 22:23:30 +11:00
commit 9c94d113d3
Signed by untrusted user who does not match committer: aria
GPG key ID: 19AB7AA462B8AB3B
10260 changed files with 1237388 additions and 0 deletions

View file

@ -0,0 +1,265 @@
unit CheckSum;
interface
uses
Classes, Forms;
type
TChecksumCRC32 = class
public
constructor Create;
procedure Reset;
procedure Provide(Data: PByte; Length: Integer);
function Checksum: Integer;
private
FCrc: Integer;
FCrcTable: array[0..255] of Integer;
end;
TFile = class
public
FileName: String;
Missing: Boolean;
FileSize: Integer;
Crc: Integer;
end;
TChecksums = class
public
constructor Create(const PathName: String);
destructor Destroy; override;
procedure Scan;
procedure Load;
procedure Save;
procedure Compare(BaseLine: TChecksums; Log: TStrings);
private
FFiles: TStringList;
FCrc: TChecksumCRC32;
FPathName: String;
procedure Process(const FileName: String);
procedure InnerScan(const PathName: String);
end;
implementation
uses SysUtils, StrUtils;
constructor TChecksumCRC32.Create;
var
c, n, k: Integer;
begin
Reset;
for n := 0 to 255 do begin
c := n;
for k := 0 to 7 do begin
if c and 1 = 1 then
c := Integer($edb88320) xor Integer(Cardinal(c) shr 1)
else
c := (c shr 1);
end;
FCrcTable[n] := c;
end;
end;
procedure TChecksumCRC32.Reset;
begin
FCrc := Integer($ffffffff);
end;
procedure TChecksumCRC32.Provide(Data: PByte; Length: Integer);
var
c, n: Integer;
begin
c := FCrc;
for n := 0 to Length-1 do
c := FCrcTable[(c xor PByte(Integer(Data) + n)^) and $ff] xor Integer(Cardinal(c) shr 8);
FCrc := c;
end;
function TChecksumCRC32.Checksum: Integer;
begin
Result := FCrc xor Integer($ffffffff);
end;
constructor TChecksums.Create(const PathName: String);
begin
FCrc := TChecksumCRC32.Create;
FFiles := TStringList.Create;
FFiles.Sorted := True;
FFiles.Duplicates := dupIgnore;
FFiles.CaseSensitive := False;
FPathName := IncludeTrailingPathDelimiter(PathName);
end;
destructor TChecksums.Destroy;
var
I: Integer;
begin
for I := 0 to FFiles.Count -1 do
FFiles.Objects[I].Free;
FreeAndNil(FFiles);
FreeAndNil(FCrc);
end;
function FileSize(fileName : wideString) : Int64;
var
Sr : TSearchRec;
begin
Result := 0;
if FindFirst(fileName, faAnyFile, Sr) = 0 then
Result := Sr.FindData.nFileSizeLow;
FindClose(Sr) ;
end;
procedure TChecksums.Scan;
begin
InnerScan(FPathName);
end;
procedure TChecksums.InnerScan(const PathName: String);
var
Sr : TSearchRec;
begin
Application.ProcessMessages;
if FindFirst(PathName + '*', faAnyFile, Sr) = 0 then begin
try
repeat
if not AnsiStartsStr('.', Sr.Name) and not AnsiEndsText('.checksum', Sr.Name) then begin
if Sr.Attr and faDirectory <> 0 then begin
InnerScan(IncludeTrailingPathDelimiter(PathName + Sr.Name));
end else begin
Process(PathName + Sr.Name);
end;
end;
until FindNext(Sr) <> 0;
finally
FindClose(Sr);
end;
end;
end;
procedure TChecksums.Process(const FileName: String);
var
FS: TFileStream;
Len: Integer;
Buffer: array[0..4095] of Byte;
Entry: TFile;
begin
Entry := TFile.Create;
Entry.FileName := AnsiLowerCase(FileName);
Entry.Missing := not FileExists(Filename);
Entry.FileSize := 0;
Entry.Crc := 0;
if not Entry.Missing then begin
Entry.FileSize := FileSize(FileName);
try
FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
try
FCrc.Reset;
while FS.Position <> FS.Size do begin
Len := FS.Read(Buffer[0], 4096);
FCrc.Provide(@Buffer[0], Len);
end;
Entry.Crc := FCrc.Checksum;
finally
FreeAndNil(FS);
end;
except
end;
end;
FFiles.AddObject(Entry.FileName, Entry);
end;
procedure Split(const S: String; Parts: TStringList);
begin
Parts.Clear;
ExtractStrings(['|'], [], PChar(S), Parts);
end;
procedure TChecksums.Load;
var
Data: TStringList;
Parts: TStringList;
I : Integer;
Entry: TFile;
begin
if not FileExists(FPathName+'sb.checksum') then
Exit;
Data := TStringList.Create;
Parts := TStringList.Create;
Data.LoadFromFile(FPathName+'sb.checksum');
for I := 0 to Data.Count -1 do begin
Split(Data.Strings[I], Parts);
if Parts.Count <> 3 then
raise Exception.Create('Checksum file parse error');
Entry := TFile.Create;
Entry.FileName := FPathName + Parts[0];
Entry.Missing := False;
Entry.FileSize := StrToInt(Parts[1]);
Entry.Crc := StrToInt(Parts[2]);
FFiles.AddObject(Entry.FileName, Entry);
end;
Parts.Free;
Data.Free;
end;
procedure TChecksums.Save;
var
Data: TStringList;
I : Integer;
Entry: TFile;
PathName: String;
begin
PathName := AnsiLowerCase(FPathName);
Data := TStringList.Create;
for I := 0 to FFiles.Count -1 do begin
Entry := TFile(FFiles.Objects[I]);
if not Entry.Missing then
Data.Append(AnsiReplaceStr(Entry.FileName, PathName, '') + '|' + IntToStr(Entry.FileSize) + '|0x' + IntToHex(Entry.Crc, 8));
end;
Data.SaveToFile(FPathName+'sb.checksum');
Data.Free;
end;
procedure TChecksums.Compare(BaseLine: TChecksums; Log: TStrings);
var
I: Integer;
L: TStringList;
Base: TFile;
Local: TFile;
A: Integer;
begin
L := TStringList.Create;
L.Sorted := True;
L.Duplicates := dupIgnore;
L.CaseSensitive := False;
for I := 0 to FFiles.Count-1 do
L.Add(FFiles.Strings[I]);
for I := 0 to BaseLine.FFiles.Count-1 do
L.Add(BaseLine.FFiles.Strings[I]);
for I := 0 to L.Count-1 do begin
Base := nil;
Local := nil;
if FFiles.Find(L[I], A) then
Local := TFile(FFiles.Objects[A]);
if BaseLine.FFiles.Find(L[I], A) then
Base := TFile(BaseLine.FFiles.Objects[A]);
if Local = nil then
Log.Append('File ' + L[I] + ' is missing.')
else if Base = nil then
Log.Append('File ' + L[I] + ' is not part of the baseline.')
else if Base.FileSize <> Local.FileSize then
Log.Append('File ' + L[I] + ' is the wrong size, expected ' +IntToStr(Base.FileSize) + ' but found ' + IntToStr(Local.FileSize) + '.')
else if Base.Crc <> Local.Crc then
Log.Append('File ' + L[I] + ' did not match checksum.');
end;
end;
end.

View file

@ -0,0 +1,38 @@
-$A8
-$B-
-$C+
-$D+
-$E-
-$F-
-$G+
-$H+
-$I+
-$J-
-$K-
-$L+
-$M-
-$N+
-$O+
-$P+
-$Q-
-$R-
-$S-
-$T-
-$U-
-$V+
-$W-
-$X+
-$YD
-$Z1
-cg
-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
-H+
-W+
-M
-$M16384,1048576
-K$00400000
-LE"e:\program files (x86)\borland\delphi7\Projects\Bpl"
-LN"e:\program files (x86)\borland\delphi7\Projects\Bpl"
-w-UNSAFE_TYPE
-w-UNSAFE_CODE
-w-UNSAFE_CAST

View file

@ -0,0 +1,136 @@
[FileVersion]
Version=7.0
[Compiler]
A=8
B=0
C=1
D=1
E=0
F=0
G=1
H=1
I=1
J=0
K=0
L=1
M=0
N=1
O=1
P=1
Q=0
R=0
S=0
T=0
U=0
V=1
W=0
X=1
Y=1
Z=1
ShowHints=1
ShowWarnings=1
UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
NamespacePrefix=
SymbolDeprecated=1
SymbolLibrary=1
SymbolPlatform=1
UnitLibrary=1
UnitPlatform=1
UnitDeprecated=1
HResultCompat=1
HidingMember=1
HiddenVirtual=1
Garbage=1
BoundsError=1
ZeroNilCompat=1
StringConstTruncated=1
ForLoopVarVarPar=1
TypedConstVarPar=1
AsgToTypedConst=1
CaseLabelRange=1
ForVariable=1
ConstructingAbstract=1
ComparisonFalse=1
ComparisonTrue=1
ComparingSignedUnsigned=1
CombiningSignedUnsigned=1
UnsupportedConstruct=1
FileOpen=1
FileOpenUnitSrc=1
BadGlobalSymbol=1
DuplicateConstructorDestructor=1
InvalidDirective=1
PackageNoLink=1
PackageThreadVar=1
ImplicitImport=1
HPPEMITIgnored=1
NoRetVal=1
UseBeforeDef=1
ForLoopVarUndef=1
UnitNameMismatch=1
NoCFGFileFound=1
MessageDirective=1
ImplicitVariants=1
UnicodeToLocale=1
LocaleToUnicode=1
ImagebaseMultiple=1
SuspiciousTypecast=1
PrivatePropAccessor=1
UnsafeType=0
UnsafeCode=0
UnsafeCast=0
[Linker]
MapFile=0
OutputObjs=0
ConsoleApp=1
DebugInfo=0
RemoteSymbols=0
MinStackSize=16384
MaxStackSize=1048576
ImageBase=4194304
ExeDescription=
[Directories]
OutputDir=
UnitOutputDir=
PackageDLLOutputDir=
PackageDCPOutputDir=
SearchPath=
Packages=vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP
Conditionals=
DebugSourceDirs=
UsePackages=0
[Parameters]
RunParams=
HostApplication=
Launcher=
UseLauncher=0
DebugCWD=
[Language]
ActiveLang=
ProjectLang=
RootDir=
[Version Info]
IncludeVerInfo=0
AutoIncBuild=0
MajorVer=1
MinorVer=0
Release=0
Build=0
Debug=0
PreRelease=0
Special=0
Private=0
DLL=0
Locale=1043
CodePage=1252
[Version Info Keys]
CompanyName=
FileDescription=
FileVersion=1.0.0.0
InternalName=
LegalCopyright=
LegalTrademarks=
OriginalFilename=
ProductName=
ProductVersion=1.0.0.0
Comments=

View file

@ -0,0 +1,15 @@
program SBDiagnose;
uses
Forms,
SBDiagnoseForm in 'SBDiagnoseForm.pas' {Form1},
CheckSum in 'CheckSum.pas';
{$R *.res}
begin
Application.Initialize;
Application.Title := 'Starbound Diagnostics';
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

Binary file not shown.

View file

@ -0,0 +1,175 @@
object Form1: TForm1
Left = 714
Top = 318
Width = 851
Height = 547
Caption = 'Starbound Diagnostics'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
Icon.Data = {
0000010001002020000001002000A81000001600000028000000200000004000
000001002000000000000020000000000000000000000000000000000000FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF016ABA
F95D6ABAFAFF6ABAFAFF6ABAFAFF6ABAFAFF5B9ADFFF4B75C0FF4B75C0FFFFFF
FF01FFFFFF016AB9F98B6ABAFAFF6ABAFAFF6ABAFAFF6ABAFAFF6ABAFAFF6ABA
FAFF67B4F5FF4B75C0FF4B75C0FF4976C045FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF016ABA
F95D6ABAFAFF6ABAFAFF6ABAFAFF6ABAFAFF5B9ADFFF4B75C0FF4B75C0FFFFFF
FF01FFFFFF016AB9F98B6ABAFAFF6ABAFAFF6ABAFAFF6ABAFAFF6ABAFAFF6ABA
FAFF67B4F5FF4B75C0FF4B75C0FF4976C045FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01704D4D2B6E4C4C716E4C4C716E4C4C716E4C4C717073
86A37293B4FF7293B4FF7293B4FF7293B4FF6A81A5FF616C93FF616C93FFDAC4
D871DAC4D871ACC0E5BF9BBEEBFF9BBEEBFF9BBEEBFF9BBEEBFF73A8E4FF5C9B
E0FF5A98DDF74A75C08F4A75C08F4775BD27FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF016E4D4D5F6F4D4DFF6F4D4DFF6F4D4DFF6F4D4DFF7454
52FF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFFDAC5
D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FF7E91C9FF4B75
C0FF4A75BEEBFFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF016E4D4D5F6F4D4DFF6F4D4DFF6F4D4DFF6F4D4DFF7454
52FF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFFDAC5
D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FF7E91C9FF4B75
C0FF4A75BEEBFFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF015555550366333305663333057C615AD17C615AFF6A4E
4CFF492B32FF492B32FF492B32FF492B32FF775965FFAF91A2FFAF91A2FFDAC5
D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FFD8C4D8FFD8C3
D8FFCCB7CBFF492A30FB492A30FB48293143FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF017C6159CF7D625BFF6A4E
4CFF492B32FF492B32FF492B32FF492B32FF775965FFB092A3FFB092A3FFDAC5
D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5D9FFDAC5
D9FFCEB8CBFF492B32FF492B32FF492C3345FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01614344CF614445FF6245
46FF644847FF644847FF4B2D34FF492B32FF816672FFC6ADBFFFC6ADBFFFDAC5
D9FFDAC5D9FFDFCFE1FFE4D8E7FFE4D8E7FFE4D8E7FFE4D8E7FFDDCCDEFFDAC5
D9FFCEB8CBFF492B32FF492B32FF492C3345FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01482B32CF492B32FF5B3E
40FF7D625BFF7D625BFF4D3035FF492B32FF8A707DFFDAC5D9FFDAC5D9FFDAC5
D9FFDAC5D9FFE4D9E8FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFE0D2E3FFDAC5
D9FFCEB8CBFF492B32FF492B32FF492C3345FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF014C2D33CF4C2D34FF5D40
42FF7D625BFF7D625BFF4D3035FF492B32FF8A707DFFDAC5D9FFDAC5D9FFDBC7
DBFFDBC7DBFFE5DAE9FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFE1D4E4FFDBC7
DBFFCFBBCDFF492B32FF492B32FF492C3345FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF016D4D4DCF6F4D4DFF7454
52FF7D625BFF7D625BFF4D3035FF492B32FF8A707DFFDAC5D9FFDAC5D9FFEDEA
F5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEA
F5FFDFDAE5FF492B32FF492B32FF492C3345FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF016D4D4DCF6F4D4DFF7454
52FF7D625BFF7D625BFF4D3035FF492B32FF8A707DFFDAC5D9FFDAC5D9FFEDEA
F5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEA
F5FFDFDAE5FF492B32FF492B32FF492C3345FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01775954CF775A55FF795C
57FF7D625BFF7D625BFF4D3035FF492B32FF8A707DFFDAC5D9FFDAC5D9FFEDEA
F5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEA
F5FFDFDAE5FF492B32FF492B32FF492C3345FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF017C6159CF7D625BFF7D62
5BFF7D625BFF7D625BFF4D3035FF492B32FF8A707DFFDAC5D9FFDAC5D9FFEDEA
F5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEA
F5FFDFDAE5FF492B32FF492B32FF492C3345FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF017C6159CF7D625BFF7D62
5BFF7D625BFF7D625BFF53353AFF4F3036FF8E7480FFDAC5D9FFDAC5D9FFEDEA
F5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEAE5F1FFE9E3
F0FFDDD5E1FF4F3036FF4F3036FF4D303745FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF017C6159CF7D625BFF7D62
5BFF7D625BFF7D625BFF704E4EFF6F4D4DFF9F838CFFDAC5D9FFDAC5D9FFEDEA
F5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFE0D2E3FFDAC5
D9FFD1BBCDFF6F4D4DFF6F4D4DFF6E4D4D45FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF017C6159CF7D625BFF7D62
5BFF7D625BFF7D625BFF704E4EFF6F4D4DFF9F838CFFDAC5D9FFDAC5D9FFEDEA
F5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFEDEAF5FFE0D2E3FFDAC5
D9FFD1BBCDFF6F4D4DFF6F4D4DFF6E4D4D45FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF017D635A3B7A615A497C62
5B897D625BFF7D625BFF795C57FF795C57FF977B80FFBBA0B2FFBBA0B2FFDFCF
E0FFDFCFE0FFE6DDEBFFEDEAF5FFEBE7F3FFDFCFE0FFDFCFE0FFC8B1C2FFBBA0
B2FFB99DAEF16C4C4C496C4C4C496B505013FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF017E62
5A5D7D625BFF7D625BFF7D625BFF7D625BFF94777BFFB092A3FFB092A3FFDAC5
D9FFDAC5D9FFE4D9E8FFEDEAF5FFEBE6F2FFDAC5D9FFDAC5D9FFBFA4B6FFB092
A3FFAF92A1EBFFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01785D
575D795C57FF795C57FF7C615AFF7D625BFF8D7172FFA2858FFFA2858FFFC1AA
B7FFC1AAB7FFC8B9C2FFCFC5CBFFCDC3CAFFC1AAB7FFC1AAB7FFAB8F9BFF9E7F
8CFF9E7E8BEBFFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF016D4C
4C5D6F4D4DFF6F4D4DFF7B6059FF7D625BFF7D625BFF7D625BFF7D625BFF7D62
5BFF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF745452FF6F4D
4DFF6E4D4DEBFFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF016D4C
4C5D6F4D4DFF6F4D4DFF7B6059FF7D625BFF7D625BFF7D625BFF7D625BFF7D62
5BFF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF745452FF6F4D
4DFF6E4D4DEBFFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01785D
575D7A5E58FF7A5E58FF7C615AFF7D625BFF7D625BFF7D625BFF7D625BFF7D62
5BFF7D625BFF7489A1FF6DA9DCFF6DA9DCFF6DA9DCFF6DA9DCFF6BA7DAFF6AA5
D9FF69A5DBFB69BAF8CF69BAF8CF6BBBFA39FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF017E62
5A5D7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF7D62
5BFF7D625BFF7292B1FF6ABAFAFF6ABAFAFF6ABAFAFF6ABAFAFF6ABAFAFF6ABA
FAFF6ABAFAFF6ABAFAFF6ABAFAFF6BB8F745FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF017E62
5A5D7D625BFF7D625BFF7D625BFF7D625BFF8C726FFF9E8588FF9E8588FF7D62
5BFF7D625BFF6C84A6FF5EA1E5FF5FA3E7FF6ABAFAFF6ABAFAFF6ABAFAFF6ABA
FAFF6AB9F9F76ABAFAA36ABAFAA36BBAF92DFFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF017E62
5A5D7D625BFF7D625BFF7D625BFF7D625BFFA78E94FFDAC5D9FFDAC5D9FF7D62
5BFF7D625BFF616C92FF4B75C0FF4D7BC5FF6ABAFAFF6ABAFAFF6ABAFAFF6ABA
FAFF6AB9F9EBFFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF017E62
5A5D7D625BFF7D625BFF7D625BFF7D625BFFA78E94FFDAC5D9FFDAC5D9FF7D62
5BFF7D625BFF616C92FF4B75C0FF4D7BC5FF6ABAFAFF6ABAFAFF6ABAFAFF6ABA
FAFF6AB9F9EBFFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01704C
4C5D704E4EFF704E4EFF7B6059FF7D625BFF806660FF856B66FF856B66FF7D62
5BFF7D625BFF7A6260FF786364FF786464FF7B6A69FF7B6A69FF735E61FF6E57
5DFF6D565DEBFFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF016D4C
4C5D6F4D4DFF6F4D4DFF7B6059FF7D625BFF7D625BFF7D625BFF7D625BFF7D62
5BFF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF7D625BFF745452FF6F4D
4DFF6E4D4DEBFFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01704B
4B3D6F4C4CA76F4C4CA7765854F7785A56FF7A5E58FF7D625BFF7D625BFF7D62
5BFF7D625BFF7D625BFF7D625BFF7C615AFF785A56FF785A56FF735350C76F4C
4CA76F4C4C99FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF016F4D4DE76F4D4DFF755653FF7D625BFF7D625BFF7D62
5BFF7D625BFF7D625BFF7D625BFF7B6059FF6F4D4DFF6F4D4DFF6D4C4C5DFFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFF
FF01FFFFFF01FFFFFF016F4D4DE76F4D4DFF755653FF7D625BFF7D625BFF7D62
5BFF7D625BFF7D625BFF7D625BFF7B6059FF6F4D4DFF6F4D4DFF6D4C4C5DFFFF
FF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FFFFFF01FF80
C00FFF80C00FFF00C00FF000003FF000003FFC00000FFC00000FFC00000FFC00
000FFC00000FFC00000FFC00000FFC00000FFC00000FFC00000FFC00000FFC00
000FFF00003FFF80003FFF80003FFF80003FFF80003FFF80000FFF80000FFF80
000FFF80003FFF80003FFF80003FFF80003FFF80003FFFE001FFFFE001FF}
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Log: TMemo
Left = 0
Top = 0
Width = 835
Height = 489
Align = alCustom
Anchors = [akLeft, akTop, akRight, akBottom]
ScrollBars = ssBoth
TabOrder = 0
end
object ProgressBar1: TProgressBar
Left = 0
Top = 492
Width = 835
Height = 17
Align = alBottom
TabOrder = 1
end
object Timer1: TTimer
Interval = 100
OnTimer = Timer1Timer
Left = 216
Top = 240
end
end

View file

@ -0,0 +1,272 @@
unit SBDiagnoseForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, CheckSum, ComCtrls;
type
TForm1 = class(TForm)
Log: TMemo;
Timer1: TTimer;
ProgressBar1: TProgressBar;
procedure Timer1Timer(Sender: TObject);
private
procedure ScanBaseInformation;
procedure ScanSteamInformation;
procedure ScanSteamOverlay;
procedure ScanCompatFlags;
procedure ScanHsSrvDll;
procedure ScanChecksums;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
Registry, StrUtils;
{$R *.dfm}
function GetEnvVarValue(const VarName: String): String;
var
BufSize: Integer;
begin
BufSize := GetEnvironmentVariable(PChar(VarName), nil, 0);
if BufSize > 0 then
begin
SetLength(Result, BufSize - 1);
GetEnvironmentVariable(PChar(VarName), PChar(Result), BufSize);
end
else
Result := '';
end;
function ErrorMessage: String;
var
Error: DWORD;
begin
Error := GetLastError;
Result := IntToStr(Error) + ' ' + SysErrorMessage(Error);
end;
procedure TForm1.ScanBaseInformation;
var
Handle: HMODULE;
ProcessAffinityMask: DWORD;
SystemAffinityMask: DWORD;
begin
Log.Lines.Append('Number of processors: '+GetEnvVarValue('NUMBER_OF_PROCESSORS'));
Log.Lines.Append('Processor architecture: '+GetEnvVarValue('PROCESSOR_ARCHITECTURE'));
Log.Lines.Append('Processor: '+GetEnvVarValue('PROCESSOR_IDENTIFIER'));
Handle := GetCurrentProcess;
if not GetProcessAffinityMask(Handle, ProcessAffinityMask, SystemAffinityMask) then begin
Log.Lines.Append('ProcessAffinityMask: Failed to query, error: '+ErrorMessage);
end
else begin
Log.Lines.Append('ProcessAffinityMask: '+IntToHex(Integer(ProcessAffinityMask), 8));
Log.Lines.Append('SystemAffinityMask: '+IntToHex(Integer(SystemAffinityMask), 8));
end;
Log.Lines.Append('WindowsVersion: '+IntToStr(Win32MajorVersion)+'.'+IntToStr(Win32MinorVersion)+'.'+IntToStr(Win32BuildNumber)+' '+Win32CSDVersion);
if (Win32MajorVersion < 5) or ((Win32MajorVersion = 5) and (Win32MinorVersion < 1)) then begin
Log.Lines.Append('Versions of windows before Windows XP are not supported.');
end;
if (Win32MajorVersion = 5) and (Win32MinorVersion > 0) then begin
Log.Lines.Append('Windows XP detected, it is recommended to use a more recent version of windows.');
end;
Log.Lines.Append('');
end;
procedure TForm1.ScanSteamInformation;
begin
Log.Lines.Append('EnvAppId: '+GetEnvVarValue('SteamAppId'));
Log.Lines.Append('');
end;
procedure TForm1.ScanSteamOverlay;
var
Handle: HMODULE;
begin
Handle := GetModuleHandle('GameOverlayRenderer');
if Handle <> 0 then begin
Log.Lines.Append('The Steam Overlay has been detected.');
Log.Lines.Append('Disabling the Steam overlay may improve render performance.');
Log.Lines.Append('http://community.playstarbound.com/index.php?threads/sbdiagnose-faq.52470/');
Log.Lines.Append('');
end;
end;
procedure TForm1.ScanCompatFlags;
var
Registry: TRegistry;
Steam: Boolean;
Starbound: Boolean;
procedure Scan;
var
I: Integer;
Entries: TStringList;
begin
Entries := TStringList.Create;
if Registry.OpenKey('Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers\', False) then begin
Registry.GetValueNames(Entries);
for I := 0 to Entries.Count-1 do begin
if AnsiContainsText(Entries[i], '\steam.exe') then
Steam := True;
if AnsiContainsText(Entries[i], '\starbound.exe') then
Starbound := True;
if AnsiContainsText(Entries[i], '\starbound_opengl.exe') then
Starbound := True;
if AnsiContainsText(Entries[i], '\starbound\win32\') then
Starbound := True;
end;
Registry.CloseKey;
end;
Entries.Free;
Registry.Free;
end;
begin
if (GetEnvVarValue('__COMPAT_LAYER') <> '') then begin
Log.Lines.Append('Environment Compatibility Flags: '+GetEnvVarValue('__COMPAT_LAYER'));
Log.Lines.Append('');
end;
Steam := False;
Starbound := False;
Registry := TRegistry.Create;
Registry.RootKey := HKEY_CURRENT_USER;
Scan;
Registry := TRegistry.Create;
Registry.RootKey := HKEY_LOCAL_MACHINE;
Scan;
Registry := TRegistry.Create;
Registry.RootKey := HKEY_CURRENT_USER;
Registry.Access := $000f013f;
Scan;
Registry := TRegistry.Create;
Registry.RootKey := HKEY_LOCAL_MACHINE;
Registry.Access := $000f013f;
Scan;
if Steam then begin
Log.Lines.Append('Steam is running in compatibility mode.');
Log.Lines.Append('Running steam in compatbility mode can cause stability and performance problems.');
Log.Lines.Append('http://community.playstarbound.com/index.php?threads/sbdiagnose-faq.52470/');
Log.Lines.Append('');
end;
if Starbound then begin
Log.Lines.Append('Starbound is running in compatibility mode.');
Log.Lines.Append('Running starbound in compatbility mode can cause stability and performance problems.');
Log.Lines.Append('http://community.playstarbound.com/index.php?threads/sbdiagnose-faq.52470/');
Log.Lines.Append('');
end;
end;
procedure TForm1.ScanHsSrvDll;
var
Handle: HMODULE;
begin
Handle := LoadLibraryEx('hssrv.dll', 0, LOAD_LIBRARY_AS_DATAFILE);
if Handle = 0 then
Handle := GetModuleHandle('HsSrv');
if Handle <> 0 then begin
Log.Lines.Append('HsSrv.dll detected (Asus Xonar Drivers).');
Log.Lines.Append('There have been reports of this driver having compatibility issues with starbound.');
Log.Lines.Append('http://community.playstarbound.com/index.php?threads/sbdiagnose-faq.52470/');
Log.Lines.Append('');
end;
end;
procedure TForm1.ScanChecksums;
var
A, B: TChecksums;
F: String;
begin
F := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName)) + '..\assets\';
Log.Lines.Add('Scanning checksums...');
Application.ProcessMessages;
try
if not FileExists(F + 'sb.checksum') then begin
Log.Lines.Add('No baseline found, creating.');
Application.ProcessMessages;
A := TChecksums.Create(F);
A.Scan;
A.Save;
A.Free;
end else begin
A := TChecksums.Create(F);
A.Scan;
Log.Lines.Add('Loading baseline.');
Application.ProcessMessages;
B := TChecksums.Create(F);
B.Load;
Log.Lines.Add('Comparing checksums.');
Application.ProcessMessages;
A.Compare(B, Log.Lines);
A.Free;
end;
except
on E: Exception do
Log.Lines.Add('Failed to scan checksums: ' + E.ClassName + ': ' + E.Message);
end;
Log.Lines.Add('done.');
Log.Lines.Add('');
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
Log.Lines.Append('Scanning System');
Log.Lines.Append('');
Application.ProcessMessages;
ProgressBar1.Position := 10;
Application.ProcessMessages;
ScanChecksums;
ProgressBar1.Position := 50;
Application.ProcessMessages;
ScanBaseInformation;
ProgressBar1.Position := 60;
Application.ProcessMessages;
ScanSteamInformation;
ProgressBar1.Position := 70;
Application.ProcessMessages;
ScanSteamOverlay;
ProgressBar1.Position := 80;
Application.ProcessMessages;
ScanCompatFlags;
ProgressBar1.Position := 90;
Application.ProcessMessages;
ScanHsSrvDll;
ProgressBar1.Position := ProgressBar1.Max;
ProgressBar1.Enabled := False;
Log.Lines.Append('Done.');
end;
end.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -0,0 +1,163 @@
/* Copyright (c) 2008, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ---
* Author: David Vitek
*
* Dump function addresses using Microsoft debug symbols. This works
* on PDB files. Note that this program will download symbols to
* c:\websymbols without asking.
*/
#define WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <dbghelp.h>
#define SEARCH_CAP (1024*1024)
#define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols"
void usage() {
fprintf(stderr, "usage: "
"addr2line-pdb [-f|--functions] [-C|--demangle] [-e filename]\n");
fprintf(stderr, "(Then list the hex addresses on stdin, one per line)\n");
}
int main(int argc, char *argv[]) {
DWORD error;
HANDLE process;
ULONG64 module_base;
int i;
char* search;
char buf[256]; /* Enough to hold one hex address, I trust! */
int rv = 0;
/* We may add SYMOPT_UNDNAME if --demangle is specified: */
DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES;
char* filename = "a.out"; /* The default if -e isn't specified */
int print_function_name = 0; /* Set to 1 if -f is specified */
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "--functions") == 0 || strcmp(argv[i], "-f") == 0) {
print_function_name = 1;
} else if (strcmp(argv[i], "--demangle") == 0 ||
strcmp(argv[i], "-C") == 0) {
symopts |= SYMOPT_UNDNAME;
} else if (strcmp(argv[i], "-e") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "FATAL ERROR: -e must be followed by a filename\n");
return 1;
}
filename = argv[i+1];
i++; /* to skip over filename too */
} else if (strcmp(argv[i], "--help") == 0) {
usage();
exit(0);
} else {
usage();
exit(1);
}
}
process = GetCurrentProcess();
if (!SymInitialize(process, NULL, FALSE)) {
error = GetLastError();
fprintf(stderr, "SymInitialize returned error : %d\n", error);
return 1;
}
search = malloc(SEARCH_CAP);
if (SymGetSearchPath(process, search, SEARCH_CAP)) {
if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) {
fprintf(stderr, "Search path too long\n");
SymCleanup(process);
return 1;
}
strcat(search, ";" WEBSYM);
} else {
error = GetLastError();
fprintf(stderr, "SymGetSearchPath returned error : %d\n", error);
rv = 1; /* An error, but not a fatal one */
strcpy(search, WEBSYM); /* Use a default value */
}
if (!SymSetSearchPath(process, search)) {
error = GetLastError();
fprintf(stderr, "SymSetSearchPath returned error : %d\n", error);
rv = 1; /* An error, but not a fatal one */
}
SymSetOptions(symopts);
module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0);
if (!module_base) {
/* SymLoadModuleEx failed */
error = GetLastError();
fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n",
error, filename);
SymCleanup(process);
return 1;
}
buf[sizeof(buf)-1] = '\0'; /* Just to be safe */
while (fgets(buf, sizeof(buf)-1, stdin)) {
/* GNU addr2line seems to just do a strtol and ignore any
* weird characters it gets, so we will too.
*/
unsigned __int64 addr = _strtoui64(buf, NULL, 16);
ULONG64 buffer[(sizeof(SYMBOL_INFO) +
MAX_SYM_NAME*sizeof(TCHAR) +
sizeof(ULONG64) - 1)
/ sizeof(ULONG64)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
IMAGEHLP_LINE64 line;
DWORD dummy;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
if (print_function_name) {
if (SymFromAddr(process, (DWORD64)addr, NULL, pSymbol)) {
printf("%s\n", pSymbol->Name);
} else {
printf("??\n");
}
}
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymGetLineFromAddr64(process, (DWORD64)addr, &dummy, &line)) {
printf("%s:%d\n", line.FileName, (int)line.LineNumber);
} else {
printf("??:0\n");
}
}
SymUnloadModule64(process, module_base);
SymCleanup(process);
return rv;
}

Binary file not shown.

View file

@ -0,0 +1,201 @@
{
"commandName" : "giveBeamaxe",
"onlyOnce" : true,
"icon" : "beamaxe.png",
"actions" : [
{
"action" : "GivePlayerItems",
"items" : [ "beamaxe", 1],
"essentialItem" : "beamaxe"
},
{
"action" : "PlayCinematic",
"cinematicConfig" : {
"resource" : "/cinematics/beamaxe.cinematic"
}
},
{
"action" : "DisableCommand",
"command" : "giveBeamaxe"
},
{
"action" : "EnableCommand",
"command" : "enableTeleporter"
},
{
"action" : "EnableCommand",
"command" : "upgradeBeamaxeSize1"
}
],
"speciesText" : {
"apex" : {
"buttonText" : "Enable Matter Manipulator",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "The matter manipulator is a very powerful tool. Capable of manipulating any kind of matter at a distance.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "I have switched on your matter manipulator. The matter manipulator enables you to pick up, move and collect objects and materials.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure",
"speedModifier" : 1.0
}
]
},
"avian" : {
"buttonText" : "Enable Matter Manipulator",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "The matter manipulator channels the very essence of Kluex himself. It can manipulate matter of all kinds.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Your matter manipulator has been enabled. The matter manipulator enables you to pick up, move and collect objects and materials.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure",
"speedModifier" : 1.0
}
]
},
"floran" : {
"buttonText" : "Enable Matter Manipulator",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "The matter manipulator is very powerful!! Hehehe, it will let you dessstroy matter!!",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Yes!! The matter manipulator is working! The matter manipulator enables you to pick up, move and collect objects and materials.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure",
"speedModifier" : 1.0
}
]
},
"glitch" : {
"buttonText" : "Enable Matter Manipulator",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "To wield the matter manipulator is to wield magic itself.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Your matter manipulator is enabled your grace! The matter manipulator enables you to pick up, move and collect objects and materials.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure",
"speedModifier" : 1.0
}
]
},
"human" : {
"buttonText" : "Enable Matter Manipulator",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "Your matter manipulator is an awesome way of interacting with the world! I can try to enable it for you!",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "It worked! The matter manipulator enables you to pick up, move and collect objects and materials.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure",
"speedModifier" : 1.0
}
]
},
"novakid" : {
"buttonText" : "Enable Matter Manipulator",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "Your matter manipulator is an awesome way of interacting with the world! I can try to enable it for you!",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "It worked! The matter manipulator enables you to pick up, move and collect objects and materials.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure",
"speedModifier" : 1.0
}
]
},
"hylotl" : {
"buttonText" : "Enable Matter Manipulator",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "Remember. He that would perfect his work must first sharpen his tools.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "It has been a success. The matter manipulator is ready. The matter manipulator enables you to pick up, move and collect objects and materials.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure",
"speedModifier" : 1.0
}
]
}
}
}

View file

@ -0,0 +1,194 @@
{
"commandName" : "upgradeBeamaxeLiquid1",
"onlyOnce" : true,
"icon" : "beamaxe.png",
"actions" : [
{
"action" : "UpdatePlayerEssentialItem",
"itemsRequired" : [ ["goldbar", 12] ],
"parameters" : {
"canCollectLiquid" : true
},
"essentialItem" : "beamaxe"
},
{
"action" : "DisableCommand",
"command" : "upgradeBeamaxeLiquid1"
},
{
"action" : "EnableCommand",
"command" : "upgradeBeamaxeSize2"
}
],
"speciesText" : {
"apex" : {
"buttonText" : "Enable M. M. Liquid Collection",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 12 bars of refined gold, I can upgrade your matter manipulator to allow the collection of liquids.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 12 gold bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"avian" : {
"buttonText" : "Enable M. M. Liquid Collection",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 12 bars of refined gold, I can upgrade your matter manipulator to allow the collection of liquids.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 12 gold bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"floran" : {
"buttonText" : "Enable M. M. Liquid Collection",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 12 bars of refined gold, I can upgrade your matter manipulator to allow the collection of liquids.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 12 gold bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"glitch" : {
"buttonText" : "Enable M. M. Liquid Collection",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 12 bars of refined gold, I can upgrade your matter manipulator to allow the collection of liquids.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 12 gold bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"human" : {
"buttonText" : "Enable M. M. Liquid Collection",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 12 bars of refined gold, I can upgrade your matter manipulator to allow the collection of liquids.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 12 gold bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"novakid" : {
"buttonText" : "Enable M. M. Liquid Collection",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 12 bars of refined gold, I can upgrade your matter manipulator to allow the collection of liquids.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 12 gold bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"hylotl" : {
"buttonText" : "Enable M. M. Liquid Collection",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 12 bars of refined gold, I can upgrade your matter manipulator to allow the collection of liquids.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 12 gold bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
}
}
}

View file

@ -0,0 +1,196 @@
{
"commandName" : "upgradeBeamaxePower1",
"onlyOnce" : true,
"icon" : "beamaxe.png",
"actions" : [
{
"action" : "UpdatePlayerEssentialItem",
"itemsRequired" : [ ["silverbar", 8] ],
"parameters" : {
"tileDamage" : 1.5,
"minBeamJitter" : 0.1,
"maxBeamJitter" : 0.2
},
"essentialItem" : "beamaxe"
},
{
"action" : "DisableCommand",
"command" : "upgradeBeamaxePower1"
},
{
"action" : "EnableCommand",
"command" : "upgradeBeamaxeLiquid1"
}
],
"speciesText" : {
"apex" : {
"buttonText" : "Upgrade M. M. - Power I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined silver, I can increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 silver bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"avian" : {
"buttonText" : "Upgrade M. M. - Power I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined silver, I can increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 silver bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"floran" : {
"buttonText" : "Upgrade M. M. - Power I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined silver, I can increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 silver bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"glitch" : {
"buttonText" : "Upgrade M. M. - Power I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined silver, I can increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 silver bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"human" : {
"buttonText" : "Upgrade M. M. - Power I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined silver, I can increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 silver bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"novakid" : {
"buttonText" : "Upgrade M. M. - Power I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined silver, I can increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 silver bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"hylotl" : {
"buttonText" : "Upgrade M. M. - Power I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined silver, I can increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 silver bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
}
}
}

View file

@ -0,0 +1,200 @@
{
"commandName" : "upgradeBeamaxePower2",
"onlyOnce" : true,
"icon" : "beamaxe.png",
"actions" : [
{
"action" : "UpdatePlayerEssentialItem",
"itemsRequired" : [ ["diamond", 8] ],
"parameters" : {
"tileDamage" : 2.0,
"minBeamJitter" : 0.15,
"maxBeamJitter" : 0.3
},
"essentialItem" : "beamaxe"
},
{
"action" : "DisableCommand",
"command" : "upgradeBeamaxePower2"
},
{
"action" : "EnableCommand",
"command" : "upgradeBeamaxePower3"
},
{
"action" : "EnableCommand",
"command" : "upgradeBeamaxeSize3"
}
],
"speciesText" : {
"apex" : {
"buttonText" : "Upgrade M. M. - Power II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 diamonds, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 diamonds to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"avian" : {
"buttonText" : "Upgrade M. M. - Power II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 diamonds, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 diamonds to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"floran" : {
"buttonText" : "Upgrade M. M. - Power II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 diamonds, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 diamonds to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"glitch" : {
"buttonText" : "Upgrade M. M. - Power II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 diamonds, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 diamonds to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"human" : {
"buttonText" : "Upgrade M. M. - Power II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 diamonds, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 diamonds to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"novakid" : {
"buttonText" : "Upgrade M. M. - Power II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 diamonds, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 diamonds to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"hylotl" : {
"buttonText" : "Upgrade M. M. - Power II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 diamonds, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 diamonds to complete this upgrade.",
"speedModifier" : 1.0
}
]
}
}
}

View file

@ -0,0 +1,196 @@
{
"commandName" : "upgradeBeamaxePower3",
"onlyOnce" : true,
"icon" : "beamaxe.png",
"actions" : [
{
"action" : "UpdatePlayerEssentialItem",
"itemsRequired" : [ ["refinedviolium", 8] ],
"parameters" : {
"tileDamage" : 2.5,
"minBeamJitter" : 0.2,
"maxBeamJitter" : 0.4
},
"essentialItem" : "beamaxe"
},
{
"action" : "DisableCommand",
"command" : "upgradeBeamaxePower3"
},
{
"action" : "EnableCommand",
"command" : "upgradeBeamaxePower4"
}
],
"speciesText" : {
"apex" : {
"buttonText" : "Upgrade M. M. - Power III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined violium, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 violium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"avian" : {
"buttonText" : "Upgrade M. M. - Power III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined violium, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 violium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"floran" : {
"buttonText" : "Upgrade M. M. - Power III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined violium, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 violium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"glitch" : {
"buttonText" : "Upgrade M. M. - Power III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined violium, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 violium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"human" : {
"buttonText" : "Upgrade M. M. - Power III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined violium, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 violium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"novakid" : {
"buttonText" : "Upgrade M. M. - Power III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined violium, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 violium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"hylotl" : {
"buttonText" : "Upgrade M. M. - Power III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined violium, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 violium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
}
}
}

View file

@ -0,0 +1,192 @@
{
"commandName" : "upgradeBeamaxePower4",
"onlyOnce" : true,
"icon" : "beamaxe.png",
"actions" : [
{
"action" : "UpdatePlayerEssentialItem",
"itemsRequired" : [ ["imperviumcompound", 8] ],
"parameters" : {
"tileDamage" : 3.0,
"minBeamJitter" : 0.25,
"maxBeamJitter" : 0.5
},
"essentialItem" : "beamaxe"
},
{
"action" : "DisableCommand",
"command" : "upgradeBeamaxePower4"
}
],
"speciesText" : {
"apex" : {
"buttonText" : "Upgrade M. M. - Power IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of impervium compound, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 impervium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"avian" : {
"buttonText" : "Upgrade M. M. - Power IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of impervium compound, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 impervium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"floran" : {
"buttonText" : "Upgrade M. M. - Power IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of impervium compound, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 impervium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"glitch" : {
"buttonText" : "Upgrade M. M. - Power IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of impervium compound, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 impervium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"human" : {
"buttonText" : "Upgrade M. M. - Power IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of impervium compound, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 impervium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"novakid" : {
"buttonText" : "Upgrade M. M. - Power IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of impervium compound, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 impervium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"hylotl" : {
"buttonText" : "Upgrade M. M. - Power IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of impervium compound, I can further increase your matter manipulator's power.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 impervium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
}
}
}

View file

@ -0,0 +1,196 @@
{
"commandName" : "upgradeBeamaxeSize1",
"onlyOnce" : true,
"icon" : "beamaxe.png",
"actions" : [
{
"action" : "UpdatePlayerEssentialItem",
"itemsRequired" : [ ["copperbar", 8] ],
"parameters" : {
"blockRadius" : 2,
"minBeamWidth" : 3,
"maxBeamWidth" : 5
},
"essentialItem" : "beamaxe"
},
{
"action" : "DisableCommand",
"command" : "upgradeBeamaxeSize1"
},
{
"action" : "EnableCommand",
"command" : "upgradeBeamaxePower1"
}
],
"speciesText" : {
"apex" : {
"buttonText" : "Upgrade M. M. - Size I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined copper, I can upgrade your matter manipulator to mine in a larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 copper bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"avian" : {
"buttonText" : "Upgrade M. M. - Size I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined copper, I can upgrade your matter manipulator to mine in a larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 copper bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"floran" : {
"buttonText" : "Upgrade M. M. - Size I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined copper, I can upgrade your matter manipulator to mine in a larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 copper bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"glitch" : {
"buttonText" : "Upgrade M. M. - Size I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined copper, I can upgrade your matter manipulator to mine in a larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 copper bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"human" : {
"buttonText" : "Upgrade M. M. - Size I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined copper, I can upgrade your matter manipulator to mine in a larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 copper bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"novakid" : {
"buttonText" : "Upgrade M. M. - Size I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined copper, I can upgrade your matter manipulator to mine in a larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 copper bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"hylotl" : {
"buttonText" : "Upgrade M. M. - Size I",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined copper, I can upgrade your matter manipulator to mine in a larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 copper bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
}
}
}

View file

@ -0,0 +1,196 @@
{
"commandName" : "upgradeBeamaxeSize2",
"onlyOnce" : true,
"icon" : "beamaxe.png",
"actions" : [
{
"action" : "UpdatePlayerEssentialItem",
"itemsRequired" : [ ["platinumbar", 8] ],
"parameters" : {
"blockRadius" : 3,
"minBeamWidth" : 5,
"maxBeamWidth" : 7
},
"essentialItem" : "beamaxe"
},
{
"action" : "DisableCommand",
"command" : "upgradeBeamaxeSize2"
},
{
"action" : "EnableCommand",
"command" : "upgradeBeamaxePower2"
}
],
"speciesText" : {
"apex" : {
"buttonText" : "Upgrade M. M. - Size II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined platinum, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 platinum bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"avian" : {
"buttonText" : "Upgrade M. M. - Size II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined platinum, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 platinum bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"floran" : {
"buttonText" : "Upgrade M. M. - Size II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined platinum, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 platinum bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"glitch" : {
"buttonText" : "Upgrade M. M. - Size II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined platinum, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 platinum bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"human" : {
"buttonText" : "Upgrade M. M. - Size II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined platinum, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 platinum bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"novakid" : {
"buttonText" : "Upgrade M. M. - Size II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined platinum, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 platinum bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"hylotl" : {
"buttonText" : "Upgrade M. M. - Size II",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined platinum, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 platinum bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
}
}
}

View file

@ -0,0 +1,196 @@
{
"commandName" : "upgradeBeamaxeSize3",
"onlyOnce" : true,
"icon" : "beamaxe.png",
"actions" : [
{
"action" : "UpdatePlayerEssentialItem",
"itemsRequired" : [ ["refinedrubium", 8] ],
"parameters" : {
"blockRadius" : 4,
"minBeamWidth" : 7,
"maxBeamWidth" : 9
},
"essentialItem" : "beamaxe"
},
{
"action" : "DisableCommand",
"command" : "upgradeBeamaxeSize3"
},
{
"action" : "EnableCommand",
"command" : "upgradeBeamaxeSize4"
}
],
"speciesText" : {
"apex" : {
"buttonText" : "Upgrade M. M. - Size III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined rubium, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 rubium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"avian" : {
"buttonText" : "Upgrade M. M. - Size III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined rubium, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 rubium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"floran" : {
"buttonText" : "Upgrade M. M. - Size III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined rubium, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 rubium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"glitch" : {
"buttonText" : "Upgrade M. M. - Size III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined rubium, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 rubium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"human" : {
"buttonText" : "Upgrade M. M. - Size III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined rubium, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 rubium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"novakid" : {
"buttonText" : "Upgrade M. M. - Size III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined rubium, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 rubium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"hylotl" : {
"buttonText" : "Upgrade M. M. - Size III",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of refined rubium, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 rubium bars to complete this upgrade.",
"speedModifier" : 1.0
}
]
}
}
}

View file

@ -0,0 +1,192 @@
{
"commandName" : "upgradeBeamaxeSize4",
"onlyOnce" : true,
"icon" : "beamaxe.png",
"actions" : [
{
"action" : "UpdatePlayerEssentialItem",
"itemsRequired" : [ ["ceruliumcompound", 8] ],
"parameters" : {
"blockRadius" : 5,
"minBeamWidth" : 9,
"maxBeamWidth" : 11
},
"essentialItem" : "beamaxe"
},
{
"action" : "DisableCommand",
"command" : "upgradeBeamaxeSize4"
}
],
"speciesText" : {
"apex" : {
"buttonText" : "Upgrade M. M. - Size IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of cerulium compound, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 cerulium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"avian" : {
"buttonText" : "Upgrade M. M. - Size IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of cerulium compound, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 cerulium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"floran" : {
"buttonText" : "Upgrade M. M. - Size IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of cerulium compound, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 cerulium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"glitch" : {
"buttonText" : "Upgrade M. M. - Size IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of cerulium compound, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 cerulium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"human" : {
"buttonText" : "Upgrade M. M. - Size IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of cerulium compound, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 cerulium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"novakid" : {
"buttonText" : "Upgrade M. M. - Size IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of cerulium compound, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 cerulium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
},
"hylotl" : {
"buttonText" : "Upgrade M. M. - Size IV",
"selectSpeech" : [
{
"animation" : "talk",
"text" : "With 8 bars of cerulium compound, I can upgrade your matter manipulator to mine in an even larger area.",
"speedModifier" : 1.0
}
],
"successSpeech" : [
{
"animation" : "talk",
"text" : "Success! Your Matter Manipulator has been upgraded.",
"speedModifier" : 1.0
}
],
"failSpeech" : [
{
"animation" : "talk",
"text" : "Failure. We'll need 8 cerulium compound to complete this upgrade.",
"speedModifier" : 1.0
}
]
}
}
}

View file

@ -0,0 +1,24 @@
INCLUDE_DIRECTORIES (
${STAR_CORE_INCLUDES}
${STAR_AUTHENTICATION_INCLUDES}
)
SET (authentication_HEADERS
StarAuthenticationDatabaseFacade.hpp
StarAuthenticationKey.hpp
StarAuthenticationService.hpp
StarAuthenticationConnection.hpp
StarClientAuthentication.hpp
StarServerAuthentication.hpp
)
SET (authentication_SOURCES
StarAuthenticationKey.cpp
StarAuthenticationService.cpp
StarAuthenticationConnection.cpp
StarClientAuthentication.cpp
StarServerAuthentication.cpp
)
ADD_LIBRARY (star_authentication ${authentication_SOURCES} ${authentication_HEADERS})
TARGET_LINK_LIBRARIES (star_authentication star)

View file

@ -0,0 +1,65 @@
#include "StarAuthenticationConnection.hpp"
#include "StarClock.hpp"
#include "StarTcp.hpp"
namespace Star {
namespace Auth {
AuthenticationConnection::AuthenticationConnection(String const& authServer, int port) {
m_authServer = authServer;
m_port = port;
}
String AuthenticationConnection::query(String const& request) {
auto socket = TcpSocket::connectTo(HostAddress(m_authServer, m_port));
socket->setNoDelay(true);
socket->setSocketTimeout(AuthRequestTimeout);
String requestHeader = "POST /auth.sb HTTP/1.1\r\nHost: " + m_authServer + "\r\nContent-Type: application/json\r\nConnection: close\r\n\r\n";
socket->writeFull(requestHeader.utf8Ptr(), requestHeader.utf8Size());
socket->writeFull(request.utf8Ptr(), request.utf8Size());
String requestFooter = "\r\n\r\n";
socket->writeFull(requestFooter.utf8Ptr(), requestFooter.utf8Size());
socket->flush();
int64_t deadline = Clock::currentTime() + AuthRequestTimeout;
Buffer buffer(ResponseBufferCapacity);
bool headerMode = true;
int newlineCounter = 0;
while (socket->isOpen()) {
if (Clock::currentTime() >= deadline) {
throw StarException("Timeout reading auth server response.");
}
char c;
socket->readFull(&c, 1);
throw StarException("Unexpected result from socket read.");
if (c == '\r')
continue;
buffer.writeFull(&c, 1);
if (buffer.pos() >= ResponseBufferCapacity) {
throw StarException("Auth server response too long.");
}
if (c == '\n')
newlineCounter++;
else
newlineCounter = 0;
if (newlineCounter == 2) {
if (headerMode) {
String header = String(buffer.ptr(), buffer.pos());
if (!header.beginsWith("HTTP/1.1 200 OK\n")) {
throw StarException("Auth server invalid response.");
}
headerMode = false;
buffer.clear();
newlineCounter = 0;
}
else {
return String(buffer.ptr(), buffer.pos() - 2); // remove trailing newlines, guaranteed to be there
}
}
}
throw StarException("Connection lost.");
}
}
}

View file

@ -0,0 +1,28 @@
#ifndef _STAR_AUTHENTICATION_CONNECTION_HPP_
#define _STAR_AUTHENTICATION_CONNECTION_HPP_
#include "StarVariant.hpp"
namespace Star {
namespace Auth {
static int const AuthRequestTimeout = 10*1000;
static int const ResponseBufferCapacity = 15*1024;
class AuthenticationConnection {
public:
AuthenticationConnection(String const& authServer, int port);
String query(String const& request);
private:
String m_authServer;
int m_port;
};
}
}
#endif

View file

@ -0,0 +1,27 @@
#ifndef _STAR_AUTHENTICATION_DATABASE_HPP_
#define _STAR_AUTHENTICATION_DATABASE_HPP_
#include "StarException.hpp"
#include "StarVariant.hpp"
namespace Star {
namespace Auth {
class Database {
public:
virtual ~Database() {}
virtual bool validateUser(String const& username) = 0;
virtual bool validateUserAndPassword(String const& username, String const& passwordPreHashed) = 0;
virtual bool setUserRecord(String const& username, String const& passwordPreHashed, bool active) = 0;
virtual bool activateUserRecord(String const& username, bool active) = 0;
virtual int usersCount() = 0;
};
typedef shared_ptr<Database> DatabasePtr;
}
}
#endif

View file

@ -0,0 +1,437 @@
#include "StarAuthenticationKey.hpp"
#include "StarClock.hpp"
#include "StarEncode.hpp"
#include "StarSha256.hpp"
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
#include <openssl/des.h>
#include <openssl/rand.h>
#include <openssl/buffer.h>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstring>
#include <openssl/x509.h>
#include <vector>
#include "StarRandom.hpp"
namespace Star {
namespace Auth {
std::ostream &operator<<(std::ostream &out, const Key &key) {
return out << "Private Key :" << key.privateKey() << std::endl << " Public Key :" << key.publicKey() << std::endl;
}
Key::Key() : m_key(NULL), m_mdCtx(NULL) {
// ERR_load_crypto_strings will only load things once even if called multiple times
ERR_load_crypto_strings();
m_key = EVP_PKEY_new();
if (m_key == NULL)
throw CryptoException("Unable to Establish Key Container");
m_mdCtx = EVP_MD_CTX_create();
if (m_mdCtx == NULL) {
EVP_PKEY_free(m_key);
m_key = NULL;
throw CryptoException("Unable to Establish EVP Message Digest Context");
}
}
Key::Key(bool generate) : Key() {
if (generate) {
regenerate();
}
}
Key::Key(String const& key, bool privateKey) : Key() {
if (privateKey) {
loadPrivateKey(key);
} else {
loadPublicKey(key);
}
}
Key::~Key() {
if (m_key != NULL)
EVP_PKEY_free(m_key);
if (m_mdCtx != NULL)
EVP_MD_CTX_destroy(m_mdCtx);
// We could call ERR_free_strings but that would just mean the next Key
// to be created would make ERR_load_crypto_strings actually process
// so eliminate that thrashing by not calling ERR_free_strings
}
void Key::regenerate() {
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (EVP_PKEY_keygen_init(ctx) <= 0)
throw cryptoException(ctx, "Unable to initialize EVP Key Generator");
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, KeySize) <= 0)
throw cryptoException(ctx, "Unable to set EVP Key Generator size");
if (EVP_PKEY_keygen(ctx, &m_key) <= 0)
throw cryptoException(ctx, "Unable to generate new Client Key");
EVP_PKEY_CTX_free(ctx);
m_isPrivate = 1;
}
CryptoException Key::cryptoException(BIO *bio, const char* errorString) const {
unsigned long err = ERR_get_error();
BIO_free_all(bio);
if (errorString == nullptr) {
errorString = ERR_error_string(err, NULL);
}
return CryptoException(ERR_error_string(err, NULL));
}
CryptoException Key::cryptoException(EVP_PKEY_CTX *ctx, const char* errorString) const {
unsigned long err = ERR_get_error();
EVP_PKEY_CTX_free(ctx);
if (errorString == nullptr) {
errorString = ERR_error_string(err, NULL);
}
return CryptoException(errorString);
}
void Key::loadPrivateKey(String const& key) {
if (key.empty())
throw StarException("Empty key.");
BIO *bIn = BIO_push(
BIO_new(BIO_f_base64()),
BIO_new_mem_buf((void*) key.utf8Ptr(), key.utf8Size())
);
BIO_set_flags(bIn, BIO_FLAGS_BASE64_NO_NL);
RSA * rsa;
if ((rsa = d2i_RSAPrivateKey_bio(bIn, NULL)) == 0)
throw cryptoException(bIn);
EVP_PKEY_set1_RSA(m_key, rsa);
BIO_free_all(bIn);
m_isPrivate = 1;
}
void Key::loadPublicKey(String const& key) {
if (key.empty())
throw StarException("Empty key.");
BIO *bIn = BIO_push(
BIO_new(BIO_f_base64()),
BIO_new_mem_buf((void*) key.utf8Ptr(), key.utf8Size())
);
BIO_set_flags(bIn, BIO_FLAGS_BASE64_NO_NL);
RSA * rsa;
if ((rsa = d2i_RSAPublicKey_bio(bIn, NULL)) == 0)
throw cryptoException(bIn);
EVP_PKEY_set1_RSA(m_key, rsa);
BIO_free_all(bIn);
m_isPrivate = 0;
}
String Key::publicKey() const {
BIO *b64 = BIO_push(
BIO_new(BIO_f_base64()),
BIO_new(BIO_s_mem())
);
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
i2d_RSAPublicKey_bio(b64, EVP_PKEY_get1_RSA(m_key));
(void) BIO_flush(b64);
BUF_MEM *bPtr;
BIO_get_mem_ptr(b64, &bPtr);
String out(bPtr->data, bPtr->length);
BIO_free_all(b64);
return out;
}
String Key::privateKey() const {
if (!m_isPrivate)
throw CryptoException("Private Key not loaded.");
BIO *b64 = BIO_push(
BIO_new(BIO_f_base64()),
BIO_new(BIO_s_mem())
);
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
i2d_RSAPrivateKey_bio(b64, EVP_PKEY_get1_RSA(m_key));
(void) BIO_flush(b64);
BUF_MEM *bPtr;
BIO_get_mem_ptr(b64, &bPtr);
String out(bPtr->data, bPtr->length);
BIO_free_all(b64);
return out;
}
String Key::encryptMessage(String const& message) const {
size_t bufLen;
unsigned char * buf;
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(m_key, NULL);
if (EVP_PKEY_encrypt_init(ctx) != 1)
throw cryptoException(ctx);
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) != 1)
throw cryptoException(ctx);
if (EVP_PKEY_encrypt(ctx, NULL, &bufLen, (unsigned char *) message.utf8Ptr(), message.utf8Size()) != 1)
throw cryptoException(ctx);
buf = new unsigned char[bufLen];
if (EVP_PKEY_encrypt(ctx, (unsigned char *) buf, &bufLen, (unsigned char *) message.utf8Ptr(), message.utf8Size()) <= 0) {
delete[] buf;
throw cryptoException(ctx);
}
EVP_PKEY_CTX_free(ctx);
String oString(base64Encode((char const*)buf, bufLen));
delete[] buf;
return oString;
}
String Key::decryptMessage(String const& cryptText) const {
ByteArray iString(base64Decode(cryptText));
size_t bufLen;
unsigned char * buf;
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(m_key, NULL);
if (EVP_PKEY_decrypt_init(ctx) <= 0)
throw cryptoException(ctx);
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
throw cryptoException(ctx);
if (EVP_PKEY_decrypt(ctx, NULL, &bufLen, (unsigned char *) iString.ptr(), iString.size()) <= 0)
throw cryptoException(ctx);
buf = new unsigned char[bufLen];
if (EVP_PKEY_decrypt(ctx, (unsigned char *) buf, &bufLen, (unsigned char *) iString.ptr(), iString.size()) != 1) {
delete[] buf;
throw cryptoException(ctx);
}
EVP_PKEY_CTX_free(ctx);
String oString((const char *) buf, bufLen);
delete[] buf;
return oString;
}
String Key::signMessage(String const& message) const {
if (!m_isPrivate)
throw CryptoException("Private Key not Loaded");
size_t sigLen;
unsigned char *sig;
ByteArray shaMessage(sha256(ByteArray(message.utf8Ptr(), message.utf8Size())));
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(m_key, NULL);
if (EVP_PKEY_sign_init(ctx) <= 0)
throw cryptoException(ctx);
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0)
throw cryptoException(ctx);
if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0)
throw cryptoException(ctx);
if (EVP_PKEY_sign(ctx, NULL, &sigLen, (unsigned char *) shaMessage.ptr(), shaMessage.size()) <= 0)
throw cryptoException(ctx);
if (!(sig = (unsigned char *) OPENSSL_malloc(sigLen)))
throw cryptoException(ctx);
if (EVP_PKEY_sign(ctx, sig, &sigLen, (unsigned char *) shaMessage.ptr(), shaMessage.size()) <= 0)
throw cryptoException(ctx);
EVP_PKEY_CTX_free(ctx);
String oString(base64Encode((const char *)sig, sigLen));
OPENSSL_free(sig);
return oString;
}
bool Key::verifyMessage(String const& message, String const& signature) const {
ByteArray shaMessage(sha256(ByteArray(message.utf8Ptr(), message.utf8Size())));
ByteArray rawSignature(base64Decode(signature));
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(m_key, NULL);
if (EVP_PKEY_verify_init(ctx) <= 0)
throw cryptoException(ctx);
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0)
throw cryptoException(ctx);
if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0)
throw cryptoException(ctx);
int rv = EVP_PKEY_verify(ctx, (unsigned char *) rawSignature.ptr(), rawSignature.size(), (unsigned char *) shaMessage.ptr(), shaMessage.size());
if (rv < 0)
throw cryptoException(ctx);
EVP_PKEY_CTX_free(ctx);
return rv == 1;
}
void initializeKeyLogic() {
// intitial initialization of DES_random_key and friends scans the whole heap.
// do it as early as possible.
generateKey();
}
String generateKey() {
// Init desKey to week key to avoid valgrind warning
DES_cblock desKey = {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01};
ByteArray key = ByteArray::withReserve(24);
if (DES_random_key(&desKey) == 0)
throw CryptoException("RNG could not generate a secure key");
key.append((const char *) desKey, 8);
if (DES_random_key(&desKey) == 0)
throw CryptoException("RNG could not generate a secure key");
key.append((const char *) desKey, 8);
if (DES_random_key(&desKey) == 0)
throw CryptoException("RNG could not generate a secure key");
key.append((const char *) desKey, 8);
return base64Encode(key);
}
/**
* Encrypts a Message
* @param message Message to Encrypt
* @param key Base64 encoded 24 byte key
* @return Base64 Encoded String containing encrypted message
*/
String encryptMessage(String const& message, String const& key) {
DES_cblock desKey;
DES_cblock ivec;
DES_key_schedule desSchedule1;
DES_key_schedule desSchedule2;
DES_key_schedule desSchedule3;
int n = 0;
/* Prepare the key for use with DES_cfb64_encrypt */
ByteArray iKey(base64Decode(key));
if (iKey.size() != 24)
throw StarException("Key size mismatch.");
std::memcpy(desKey, iKey.ptr(), 8);
DES_set_odd_parity(&desKey);
DES_set_key_checked(&desKey, &desSchedule1);
std::memcpy(desKey, iKey.ptr() + 8, 8);
DES_set_odd_parity(&desKey);
DES_set_key_checked(&desKey, &desSchedule2);
std::memcpy(desKey, iKey.ptr() + 16, 8);
DES_set_odd_parity(&desKey);
DES_set_key_checked(&desKey, &desSchedule3);
std::memcpy(ivec, iKey.ptr() + 12, 8);
/* Encryption occurs here */
unsigned char * buf = new unsigned char[message.utf8Size()];
DES_ede3_cfb64_encrypt((unsigned char *) message.utf8Ptr(), buf, message.utf8Size(), &desSchedule1, &desSchedule2, &desSchedule3, &ivec, &n, DES_ENCRYPT);
String output(base64Encode((const char*)buf, message.utf8Size()));
delete[] buf;
return output;
}
/**
* Decrypts a Message
* @param message Base64 Encoded DES3 encrypted message
* @param key Base64 encoded 24 byte key
* @return String containing decrypted message
*/
String decryptMessage(String const& message, String const& key) {
DES_cblock desKey;
DES_cblock ivec;
DES_key_schedule desSchedule1;
DES_key_schedule desSchedule2;
DES_key_schedule desSchedule3;
int n = 0;
ByteArray iMessage(base64Decode(message));
/* Prepare the key for use with DES_cfb64_encrypt */
ByteArray iKey(base64Decode(key));
if (iKey.size() != 24)
throw StarException("Key size mismatch.");
std::memcpy(desKey, iKey.ptr(), 8);
DES_set_odd_parity(&desKey);
DES_set_key_checked(&desKey, &desSchedule1);
std::memcpy(desKey, iKey.ptr() + 8, 8);
DES_set_odd_parity(&desKey);
DES_set_key_checked(&desKey, &desSchedule2);
std::memcpy(desKey, iKey.ptr() + 16, 8);
DES_set_odd_parity(&desKey);
DES_set_key_checked(&desKey, &desSchedule3);
std::memcpy(ivec, iKey.ptr() + 12, 8);
/* Encryption occurs here */
unsigned char * buf = new unsigned char[message.utf8Size()];
DES_ede3_cfb64_encrypt((unsigned char *) iMessage.ptr(), buf, iMessage.size(), &desSchedule1, &desSchedule2, &desSchedule3, &ivec, &n, DES_DECRYPT);
String output((const char *) buf, iMessage.size());
delete[] buf;
return output;
}
String preHashPassword(String const& username, String const& password) {
String passPreHash = username + ":" + password + ":starbound";
return base64Encode(sha256(passPreHash.utf8Ptr(), passPreHash.utf8Size()));
}
double const bcrypt_goal_duration = 0.032;
double const bcrypt_max_validate_duration = 0.5;
double const bcrypt_max_generation_duration = 5.0;
int const bcrypt_minimal_rounds = 100;
String bcrypt(String const& message, String const& salt, int& rounds) {
rounds = 0;
auto startTime = Clock::currentTime();
ByteArray saltBuffer(salt.utf8Ptr(), salt.utf8Size());
ByteArray messageBuffer(sha256(ByteArray(message.utf8Ptr(), message.utf8Size())));
ByteArray roundBuffer;
while ((rounds < bcrypt_minimal_rounds) || (Clock::secondsSince(startTime) < bcrypt_goal_duration)) {
roundBuffer.resize(0);
roundBuffer.writeFrom(messageBuffer.ptr(), 0, messageBuffer.size());
roundBuffer.writeFrom(saltBuffer.ptr(), messageBuffer.size(), saltBuffer.size());
sha256(roundBuffer, messageBuffer);
rounds++;
}
return base64Encode(messageBuffer);
}
String bcryptWithRounds(String const& message, String const& salt, int rounds) {
if (rounds < bcrypt_minimal_rounds)
throw StarException("Not enough rounds for bcrypt.");
ByteArray saltBuffer(salt.utf8Ptr(), salt.utf8Size());
ByteArray messageBuffer(sha256(ByteArray(message.utf8Ptr(), message.utf8Size())));
ByteArray roundBuffer;
auto startTime = Clock::currentTime();
while (rounds > 0) {
if (Clock::secondsSince(startTime) > bcrypt_max_generation_duration)
throw StarException("Timeout generating bcrypt.");
roundBuffer.resize(0);
roundBuffer.writeFrom(messageBuffer.ptr(), 0, messageBuffer.size());
roundBuffer.writeFrom(saltBuffer.ptr(), messageBuffer.size(), saltBuffer.size());
sha256(roundBuffer, messageBuffer);
rounds--;
}
return base64Encode(messageBuffer);
}
bool bcryptValidate(String const& message, String const& salt, String const& hash, int rounds) {
if (rounds < bcrypt_minimal_rounds)
return false;
ByteArray saltBuffer(salt.utf8Ptr(), salt.utf8Size());
ByteArray messageBuffer(sha256(ByteArray(message.utf8Ptr(), message.utf8Size())));
ByteArray roundBuffer;
auto startTime = Clock::currentTime();
while (rounds > 0) {
if (Clock::secondsSince(startTime) > bcrypt_max_validate_duration)
return false;
roundBuffer.resize(0);
roundBuffer.writeFrom(messageBuffer.ptr(), 0, messageBuffer.size());
roundBuffer.writeFrom(saltBuffer.ptr(), messageBuffer.size(), saltBuffer.size());
sha256(roundBuffer, messageBuffer);
rounds--;
}
return base64Encode(messageBuffer) == hash;
}
}
}

View file

@ -0,0 +1,68 @@
#ifndef _STAR_AUTHENTICATION_KEY_HPP_
#define _STAR_AUTHENTICATION_KEY_HPP_
#include "StarException.hpp"
#include "StarVariant.hpp"
#include <openssl/evp.h>
#include <string>
namespace Star {
namespace Auth {
STAR_EXCEPTION(CryptoException, StarException);
STAR_EXCEPTION(AuthException, StarException);
class Key {
public:
Key();
Key(bool generate);
Key(String const& key, bool privateKey = false);
~Key();
void regenerate();
void loadPrivateKey(String const& key);
void loadPublicKey(String const& key);
bool isPrivateKey() const {
return m_isPrivate;
}
String publicKey() const;
String privateKey() const;
String encryptMessage(String const& message) const;
String decryptMessage(String const& message) const;
String signMessage(String const& message) const;
bool verifyMessage(String const& message, String const& signature) const;
private:
static int const KeySize = 4096;
// Deleted copy constructor / assignment operator.
Key(Key const& that);
Key& operator=(Key const&);
bool m_isPrivate;
EVP_PKEY * m_key;
EVP_MD_CTX * m_mdCtx;
friend std::ostream &operator<<(std::ostream &cout, const Key &key);
CryptoException cryptoException(EVP_PKEY_CTX *ctx, const char* errorString = nullptr) const;
CryptoException cryptoException(BIO *bio, const char* errorString = nullptr) const;
};
void initializeKeyLogic();
String generateKey();
String encryptMessage(String const& message, String const& key);
String decryptMessage(String const& message, String const& key);
String preHashPassword(String const& username, String const& password);
String bcrypt(String const& message, String const& salt, int& rounds);
String bcryptWithRounds(String const& message, String const& salt, int rounds);
bool bcryptValidate(String const& message, String const& salt, String const& hash, int rounds);
}
}
#endif

View file

@ -0,0 +1,353 @@
#include "StarAuthenticationService.hpp"
#include "StarAuthenticationKey.hpp"
#include "StarClock.hpp"
#include "StarLogging.hpp"
#include "StarFile.hpp"
#include <ctime>
namespace Star {
namespace Auth {
AuthenticationService::AuthenticationService(DatabasePtr db) {
m_db = db;
Variant config = Variant::parseJson(File::readFileString("auth.config"));
m_rootPublicKey.loadPublicKey(config.getString("rootPublicKey"));
m_authPrivateKey.loadPrivateKey(config.getString("authPrivateKey"));
m_certificate = config.get("authCertificate");
String certMetadata = config.get("authCertificate").get("signedAuthKey").repr(0, true);
String certSignature = config.get("authCertificate").get("rootSignedAuthKeySignature").toString();
if (!m_rootPublicKey.verifyMessage(certMetadata, certSignature)) {
throw CryptoException("Invalid Certificate");
}
}
AuthenticationService::~AuthenticationService() {
}
/**
* {
* "signedAuthKey" : {
* "authPublicKey": ...
* "validFrom":...
* "validTo":...
* }
* "rootSignedAuthKeySignature": (signature made with root privkey)
* }
*/
Variant AuthenticationService::getCertificate() {
return m_certificate;
}
/**
* Process Client Request
*
* request:
* {
* "envelopeSignature" (signed with client privkey)
* "envelopeKey" (encyrpted with auth pubkey)
* "envelopeBody" === { encrypted body
* "request": {
* "metadata": {
* "username"
* "password"
* }
* "signature"
* }
* "claim" : {
* "metadata: {
* "clientPublicKey": (client public key)
* "username": (username)
( "validFrom": (utctime)
* "validTo": (utctime)
* },
* "signature": (produced by signing the 'claim' with the client private key)
* }
* }
* }
*
* response:
* {
* "claim": {
* "metadata: {
* "clientPublicKey":...
* "username":...
* "validFrom":...
* "validTo":...
* }
* "signature"
* }
* "authSignature": {
* "signedAuthKey" : {
* "authPublicKey": ...
* "validFrom":...
* "validTo":...
* }
* "rootSignedAuthKeySignature": (signature made with root privkey)
* }
* "signature": (signature of main message with authPrivateKey)
* }
*
*/
Variant AuthenticationService::authorizeClient(Variant const& request) {
String envelopeSignature = request.getString("envelopeSignature");
String envelopeBodyString = request.getString("envelopeBody");
String envelopeKey = m_authPrivateKey.decryptMessage(request.getString("envelopeKey"));
String envelopeBody = Star::Auth::decryptMessage(envelopeBodyString, envelopeKey);
Variant requestMessage = Variant::parse(envelopeBody);
Variant claim = requestMessage["claim"];
if (!validateClientInnerClaim(claim))
throw StarException("Request claim fail.");
Key clientKey(claim["metadata"].getString("clientPublicKey"));
if (!clientKey.verifyMessage(envelopeBodyString, envelopeSignature))
throw StarException("Request outer signature fail.");
String requestSignature = requestMessage["request"].getString("signature");
auto requestMetadata = requestMessage["request"]["metadata"];
if (!clientKey.verifyMessage(requestMetadata.repr(0, true), requestSignature))
throw StarException("Request signature fail.");
int64_t validFrom = claim["metadata"].getInt("validFrom");
int64_t validTo = claim["metadata"].getInt("validTo");
if (Clock::currentTime() - 1LL*25LL*60LL*60LL*1000LL > validFrom)
throw StarException("Claim is too old.");
if (Clock::currentTime() < validFrom)
throw StarException("Claim not yet valid");
if (Clock::currentTime()+ 8LL*24LL*60LL*60LL*1000LL < validTo)
throw StarException("Claim is valid for too long.");
String username = requestMetadata.getString("username");
String password = requestMetadata.getString("password");
String claimUsername = claim["metadata"].getString("username");
if (username != claimUsername) {
throw StarException("Username does not match claim.");
}
if (!m_db->validateUserAndPassword(username, password)) {
throw StarException("Unable to authenticate user");
}
Variant responseMessage = VariantMap{
{"claim", claim},
{"authSignature", m_certificate},
{"signature", m_authPrivateKey.signMessage(claim.repr(0, true))}
};
String messageKey = Star::Auth::generateKey();
String responseBodyString = responseMessage.repr(0, true);
String responseEnvelopeBody = encryptMessage(responseBodyString, messageKey);
Variant responseEnvelope = VariantMap{
{"envelopeBody", responseEnvelopeBody},
{"envelopeKey", clientKey.encryptMessage(messageKey)},
{"envelopeSignature", m_authPrivateKey.signMessage(responseEnvelopeBody)}
};
return responseEnvelope;
}
/**
* Process Client Request
*
* request:
* {
* "envelopeSignature" (signed with client privkey)
* "envelopeKey" (encyrpted with auth pubkey)
* "envelopeBody" === { crypted body
* "request": {
* "metadata": (claim)
* "signature"
* }
* }
* }
*
* response:
* {
* "result": (bool)
* "authSignature": {
* "signedAuthKey" : {
* "authPublicKey": ...
* "validFrom":...
* "validTo":...
* }
* "rootSignedAuthKeySignature": (signature made with root privkey)
* }
* }
* // message is fullbody encrypted so the response is trust worthyish
*
*/
Variant AuthenticationService::validateClient(Variant const& request) {
bool valid = false;
String clientPublicKey;
try {
String envelopeSignature = request.getString("envelopeSignature");
String envelopeBodyString = request.getString("envelopeBody");
String envelopeKey = m_authPrivateKey.decryptMessage(request.getString("envelopeKey"));
String envelopeBody = Star::Auth::decryptMessage(envelopeBodyString, envelopeKey);
Variant requestMessage = Variant::parse(envelopeBody);
Variant claim = requestMessage["request"]["metadata"];
clientPublicKey = claim["claim"]["metadata"].getString("clientPublicKey");
if (!validateClientClaim(m_rootPublicKey, claim))
throw StarException("Request claim fail.");
Key clientKey(clientPublicKey);
if (!clientKey.verifyMessage(envelopeBodyString, envelopeSignature))
throw StarException("Request outer signature fail.");
String requestSignature = requestMessage["request"].getString("signature");
auto requestMetadata = requestMessage["request"]["metadata"];
if (!clientKey.verifyMessage(requestMetadata.repr(0, true), requestSignature))
throw StarException("Request signature fail.");
String username = claim["claim"]["metadata"].getString("username");
if (!m_db->validateUser(username)) {
throw StarException("Username is not valid.");
}
valid = true;
}
catch (std::exception const& e) {
Logger::error("failure validating client claim %s", e.what());
valid = false;
}
Variant responseMessage = VariantMap{
{"result", valid},
{"authSignature", m_certificate}
};
String messageKey = Star::Auth::generateKey();
String responseBodyString = responseMessage.repr(0, true);
String envelopeBody = encryptMessage(responseBodyString, messageKey);
Key clientKey(clientPublicKey);
Variant responseEnvelope = VariantMap{
{"envelopeBody", envelopeBody},
{"envelopeKey", clientKey.encryptMessage(messageKey)},
{"envelopeSignature", m_authPrivateKey.signMessage(envelopeBody)}
};
return responseEnvelope;
}
/**
* response:
* {
* "rootPublicKey" : string,
* "authPrivateKey" : string,
* "authCertificate" : {
* "signedAuthKey" : {
* "authPublicKey" : string,
* "validFrom" : long,
* "validTo" : long,
* }
* "rootSignedAuthKeySignature" : string,
* }
* }
*
*/
Variant AuthenticationService::generateAuthenticationConfig(String const& rootPrivateKey, int64_t valid, int64_t expires) {
// Load Root Key
Star::Auth::Key rootKey(rootPrivateKey, true);
// Generate new Authsvr Key
Star::Auth::Key authKey(true);
Variant signedAuthKey = VariantMap{
{"authPublicKey", authKey.publicKey()},
{"validFrom", valid},
{"validTo", expires}
};
Variant config = VariantMap{
{"rootPublicKey", rootKey.publicKey()},
{"authPrivateKey", authKey.privateKey()},
{"authCertificate", VariantMap{
{"signedAuthKey", signedAuthKey},
{"rootSignedAuthKeySignature", rootKey.signMessage(signedAuthKey.repr(0, true))}
}}
};
if (!validateAuthSignature(rootKey, config["authCertificate"]))
throw StarException("Generation failed.");
return config;
}
bool AuthenticationService::validateAuthSignature(Key const& rootPublicKey, Variant const& authSignature) {
auto signedAuthKey = authSignature.get("signedAuthKey");
auto rootSignedAuthKeySignature = authSignature.getString("rootSignedAuthKeySignature");
if (!rootPublicKey.verifyMessage(signedAuthKey.repr(0, true), rootSignedAuthKeySignature)) {
Logger::error("failed to validate signedAuthKey with rootSignedAuthKeySignature");
return false;
}
auto authPublicKey = signedAuthKey.getString("authPublicKey");
if (authPublicKey.empty()) {
Logger::error("empty public key");
return false;
}
auto signedAuthKeyValidFrom = signedAuthKey.getInt("validFrom");
auto signedAuthKeyValidTo = signedAuthKey.getInt("validTo");
if ((signedAuthKeyValidFrom > Clock::currentTime()) || (signedAuthKeyValidTo < Clock::currentTime())) {
Logger::error("timestamp fail %s %s %s", Clock::currentTime(), signedAuthKeyValidFrom, signedAuthKeyValidTo);
return false;
}
// implicit in use after this anyways
// Key authPublicKey(signedAuthKey);
return true;
}
bool AuthenticationService::validateClientClaim(Key const& rootPublicKey, Variant const& claim) {
if (!validateAuthSignature(rootPublicKey, claim.get("authSignature")))
return false;
auto signedAuthKey = claim.get("authSignature").get("signedAuthKey").getString("authPublicKey");
Key authPublicKey(signedAuthKey);
auto authSignature = claim.getString("signature");
auto signedClaim = claim.get("claim");
if (!authPublicKey.verifyMessage(signedClaim.repr(0, true), authSignature))
return false;
if (!validateClientInnerClaim(signedClaim))
return false;
return true;
}
bool AuthenticationService::validateClientInnerClaim(Variant const& claim) {
auto claimMetadata = claim.get("metadata");
auto clientPublicKeyData = claimMetadata.getString("clientPublicKey");
auto claimSignature = claim.getString("signature");
Key clientPublicKey(clientPublicKeyData);
if (!clientPublicKey.verifyMessage(claimMetadata.repr(0, true), claimSignature))
return false;
auto validFrom = claimMetadata.getInt("validFrom");
auto validTo = claimMetadata.getInt("validTo");
if ((validFrom > Clock::currentTime()) || (validTo < Clock::currentTime()))
return false;
return true;
}
}
}

View file

@ -0,0 +1,37 @@
#ifndef _STAR_AUTHENTICATION_SERVICE_HPP_
#define _STAR_AUTHENTICATION_SERVICE_HPP_
#include "StarAuthenticationDatabaseFacade.hpp"
#include "StarAuthenticationKey.hpp"
#include "StarVariant.hpp"
#include "StarVariantExtra.hpp"
namespace Star {
namespace Auth {
class AuthenticationService {
public:
static Variant generateAuthenticationConfig(String const& rootPrivateKey, int64_t valid, int64_t expires);
static bool validateAuthSignature(Key const& rootPublicKey, Variant const& authSignature);
static bool validateClientClaim(Key const& rootPublicKey, Variant const& claim);
static bool validateClientInnerClaim(Variant const& claim);
AuthenticationService(DatabasePtr db);
~AuthenticationService();
Variant getCertificate();
Variant authorizeClient(Variant const& request);
Variant validateClient(Variant const& request);
private:
Key m_authPrivateKey;
Key m_rootPublicKey;
DatabasePtr m_db;
Variant m_certificate;
};
}
}
#endif

View file

@ -0,0 +1,189 @@
#include "StarClientAuthentication.hpp"
#include "StarAuthenticationKey.hpp"
#include "StarAuthenticationService.hpp"
#include "StarAuthenticationConnection.hpp"
#include "StarClock.hpp"
#include "StarLogging.hpp"
#include <ctime>
namespace Star {
namespace Auth {
ClientAuthentication::ClientAuthentication(shared_ptr<Key> const& rootKey) {
m_rootPublicKey = rootKey;
}
ClientAuthentication::~ClientAuthentication() {
}
/*
* {
* "envelopeKey"
* "envelopeBody" === { encrypted body
* "request": {
* "metadata": {
* "username"
* "password"
* }
* "signature"
* }
* "claim" : {
* "metadata: {
* "clientPublicKey": (client public key)
* "username": (username)
* "validFrom": (utctime)
* "validTo": (utctime)
* }
* "signature": (produced by signing the 'claim' with the client private key)
* }
* }
* }
*/
Variant ClientAuthentication::authsvrRequest(String const& username, String const& passwordHash, String const& authClaim, Key const& clientPrivateKey) {
Variant authClaimSignature = Variant::parse(authClaim);
if (!AuthenticationService::validateAuthSignature(*m_rootPublicKey, authClaimSignature))
throw StarException("Auth claim fail.");
Key authPublicKey(authClaimSignature.get("signedAuthKey").getString("authPublicKey"));
Variant requestMetadata = VariantMap{
make_pair("username", username),
make_pair("password", passwordHash)
};
Variant claimMetadata = VariantMap{
make_pair("clientPublicKey", clientPrivateKey.publicKey()),
make_pair("username", username),
make_pair("validFrom", Clock::currentTime() - 1LL * 1LL * 60LL * 60LL * 1000LL),
make_pair("validTo", Clock::currentTime() + 7LL * 24LL * 60LL * 60LL * 1000LL)
};
Variant requestMessage = VariantMap{
make_pair("request", VariantMap{
make_pair("metadata", requestMetadata),
make_pair("signature", clientPrivateKey.signMessage(requestMetadata.repr(0, true)))
}),
make_pair("claim", VariantMap{
make_pair("metadata", claimMetadata),
make_pair("signature", clientPrivateKey.signMessage(claimMetadata.repr(0, true)))
})
};
String envelopeKey = Auth::generateKey();
String requestEnvelopeBody = requestMessage.repr(0, true);
String envelopeBody = Auth::encryptMessage(requestEnvelopeBody, envelopeKey);
Variant requestEnvelope = VariantMap{
make_pair("envelopeBody", envelopeBody),
make_pair("envelopeKey", authPublicKey.encryptMessage(envelopeKey)),
make_pair("envelopeSignature", clientPrivateKey.signMessage(envelopeBody)),
};
return requestEnvelope;
}
/**
* Client claim format:
*
* {
* "signedClaim" : {
* "claim: {
* "clientPublicKey": (client public key)
* "username": (username)
* "validFrom": (utctime)
* "validTo": (utctime)
* },
* "signature": (produced by signing the 'claim' with the client private key)
* },
* "authSignature" : {
* "signature" : (produced by signing the 'signedClaim' with the auth private key)
* "signedAuthKey": {
* "authPublicKey": (auth public key)
* "validFrom": (utctime)
* "validTo": (utctime)
* }
* "signedAuthKeySignature": (produced by signing the auth public key with the root private key)
* }
* }
*/
Variant ClientAuthentication::authsvrResponse(String const& response, Key const& clientPrivateKey) {
Variant requestEnvelope = Variant::parse(response);
String envelopeKey = clientPrivateKey.decryptMessage(requestEnvelope.getString("envelopeKey"));
String requestEnvelopeBody = requestEnvelope.getString("envelopeBody");
String envelopeBody = Auth::decryptMessage(requestEnvelopeBody, envelopeKey);
String envelopeSignature = requestEnvelope.getString("envelopeSignature");
Variant authClaimSignature = Variant::parse(envelopeBody);
Key authPublicKey(authClaimSignature.get("authSignature").get("signedAuthKey").getString("authPublicKey"));
if (!authPublicKey.verifyMessage(requestEnvelopeBody, envelopeSignature))
throw StarException("Envelop signature fail");
return authClaimSignature;
}
String ClientAuthentication::serverRequest() {
return "";
}
bool ClientAuthentication::serverResponse(String const& response) {
//todo
_unused(response);
return true;
}
Variant ClientAuthentication::authsvrValidateRequest(Variant const& claim, String const& authClaim, Key const& clientPrivateKey) {
Variant authClaimSignature = Variant::parse(authClaim);
if (!AuthenticationService::validateAuthSignature(*m_rootPublicKey, authClaimSignature))
throw StarException("Auth claim fail.");
Key authPublicKey(authClaimSignature.get("signedAuthKey").getString("authPublicKey"));
Variant requestMessage = VariantMap{
{"request", VariantMap{
{"metadata", claim},
{"signature", clientPrivateKey.signMessage(claim.repr(0, true))}
}}
};
String envelopeKey = Auth::generateKey();
String requestEnvelopeBody = requestMessage.repr(0, true);
String envelopeBody = Auth::encryptMessage(requestEnvelopeBody, envelopeKey);
Variant requestEnvelope = VariantMap{
{"envelopeBody", envelopeBody},
{"envelopeKey", authPublicKey.encryptMessage(envelopeKey)},
{"envelopeSignature", clientPrivateKey.signMessage(envelopeBody)}
};
return requestEnvelope;
}
bool ClientAuthentication::authsvrValidateResponse(String const& response, Key const& clientPrivateKey) {
Variant requestEnvelope = Variant::parse(response);
String envelopeKey = clientPrivateKey.decryptMessage(requestEnvelope.getString("envelopeKey"));
String requestEnvelopeBody = requestEnvelope.getString("envelopeBody");
String envelopeBody = Auth::decryptMessage(requestEnvelopeBody, envelopeKey);
String envelopeSignature = requestEnvelope.getString("envelopeSignature");
Variant authClaimSignature = Variant::parse(envelopeBody);
Key authPublicKey(authClaimSignature.get("authSignature").get("signedAuthKey").getString("authPublicKey"));
if (!authPublicKey.verifyMessage(requestEnvelopeBody, envelopeSignature))
throw StarException("Envelop signature fail");
return authClaimSignature.getBool("result");
}
}
}

View file

@ -0,0 +1,71 @@
#ifndef _STAR_CLIENT_AUTHENTICATION_HPP_
#define _STAR_CLIENT_AUTHENTICATION_HPP_
#include "StarAuthenticationKey.hpp"
#include "StarException.hpp"
#include "StarVariant.hpp"
#include <string>
namespace Star {
namespace Auth {
/*
<AuthSignature>=
{
"signedAuthKey" : {
"authPublicKey": ...
"validFrom":...
"validTo":...
}
"rootSignedAuthKeySignature": <signature made with root privkey>
}
<ClientClaim>=
{
"claim": {
"metadata: {
"clientPublicKey":...
"username":...
"validFrom":...
"validTo":...
}
"signature"
}
"authSignature": {
"signedAuthKey" : {
"authPublicKey": ...
"validFrom":...
"validTo":...
}
"rootSignedAuthKeySignature": <signature made with root privkey>
}
"signature": <signature of main message with authPrivateKey>
}
*/
class ClientAuthentication {
public:
ClientAuthentication(shared_ptr<Key> const& rootKey);
~ClientAuthentication();
Variant authsvrRequest(String const& username, String const& passwordHash, String const& authClaim, Key const& clientPrivateKey);
Variant authsvrResponse(String const& response, Key const& clientPrivateKey);
String serverRequest();
bool serverResponse(String const& response);
Variant authsvrValidateRequest(Variant const& claim, String const& authClaim, Key const& clientPrivateKey);
bool authsvrValidateResponse(String const& response, Key const& clientPrivateKey);
private:
shared_ptr<Key> m_rootPublicKey;
};
}
}
#endif

View file

@ -0,0 +1,37 @@
#include "StarServerAuthentication.hpp"
#include "StarAuthenticationKey.hpp"
#include <ctime>
namespace Star {
namespace Auth {
ServerAuthentication::ServerAuthentication(String const& rootPublicKey) {
m_rootPublicKey.loadPublicKey(rootPublicKey);
}
ServerAuthentication::~ServerAuthentication() {}
String ServerAuthentication::authsvrRequest(String const& username, String const& password, String const& hostname, int port, String const& authCertificate) {
//le todo
_unused(username);
_unused(password);
_unused(hostname);
_unused(port);
_unused(authCertificate);
return String();
}
bool ServerAuthentication::authsvrResponse(String const& response) {
_unused(response);
return false;
}
String ServerAuthentication::clientRequest(String const& request) {
_unused(request);
return String();
}
}
}

View file

@ -0,0 +1,32 @@
#ifndef _STAR_SERVER_AUTHENTICATION_HPP_
#define _STAR_SERVER_AUTHENTICATION_HPP_
#include "StarAuthenticationKey.hpp"
#include "StarVariant.hpp"
#include <string>
namespace Star {
namespace Auth {
class ServerAuthentication {
public:
ServerAuthentication(String const& rootPublicKey);
~ServerAuthentication();
String authsvrRequest(String const& username, String const& password, String const& hostname, int port, String const& authCertificate);
bool authsvrResponse(String const& response);
String clientRequest(String const& request);
private:
Auth::Key m_serverPrivateKey;
Auth::Key m_authPublicKey;
Auth::Key m_rootPublicKey;
Variant m_authCertificate;
Variant m_serverCertificate;
};
}
}
#endif

View file

@ -0,0 +1,23 @@
INCLUDE_DIRECTORIES (
${STAR_CORE_INCLUDES}
${STAR_GAME_INCLUDES}
${STAR_AUTHENTICATION_INCLUDES}
)
SET (authentication_server_HEADERS
StarAuthenticationDatabase.hpp
StarAuthenticationServer.hpp
StarDatabaseConnector.hpp
)
SET (authentication_server_SOURCES
StarAuthenticationDatabase.cpp
StarAuthenticationServer.cpp
StarDatabaseConnector.cpp
)
ADD_EXECUTABLE (starbound_auth_keygen keygen.cpp ${authentication_server_SOURCES} ${authentication_server_HEADERS})
ADD_EXECUTABLE (starbound_auth main.cpp ${authentication_server_SOURCES} ${authentication_server_HEADERS})
TARGET_LINK_LIBRARIES (starbound_auth_keygen star_authentication ${PQ_LIBRARY})
TARGET_LINK_LIBRARIES (starbound_auth star_authentication ${PQ_LIBRARY})

View file

@ -0,0 +1,160 @@
#include "StarAuthenticationDatabase.hpp"
#include "StarLogging.hpp"
#include "StarDatabaseConnector.hpp"
#include "StarAlgorithm.hpp"
using namespace std;
namespace Star {
namespace Auth {
AuthenticationDatabase::AuthenticationDatabase(String const& connectionString) :m_connectionString(connectionString) {
/*
if (validateUser("none"))
throw StarException("User none should not exist");
if (!validateUser("test"))
throw StarException("User test should exist");
if (!validateUserAndPassword("test", preHashPassword("test", "test")))
throw StarException("User test should be able to login using the password 'test'");
if (validateUserAndPassword("test", preHashPassword("test", "none")))
throw StarException("User test should not be able to login using the password 'none'");
*/
}
AuthenticationDatabase::~AuthenticationDatabase() {
}
bool AuthenticationDatabase::validateUser(String const& username) {
DatabaseConnector conn(m_connectionString);
{
conn.exec("BEGIN");
bool success = false;
auto transactionScope = finally([&]() {
if (success)
conn.exec("END");
else
conn.exec("ROLLBACK");
});
auto rows = conn.fetch("SELECT id_user, active FROM users WHERE username=$1", { username });
bool result;
if (rows.size() == 0) {
result = false;
}
else
{
starAssert(rows.size() == 1);
auto row = rows[0];
result = row.get("active").toBool();
}
conn.exec("INSERT INTO validations (username, timestamp, result) VALUES ($1, $2, $3)", { username, Thread::currentTime(), result });
success = true;
return result;
}
}
bool AuthenticationDatabase::validateUserAndPassword(String const& username, String const& password) {
DatabaseConnector conn(m_connectionString);
{
conn.exec("BEGIN");
bool success = false;
auto transactionScope = finally([&]() {
if (success)
conn.exec("END");
else
conn.exec("ROLLBACK");
});
auto rows = conn.fetch("SELECT id_user, active, salt, rounds, hash FROM users WHERE username=$1", { username });
bool result;
if (rows.size() == 0) {
result = false;
}
else {
starAssert(rows.size() == 1);
auto row = rows[0];
result = row.get("active").toBool();
if (result)
result = bcryptValidate(password, row.get("salt").toString(), row.get("hash").toString(), row.get("rounds").toInt());
}
conn.exec("INSERT INTO validations (username, timestamp, result) VALUES ($1, $2, $3)", { username, Thread::currentTime(), result });
success = true;
return result;
}
}
bool AuthenticationDatabase::setUserRecord(String const& username, String const& passwordPreHashed, bool active) {
DatabaseConnector conn(m_connectionString);
{
conn.exec("BEGIN");
bool success = false;
auto transactionScope = finally([&]() {
if (success)
conn.exec("END");
else
conn.exec("ROLLBACK");
});
String salt = generateKey();
int rounds = 0;
String hash = bcrypt(passwordPreHashed, salt, rounds);
auto rows = conn.fetch("SELECT id_user FROM users WHERE username=$1", { username });
if (rows.size() == 1) {
conn.exec("UPDATE users SET salt=$2, rounds=$3, hash=$4, active=$5 WHERE id_user=$1", { rows[0].get("id_user"), salt, rounds, hash, active });
}
else {
long since = Thread::currentTime();
conn.exec("INSERT INTO users (username, salt, rounds, hash, since, active) VALUES ($1, $2, $3, $4, $5, $6)", { username, salt, rounds, hash, since, active });
}
success = true;
return true;
}
}
bool AuthenticationDatabase::activateUserRecord(String const& username, bool active) {
DatabaseConnector conn(m_connectionString);
{
conn.exec("BEGIN");
bool success = false;
bool result;
auto transactionScope = finally([&]() {
if (success)
conn.exec("END");
else
conn.exec("ROLLBACK");
});
auto rows = conn.fetch("SELECT id_user FROM users WHERE username=$1", { username });
if (rows.size() == 1) {
conn.exec("UPDATE users SET active=$2 WHERE id_user=$1", { rows[0].get("id_user"), active });
result = true;
}
else
result = false;
success = true;
return result;
}
}
int AuthenticationDatabase::usersCount() {
DatabaseConnector conn(m_connectionString);
{
conn.exec("BEGIN");
int result = 0;
bool success = false;
auto transactionScope = finally([&]() {
if (success)
conn.exec("END");
else
conn.exec("ROLLBACK");
});
auto rows = conn.fetch("SELECT count(*) as amount FROM users", {});
if (rows.size() == 1) {
success = true;
result = rows[0].get("amount").toInt();
}
return result;
}
}
}
}

View file

@ -0,0 +1,34 @@
#ifndef _STAR_AUTHENTICATOR_DATABASE_HPP_
#define _STAR_AUTHENTICATOR_DATABASE_HPP_
#include "StarAuthenticationKey.hpp"
#include "StarAuthenticationService.hpp"
#include "StarException.hpp"
#include "StarVariant.hpp"
#include "StarRoot.hpp"
#include "StarTcp.hpp"
#include "StarThread.hpp"
namespace Star {
namespace Auth {
class AuthenticationDatabase: public Database {
public:
AuthenticationDatabase(String const& connectionString);
~AuthenticationDatabase();
virtual bool validateUser(String const& username) override;
virtual bool validateUserAndPassword(String const& username, String const& passwordPreHashed) override;
virtual bool setUserRecord(String const& username, String const& passwordPreHashed, bool active) override;
virtual bool activateUserRecord(String const& username, bool active) override;
virtual int usersCount() override;
private:
String m_connectionString;
};
}
}
#endif

View file

@ -0,0 +1,325 @@
#include "StarAuthenticationServer.hpp"
#include "StarLogging.hpp"
#include "StarAuthenticationDatabase.hpp"
namespace Star {
namespace Auth {
AuthenticationConnectionHandler::AuthenticationConnectionHandler(TcpSocketPtr socket, AuthenticationServer* server)
: Thread("AuthenticationConnectionHandler") {
Logger::info("Connection thread constructor.");
m_socket = socket;
m_server = server;
m_stop = false;
m_closed = false;
}
AuthenticationConnectionHandler::~AuthenticationConnectionHandler() {
Logger::info("Connection thread destructor.");
}
void AuthenticationConnectionHandler::stop() {
m_stop = true;
try {
m_socket->close();
} catch (StarException const&) {
// bartwe: I'm a jerk, close is not supposed to be called during calls to the socket on other threads, not really seeing a good way to interrupt that i care about enough to implement atm.
}
}
bool AuthenticationConnectionHandler::isClosed() {
return m_closed;
}
void AuthenticationConnectionHandler::writeResponse(String const& response) {
String body = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/html; charset=UTF-8\r\nCache-Control: no-cache, no-store\r\n\r\n" + response + "\r\n\r\n";
m_socket->write(body.utf8Ptr(), body.utf8Size());
Logger::info("Connection thread write response.");
}
void AuthenticationConnectionHandler::writeErrorResponse(String const& response) {
String body = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/html; charset=UTF-8\r\nCache-Control: no-cache, no-store\r\n\r\n" + response + "\r\n\r\n";
m_socket->write(body.utf8Ptr(), body.utf8Size());
Logger::info("Connection thread write error.");
}
void AuthenticationConnectionHandler::run() {
Logger::info("Connection thread.run");
try {
m_socket->setNoDelay(true);
m_socket->setSocketTimeout(ClientSocketTimeout);
int64_t deadline = Thread::currentTime() + ClientSocketTimeout;
bool headerMode = true;
Buffer buffer(BufferCapacity);
int newlineCounter = 0;
while (!m_stop && m_socket->isOpen()) {
if (Thread::currentTime() >= deadline) {
// client too slow, or a slow lorris attack
writeErrorResponse("Client too slow.");
break;
}
char c;
if (m_socket->read(&c, 1) != 1)
throw StarException("Unexpected result from socket read\n");
if (c == '\r')
continue; // hello dos
buffer.write(&c, 1);
if (buffer.pos() >= BufferCapacity) {
// request too long
writeErrorResponse("Request too long.");
break;
}
if (c == '\n')
newlineCounter++;
else
newlineCounter = 0;
if (newlineCounter == 2) {
if (headerMode) {
String header = String(buffer.ptr(), buffer.pos());
if (!header.beginsWith("POST /auth.sb HTTP/1.1\n")) {
writeErrorResponse("Page not found.");
break;
}
headerMode = false;
buffer.clear();
newlineCounter = 0;
} else {
String body = String(buffer.ptr(), buffer.pos() - 2); // remove trailing newlines, guaranteed to be there
auto message = make_shared<MessageToken>(body);
Logger::info("Connection thread.message received.");
m_server->addMessage(message);
if (!message->waitForResponse(ClientProcessingTimeout))
writeErrorResponse("Timed out.");
writeResponse(message->response());
break;
}
}
}
m_socket->flush();
}
catch (NetworkException const&) {
goto finally;
}
catch (StarException const& e) {
Logger::error("AuthenticationConnectionHandler: Exception caught: %s", e.what());
}
catch (std::exception const& e) {
Logger::error("AuthenticationConnectionHandler: Exception caught: %s", e.what());
goto finally;
}
catch (...) {
goto finally;
}
finally: {
m_closed = true;
if (m_socket->isOpen())
m_socket->close();
}
m_server->addMessage( { });
Logger::info("Connection thread.run.end");
}
AuthenticationServer::AuthenticationServer() {
m_stop = false;
String connectionString = Variant::parseJson(File::readFileString("connectionstring.config")).getString("connectionString");
DatabasePtr db = as<Database>(make_shared<AuthenticationDatabase>(connectionString));
m_service = make_shared<AuthenticationService>(db);
m_requestCount = 0;
m_getAuthKeyCounter = 0;
m_authorizeClientCounter = 0;
m_authorizeClientFailure = 0;
m_validateClientCounter = 0;
m_validateClientFailure = 0;
m_munin = make_shared<MuninNode>(Variant::parseJson(File::readFileString("authmunin.config")));
m_munin->setCallback([=]() {
MutexLocker locker(m_mainLock);
m_munin->set("sbauth", "users", db->usersCount());
m_munin->set("sbauth", "requests", m_requestCount);
m_munin->set("sbauth", "getAuthKey", m_getAuthKeyCounter);
m_munin->set("sbauth", "authorizeClient", m_authorizeClientCounter);
m_munin->set("sbauth", "authorizeClientFailure", m_authorizeClientFailure);
m_munin->set("sbauth", "validateClient", m_validateClientCounter);
m_munin->set("sbauth", "validateClientFailure", m_validateClientFailure);
});
}
AuthenticationServer::~AuthenticationServer() {}
void AuthenticationServer::acceptConnection(TcpSocketPtr socket) {
MutexLocker locker(m_mainLock);
if (m_stop) {
socket->close();
} else {
auto handler = make_shared<AuthenticationConnectionHandler>(socket, this);
m_handlers.add(handler);
handler->start();
}
}
void AuthenticationServer::run() {
TcpServer tcpServer(ListenPort);
tcpServer.setAcceptCallback(std::bind(&AuthenticationServer::acceptConnection, this, std::placeholders::_1));
Logger::info("Auth server started.");
List<AuthenticationConnectionHandlerPtr> cleanup;
while (true) {
try {
MessageTokenPtr message;
{
MutexLocker locker(m_mainLock);
if (m_stop)
break;
for (auto& handler : m_handlers) {
if (handler->isClosed())
cleanup.append(handler);
}
m_handlers.removeAll(cleanup);
if (m_messages.empty() && cleanup.empty())
m_signal.wait(m_mainLock);
if (!m_messages.empty())
message = m_messages.takeFirst();
}
cleanup.clear();
if (message) {
try {
handleMessage(message);
if (!message->hasResponse())
message->setResponse("");
}
catch (std::exception const&) {
if (!message->hasResponse())
message->setResponse("");
throw;
}
}
}
catch (std::exception const& e) {
Logger::error("AuthenticationServer exception caught: %s", e.what());
}
}
Logger::info("Finishing remaining connections.");
try {
MutexLocker locker(m_mainLock);
m_stop = true;
tcpServer.close();
} catch (std::exception const& e) {
Logger::error("AuthenticationServer exception caught cleaning up: %s", e.what());
}
{
MutexLocker locker(m_mainLock);
for (auto & message : m_messages)
message->setResponse("stopping");
m_messages.clear();
}
// locking should no longer be needed at this point
// unused to avoid deadlock scenario where the handler calls addMessage
for (auto& handler : m_handlers)
handler->stop();
m_handlers.clear();
}
void AuthenticationServer::stop() {
Logger::info("Auth server stopping.");
MutexLocker locker(m_mainLock);
m_stop = true;
m_signal.signal();
}
void AuthenticationServer::addMessage(MessageTokenPtr const& message) {
MutexLocker locker(m_mainLock);
m_requestCount++;
if (m_stop) {
if (message)
message->setResponse("stopped");
} else {
m_messages.append(message);
m_signal.signal();
}
}
void AuthenticationServer::handleMessage(MessageTokenPtr const& message) {
Variant command = Variant::parse(message->request());
if (command.getString("command") == "getAuthKey") {
m_getAuthKeyCounter++;
auto response = m_service->getCertificate();
message->setResponse(response.repr(0, true));
} else if (command.getString("command") == "authorizeClient") {
m_authorizeClientCounter++;
try {
auto response = m_service->authorizeClient(command.getMap("body"));
message->setResponse(response.repr(0, true));
}
catch (...) {
m_authorizeClientFailure++;
throw;
}
} else if (command.getString("command") == "validateClient") {
m_validateClientCounter++;
try {
auto response = m_service->validateClient(command.getMap("body"));
message->setResponse(response.repr(0, true));
}
catch (...) {
m_validateClientFailure++;
throw;
}
}
}
MessageToken::MessageToken(String const& request) {
m_request = request;
m_hasResponse = false;
}
bool MessageToken::hasResponse() {
MutexLocker locker(m_lock);
return m_hasResponse;
}
bool MessageToken::waitForResponse(unsigned millis) {
MutexLocker locker(m_lock);
int64_t timeout = millis;
while (true) {
if (m_hasResponse)
return true;
if (timeout <= 0)
return false;
int64_t startTime = Thread::currentTime();
m_signal.wait(m_lock, (unsigned)timeout);
timeout -= Thread::currentTime() - startTime;
}
}
void MessageToken::setResponse(String const& response) {
{
MutexLocker locker(m_lock);
starAssert(!m_hasResponse);
m_response = response;
m_hasResponse = true;
}
m_signal.signal();
}
String MessageToken::response() {
MutexLocker locker(m_lock);
starAssert(m_hasResponse);
return m_response;
}
String MessageToken::request() {
return m_request;
}
}
}

View file

@ -0,0 +1,111 @@
#ifndef _STAR_AUTHENTICATOR_SERVER_HPP_
#define _STAR_AUTHENTICATOR_SERVER_HPP_
#include "StarAuthenticationKey.hpp"
#include "StarAuthenticationService.hpp"
#include "StarException.hpp"
#include "StarVariant.hpp"
#include "StarRoot.hpp"
#include "StarTcp.hpp"
#include "StarThread.hpp"
#include "StarMunin.hpp"
namespace Star {
namespace Auth {
//todo, port 80, hide behind a normal httpd, etc.
static int const ListenPort = 21027;
static unsigned const ClientSocketTimeout = 10000; // 10 seconds
static unsigned const ClientProcessingTimeout = 30000; // 30 seconds
static int const BufferCapacity = 15*1024;
class AuthenticationServer;
typedef shared_ptr<AuthenticationServer> AuthenticationServerPtr;
//todo: bad on purpose, replace with a httpd frontend and deliver zmq messages
// interops with the main thread using MessageToken, suitable to attach to zmq style, think mongrel httpd
class AuthenticationConnectionHandler: public Thread {
public:
AuthenticationConnectionHandler(TcpSocketPtr socket, AuthenticationServer* server);
~AuthenticationConnectionHandler();
// requests a stop, doesn't actually stop the, for that you'll need to finalize or join()
// which may take a long while due to socket operations not being interrupted.
void stop();
bool isClosed();
virtual void run();
private:
TcpSocketPtr m_socket;
AuthenticationServer* m_server;
bool m_stop;
bool m_closed;
Mutex m_lock;
void writeResponse(String const& response);
void writeErrorResponse(String const& response);
};
typedef shared_ptr<AuthenticationConnectionHandler> AuthenticationConnectionHandlerPtr;
class MessageToken {
public:
MessageToken(String const& request);
bool hasResponse();
bool waitForResponse(unsigned millis);
void setResponse(String const& response);
String request();
String response();
private:
Mutex m_lock;
ConditionVariable m_signal;
bool m_hasResponse;
String m_request;
String m_response;
};
typedef shared_ptr<MessageToken> MessageTokenPtr;
class AuthenticationServer {
public:
AuthenticationServer();
~AuthenticationServer();
void run();
void stop();
void addMessage(MessageTokenPtr const& message);
private:
shared_ptr<AuthenticationService> m_service;
Set<AuthenticationConnectionHandlerPtr> m_handlers;
List<MessageTokenPtr> m_messages;
ConditionVariable m_signal;
Mutex m_mainLock;
bool m_stop;
MuninNodePtr m_munin;
int m_requestCount;
int m_getAuthKeyCounter;
int m_authorizeClientCounter;
int m_authorizeClientFailure;
int m_validateClientCounter;
int m_validateClientFailure;
void acceptConnection(TcpSocketPtr socket);
void handleMessage(MessageTokenPtr const& message);
};
}
}
#endif

View file

@ -0,0 +1,83 @@
#include "StarDatabaseConnector.hpp"
#include "StarLogging.hpp"
//todo, ifdef for database type or something ?
#include <iostream>
#include "libpq-fe.h"
using namespace std;
namespace Star {
class DatabaseConnectionImpl {
public:
PGconn* conn;
};
DatabaseConnector::DatabaseConnector(String const& connectionString) {
m_impl = new DatabaseConnectionImpl;
m_impl->conn = PQconnectdb(connectionString.utf8Ptr());
if (PQstatus(m_impl->conn) != CONNECTION_OK) {
throw StarException(strf("Fail to connect to the database. %s", PQerrorMessage(m_impl->conn)));
}
}
DatabaseConnector::~DatabaseConnector() {
PQfinish(m_impl->conn);
delete m_impl;
}
List<VariantMap> DatabaseConnector::fetch(String const& command, VariantList const& arguments) {
int nParams = arguments.size();
List<String> paramValuesBacking(nParams);
DynamicArray<const char*> paramValues(nParams, (const char*)nullptr);
for (int i = 0; i < nParams; i++) {
if (arguments[i].type() == Variant::Type::BOOL)
paramValuesBacking[i] = arguments[i].toBool()?"t":"f";
else
paramValuesBacking[i] = arguments[i].toString();
paramValues[i] = paramValuesBacking[i].utf8Ptr();
}
auto res = PQexecParams(m_impl->conn, command.utf8Ptr(), nParams, NULL, paramValues.ptr(), NULL, NULL, 0);
if (PQresultStatus(res) == PGRES_COMMAND_OK) {
PQclear(res);
return {};
}
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
auto message = strf("Command failed. Error: (%d) %s", PQresultStatus(res), PQresultErrorMessage(res));
PQclear(res);
throw StarException(message);
}
List<String> columns;
int nFields = PQnfields(res);
for (int i = 0; i < nFields; i++)
columns.append(PQfname(res, i));
List<VariantMap> result;
for (int i = 0; i < PQntuples(res); i++)
{
result.append({});
VariantMap& row = result.last();
for (int j = 0; j < nFields; j++)
row.insert(columns[j], PQgetvalue(res, i, j));
}
PQclear(res);
return result;
}
VariantMap DatabaseConnector::fetchRow(String const& command, VariantList const& arguments) {
auto result = fetch(command, arguments);
if (result.size() != 1)
throw StarException(strf("Command failed. Expected single row. Got %s", result.size()));
return result[0];
}
void DatabaseConnector::exec(String const& command, VariantList const& arguments) {
auto result = fetch(command, arguments);
if (result.size() != 0)
throw StarException(strf("Command failed. Expected no result row. Got %s", result.size()));
}
}

View file

@ -0,0 +1,31 @@
#ifndef _STAR_DATABASE_CONNECTOR_HPP_
#define _STAR_DATABASE_CONNECTOR_HPP_
#include "StarAuthenticationKey.hpp"
#include "StarAuthenticationService.hpp"
#include "StarException.hpp"
#include "StarVariant.hpp"
#include "StarRoot.hpp"
#include "StarTcp.hpp"
#include "StarThread.hpp"
namespace Star {
class DatabaseConnectionImpl;
class DatabaseConnector
{
public:
DatabaseConnector(String const& connectionString);
~DatabaseConnector();
List<VariantMap> fetch(String const& command, VariantList const& arguments = VariantList());
VariantMap fetchRow(String const& command, VariantList const& arguments = VariantList());
void exec(String const& command, VariantList const& arguments = VariantList());
private:
DatabaseConnectionImpl* m_impl;
};
}
#endif

View file

@ -0,0 +1,80 @@
#include "StarString.hpp"
#include "StarThread.hpp"
#include "StarRandom.hpp"
#include "StarAuthenticationKey.hpp"
#include "StarAuthenticationService.hpp"
#include "StarAuthenticationDatabase.hpp"
#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
using namespace std;
using namespace Star;
int usage(int rc) {
std::cout
<< "USAGE: " << std::endl
<< " keygen rootkey <rootPrivateFile> <rootPublicFile>" << std::endl
<< " keygen authkey <rootPrivateFile> <authPrivateFile>" << std::endl
<< " keygen hashpass <username> <password>" << std::endl
<< " keygen insertuser <username> <passhash>" << std::endl
<< " keygen enableuser <username>" << std::endl
<< " keygen disableuser <username>" << std::endl;
return rc;
}
int main(int argc, char ** argv) {
try {
Random::randu32();
StringList args;
for (int i = 1; i < argc; i++)
args.append(argv[i]);
String connectionString = Variant::parseJson(File::readFileString("connectionstring.config")).getString("connectionString");
if (argc == 4 && !String("rootkey").compare(args[0])) {
Star::Auth::Key rootKey(true);
std::ofstream oFile;
oFile.open(args[1].utf8());
oFile << rootKey.privateKey();
oFile.close();
oFile.open(args[2].utf8());
oFile << rootKey.publicKey();
oFile.close();
return 0;
} else if (argc == 4 && !String("authkey").compare(args[0])) {
std::ifstream iFile(args[1].utf8());
String rootPrivateKey;
iFile >> rootPrivateKey;
iFile.close();
std::ofstream oFile(args[2].utf8());
oFile << Star::Auth::AuthenticationService::generateAuthenticationConfig(rootPrivateKey, Thread::currentTime() - 1LL * 25LL * 60LL * 60LL * 1000LL, Thread::currentTime() + 38LL * 24LL * 60LL * 60LL * 1000LL).repr(0, true);
oFile.close();
return 0;
} else if (argc == 4 && !String("hashpass").compare(args[0])) {
cout << Auth::preHashPassword(args[1], args[2]);
} else if (argc == 4 && !String("insertuser").compare(args[0])) {
Auth::AuthenticationDatabase database(connectionString);
database.setUserRecord(args[1], args[2], true);
cout << "Enabled user: " << args[1] << "\n";
} else if (argc == 3 && !String("disableuser").compare(args[0])) {
Auth::AuthenticationDatabase database(connectionString);
if (database.activateUserRecord(args[1], false))
cout << "Disabled user: " << args[1] << "\n";
else
cout << "No such user\n";
} else if (argc == 3 && !String("enableuser").compare(args[0])) {
Auth::AuthenticationDatabase database(connectionString);
if (database.activateUserRecord(args[1], true))
cout << "Enabled user: " << args[1] << "\n";
else
cout << "No such user\n";
} else {
return usage(-1);
}
} catch (std::exception const& e) {
cerr << e.what() << "\n";
return -1;
}
}

40
attic/authserver/main.cpp Normal file
View file

@ -0,0 +1,40 @@
#include "StarAuthenticationServer.hpp"
#include "StarRandom.hpp"
#include "StarLexicalCast.hpp"
#include "StarLogging.hpp"
#include "StarSignalHandler.hpp"
using namespace Star;
using namespace Star::Auth;
int main(int argc, char **argv) {
_unused(argc);
_unused(argv);
SignalHandler signalHandler;
try {
Logger::addSink(make_shared<FileLogSink>("starbound_auth.log", Logger::Debug));
Thread::prepareThread();
Auth::initializeKeyLogic();
StarException::initialize();
Logger::info("Auth server starting.");
auto authServer = make_shared<AuthenticationServer>();
signalHandler.setInterruptHandler([&authServer]() {
Logger::info("Interrupt received.");
if (authServer)
authServer->stop();
});
authServer->run();
authServer.reset();
Logger::info("Server shutdown gracefully");
} catch (std::exception const& e) {
fatalException(e);
}
return 0;
}

View file

@ -0,0 +1,60 @@
{
"name" : "heck",
"friendlyName" : "Heck",
"mainBlock" : "hellstone",
"subBlocks" : [ "brains", "rock04" ],
"ores" : "depth2",
"hueShiftOptions" : [0],
"parallax" : "/parallax/underground/dirtunderground.parallax",
"sky" : {
"topColor" : [182, 204, 255],
"bottomColor" : [224, 239, 255],
"nightTopColor" : [0, 0, 30],
"nightBottomColor" : [0, 0, 0]
},
"undergroundPlaceables" : {
"grassMod" : [ "heckgrass" ],
"grassModDensity" : 0.1,
"items" : [
{
"mode" : "floor",
"priority" : 4.0,
"variants" : 1,
"distribution" : "/biomes/distributions.config:denseLarge",
"type" : "grass",
"grasses" : [ "heckflower" ]
},
{
"mode" : "floor",
"priority" : 0.1,
"variants" : 11,
"distribution" : "/biomes/distributions.config:denseSmall",
"type" : "object",
"objectSets" : [
{
"pool" : [ [0.35, "heckbush1" ], [0.35, "heckbush2" ], [0.35, "heckbush3" ], [0.35, "heckbush4" ], [0.35, "heckbush5" ], [0.35, "heckbush6" ], [0.35, "heckbush7" ], [0.35, "heckbush8" ], [0.35, "heckbush9" ], [0.35, "heckbush10" ], [0.35, "hecklight1" ], [0.35, "hecklight2" ], [0.35, "heckaltar" ], [0.35, "woodentalllantern" ], [0.1, "huntingpike1" ], [0.1, "huntingpike2" ], [0.1, "huntingpike3" ], [0.35, "heckpillar1" ], [0.35, "heckpillar2" ], [0.05, "hecksign" ] ],
"parameters" : { }
}
]
},
{
"mode" : "ceiling",
"priority" : 2.0,
"variants" : 1,
"distribution" : "/biomes/distributions.config:denseMedium",
"type" : "tree",
"treeFoliageHueShiftMax" : 180,
"treeStemHueShiftMax" : 180,
"treeStemList" : [ "podvine" ]
}
]
}
}

View file

@ -0,0 +1,114 @@
{
"stateTypes" : {
"movement" : {
"idle" : {
"frames" : 1
},
"walk" : {
"frames" : 8,
"cycle" : 1.0,
"mode" : "loop"
}
},
"attack" : {
"idle" : {
"frames" : 1
},
"melee" : {
"frames" : 4,
"cycle" : 1.4,
"mode" : "transition",
"transition" : "idle"
},
"shooting" : {
"frames" : 1
}
}
},
"partTypes" : {
"backArm" : {
"position" : [0, 0],
"states" : {
"attack" : {
"melee" : "<base>:melee.<frame>"
},
"movement" : {
"idle" : "<base>:idle",
"walk" : "<base>:walk.<frame>"
}
}
},
"legs" : {
"position" : [0, 0],
"states" : {
"movement" : {
"idle" : "<base>:idle",
"walk" : "<base>:walk.<frame>"
}
}
},
"chest" : {
"position" : [0, 0],
"states" : {
"movement" : {
"idle" : "<base>:idle",
"walk" : "<base>:walk.<frame>"
}
}
},
"head" : {
"position" : [0, 0],
"states" : {
"movement" : {
"idle" : "<base>:idle",
"walk" : "<base>:walk.<frame>"
}
}
},
"frontArm" : {
"position" : [0, 0],
"states" : {
"attack" : {
"melee" : "<base>:melee.<frame>"
},
"movement" : {
"idle" : "<base>:idle",
"walk" : "<base>:walk.<frame>"
}
}
}
},
"rotationGroups" : {
"projectileAim" : {
"parts" : ["frontArm", "backArm"],
"angularVelocity" : 1.5
}
},
"particleEmitters" : {
"damage" : {
"emissionRate" : 2.0,
"particle" : {
"type" : "textured",
"image" : "/particles/hazard/hazardstat.png",
"size" : "1.0",
"color" : [73, 179, 253, 255],
"fade" : 0,
"destructionAction" : "shrink",
"destructionTime" : 7,
"initialVelocity" : [3, 4],
"finalVelocity" : [-3, 2],
"approach" : [4, 1],
"timeToLive" : 1,
"aboveForeground" : false
}
}
}
}

View file

@ -0,0 +1,38 @@
{
"type" : "bipedal",
"animation" : "animation.config",
"colors" : "colors.config",
"categories" : [ "biped_organic", "biped_robotic" ],
"parts" : [ "arms", "legs", "chest", "head" ],
"reversed" : false,
"maxHealth" : 50.0,
"maxEnergy" : 100.0,
"meleeDamage" : 50,
"maxPlayerRadius" : 40.0,
"metaBoundBox" : [-1.0, -2.5, 1.0, 1.75],
"hitbox" : [ [-0.75, -2.0], [-0.35, -2.5], [0.35, -2.5], [0.75, -2.0], [0.75, 0.65], [0.35, 1.22], [-0.35, 1.22], [-0.75, 0.65] ],
"movementControllerSettings" : {
"collisionPoly" : [ [-0.75, -2.0], [-0.35, -2.5], [0.35, -2.5], [0.75, -2.0], [0.75, 0.65], [0.35, 1.22], [-0.35, 1.22], [-0.75, 0.65] ],
"walkSpeed" : 7.0,
"runSpeed" : 11.0
},
"blockSensorPositions" : [ [1.0, -2.0], [2.0, -2.0] ],
"minimumAttackDistance" : 4.0,
"playerQueryTime" : 5.0,
"knockbackTime" : 0.1,
"jumpTime" : 2.0,
"jumpTimeVariance" : 2.0,
"exhaustedTime" : 6.0,
"exhaustedMinDistance" : 5.0,
"exhaustedWanderTime" : 6.0
}

253
attic/biped/colors.config Normal file
View file

@ -0,0 +1,253 @@
{
"swaps" : [
{
"6f2919" : "12384e", "a85636" : "176795", "e0975c" : "1e88c6", "ffca8a" : "54baf5",
"735e3a" : "93918a", "a38d59" : "bfb697", "d9c189" : "dcce9c", "f7e7b2" : "f1e4b8",
"951500" : "958400", "be1b00" : "bea800", "dc1f00" : "dcc300", "f32200" : "f3d700"
},
{
"6f2919" : "2b3916", "a85636" : "547225", "e0975c" : "80b32f", "ffca8a" : "b6eb5a",
"735e3a" : "2d506b", "a38d59" : "4787b3", "d9c189" : "63aee4", "f7e7b2" : "91dcff",
"951500" : "249500", "be1b00" : "2ebe00", "dc1f00" : "35dc00", "f32200" : "3bf300"
},
{
"6f2919" : "574b38", "a85636" : "81725b", "e0975c" : "bdae97", "ffca8a" : "dfd3c1",
"735e3a" : "574b38", "a38d59" : "d8b98a", "d9c189" : "efd5ab", "f7e7b2" : "f9e6cc",
"951500" : "69c4d8", "be1b00" : "74d7ee", "dc1f00" : "9beaff", "f32200" : "c6f6ff"
},
{
"6f2919" : "7e3b3b", "a85636" : "a24b4b", "e0975c" : "ca7272", "ffca8a" : "e69292",
"735e3a" : "353331", "a38d59" : "4b3c36", "d9c189" : "594037", "f7e7b2" : "634c45",
"951500" : "51a08b", "be1b00" : "3bba98", "dc1f00" : "42d2ab", "f32200" : "90e5cd"
},
{
"6f2919" : "1d6f19", "a85636" : "36a83c", "e0975c" : "5ce078", "ffca8a" : "8affaf",
"735e3a" : "735e3a", "a38d59" : "a38d59", "d9c189" : "d9c189", "f7e7b2" : "f7e7b2",
"951500" : "951500", "be1b00" : "be1b00", "dc1f00" : "dc1f00", "f32200" : "f32200"
},
{
"6f2919" : "40196f", "a85636" : "7436a8", "e0975c" : "ba5ce0", "ffca8a" : "e98aff",
"735e3a" : "3a7343", "a38d59" : "59a36a", "d9c189" : "89d99c", "f7e7b2" : "b2f7c7",
"951500" : "951500", "be1b00" : "be1b00", "dc1f00" : "dc1f00", "f32200" : "f32200"
},
{
"6f2919" : "19566f", "a85636" : "367ca8", "e0975c" : "5c97e0", "ffca8a" : "8ab3ff",
"735e3a" : "73673a", "a38d59" : "a39959", "d9c189" : "d9cf89", "f7e7b2" : "f7f3b2",
"951500" : "95004c", "be1b00" : "be0060", "dc1f00" : "dc0070", "f32200" : "f3007b"
},
{
"6f2919" : "6f4719", "a85636" : "a87e36", "e0975c" : "e0c65c", "ffca8a" : "fff38a",
"735e3a" : "736e3a", "a38d59" : "a3a359", "d9c189" : "d8d989", "f7e7b2" : "f2f7b2",
"951500" : "260095", "be1b00" : "3200be", "dc1f00" : "3900dc", "f32200" : "4000f3"
},
{
"6f2919" : "6f1936", "a85636" : "a83651", "e0975c" : "e05c64", "ffca8a" : "ff8e8a",
"735e3a" : "3a3e73", "a38d59" : "5b59a3", "d9c189" : "8b89d9", "f7e7b2" : "b8b2f7",
"951500" : "949500", "be1b00" : "bbbe00", "dc1f00" : "d9dc00", "f32200" : "eff300"
},
{
"6f2919" : "25303b", "a85636" : "3f4a5d", "e0975c" : "5e6580", "ffca8a" : "7b7e99",
"595b51" : "595b51", "a38d59" : "808477", "d9c189" : "b4b8aa", "f7e7b2" : "d6dace",
"951500" : "e9e9e9", "be1b00" : "ebebeb", "dc1f00" : "ededed", "f32200" : "efefef"
},
{
"6f2919" : "171717", "a85636" : "515151", "e0975c" : "767676", "ffca8a" : "9f9f9f",
"735e3a" : "503224", "a38d59" : "965751", "d9c189" : "df7e8b", "f7e7b2" : "efa4ca",
"951500" : "953800", "be1b00" : "be5000", "dc1f00" : "dc6200", "f32200" : "f36700"
},
{
"6f2919" : "0a0a0a", "a85636" : "434343", "e0975c" : "666666", "ffca8a" : "898989",
"735e3a" : "4b4b4b", "a38d59" : "828282", "d9c189" : "b6b6b6", "f7e7b2" : "d9d9d9",
"951500" : "951500", "be1b00" : "be1b00", "dc1f00" : "dc1f00", "f32200" : "f32200"
},
{
"6f2919" : "171717", "a85636" : "515151", "e0975c" : "767676", "ffca8a" : "9f9f9f",
"735e3a" : "6c5d22", "a38d59" : "b0a747", "d9c189" : "e2e189", "f7e7b2" : "f0f0c2",
"951500" : "953800", "be1b00" : "be5000", "dc1f00" : "dc6200", "f32200" : "f36700"
},
{
"6f2919" : "4b4b4b", "a85636" : "828282", "e0975c" : "b6b6b6", "ffca8a" : "d9d9d9",
"735e3a" : "66452e", "a38d59" : "a47c56", "d9c189" : "d9aa7b", "f7e7b2" : "f7ddb0",
"951500" : "95004a", "be1b00" : "be005e", "dc1f00" : "dc0068", "f32200" : "f30072"
},
{
"6f2919" : "4b4b4b", "a85636" : "828282", "e0975c" : "b6b6b6", "ffca8a" : "d9d9d9",
"735e3a" : "6c5d22", "a38d59" : "b0a747", "d9c189" : "e2e189", "f7e7b2" : "f0f0c2",
"951500" : "954d00", "be1b00" : "be6b00", "dc1f00" : "dc9600", "f32200" : "f3b700"
},
{
"6f2919" : "5c5c5c", "a85636" : "a5a5a5", "e0975c" : "e6e6e6", "ffca8a" : "f8f8f8",
"735e3a" : "41546c", "a38d59" : "6995b7", "d9c189" : "96cbe6", "f7e7b2" : "96cbe6",
"951500" : "008595", "be1b00" : "00b8be", "dc1f00" : "00dcda", "f32200" : "00f3df"
},
{
"6f2919" : "652651", "a85636" : "9d418f", "e0975c" : "cd5fd2", "ffca8a" : "d790e9",
"735e3a" : "66452e", "a38d59" : "a47c56", "d9c189" : "d9aa7b", "f7e7b2" : "f7ddb0",
"951500" : "951500", "be1b00" : "be1b00", "dc1f00" : "dc1f00", "f32200" : "f32200"
},
{
"6f2919" : "39164a", "a85636" : "6d327e", "e0975c" : "b14ab2", "ffca8a" : "e673cd",
"735e3a" : "485548", "a38d59" : "728473", "d9c189" : "acc8ac", "f7e7b2" : "d8e5d6",
"951500" : "008595", "be1b00" : "00b8be", "dc1f00" : "00dcda", "f32200" : "00f3df"
},
{
"6f2919" : "742977", "a85636" : "bb4fba", "e0975c" : "e884e7", "ffca8a" : "ffc3fb",
"735e3a" : "455d1e", "a38d59" : "839731", "d9c189" : "d0dc61", "f7e7b2" : "f5f898",
"951500" : "95004a", "be1b00" : "be005e", "dc1f00" : "dc0068", "f32200" : "f30072"
},
{
"6f2919" : "503224", "a85636" : "965751", "e0975c" : "df7e8b", "ffca8a" : "efa4ca",
"735e3a" : "6e5c17", "a38d59" : "b2a025", "d9c189" : "e8e63a", "f7e7b2" : "fefebb",
"951500" : "5b0095", "be1b00" : "7900be", "dc1f00" : "9b00dc", "f32200" : "bd00f3"
},
{
"6f2919" : "623221", "a85636" : "9f4d29", "e0975c" : "d47744", "ffca8a" : "faba86",
"735e3a" : "5f5b4b", "a38d59" : "939070", "d9c189" : "c2c2a0", "f7e7b2" : "e5e5d4",
"951500" : "171717", "be1b00" : "515151", "dc1f00" : "767676", "f32200" : "9f9f9f"
},
{
"6f2919" : "68320d", "a85636" : "a56220", "e0975c" : "e48c37", "ffca8a" : "fad086",
"735e3a" : "5b553d", "a38d59" : "b2a025", "d9c189" : "e8e63a", "f7e7b2" : "fefebb",
"951500" : "95004a", "be1b00" : "be005e", "dc1f00" : "dc0068", "f32200" : "f30072"
},
{
"6f2919" : "624254", "a85636" : "91528e", "e0975c" : "bb71bf", "ffca8a" : "daaadf",
"735e3a" : "184817", "a38d59" : "389042", "d9c189" : "71d071", "f7e7b2" : "b7faae",
"951500" : "00954d", "be1b00" : "00be67", "dc1f00" : "00dc7c", "f32200" : "00f39a"
},
{
"6f2919" : "5c463c", "a85636" : "956f6b", "e0975c" : "dfaeb4", "ffca8a" : "eacfdd",
"735e3a" : "5b371a", "a38d59" : "8b6a31", "d9c189" : "71d071", "b7a258" : "d4d17b",
"951500" : "000495", "be1b00" : "000dbe", "dc1f00" : "0043dc", "f32200" : "0072f3"
},
{
"6f2919" : "6f2919", "a85636" : "a85636", "e0975c" : "e0975c", "ffca8a" : "ffca8a",
"735e3a" : "735e3a", "a38d59" : "a38d59", "d9c189" : "d9c189", "b7a258" : "f7e7b2",
"951500" : "951500", "be1b00" : "be1b00", "dc1f00" : "dc1f00", "f32200" : "f32200"
},
{
"6f2919" : "682d10", "a85636" : "9d5f27", "e0975c" : "dd9d58", "ffca8a" : "f7cd8f",
"735e3a" : "485548", "a38d59" : "728473", "d9c189" : "acc8ac", "b7a258" : "d8e5d6",
"951500" : "192747", "be1b00" : "325184", "dc1f00" : "4682b0", "f32200" : "5eb7db"
},
{
"6f2919" : "6a0715", "a85636" : "a32424", "e0975c" : "e45e50", "ffca8a" : "ff9b7c",
"735e3a" : "673e45", "a38d59" : "9a6262", "d9c189" : "cd9494", "b7a258" : "eccbcb",
"951500" : "950093", "be1b00" : "be00b8", "dc1f00" : "dc00c5", "f32200" : "f300bd"
},
{
"6f2919" : "672135", "a85636" : "a03755", "e0975c" : "d25679", "ffca8a" : "e88aa5",
"735e3a" : "66452e", "a38d59" : "a47c56", "d9c189" : "d9aa7b", "b7a258" : "f7ddb0",
"951500" : "009504", "be1b00" : "1bbe00", "dc1f00" : "34dc00", "f32200" : "50f300"
},
{
"6f2919" : "5b553d", "a85636" : "9a9460", "e0975c" : "c8c782", "ffca8a" : "f1f1ba",
"735e3a" : "5c463c", "a38d59" : "956f6b", "d9c189" : "dfaeb4", "b7a258" : "eacfdd",
"951500" : "66139b", "be1b00" : "8826bf", "dc1f00" : "bc61e2", "f32200" : "eaacfb"
},
{
"6f2919" : "66452e", "a85636" : "a47c56", "e0975c" : "d9aa7b", "ffca8a" : "f7ddb0",
"735e3a" : "2b531a", "a38d59" : "63822d", "d9c189" : "9dba44", "b7a258" : "c8e96f",
"951500" : "00954d", "be1b00" : "00be67", "dc1f00" : "00dc7c", "f32200" : "00f39a"
},
{
"6f2919" : "673e45", "a85636" : "9a6262", "e0975c" : "cd9494", "ffca8a" : "eccbcb",
"735e3a" : "485548", "a38d59" : "728473", "d9c189" : "acc8ac", "b7a258" : "d8e5d6",
"951500" : "47192e", "be1b00" : "84325d", "dc1f00" : "b04691", "f32200" : "db5ec9"
},
{
"6f2919" : "400911", "a85636" : "731d1d", "e0975c" : "a75757", "ffca8a" : "d09090",
"735e3a" : "4c525e", "a38d59" : "76859b", "d9c189" : "a2bacc", "b7a258" : "d2e4eb",
"951500" : "5b0095", "be1b00" : "7900be", "dc1f00" : "b04691", "9b00dc" : "bd00f3"
},
{
"6f2919" : "400911", "a85636" : "731d1d", "e0975c" : "a75757", "ffca8a" : "d09090",
"735e3a" : "4c525e", "a38d59" : "76859b", "d9c189" : "a2bacc", "b7a258" : "d2e4eb",
"951500" : "5b0095", "be1b00" : "7900be", "dc1f00" : "b04691", "9b00dc" : "bd00f3"
},
{
"6f2919" : "6e5c17", "a85636" : "b2a025", "e0975c" : "e8e63a", "ffca8a" : "fefebb",
"735e3a" : "195519", "a38d59" : "3b9c2b", "d9c189" : "7cd855", "b7a258" : "c0f6a2",
"951500" : "953800", "be1b00" : "be5000", "dc1f00" : "dc6200", "9b00dc" : "f36700"
},
{
"6f2919" : "493415", "a85636" : "806b22", "e0975c" : "bba93e", "ffca8a" : "e6e373",
"735e3a" : "0a0a0a", "a38d59" : "434343", "d9c189" : "666666", "b7a258" : "898989",
"951500" : "956200", "be1b00" : "be8f00", "dc1f00" : "dcca00", "9b00dc" : "f3f100"
},
{
"6f2919" : "6a1c1c", "a85636" : "ae3c3c", "e0975c" : "e15757", "ffca8a" : "f79696",
"735e3a" : "195519", "a38d59" : "3b9c2b", "d9c189" : "7cd855", "b7a258" : "c0f6a2",
"951500" : "009504", "be1b00" : "1bbe00", "dc1f00" : "34dc00", "9b00dc" : "50f300"
},
{
"6f2919" : "67212b", "a85636" : "a03737", "e0975c" : "d26256", "ffca8a" : "e8a08a",
"735e3a" : "6c5d22", "a38d59" : "b0a747", "d9c189" : "e2e189", "b7a258" : "f0f0c2",
"951500" : "192747", "be1b00" : "325184", "dc1f00" : "4682b0", "9b00dc" : "5eb7db"
},
{
"6f2919" : "195519", "a85636" : "3b9c2b", "e0975c" : "7cd855", "ffca8a" : "c0f6a2",
"735e3a" : "6e5c17", "a38d59" : "b2a025", "d9c189" : "e8e63a", "b7a258" : "fefebb",
"951500" : "950093", "be1b00" : "be00b8", "dc1f00" : "dc00c5", "9b00dc" : "f300bd"
},
{
"6f2919" : "266554", "a85636" : "4aa586", "e0975c" : "72ddb3", "ffca8a" : "b8f4d9",
"735e3a" : "6c5d22", "a38d59" : "b0a747", "d9c189" : "e2e189", "b7a258" : "f0f0c2",
"951500" : "000495", "be1b00" : "000dbe", "dc1f00" : "0043dc", "9b00dc" : "0072f3"
},
{
"6f2919" : "40495e", "a85636" : "617a9f", "e0975c" : "84b3d7", "ffca8a" : "b4dded",
"735e3a" : "68320d", "a38d59" : "a56220", "d9c189" : "e48c37", "b7a258" : "fad086",
"951500" : "951500", "be1b00" : "be1b00", "dc1f00" : "dc1f00", "9b00dc" : "9b00dc"
},
{
"6f2919" : "455d1e", "a85636" : "839731", "e0975c" : "d0dc61", "ffca8a" : "f5f898",
"735e3a" : "503224", "a38d59" : "965751", "d9c189" : "df7e8b", "b7a258" : "efa4ca",
"951500" : "950093", "be1b00" : "be00b8", "dc1f00" : "dc00c5", "9b00dc" : "f300bd"
},
{
"6f2919" : "1a5329", "a85636" : "3e822d", "e0975c" : "7bae39", "ffca8a" : "a4d458",
"735e3a" : "66452e", "a38d59" : "a47c56", "d9c189" : "d9aa7b", "b7a258" : "f7ddb0",
"951500" : "00954d", "be1b00" : "00be67", "dc1f00" : "00dc7c", "9b00dc" : "00f39a"
},
{
"6f2919" : "192747", "a85636" : "325184", "e0975c" : "4682b0", "ffca8a" : "5eb7db",
"735e3a" : "365115", "a38d59" : "728c22", "d9c189" : "adc331", "b7a258" : "e5ef6c",
"951500" : "5f9500", "be1b00" : "86be00", "dc1f00" : "abdc00", "9b00dc" : "cef300"
},
{
"6f2919" : "392450", "a85636" : "615196", "e0975c" : "807edf", "ffca8a" : "a4bfef",
"735e3a" : "742977", "a38d59" : "bb4fba", "d9c189" : "e884e7", "b7a258" : "ffc3fb",
"951500" : "950093", "be1b00" : "be00b8", "dc1f00" : "dc00c5", "9b00dc" : "f300bd"
},
{
"6f2919" : "1b472d", "a85636" : "2b7e39", "e0975c" : "5fbd5d", "ffca8a" : "9fe296",
"735e3a" : "574943", "a38d59" : "907471", "d9c189" : "cca1a6", "b7a258" : "e0becf",
"951500" : "954d00", "be1b00" : "be6b00", "dc1f00" : "dc9600", "9b00dc" : "f3b700"
},
{
"6f2919" : "485548", "a85636" : "728473", "e0975c" : "acc8ac", "ffca8a" : "d8e5d6",
"735e3a" : "5f5b4b", "a38d59" : "939070", "d9c189" : "c2c2a0", "b7a258" : "e5e5d4",
"951500" : "008595", "be1b00" : "00b8be", "dc1f00" : "00dcda", "9b00dc" : "00f3df"
},
{
"6f2919" : "263760", "a85636" : "486ca6", "e0975c" : "58a2db", "ffca8a" : "91d3ee",
"735e3a" : "4c525e", "a38d59" : "76859b", "d9c189" : "a2bacc", "b7a258" : "d2e4eb",
"951500" : "4b4b4b", "be1b00" : "828282", "dc1f00" : "b6b6b6", "9b00dc" : "d9d9d9"
},
// change change change change
// Null entry, means do no color swap
{ }
]
}

View file

@ -0,0 +1,10 @@
{
"name" : "organiccloakarm",
"category" : "biped",
"type" : "arms",
"frames" : {
"frontArm" : "cloakfarm.frames",
"backArm" : "cloakbarm.frames"
}
}

View file

@ -0,0 +1,13 @@
{
"image" : "cloakbarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

View file

@ -0,0 +1,13 @@
{
"image" : "cloakfarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -0,0 +1,10 @@
{
"name" : "organicdiverarm",
"category" : "biped",
"type" : "arms",
"frames" : {
"frontArm" : "diverfarm.frames",
"backArm" : "diverbarm.frames"
}
}

View file

@ -0,0 +1,13 @@
{
"image" : "diverbarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -0,0 +1,13 @@
{
"image" : "diverfarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1,10 @@
{
"name" : "organicflexarm",
"category" : "biped",
"type" : "arms",
"frames" : {
"frontArm" : "flexfarm.frames",
"backArm" : "flexbarm.frames"
}
}

View file

@ -0,0 +1,13 @@
{
"image" : "flexbarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1,13 @@
{
"image" : "flexfarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1,10 @@
{
"name" : "organicfloatingarm",
"category" : "biped",
"type" : "arms",
"frames" : {
"frontArm" : "floatingfarm.frames",
"backArm" : "floatingbarm.frames"
}
}

View file

@ -0,0 +1,13 @@
{
"image" : "floatingbarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View file

@ -0,0 +1,13 @@
{
"image" : "floatingfarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

@ -0,0 +1,10 @@
{
"name" : "organicgirlarm",
"category" : "biped",
"type" : "arms",
"frames" : {
"frontArm" : "girlfarm.frames",
"backArm" : "girlbarm.frames"
}
}

View file

@ -0,0 +1,13 @@
{
"image" : "girlbarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,13 @@
{
"image" : "girlfarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,10 @@
{
"name" : "organichydraarm",
"category" : "biped",
"type" : "arms",
"frames" : {
"frontArm" : "hydrafarm.frames",
"backArm" : "hydrabarm.frames"
}
}

View file

@ -0,0 +1,13 @@
{
"image" : "hydrabarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -0,0 +1,13 @@
{
"image" : "hydrafarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,10 @@
{
"name" : "organicimparm",
"category" : "biped",
"type" : "arms",
"frames" : {
"frontArm" : "impfarm.frames",
"backArm" : "impbarm.frames"
}
}

View file

@ -0,0 +1,13 @@
{
"image" : "impbarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,13 @@
{
"image" : "impfarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,10 @@
{
"name" : "organicoctoarm",
"category" : "biped",
"type" : "arms",
"frames" : {
"frontArm" : "octofarm.frames",
"backArm" : "octobarm.frames"
}
}

View file

@ -0,0 +1,13 @@
{
"image" : "octobarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,13 @@
{
"image" : "octofarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -0,0 +1,10 @@
{
"name" : "organicpincerarm",
"category" : "biped",
"type" : "arms",
"frames" : {
"frontArm" : "pincerfarm.frames",
"backArm" : "pincerbarm.frames"
}
}

View file

@ -0,0 +1,13 @@
{
"image" : "pincerbarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1,13 @@
{
"image" : "pincerfarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -0,0 +1,10 @@
{
"name" : "organicrobosuitarm",
"category" : "biped",
"type" : "arms",
"frames" : {
"frontArm" : "robosuitfarm.frames",
"backArm" : "robosuitbarm.frames"
}
}

View file

@ -0,0 +1,13 @@
{
"image" : "robosuitbarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,13 @@
{
"image" : "robosuitfarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,10 @@
{
"name" : "organicrockarm",
"category" : "biped",
"type" : "arms",
"frames" : {
"frontArm" : "rockfarm.frames",
"backArm" : "rockbarm.frames"
}
}

View file

@ -0,0 +1,13 @@
{
"image" : "rockbarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -0,0 +1,13 @@
{
"image" : "rockfarm.png",
"frameGrid" : {
"size" : [42, 42],
"dimensions" : [9, 3],
"names" : [
[ null, "idle" ],
[ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
[ null, "jump", null, "melee.1", "melee.2", "melee.3", "melee.4", null, null ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

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