mirror of
https://github.com/Wincent01/InfectedRose.git
synced 2025-12-16 17:49:50 -06:00
Initial commit
This commit is contained in:
571
.gitignore
vendored
Normal file
571
.gitignore
vendored
Normal file
@@ -0,0 +1,571 @@
|
||||
|
||||
# Created by https://www.gitignore.io/api/rider,csharp,visualstudio
|
||||
# Edit at https://www.gitignore.io/?templates=rider,csharp,visualstudio
|
||||
|
||||
### Csharp ###
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
### Rider ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### VisualStudio ###
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
|
||||
# Build results
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
|
||||
# MSTest test Results
|
||||
|
||||
# NUNIT
|
||||
|
||||
# Build Results of an ATL Project
|
||||
|
||||
# Benchmark Results
|
||||
|
||||
# .NET Core
|
||||
|
||||
# StyleCop
|
||||
|
||||
# Files built by Visual Studio
|
||||
|
||||
# Chutzpah Test files
|
||||
|
||||
# Visual C++ cache files
|
||||
|
||||
# Visual Studio profiler
|
||||
|
||||
# Visual Studio Trace Files
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
|
||||
# TeamCity is a build add-in
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
|
||||
# Visual Studio code coverage results
|
||||
|
||||
# NCrunch
|
||||
|
||||
# MightyMoose
|
||||
|
||||
# Web workbench (sass)
|
||||
|
||||
# Installshield output folder
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
|
||||
# Click-Once directory
|
||||
|
||||
# Publish Web Output
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
|
||||
# NuGet Packages
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
# except build/, which is used as an MSBuild target.
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
|
||||
# Windows Store app package directories and files
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
# but keep track of directories ending in .cache
|
||||
|
||||
# Others
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
|
||||
# SQL Server files
|
||||
|
||||
# Business Intelligence projects
|
||||
|
||||
# Microsoft Fakes
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
|
||||
# Visual Studio 6 build log
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
|
||||
# Paket dependency manager
|
||||
|
||||
# FAKE - F# Make
|
||||
|
||||
# JetBrains Rider
|
||||
|
||||
# CodeRush personal settings
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
|
||||
# BizTalk build output
|
||||
|
||||
# OpenCover UI analysis results
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
|
||||
# Local History for Visual Studio
|
||||
|
||||
# End of https://www.gitignore.io/api/rider,csharp,visualstudio
|
||||
|
||||
.DS_Store
|
||||
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "RakDotNet.IO"]
|
||||
path = "RakDotNet.IO"
|
||||
url = https://github.com/yuwui/RakDotNet.IO.git
|
||||
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
# Default ignored files
|
||||
/.idea.InfectedRose/.idea/workspace.xml
|
||||
46
InfectedRose.Core/Extensions/BitReaderExtensions.cs
Normal file
46
InfectedRose.Core/Extensions/BitReaderExtensions.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Core
|
||||
{
|
||||
public static class BitReaderExtensions
|
||||
{
|
||||
public static string ReadNiString(this BitReader @this, bool wide = false, bool small = false)
|
||||
{
|
||||
var len = small ? @this.Read<byte>() : @this.Read<uint>();
|
||||
var str = new char[len];
|
||||
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
str[i] = (char) (wide ? @this.Read<ushort>() : @this.Read<byte>());
|
||||
}
|
||||
|
||||
|
||||
return new string(str);
|
||||
}
|
||||
|
||||
public static Quaternion ReadNiQuaternion(this BitReader @this)
|
||||
{
|
||||
return new Quaternion
|
||||
{
|
||||
W = @this.Read<float>(),
|
||||
X = @this.Read<float>(),
|
||||
Y = @this.Read<float>(),
|
||||
Z = @this.Read<float>()
|
||||
};
|
||||
}
|
||||
|
||||
public static byte[] ReadBuffer(this BitReader @this, uint length)
|
||||
{
|
||||
var buffer = new byte[length];
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
buffer[i] = @this.Read<byte>();
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
InfectedRose.Core/Extensions/BitWriterExtensions.cs
Normal file
36
InfectedRose.Core/Extensions/BitWriterExtensions.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Numerics;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Core
|
||||
{
|
||||
public static class BitWriterExtensions
|
||||
{
|
||||
public static void WriteNiString(this BitWriter @this, string str, bool wide = false, bool small = false)
|
||||
{
|
||||
if (small) @this.Write((byte) str.Length);
|
||||
else @this.Write((uint) str.Length);
|
||||
|
||||
foreach (var c in str)
|
||||
{
|
||||
if (wide) @this.Write((ushort) c);
|
||||
else @this.Write((byte) c);
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteNiQuaternion(this BitWriter @this, Quaternion quaternion)
|
||||
{
|
||||
@this.Write(quaternion.W);
|
||||
@this.Write(quaternion.X);
|
||||
@this.Write(quaternion.Y);
|
||||
@this.Write(quaternion.Z);
|
||||
}
|
||||
|
||||
public static void Write(this BitWriter @this, byte[] buffer)
|
||||
{
|
||||
foreach (var value in buffer)
|
||||
{
|
||||
@this.Write(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
InfectedRose.Core/IConstruct.cs
Normal file
8
InfectedRose.Core/IConstruct.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Core
|
||||
{
|
||||
public interface IConstruct : ISerializable, IDeserializable
|
||||
{
|
||||
}
|
||||
}
|
||||
11
InfectedRose.Core/InfectedRose.Core.csproj
Normal file
11
InfectedRose.Core/InfectedRose.Core.csproj
Normal file
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RakDotNet.IO\RakDotNet.IO\RakDotNet.IO.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
122
InfectedRose.Database/AccessDatabase.cs
Normal file
122
InfectedRose.Database/AccessDatabase.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using InfectedRose.Database.Generic;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
public class AccessDatabase : IList<Table>
|
||||
{
|
||||
public DatabaseFile File { get; private set; }
|
||||
|
||||
public AccessDatabase(DatabaseFile file)
|
||||
{
|
||||
File = file;
|
||||
}
|
||||
|
||||
public IEnumerator<Table> GetEnumerator()
|
||||
{
|
||||
return File.TableHeader.Tables.Select(t => new Table(t.info, t.data)).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void Add(Table item)
|
||||
{
|
||||
if (item == default) return;
|
||||
|
||||
var list = File.TableHeader.Tables.ToList();
|
||||
list.Add((item.Info, item.Data));
|
||||
File.TableHeader.Tables = list.ToArray();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
File.TableHeader.Tables = new (FdbColumnHeader info, FdbRowBucket data)[0];
|
||||
}
|
||||
|
||||
public bool Contains(Table item)
|
||||
{
|
||||
return this.Any(value => value == item);
|
||||
}
|
||||
|
||||
public void CopyTo(Table[] array, int arrayIndex)
|
||||
{
|
||||
var list = File.TableHeader.Tables.Select(t => new Table(t.info, t.data)).ToList();
|
||||
list.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public bool Remove(Table item)
|
||||
{
|
||||
if (item == default) return false;
|
||||
|
||||
var removal = File.TableHeader.Tables.FirstOrDefault(t => t.info == item.Info && t.data == item.Data);
|
||||
|
||||
if (removal == default) return false;
|
||||
|
||||
var list = File.TableHeader.Tables.ToList();
|
||||
list.Remove(removal);
|
||||
File.TableHeader.Tables = list.ToArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int Count => File.TableHeader.Tables.Length;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public int IndexOf(Table item)
|
||||
{
|
||||
if (item == default) return -1;
|
||||
|
||||
return File.TableHeader.Tables.ToList().IndexOf(
|
||||
File.TableHeader.Tables.First(t => t.info == item.Info && t.data == item.Data)
|
||||
);
|
||||
}
|
||||
|
||||
public void Insert(int index, Table item)
|
||||
{
|
||||
if (item == default) return;
|
||||
|
||||
var list = File.TableHeader.Tables.ToList();
|
||||
list.Insert(index, (item.Info, item.Data));
|
||||
File.TableHeader.Tables = list.ToArray();
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
var list = File.TableHeader.Tables.ToList();
|
||||
list.RemoveAt(index);
|
||||
File.TableHeader.Tables = list.ToArray();
|
||||
}
|
||||
|
||||
public Table this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
var (info, data) = File.TableHeader.Tables[index];
|
||||
|
||||
return new Table(info, data);
|
||||
}
|
||||
set => File.TableHeader.Tables[index] = (value.Info, value.Data);
|
||||
}
|
||||
|
||||
public Table this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var (info, data) in File.TableHeader.Tables)
|
||||
{
|
||||
if (info.TableName == name)
|
||||
return new Table(info, data);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
115
InfectedRose.Database/Column.cs
Normal file
115
InfectedRose.Database/Column.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
public class Column : IList<Field>
|
||||
{
|
||||
internal FdbRowInfo Data { get; private set; }
|
||||
|
||||
internal Table Table { get; private set; }
|
||||
|
||||
internal Column(FdbRowInfo data, Table table)
|
||||
{
|
||||
Data = data;
|
||||
Table = table;
|
||||
}
|
||||
|
||||
public IEnumerator<Field> GetEnumerator()
|
||||
{
|
||||
int index = default;
|
||||
|
||||
return Data.DataHeader.Data.Fields.Select(
|
||||
field => new Field(Data.DataHeader.Data, index++, Table)
|
||||
).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void Add(Field item)
|
||||
{
|
||||
throw new NotSupportedException("Fields should fallow the table structure, and their signature should not be changed.");
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
throw new NotSupportedException("Fields should fallow the table structure, and their signature should not be changed.");
|
||||
}
|
||||
|
||||
public bool Contains(Field item)
|
||||
{
|
||||
if (item == default) return false;
|
||||
|
||||
int index = default;
|
||||
|
||||
var list = Data.DataHeader.Data.Fields.Select(
|
||||
field => new Field(Data.DataHeader.Data, index++, Table)
|
||||
).ToList();
|
||||
|
||||
return list.Any(c => c.Data == item.Data && c.Index == item.Index);
|
||||
}
|
||||
|
||||
public void CopyTo(Field[] array, int arrayIndex)
|
||||
{
|
||||
int index = default;
|
||||
|
||||
var list = Data.DataHeader.Data.Fields.Select(
|
||||
field => new Field(Data.DataHeader.Data, index++, Table)
|
||||
).ToList();
|
||||
|
||||
list.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public bool Remove(Field item)
|
||||
{
|
||||
throw new NotSupportedException("Fields should fallow the table structure, and their signature should not be changed.");
|
||||
}
|
||||
|
||||
public int Count => Data.DataHeader.Data.Fields.Length;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public int IndexOf(Field item)
|
||||
{
|
||||
return item?.Index ?? -1;
|
||||
}
|
||||
|
||||
public void Insert(int index, Field item)
|
||||
{
|
||||
throw new NotSupportedException("Fields should fallow the table structure, and their signature should not be changed.");
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
throw new NotSupportedException("Fields should fallow the table structure, and their signature should not be changed.");
|
||||
}
|
||||
|
||||
public Field this[int index]
|
||||
{
|
||||
get => new Field(Data.DataHeader.Data, index, Table);
|
||||
set => throw new NotSupportedException("Fields should fallow the table structure, and their signature should not be changed.");
|
||||
}
|
||||
|
||||
public Field this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
int index = default;
|
||||
|
||||
for (var i = 0; i < Table.TableInfo.Count; i++)
|
||||
{
|
||||
var column = Table.TableInfo[i];
|
||||
|
||||
if (column.Name == name) index = i;
|
||||
}
|
||||
|
||||
return new Field(Data.DataHeader.Data, index, Table);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
InfectedRose.Database/ColumnInfo.cs
Normal file
44
InfectedRose.Database/ColumnInfo.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
public class ColumnInfo
|
||||
{
|
||||
internal Table Table { get; private set; }
|
||||
|
||||
internal int Index { get; private set; }
|
||||
|
||||
public DataType Type
|
||||
{
|
||||
get => Table.Info.Data.Fields[Index].type;
|
||||
set
|
||||
{
|
||||
var dataField = Table.Info.Data.Fields[Index];
|
||||
|
||||
dataField.type = value;
|
||||
|
||||
Table.Info.Data.Fields[Index] = dataField;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => Table.Info.Data.Fields[Index].name;
|
||||
set
|
||||
{
|
||||
var dataField = Table.Info.Data.Fields[Index];
|
||||
|
||||
dataField.name = new FdbString
|
||||
{
|
||||
Value = value
|
||||
};
|
||||
|
||||
Table.Info.Data.Fields[Index] = dataField;
|
||||
}
|
||||
}
|
||||
|
||||
internal ColumnInfo(Table table, int index)
|
||||
{
|
||||
Table = table;
|
||||
Index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
InfectedRose.Database/DataType.cs
Normal file
15
InfectedRose.Database/DataType.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
public enum DataType : uint
|
||||
{
|
||||
Nothing, // can’t remember if those are just skipped/ignored or even showed up
|
||||
Integer,
|
||||
Unknown1, // never used?
|
||||
Float,
|
||||
Text, // called STRING in MSSQL?
|
||||
Boolean,
|
||||
Bigint, // or DATETIME?
|
||||
Unknown2, // never used?
|
||||
Varchar // called TEXT in MSSQL?
|
||||
}
|
||||
}
|
||||
11
InfectedRose.Database/DatabaseData.cs
Normal file
11
InfectedRose.Database/DatabaseData.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
public abstract class DatabaseData : IDeserializable
|
||||
{
|
||||
internal abstract void Compile(DatabaseFile databaseFile);
|
||||
|
||||
public abstract void Deserialize(BitReader reader);
|
||||
}
|
||||
}
|
||||
109
InfectedRose.Database/DatabaseFile.cs
Normal file
109
InfectedRose.Database/DatabaseFile.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
public class DatabaseFile : IDeserializable
|
||||
{
|
||||
public List<object> Structure { get; set; }
|
||||
|
||||
internal FdbTableHeader TableHeader { get; set; }
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
var tableCount = reader.Read<uint>();
|
||||
|
||||
using (new DatabaseScope(reader))
|
||||
{
|
||||
TableHeader = new FdbTableHeader(tableCount);
|
||||
|
||||
TableHeader.Deserialize(reader);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compile the database to a hash-map
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a really long process and should be run in a Task.
|
||||
/// </remarks>
|
||||
/// <returns>Compiled database</returns>
|
||||
public byte[] Compile(Action<int> onData)
|
||||
{
|
||||
Structure = new List<object>
|
||||
{
|
||||
(uint) TableHeader.Tables.Length,
|
||||
TableHeader
|
||||
};
|
||||
|
||||
TableHeader.Compile(this);
|
||||
|
||||
var fdb = new List<byte>();
|
||||
var pointers = new List<(DatabaseData, int)>();
|
||||
|
||||
int index = default;
|
||||
foreach (var obj in Structure)
|
||||
{
|
||||
onData(++index);
|
||||
|
||||
switch (obj)
|
||||
{
|
||||
case null:
|
||||
fdb.AddRange(ToBytes(-1));
|
||||
break;
|
||||
case DatabaseData data:
|
||||
{
|
||||
var pointer = pointers.Where(p => p.Item1 == data).ToArray();
|
||||
if (pointer.Any())
|
||||
{
|
||||
var bytes = ToBytes(fdb.Count);
|
||||
|
||||
foreach (var tuple in pointer)
|
||||
{
|
||||
pointers.Remove(tuple);
|
||||
for (var j = 0; j < 4; j++) fdb[tuple.Item2 + j] = bytes[j];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save pointers for last
|
||||
pointers.Add((data, fdb.Count));
|
||||
|
||||
// Reserve space for pointer
|
||||
fdb.AddRange(new byte[4]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fdb.AddRange(ToBytes(obj));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return fdb.ToArray();
|
||||
}
|
||||
|
||||
private static byte[] ToBytes(object obj)
|
||||
{
|
||||
if (!obj.GetType().IsValueType)
|
||||
{
|
||||
Console.WriteLine($"{obj} is not a valid struct");
|
||||
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
var size = Marshal.SizeOf(obj);
|
||||
var buf = new byte[size];
|
||||
var ptr = Marshal.AllocHGlobal(size);
|
||||
|
||||
Marshal.StructureToPtr(obj, ptr, false);
|
||||
Marshal.Copy(ptr, buf, 0, size);
|
||||
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
InfectedRose.Database/DatabaseScope.cs
Normal file
30
InfectedRose.Database/DatabaseScope.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
internal class DatabaseScope : IDisposable
|
||||
{
|
||||
private readonly long _current;
|
||||
private readonly int _pointer;
|
||||
private readonly BitReader _reader;
|
||||
|
||||
public DatabaseScope(BitReader reader, bool signed = false)
|
||||
{
|
||||
_current = reader.BaseStream.Position + 4;
|
||||
_pointer = signed ? reader.Read<int>() : (int) reader.Read<uint>();
|
||||
if (_pointer != -1) reader.BaseStream.Position = _pointer;
|
||||
_reader = reader;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_reader.BaseStream.Position = _current;
|
||||
}
|
||||
|
||||
public static implicit operator bool(DatabaseScope s)
|
||||
{
|
||||
return s._pointer != -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
InfectedRose.Database/FdbBitInt.cs
Normal file
22
InfectedRose.Database/FdbBitInt.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
internal class FdbBitInt : DatabaseData
|
||||
{
|
||||
public long Value { get; set; }
|
||||
|
||||
internal override void Compile(DatabaseFile databaseFile)
|
||||
{
|
||||
databaseFile.Structure.Add(this);
|
||||
databaseFile.Structure.Add(Value);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
using var s = new DatabaseScope(reader, true);
|
||||
|
||||
if (s) Value = reader.Read<long>();
|
||||
}
|
||||
}
|
||||
}
|
||||
41
InfectedRose.Database/FdbColumnData.cs
Normal file
41
InfectedRose.Database/FdbColumnData.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
internal class FdbColumnData : DatabaseData
|
||||
{
|
||||
private readonly uint _columnCount;
|
||||
|
||||
public FdbColumnData(uint columnCount)
|
||||
{
|
||||
_columnCount = columnCount;
|
||||
}
|
||||
|
||||
public (DataType type, FdbString name)[] Fields { get; set; }
|
||||
|
||||
internal override void Compile(DatabaseFile databaseFile)
|
||||
{
|
||||
databaseFile.Structure.Add(this);
|
||||
for (var i = 0; i < Fields.Length; i++)
|
||||
{
|
||||
databaseFile.Structure.Add((uint) Fields[i].type);
|
||||
databaseFile.Structure.Add(Fields[i].name);
|
||||
}
|
||||
|
||||
foreach (var s in Fields) s.name.Compile(databaseFile);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
Fields = new (DataType type, FdbString name)[_columnCount];
|
||||
|
||||
for (var i = 0; i < _columnCount; i++)
|
||||
{
|
||||
Fields[i].type = (DataType) reader.Read<uint>();
|
||||
|
||||
Fields[i].name = new FdbString();
|
||||
Fields[i].name.Deserialize(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
41
InfectedRose.Database/FdbColumnHeader.cs
Normal file
41
InfectedRose.Database/FdbColumnHeader.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
internal class FdbColumnHeader : DatabaseData
|
||||
{
|
||||
public FdbString TableName { get; set; }
|
||||
|
||||
public FdbColumnData Data { get; set; }
|
||||
|
||||
internal override void Compile(DatabaseFile databaseFile)
|
||||
{
|
||||
databaseFile.Structure.Add(this);
|
||||
databaseFile.Structure.Add((uint) Data.Fields.Length);
|
||||
databaseFile.Structure.Add(TableName);
|
||||
databaseFile.Structure.Add(Data);
|
||||
|
||||
TableName.Compile(databaseFile);
|
||||
Data.Compile(databaseFile);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
var columnCount = reader.Read<uint>();
|
||||
|
||||
TableName = new FdbString();
|
||||
TableName.Deserialize(reader);
|
||||
|
||||
using (new DatabaseScope(reader))
|
||||
{
|
||||
Data = new FdbColumnData(columnCount);
|
||||
Data.Deserialize(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return TableName;
|
||||
}
|
||||
}
|
||||
}
|
||||
51
InfectedRose.Database/FdbRowBucket.cs
Normal file
51
InfectedRose.Database/FdbRowBucket.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
internal class FdbRowBucket : DatabaseData
|
||||
{
|
||||
public FdbRowHeader RowHeader { get; set; }
|
||||
|
||||
internal override void Compile(DatabaseFile databaseFile)
|
||||
{
|
||||
databaseFile.Structure.Add(this);
|
||||
Console.WriteLine(NextPowerOf2(RowHeader.RowInfos.Length));
|
||||
databaseFile.Structure.Add(NextPowerOf2(RowHeader.RowInfos.Length));
|
||||
|
||||
databaseFile.Structure.Add(RowHeader);
|
||||
|
||||
RowHeader?.Compile(databaseFile);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
var rowCount = reader.Read<uint>();
|
||||
|
||||
using var s = new DatabaseScope(reader, true);
|
||||
|
||||
if (!s) return;
|
||||
|
||||
RowHeader = new FdbRowHeader(rowCount);
|
||||
RowHeader.Deserialize(reader);
|
||||
}
|
||||
|
||||
internal static uint NextPowerOf2(int n)
|
||||
{
|
||||
var count = 0;
|
||||
|
||||
// First n in the below condition
|
||||
// is for the case where n is 0
|
||||
if (n > 0 && (n & (n - 1)) == 0)
|
||||
return (uint) n;
|
||||
|
||||
while (n != 0)
|
||||
{
|
||||
n >>= 1;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return (uint) (1 << count);
|
||||
}
|
||||
}
|
||||
}
|
||||
80
InfectedRose.Database/FdbRowData.cs
Normal file
80
InfectedRose.Database/FdbRowData.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
internal class FdbRowData : DatabaseData
|
||||
{
|
||||
public FdbRowData(uint columnCount)
|
||||
{
|
||||
Fields = new (DataType, object)[columnCount];
|
||||
}
|
||||
|
||||
public (DataType type, object value)[] Fields { get; set; }
|
||||
|
||||
internal override void Compile(DatabaseFile databaseFile)
|
||||
{
|
||||
databaseFile.Structure.Add(this);
|
||||
|
||||
for (var i = 0; i < Fields.Length; i++)
|
||||
{
|
||||
databaseFile.Structure.Add((uint) Fields[i].type);
|
||||
databaseFile.Structure.Add(Fields[i].value);
|
||||
}
|
||||
|
||||
foreach (var o in Fields)
|
||||
if (o.value is DatabaseData data)
|
||||
data.Compile(databaseFile);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
for (var i = 0; i < Fields.Length; i++)
|
||||
{
|
||||
Fields[i].type = (DataType) reader.Read<uint>();
|
||||
|
||||
switch (Fields[i].type)
|
||||
{
|
||||
case DataType.Nothing:
|
||||
Fields[i].value = reader.Read<int>();
|
||||
break;
|
||||
case DataType.Integer:
|
||||
Fields[i].value = reader.Read<int>();
|
||||
break;
|
||||
case DataType.Unknown1:
|
||||
Fields[i].value = reader.Read<int>();
|
||||
break;
|
||||
case DataType.Float:
|
||||
Fields[i].value = reader.Read<float>();
|
||||
break;
|
||||
case DataType.Text:
|
||||
var str = new FdbString();
|
||||
str.Deserialize(reader);
|
||||
|
||||
Fields[i].value = str;
|
||||
break;
|
||||
case DataType.Boolean:
|
||||
Fields[i].value = reader.Read<int>() != 0;
|
||||
break;
|
||||
case DataType.Bigint:
|
||||
var bigInt = new FdbBitInt();
|
||||
bigInt.Deserialize(reader);
|
||||
|
||||
Fields[i].value = bigInt;
|
||||
break;
|
||||
case DataType.Unknown2:
|
||||
Fields[i].value = reader.Read<int>();
|
||||
break;
|
||||
case DataType.Varchar:
|
||||
var str1 = new FdbString();
|
||||
str1.Deserialize(reader);
|
||||
|
||||
Fields[i].value = str1;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
InfectedRose.Database/FdbRowDataHeader.cs
Normal file
31
InfectedRose.Database/FdbRowDataHeader.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
internal class FdbRowDataHeader : DatabaseData
|
||||
{
|
||||
public FdbRowData Data { get; set; }
|
||||
|
||||
internal override void Compile(DatabaseFile databaseFile)
|
||||
{
|
||||
databaseFile.Structure.Add(this);
|
||||
databaseFile.Structure.Add((uint) Data.Fields.Length);
|
||||
databaseFile.Structure.Add(Data);
|
||||
|
||||
Data?.Compile(databaseFile);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
var columnCount = reader.Read<uint>();
|
||||
|
||||
using var s = new DatabaseScope(reader, true);
|
||||
|
||||
if (!s) return;
|
||||
|
||||
Data = new FdbRowData(columnCount);
|
||||
|
||||
Data.Deserialize(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
45
InfectedRose.Database/FdbRowHeader.cs
Normal file
45
InfectedRose.Database/FdbRowHeader.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
internal class FdbRowHeader : DatabaseData
|
||||
{
|
||||
private readonly uint _rowCount;
|
||||
|
||||
public FdbRowHeader(uint rowCount)
|
||||
{
|
||||
_rowCount = rowCount;
|
||||
}
|
||||
|
||||
public FdbRowInfo[] RowInfos;
|
||||
|
||||
internal override void Compile(DatabaseFile databaseFile)
|
||||
{
|
||||
databaseFile.Structure.Add(this);
|
||||
|
||||
foreach (var rowInfo in RowInfos) databaseFile.Structure.Add(rowInfo);
|
||||
|
||||
for (var i = 0; i < FdbRowBucket.NextPowerOf2(RowInfos.Length) - RowInfos.Length; i++)
|
||||
{
|
||||
databaseFile.Structure.Add(-1);
|
||||
}
|
||||
|
||||
foreach (var rowInfo in RowInfos) rowInfo?.Compile(databaseFile);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
RowInfos = new FdbRowInfo[_rowCount];
|
||||
|
||||
for (var i = 0; i < _rowCount; i++)
|
||||
{
|
||||
using var s = new DatabaseScope(reader, true);
|
||||
|
||||
if (!s) continue;
|
||||
|
||||
RowInfos[i] = new FdbRowInfo();
|
||||
RowInfos[i].Deserialize(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
InfectedRose.Database/FdbRowInfo.cs
Normal file
47
InfectedRose.Database/FdbRowInfo.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
internal class FdbRowInfo : DatabaseData
|
||||
{
|
||||
public FdbRowDataHeader DataHeader { get; set; }
|
||||
|
||||
public FdbRowInfo Linked { get; set; }
|
||||
|
||||
internal override void Compile(DatabaseFile databaseFile)
|
||||
{
|
||||
databaseFile.Structure.Add(this);
|
||||
databaseFile.Structure.Add(DataHeader);
|
||||
|
||||
if (Linked == default)
|
||||
databaseFile.Structure.Add(-1);
|
||||
else
|
||||
databaseFile.Structure.Add(Linked);
|
||||
|
||||
DataHeader?.Compile(databaseFile);
|
||||
Linked?.Compile(databaseFile);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
using (var s = new DatabaseScope(reader, true))
|
||||
{
|
||||
if (s)
|
||||
{
|
||||
DataHeader = new FdbRowDataHeader();
|
||||
|
||||
DataHeader.Deserialize(reader);
|
||||
}
|
||||
}
|
||||
|
||||
using (var s = new DatabaseScope(reader, true))
|
||||
{
|
||||
if (!s) return;
|
||||
|
||||
Linked = new FdbRowInfo();
|
||||
|
||||
Linked.Deserialize(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
45
InfectedRose.Database/FdbString.cs
Normal file
45
InfectedRose.Database/FdbString.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.Text;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
internal class FdbString : DatabaseData
|
||||
{
|
||||
public string Value { get; set; }
|
||||
|
||||
public static implicit operator string(FdbString s)
|
||||
{
|
||||
return s.Value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
internal override void Compile(DatabaseFile databaseFile)
|
||||
{
|
||||
databaseFile.Structure.Add(this);
|
||||
foreach (var c in Value) databaseFile.Structure.Add((byte) c);
|
||||
|
||||
databaseFile.Structure.Add((byte) 0);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
using (new DatabaseScope(reader))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var c = reader.Read<byte>();
|
||||
if (c == 0) break;
|
||||
builder.Append((char) c);
|
||||
}
|
||||
}
|
||||
|
||||
Value = builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
53
InfectedRose.Database/FdbTableHeader.cs
Normal file
53
InfectedRose.Database/FdbTableHeader.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
internal class FdbTableHeader : DatabaseData
|
||||
{
|
||||
private readonly uint _tableCount;
|
||||
|
||||
public FdbTableHeader(uint tableCount)
|
||||
{
|
||||
_tableCount = tableCount;
|
||||
}
|
||||
|
||||
public (FdbColumnHeader info, FdbRowBucket data)[] Tables { get; set; }
|
||||
|
||||
internal override void Compile(DatabaseFile databaseFile)
|
||||
{
|
||||
databaseFile.Structure.Add(this);
|
||||
|
||||
for (var i = 0; i < Tables.Length; i++)
|
||||
{
|
||||
databaseFile.Structure.Add(Tables[i].info);
|
||||
databaseFile.Structure.Add(Tables[i].data);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Tables.Length; i++)
|
||||
{
|
||||
Tables[i].data.Compile(databaseFile);
|
||||
Tables[i].info.Compile(databaseFile);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
Tables = new (FdbColumnHeader info, FdbRowBucket data)[_tableCount];
|
||||
|
||||
for (var i = 0; i < _tableCount; i++)
|
||||
{
|
||||
using (new DatabaseScope(reader))
|
||||
{
|
||||
Tables[i].info = new FdbColumnHeader();
|
||||
Tables[i].info.Deserialize(reader);
|
||||
}
|
||||
|
||||
using (new DatabaseScope(reader))
|
||||
{
|
||||
Tables[i].data = new FdbRowBucket();
|
||||
Tables[i].data.Deserialize(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
48
InfectedRose.Database/Field.cs
Normal file
48
InfectedRose.Database/Field.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
public class Field
|
||||
{
|
||||
internal FdbRowData Data { get; private set; }
|
||||
|
||||
internal int Index { get; private set; }
|
||||
|
||||
public DataType Type
|
||||
{
|
||||
get => Data.Fields[Index].type;
|
||||
set
|
||||
{
|
||||
var dataField = Data.Fields[Index];
|
||||
|
||||
dataField.type = value;
|
||||
|
||||
Data.Fields[Index] = dataField;
|
||||
}
|
||||
}
|
||||
|
||||
public object Value
|
||||
{
|
||||
get => Data.Fields[Index].value;
|
||||
set
|
||||
{
|
||||
var dataField = Data.Fields[Index];
|
||||
|
||||
value = value switch
|
||||
{
|
||||
string str => new FdbString {Value = str},
|
||||
long lon => new FdbBitInt {Value = lon},
|
||||
_ => value
|
||||
};
|
||||
|
||||
dataField.value = value;
|
||||
|
||||
Data.Fields[Index] = dataField;
|
||||
}
|
||||
}
|
||||
|
||||
internal Field(FdbRowData data, int index, Table table)
|
||||
{
|
||||
Data = data;
|
||||
Index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
InfectedRose.Database/Generic/AccessDatabaseExtensions.cs
Normal file
21
InfectedRose.Database/Generic/AccessDatabaseExtensions.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Reflection;
|
||||
|
||||
namespace InfectedRose.Database.Generic
|
||||
{
|
||||
public static class TableExtensions
|
||||
{
|
||||
public static TypedTable<T> Typed<T>(this AccessDatabase @this) where T : class
|
||||
{
|
||||
var type = typeof(T);
|
||||
|
||||
var attribute = type.GetCustomAttribute<TableAttribute>();
|
||||
|
||||
var id = attribute?.Name ?? type.Name;
|
||||
|
||||
var table = @this[id];
|
||||
|
||||
return new TypedTable<T>(table.Info, table.Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
87
InfectedRose.Database/Generic/TypedTable.cs
Normal file
87
InfectedRose.Database/Generic/TypedTable.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace InfectedRose.Database.Generic
|
||||
{
|
||||
public class TypedTable<T> : Table where T : class
|
||||
{
|
||||
private readonly Dictionary<T, int> _managed;
|
||||
|
||||
internal TypedTable(FdbColumnHeader info, FdbRowBucket data) : base(info, data)
|
||||
{
|
||||
_managed = new Dictionary<T, int>();
|
||||
}
|
||||
|
||||
public new T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_managed.ContainsValue(index))
|
||||
{
|
||||
return _managed.First(m => m.Value == index).Key;
|
||||
}
|
||||
|
||||
var type = typeof(T);
|
||||
|
||||
var instance = (T) Activator.CreateInstance(type, true);
|
||||
|
||||
var baseColumn = base[index];
|
||||
|
||||
foreach (var property in type.GetProperties())
|
||||
{
|
||||
var attribute = property.GetCustomAttribute<ColumnAttribute>();
|
||||
|
||||
var id = attribute?.Name ?? property.Name;
|
||||
|
||||
var data = baseColumn[id].Value;
|
||||
|
||||
property.SetValue(instance, data);
|
||||
}
|
||||
|
||||
_managed[instance] = index;
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public new T Create()
|
||||
{
|
||||
base.Create(out var index);
|
||||
|
||||
return this[index];
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
var type = typeof(T);
|
||||
|
||||
var properties = type.GetProperties();
|
||||
|
||||
foreach (var (column, index) in _managed)
|
||||
{
|
||||
var baseColumn = base[index];
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var attribute = property.GetCustomAttribute<ColumnAttribute>();
|
||||
|
||||
var id = attribute?.Name ?? property.Name;
|
||||
|
||||
var value = property.GetValue(column);
|
||||
|
||||
var data = value switch
|
||||
{
|
||||
long lon => new FdbBitInt {Value = lon},
|
||||
string str => new FdbString {Value = str},
|
||||
_ => value
|
||||
};
|
||||
|
||||
baseColumn[id].Value = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
InfectedRose.Database/InfectedRose.Database.csproj
Normal file
11
InfectedRose.Database/InfectedRose.Database.csproj
Normal file
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\InfectedRose.Core\InfectedRose.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
207
InfectedRose.Database/Table.cs
Normal file
207
InfectedRose.Database/Table.cs
Normal file
@@ -0,0 +1,207 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
public class Table : IList<Column>
|
||||
{
|
||||
internal FdbColumnHeader Info { get; private set; }
|
||||
|
||||
internal FdbRowBucket Data { get; private set; }
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => Info.TableName;
|
||||
set => Info.TableName = new FdbString
|
||||
{
|
||||
Value = value
|
||||
};
|
||||
}
|
||||
|
||||
public TableInfo TableInfo => new TableInfo(this);
|
||||
|
||||
internal Table(FdbColumnHeader info, FdbRowBucket data)
|
||||
{
|
||||
Info = info;
|
||||
Data = data;
|
||||
}
|
||||
|
||||
private List<Column> Fields
|
||||
{
|
||||
get
|
||||
{
|
||||
var columns = new List<Column>();
|
||||
|
||||
foreach (var info in Data.RowHeader.RowInfos)
|
||||
{
|
||||
var linked = info;
|
||||
|
||||
while (linked != default)
|
||||
{
|
||||
columns.Add(new Column(linked, this));
|
||||
|
||||
linked = linked.Linked;
|
||||
}
|
||||
}
|
||||
|
||||
return columns;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<Column> GetEnumerator()
|
||||
{
|
||||
return Fields.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void Add(Column item)
|
||||
{
|
||||
if (item == default) return;
|
||||
|
||||
var list = Data.RowHeader.RowInfos.ToList();
|
||||
|
||||
list.Add(item.Data);
|
||||
|
||||
Data.RowHeader.RowInfos = list.ToArray();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Data.RowHeader.RowInfos = new FdbRowInfo[0];
|
||||
}
|
||||
|
||||
public bool Contains(Column item)
|
||||
{
|
||||
return Fields.Contains(item);
|
||||
}
|
||||
|
||||
public void CopyTo(Column[] array, int arrayIndex)
|
||||
{
|
||||
Fields.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public bool Remove(Column item)
|
||||
{
|
||||
if (item == default) return false;
|
||||
|
||||
foreach (var info in Data.RowHeader.RowInfos)
|
||||
{
|
||||
var linked = info;
|
||||
|
||||
if (linked == item.Data)
|
||||
{
|
||||
var fields = Data.RowHeader.RowInfos.ToList();
|
||||
|
||||
fields.Remove(linked);
|
||||
|
||||
Data.RowHeader.RowInfos = fields.ToArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
while (linked != default)
|
||||
{
|
||||
if (linked.Linked == item.Data)
|
||||
{
|
||||
linked.Linked = default;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
linked = linked.Linked;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int Count => Fields.Count;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public int IndexOf(Column item)
|
||||
{
|
||||
return Fields.IndexOf(item);
|
||||
}
|
||||
|
||||
public void Insert(int index, Column item)
|
||||
{
|
||||
if (item == default) return;
|
||||
|
||||
var list = Data.RowHeader.RowInfos.ToList();
|
||||
|
||||
list.Insert(index, item.Data);
|
||||
|
||||
Data.RowHeader.RowInfos = list.ToArray();
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
Remove(this[index]);
|
||||
}
|
||||
|
||||
public Column this[int index]
|
||||
{
|
||||
get => Fields[index];
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public Column Create() => Create(out _);
|
||||
|
||||
public Column Create(out int index)
|
||||
{
|
||||
var list = Data.RowHeader.RowInfos.ToList();
|
||||
|
||||
var column = new FdbRowInfo
|
||||
{
|
||||
DataHeader = new FdbRowDataHeader
|
||||
{
|
||||
Data = new FdbRowData((uint) Info.Data.Fields.Length)
|
||||
}
|
||||
};
|
||||
|
||||
for (var i = 0; i < Info.Data.Fields.Length; i++)
|
||||
{
|
||||
var type = Info.Data.Fields[i].type;
|
||||
|
||||
column.DataHeader.Data.Fields[i] = (type, GetDefault(type));
|
||||
}
|
||||
|
||||
index = list.Count;
|
||||
|
||||
list.Add(column);
|
||||
|
||||
Data.RowHeader.RowInfos = list.ToArray();
|
||||
|
||||
return new Column(column, this);
|
||||
}
|
||||
|
||||
private object GetDefault(DataType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
DataType.Nothing => (object) 0,
|
||||
DataType.Integer => 0,
|
||||
DataType.Unknown1 => 0,
|
||||
DataType.Float => 0,
|
||||
DataType.Boolean => 0,
|
||||
DataType.Unknown2 => 0,
|
||||
DataType.Varchar => new FdbString(),
|
||||
DataType.Text => new FdbString(),
|
||||
DataType.Bigint => new FdbBitInt(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
|
||||
};
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
120
InfectedRose.Database/TableInfo.cs
Normal file
120
InfectedRose.Database/TableInfo.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace InfectedRose.Database
|
||||
{
|
||||
public class TableInfo : IList<ColumnInfo>
|
||||
{
|
||||
internal Table Table { get; private set; }
|
||||
|
||||
internal TableInfo(Table table)
|
||||
{
|
||||
Table = table;
|
||||
}
|
||||
|
||||
public IEnumerator<ColumnInfo> GetEnumerator()
|
||||
{
|
||||
int index = default;
|
||||
|
||||
return Table.Info.Data.Fields.Select(
|
||||
field => new ColumnInfo(Table, index++)
|
||||
).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void Add(ColumnInfo item)
|
||||
{
|
||||
if (item == default) return;
|
||||
|
||||
var list = Table.Info.Data.Fields.ToList();
|
||||
|
||||
list.Add((item.Type, new FdbString
|
||||
{
|
||||
Value = item.Name
|
||||
}));
|
||||
|
||||
Table.Info.Data.Fields = list.ToArray();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Table.Info.Data.Fields = new (DataType type, FdbString name)[0];
|
||||
}
|
||||
|
||||
public bool Contains(ColumnInfo item)
|
||||
{
|
||||
return item != default && Table.Info.Data.Fields.Any(f => f.name == item.Name);
|
||||
}
|
||||
|
||||
public void CopyTo(ColumnInfo[] array, int arrayIndex)
|
||||
{
|
||||
int index = default;
|
||||
|
||||
var list = Table.Info.Data.Fields.Select(field => new ColumnInfo(Table, index++)).ToList();
|
||||
|
||||
list.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public bool Remove(ColumnInfo item)
|
||||
{
|
||||
if (item == default) return false;
|
||||
|
||||
var list = Table.Info.Data.Fields.ToList();
|
||||
|
||||
list.Remove(list.First(l => l.name == item.Name));
|
||||
|
||||
Table.Info.Data.Fields = list.ToArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int Count => Table.Info.Data.Fields.Length;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public int IndexOf(ColumnInfo item)
|
||||
{
|
||||
return item?.Index ?? -1;
|
||||
}
|
||||
|
||||
public void Insert(int index, ColumnInfo item)
|
||||
{
|
||||
if (item == default) return;
|
||||
|
||||
var list = Table.Info.Data.Fields.ToList();
|
||||
|
||||
list.Insert(index, (item.Type, new FdbString
|
||||
{
|
||||
Value = item.Name
|
||||
}));
|
||||
|
||||
Table.Info.Data.Fields = list.ToArray();
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
Remove(this[index]);
|
||||
}
|
||||
|
||||
public ColumnInfo this[int index]
|
||||
{
|
||||
get => new ColumnInfo(Table, index);
|
||||
set
|
||||
{
|
||||
var list = Table.Info.Data.Fields.ToList();
|
||||
|
||||
list[index] = (value.Type, new FdbString
|
||||
{
|
||||
Value = value.Name
|
||||
});
|
||||
|
||||
Table.Info.Data.Fields = list.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
InfectedRose.Examples/InfectedRose.Examples.csproj
Normal file
15
InfectedRose.Examples/InfectedRose.Examples.csproj
Normal file
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\InfectedRose.Database\InfectedRose.Database.csproj" />
|
||||
<ProjectReference Include="..\InfectedRose.Luz\InfectedRose.Luz.csproj" />
|
||||
<ProjectReference Include="..\InfectedRose.Lvl\InfectedRose.Lvl.csproj" />
|
||||
<ProjectReference Include="..\InfectedRose.Terrain\InfectedRose.Terrain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
251
InfectedRose.Examples/Program.cs
Normal file
251
InfectedRose.Examples/Program.cs
Normal file
@@ -0,0 +1,251 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using InfectedRose.Database;
|
||||
using InfectedRose.Database.Generic;
|
||||
using InfectedRose.Luz;
|
||||
using InfectedRose.Lvl;
|
||||
using InfectedRose.Terrain;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Examples
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
private static async Task Main(string[] args)
|
||||
{
|
||||
Console.Write("Type: ");
|
||||
|
||||
if (!int.TryParse(Console.ReadLine(), out var i)) return;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
await Terrain(args);
|
||||
return;
|
||||
case 1:
|
||||
await Luz(args);
|
||||
return;
|
||||
case 2:
|
||||
await Lvl(args);
|
||||
return;
|
||||
case 3:
|
||||
await LvlTest(args);
|
||||
return;
|
||||
case 4:
|
||||
await Database(args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task Database(IReadOnlyList<string> args)
|
||||
{
|
||||
string file;
|
||||
|
||||
if (args.Count > 0)
|
||||
{
|
||||
file = args[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write("File: ");
|
||||
|
||||
file = Console.ReadLine();
|
||||
}
|
||||
|
||||
var databaseFile = new DatabaseFile();
|
||||
|
||||
await using (var fileStream = File.OpenRead(file))
|
||||
{
|
||||
using var reader = new BitReader(fileStream);
|
||||
|
||||
databaseFile.Deserialize(reader);
|
||||
}
|
||||
|
||||
var database = new AccessDatabase(databaseFile);
|
||||
|
||||
var table = database.Typed<ZoneSummary>();
|
||||
|
||||
foreach (var col in table)
|
||||
{
|
||||
Console.WriteLine(col["ZoneId"].Value);
|
||||
}
|
||||
|
||||
var newColumn = table.Create();
|
||||
|
||||
newColumn.ZoneId = 42;
|
||||
|
||||
table.Save();
|
||||
|
||||
var margin = 0;
|
||||
var bytes = databaseFile.Compile(i =>
|
||||
{
|
||||
margin++;
|
||||
|
||||
if (margin != 100000) return;
|
||||
|
||||
margin = default;
|
||||
|
||||
Console.WriteLine($"{Math.Round(i / (double) databaseFile.Structure.Count * 100, 2)}%");
|
||||
});
|
||||
|
||||
File.WriteAllBytes($"{file}.new.fdb", bytes);
|
||||
}
|
||||
|
||||
private static async Task Terrain(IReadOnlyList<string> args)
|
||||
{
|
||||
string file;
|
||||
|
||||
if (args.Count > 0)
|
||||
{
|
||||
file = args[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write("File: ");
|
||||
|
||||
file = Console.ReadLine();
|
||||
}
|
||||
|
||||
var terrain = new TerrainFile();
|
||||
|
||||
await using (var fileStream = File.OpenRead(file))
|
||||
{
|
||||
using var reader = new BitReader(fileStream);
|
||||
|
||||
terrain.Deserialize(reader);
|
||||
|
||||
foreach (var chunk in terrain.Chunks)
|
||||
{
|
||||
var data = chunk.HeightMap.Data;
|
||||
|
||||
var min = data.Min();
|
||||
var max = data.Max();
|
||||
|
||||
uint randomIndex = default;
|
||||
for (var i = 0; i < data.Length; i++)
|
||||
{
|
||||
if (randomIndex++ == 100)
|
||||
{
|
||||
data[i] = max;
|
||||
}
|
||||
else if (randomIndex == 200)
|
||||
{
|
||||
data[i] = min;
|
||||
|
||||
randomIndex = default;
|
||||
}
|
||||
}
|
||||
|
||||
chunk.HeightMap.Data = data;
|
||||
}
|
||||
}
|
||||
|
||||
await using var writeStream = File.OpenWrite(file);
|
||||
using var writer = new BitWriter(writeStream);
|
||||
|
||||
terrain.Serialize(writer);
|
||||
|
||||
Console.Write("Done");
|
||||
}
|
||||
|
||||
private static async Task Luz(IReadOnlyList<string> args)
|
||||
{
|
||||
string file;
|
||||
|
||||
if (args.Count > 0)
|
||||
{
|
||||
file = args[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write("File: ");
|
||||
|
||||
file = Console.ReadLine();
|
||||
}
|
||||
|
||||
var luz = new LuzFile();
|
||||
|
||||
await using (var fileStream = File.OpenRead(file))
|
||||
{
|
||||
using var reader = new BitReader(fileStream);
|
||||
|
||||
luz.Deserialize(reader);
|
||||
}
|
||||
|
||||
await using var writeStream = File.OpenWrite(file);
|
||||
using var writer = new BitWriter(writeStream);
|
||||
|
||||
luz.Serialize(writer);
|
||||
|
||||
Console.Write("Done");
|
||||
}
|
||||
|
||||
private static async Task Lvl(IReadOnlyList<string> args)
|
||||
{
|
||||
string file;
|
||||
|
||||
if (args.Count > 0)
|
||||
{
|
||||
file = args[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write("File: ");
|
||||
|
||||
file = Console.ReadLine();
|
||||
}
|
||||
|
||||
var lvl = new LvlFile();
|
||||
|
||||
await using (var fileStream = File.OpenRead(file))
|
||||
{
|
||||
using var reader = new BitReader(fileStream);
|
||||
|
||||
lvl.Deserialize(reader);
|
||||
}
|
||||
|
||||
await using var writeStream = File.OpenWrite(file);
|
||||
using var writer = new BitWriter(writeStream);
|
||||
|
||||
lvl.Serialize(writer);
|
||||
|
||||
Console.Write("Done");
|
||||
}
|
||||
|
||||
private static async Task LvlTest(IReadOnlyList<string> args)
|
||||
{
|
||||
string dir;
|
||||
|
||||
if (args.Count > 0)
|
||||
{
|
||||
dir = args[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write("Dir: ");
|
||||
|
||||
dir = Console.ReadLine();
|
||||
}
|
||||
|
||||
foreach (var file in Directory.GetFiles(dir, "*.lvl", SearchOption.AllDirectories))
|
||||
{
|
||||
var lvl = new LvlFile();
|
||||
|
||||
await using var fileStream = File.OpenRead(file);
|
||||
|
||||
using var reader = new BitReader(fileStream);
|
||||
|
||||
Console.Write($"{file} -> ");
|
||||
|
||||
lvl.Deserialize(reader);
|
||||
|
||||
Console.Write('\n');
|
||||
}
|
||||
|
||||
Console.Write("Done");
|
||||
}
|
||||
}
|
||||
}
|
||||
16
InfectedRose.Examples/ZoneSummary.cs
Normal file
16
InfectedRose.Examples/ZoneSummary.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace InfectedRose.Examples
|
||||
{
|
||||
[Table("ZoneSummary")]
|
||||
public class ZoneSummary
|
||||
{
|
||||
[Column("zoneId")] public int ZoneId { get; set; }
|
||||
|
||||
[Column("type")] public int Type { get; set; }
|
||||
|
||||
[Column("value")] public int Value { get; set; }
|
||||
|
||||
[Column("_uniqueID")] public int UniqueId { get; set; }
|
||||
}
|
||||
}
|
||||
17
InfectedRose.Luz/Enums/AchievementRequired.cs
Normal file
17
InfectedRose.Luz/Enums/AchievementRequired.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public enum AchievementRequired
|
||||
{
|
||||
None,
|
||||
Builder,
|
||||
Craftsman,
|
||||
SeniorBuilder,
|
||||
Journeyman,
|
||||
MasterBuilder,
|
||||
Architect,
|
||||
SeniorArchitect,
|
||||
MasterArchitect,
|
||||
Visionary,
|
||||
Exemplar
|
||||
}
|
||||
}
|
||||
9
InfectedRose.Luz/Enums/PathBehavior.cs
Normal file
9
InfectedRose.Luz/Enums/PathBehavior.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public enum PathBehavior : uint
|
||||
{
|
||||
Loop,
|
||||
Bounce,
|
||||
Once
|
||||
}
|
||||
}
|
||||
14
InfectedRose.Luz/Enums/PathType.cs
Normal file
14
InfectedRose.Luz/Enums/PathType.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public enum PathType : uint
|
||||
{
|
||||
Movement,
|
||||
MovingPlatform,
|
||||
Property,
|
||||
Camera,
|
||||
Spawner,
|
||||
Showcase,
|
||||
Race,
|
||||
Rail
|
||||
}
|
||||
}
|
||||
14
InfectedRose.Luz/Enums/RentalTimeUnit.cs
Normal file
14
InfectedRose.Luz/Enums/RentalTimeUnit.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public enum RentalTimeUnit
|
||||
{
|
||||
Forever,
|
||||
Seconds,
|
||||
Minutes,
|
||||
Hours,
|
||||
Days,
|
||||
Weeks,
|
||||
Months,
|
||||
Years
|
||||
}
|
||||
}
|
||||
11
InfectedRose.Luz/InfectedRose.Luz.csproj
Normal file
11
InfectedRose.Luz/InfectedRose.Luz.csproj
Normal file
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\InfectedRose.Core\InfectedRose.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
39
InfectedRose.Luz/LuzCameraPath.cs
Normal file
39
InfectedRose.Luz/LuzCameraPath.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzCameraPath : LuzPathData
|
||||
{
|
||||
public string NextPath { get; set; }
|
||||
|
||||
public bool UnknownBool { get; set; }
|
||||
|
||||
public LuzCameraPath(uint version) : base(version)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteNiString(NextPath, true, true);
|
||||
|
||||
if (Version >= 14)
|
||||
writer.Write((byte) (UnknownBool ? 1 : 0));
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
NextPath = reader.ReadNiString(true, true);
|
||||
|
||||
Console.WriteLine(NextPath);
|
||||
|
||||
if (Version >= 14)
|
||||
UnknownBool = reader.Read<byte>() != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
InfectedRose.Luz/LuzCameraWaypoint.cs
Normal file
60
InfectedRose.Luz/LuzCameraWaypoint.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzCameraWaypoint : LuzPathWaypoint
|
||||
{
|
||||
public Quaternion Rotation { get; set; }
|
||||
|
||||
public float Time { get; set; }
|
||||
|
||||
public float Tension { get; set; }
|
||||
|
||||
public float Continuity { get; set; }
|
||||
|
||||
public float Bias { get; set; }
|
||||
|
||||
public float FieldOfView { get; set; }
|
||||
|
||||
public LuzCameraWaypoint(uint version) : base(version)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteNiQuaternion(Rotation);
|
||||
|
||||
writer.Write(Time);
|
||||
|
||||
writer.Write(FieldOfView);
|
||||
|
||||
writer.Write(Tension);
|
||||
|
||||
writer.Write(Continuity);
|
||||
|
||||
writer.Write(Bias);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
Rotation = reader.ReadNiQuaternion();
|
||||
|
||||
Time = reader.Read<float>();
|
||||
|
||||
FieldOfView = reader.Read<float>();
|
||||
|
||||
Tension = reader.Read<float>();
|
||||
|
||||
Continuity = reader.Read<float>();
|
||||
|
||||
Bias = reader.Read<float>();
|
||||
}
|
||||
}
|
||||
}
|
||||
239
InfectedRose.Luz/LuzFile.cs
Normal file
239
InfectedRose.Luz/LuzFile.cs
Normal file
@@ -0,0 +1,239 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzFile : IConstruct
|
||||
{
|
||||
public uint Version { get; set; }
|
||||
|
||||
public uint RevisionNumber { get; set; }
|
||||
|
||||
public uint WorldId { get; set; }
|
||||
|
||||
public Vector3 SpawnPoint { get; set; }
|
||||
|
||||
public Quaternion SpawnRotation { get; set; }
|
||||
|
||||
public LuzScene[] Scenes { get; set; }
|
||||
|
||||
public byte UnknownByte { get; set; }
|
||||
|
||||
public string TerrainFileName { get; set; }
|
||||
|
||||
public string TerrainFile { get; set; }
|
||||
|
||||
public string TerrainDescription { get; set; }
|
||||
|
||||
public LuzSceneTransition[] Transitions { get; set; }
|
||||
|
||||
public LuzPathData[] PathData { get; set; }
|
||||
|
||||
//public LvlFile[] LvlFiles { get; set; }
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(Version);
|
||||
|
||||
if (Version >= 0x24)
|
||||
{
|
||||
writer.Write(RevisionNumber);
|
||||
}
|
||||
|
||||
writer.Write(WorldId);
|
||||
|
||||
if (Version >= 0x26)
|
||||
{
|
||||
writer.Write(SpawnPoint);
|
||||
writer.Write(SpawnRotation);
|
||||
}
|
||||
|
||||
if (Version < 0x25)
|
||||
{
|
||||
writer.Write((byte) Scenes.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write((uint) Scenes.Length);
|
||||
}
|
||||
|
||||
foreach (var scene in Scenes)
|
||||
{
|
||||
scene.Serialize(writer);
|
||||
}
|
||||
|
||||
writer.Write(UnknownByte);
|
||||
|
||||
writer.WriteNiString(TerrainFileName, false, true);
|
||||
|
||||
writer.WriteNiString(TerrainFile, false, true);
|
||||
|
||||
writer.WriteNiString(TerrainDescription, false, true);
|
||||
|
||||
if (Version >= 20)
|
||||
{
|
||||
writer.Write((uint) Transitions.Length);
|
||||
|
||||
foreach (var transition in Transitions)
|
||||
{
|
||||
transition.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
if (Version < 0x23) return;
|
||||
|
||||
var position = writer.BaseStream.Position;
|
||||
|
||||
WritePaths(writer);
|
||||
|
||||
var finishPosition = writer.BaseStream.Position;
|
||||
|
||||
writer.BaseStream.Position = position;
|
||||
|
||||
writer.Write(finishPosition - position - 4);
|
||||
}
|
||||
|
||||
private void WritePaths(BitWriter writer)
|
||||
{
|
||||
writer.BaseStream.Position += 4;
|
||||
|
||||
writer.Write((uint) 1);
|
||||
|
||||
writer.Write((uint) PathData.Length);
|
||||
|
||||
foreach (var pathData in PathData)
|
||||
{
|
||||
writer.Write(pathData.Version);
|
||||
|
||||
writer.WriteNiString(pathData.PathName, true, true);
|
||||
|
||||
writer.Write((uint) pathData.Type);
|
||||
|
||||
writer.Write(pathData.UnknownInt);
|
||||
|
||||
pathData.Serialize(writer);
|
||||
|
||||
writer.Write((uint) pathData.Waypoints.Length);
|
||||
|
||||
foreach (var waypoint in pathData.Waypoints)
|
||||
{
|
||||
waypoint.Serialize(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
Version = reader.Read<uint>();
|
||||
|
||||
if (Version >= 0x24)
|
||||
{
|
||||
RevisionNumber = reader.Read<uint>();
|
||||
}
|
||||
|
||||
WorldId = reader.Read<uint>();
|
||||
|
||||
if (Version >= 0x26)
|
||||
{
|
||||
SpawnPoint = reader.Read<Vector3>();
|
||||
SpawnRotation = reader.Read<Quaternion>();
|
||||
}
|
||||
|
||||
var sceneCount = Version < 0x25 ? reader.Read<byte>() : reader.Read<uint>();
|
||||
|
||||
Scenes = new LuzScene[sceneCount];
|
||||
//LvlFiles = new LvlFile[sceneCount];
|
||||
|
||||
for (var i = 0; i < sceneCount; i++)
|
||||
{
|
||||
Scenes[i] = new LuzScene();
|
||||
Scenes[i].Deserialize(reader);
|
||||
|
||||
//LvlFiles[i] = new LvlFile($"{Path.GetDirectoryName(path)}/{Scenes[i].FileName}");
|
||||
}
|
||||
|
||||
UnknownByte = reader.Read<byte>();
|
||||
|
||||
TerrainFileName = reader.ReadNiString(false, true);
|
||||
|
||||
TerrainFile = reader.ReadNiString(false, true);
|
||||
|
||||
TerrainDescription = reader.ReadNiString(false, true);
|
||||
|
||||
if (Version >= 0x20)
|
||||
{
|
||||
var sceneTransitionCount = reader.Read<uint>();
|
||||
|
||||
Transitions = new LuzSceneTransition[sceneTransitionCount];
|
||||
|
||||
for (var i = 0; i < sceneTransitionCount; i++)
|
||||
{
|
||||
Transitions[i] = new LuzSceneTransition(Version);
|
||||
Transitions[i].Deserialize(reader);
|
||||
}
|
||||
}
|
||||
|
||||
if (Version < 0x23) return;
|
||||
{
|
||||
Console.WriteLine(reader.Read<uint>());
|
||||
reader.Read<uint>();
|
||||
|
||||
var pathDataCount = reader.Read<uint>();
|
||||
|
||||
PathData = new LuzPathData[pathDataCount];
|
||||
|
||||
for (var i = 0; i < pathDataCount; i++)
|
||||
{
|
||||
var version = reader.Read<uint>();
|
||||
var name = reader.ReadNiString(true, true);
|
||||
var type = (PathType) reader.Read<uint>();
|
||||
|
||||
Console.WriteLine($"[{i}:{name}] -> [{type}]");
|
||||
|
||||
PathData[i] = type switch
|
||||
{
|
||||
PathType.Movement => new LuzPathData(version),
|
||||
PathType.MovingPlatform => new LuzMovingPlatformPath(version),
|
||||
PathType.Property => new LuzPropertyPath(version),
|
||||
PathType.Camera => new LuzCameraPath(version),
|
||||
PathType.Spawner => new LuzSpawnerPath(version),
|
||||
PathType.Showcase => new LuzPathData(version),
|
||||
PathType.Race => new LuzPathData(version),
|
||||
PathType.Rail => new LuzPathData(version),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
PathData[i].UnknownInt = reader.Read<uint>();
|
||||
|
||||
PathData[i].PathName = name;
|
||||
PathData[i].Type = type;
|
||||
PathData[i].Deserialize(reader);
|
||||
|
||||
var count = reader.Read<uint>();
|
||||
PathData[i].Waypoints = new LuzPathWaypoint[count];
|
||||
|
||||
for (var j = 0; j < count; j++)
|
||||
{
|
||||
PathData[i].Waypoints[j] = type switch
|
||||
{
|
||||
PathType.Movement => new LuzMovementWaypoint(version),
|
||||
PathType.MovingPlatform => new LuzMovingPlatformWaypoint(version),
|
||||
PathType.Property => new LuzPathWaypoint(version),
|
||||
PathType.Camera => new LuzCameraWaypoint(version),
|
||||
PathType.Spawner => new LuzSpawnerWaypoint(version),
|
||||
PathType.Showcase => new LuzPathWaypoint(version),
|
||||
PathType.Race => new LuzRaceWaypoint(version),
|
||||
PathType.Rail => new LuzRailWaypoint(version),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
PathData[i].Waypoints[j].Deserialize(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
InfectedRose.Luz/LuzMovementWaypoint.cs
Normal file
40
InfectedRose.Luz/LuzMovementWaypoint.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.IO;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzMovementWaypoint : LuzPathWaypoint
|
||||
{
|
||||
public LuzPathConfig[] Configs { get; set; }
|
||||
|
||||
public LuzMovementWaypoint(uint version) : base(version)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((uint) Configs.Length);
|
||||
|
||||
foreach (var config in Configs)
|
||||
{
|
||||
config.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var configCount = reader.Read<uint>();
|
||||
Configs = new LuzPathConfig[configCount];
|
||||
|
||||
for (var i = 0; i < configCount; i++)
|
||||
{
|
||||
Configs[i] = new LuzPathConfig();
|
||||
Configs[i].Deserialize(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
38
InfectedRose.Luz/LuzMovingPlatformPath.cs
Normal file
38
InfectedRose.Luz/LuzMovingPlatformPath.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzMovingPlatformPath : LuzPathData
|
||||
{
|
||||
public string MovingPlatformSound { get; set; }
|
||||
|
||||
public bool TimeBased { get; set; }
|
||||
|
||||
public LuzMovingPlatformPath(uint version) : base(version)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
if (Version >= 18)
|
||||
writer.Write((byte) (TimeBased ? 1 : 0));
|
||||
else if (Version >= 13)
|
||||
writer.WriteNiString(MovingPlatformSound, true, true);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
if (Version >= 18)
|
||||
TimeBased = reader.Read<byte>() != 0;
|
||||
else if (Version >= 13)
|
||||
MovingPlatformSound = reader.ReadNiString(true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
67
InfectedRose.Luz/LuzMovingPlatformWaypoint.cs
Normal file
67
InfectedRose.Luz/LuzMovingPlatformWaypoint.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzMovingPlatformWaypoint : LuzPathWaypoint
|
||||
{
|
||||
public Quaternion Rotation { get; set; }
|
||||
|
||||
public bool LockPlayer { get; set; }
|
||||
|
||||
public float Speed { get; set; }
|
||||
|
||||
public float Wait { get; set; }
|
||||
|
||||
public string DepartSound { get; set; }
|
||||
|
||||
public string ArriveSound { get; set; }
|
||||
|
||||
public LuzMovingPlatformWaypoint(uint version) : base(version)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteNiQuaternion(Rotation);
|
||||
|
||||
writer.Write((byte) (LockPlayer ? 1 : 0));
|
||||
|
||||
writer.Write(Speed);
|
||||
|
||||
writer.Write(Wait);
|
||||
|
||||
if (Version < 13) return;
|
||||
|
||||
writer.WriteNiString(DepartSound, true, true);
|
||||
|
||||
writer.WriteNiString(ArriveSound, true, true);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
Rotation = reader.ReadNiQuaternion();
|
||||
|
||||
LockPlayer = reader.Read<byte>() != 0;
|
||||
|
||||
Speed = reader.Read<float>();
|
||||
|
||||
Wait = reader.Read<float>();
|
||||
|
||||
if (Version < 13) return;
|
||||
|
||||
DepartSound = reader.ReadNiString(true, true);
|
||||
|
||||
ArriveSound = reader.ReadNiString(true, true);
|
||||
|
||||
Console.WriteLine($"{DepartSound} -> {ArriveSound}");
|
||||
}
|
||||
}
|
||||
}
|
||||
25
InfectedRose.Luz/LuzPathConfig.cs
Normal file
25
InfectedRose.Luz/LuzPathConfig.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.IO;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzPathConfig : IConstruct
|
||||
{
|
||||
public string ConfigName { get; set; }
|
||||
|
||||
public string ConfigTypeAndValue { get; set; }
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.WriteNiString(ConfigName, true, true);
|
||||
writer.WriteNiString(ConfigTypeAndValue, true, true);
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
ConfigName = reader.ReadNiString(true, true);
|
||||
ConfigTypeAndValue = reader.ReadNiString(true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
InfectedRose.Luz/LuzPathData.cs
Normal file
38
InfectedRose.Luz/LuzPathData.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
[Serializable]
|
||||
public class LuzPathData : IConstruct
|
||||
{
|
||||
public uint Version { get; set; }
|
||||
|
||||
public string PathName { get; set; }
|
||||
|
||||
public uint UnknownInt { get; set; }
|
||||
|
||||
public PathType Type { get; set; }
|
||||
|
||||
public PathBehavior Behavior { get; set; }
|
||||
|
||||
public LuzPathWaypoint[] Waypoints { get; set; }
|
||||
|
||||
public LuzPathData(uint version)
|
||||
{
|
||||
Version = version;
|
||||
}
|
||||
|
||||
public virtual void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write((uint) Behavior);
|
||||
}
|
||||
|
||||
public virtual void Deserialize(BitReader reader)
|
||||
{
|
||||
Behavior = (PathBehavior) reader.Read<uint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
29
InfectedRose.Luz/LuzPathWaypoint.cs
Normal file
29
InfectedRose.Luz/LuzPathWaypoint.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzPathWaypoint : IConstruct
|
||||
{
|
||||
public Vector3 Position { get; set; }
|
||||
|
||||
public uint Version { get; set; }
|
||||
|
||||
public LuzPathWaypoint(uint version)
|
||||
{
|
||||
Version = version;
|
||||
}
|
||||
|
||||
public virtual void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(Position);
|
||||
}
|
||||
|
||||
public virtual void Deserialize(BitReader reader)
|
||||
{
|
||||
Position = reader.Read<Vector3>();
|
||||
}
|
||||
}
|
||||
}
|
||||
102
InfectedRose.Luz/LuzPropertyPath.cs
Normal file
102
InfectedRose.Luz/LuzPropertyPath.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzPropertyPath : LuzPathData
|
||||
{
|
||||
public int UnknownInt0 { get; set; }
|
||||
|
||||
public int UnknownInt1 { get; set; }
|
||||
|
||||
public int Price { get; set; }
|
||||
|
||||
public int RentalTime { get; set; }
|
||||
|
||||
public ulong AssociatedZone { get; set; }
|
||||
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
public string DisplayDescription { get; set; }
|
||||
|
||||
public int CloneLimit { get; set; }
|
||||
|
||||
public float ReputationMultiplier { get; set; }
|
||||
|
||||
public RentalTimeUnit TimeUnit { get; set; }
|
||||
|
||||
public AchievementRequired Achievement { get; set; }
|
||||
|
||||
public Vector3 PlayerZonePoint { get; set; }
|
||||
|
||||
public float MaxBuildHeight { get; set; }
|
||||
|
||||
public LuzPropertyPath(uint version) : base(version)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(UnknownInt0);
|
||||
|
||||
writer.Write(Price);
|
||||
|
||||
writer.Write(RentalTime);
|
||||
|
||||
writer.Write(AssociatedZone);
|
||||
|
||||
writer.WriteNiString(DisplayName, true, true);
|
||||
|
||||
writer.WriteNiString(DisplayDescription, true);
|
||||
|
||||
writer.Write(UnknownInt1);
|
||||
|
||||
writer.Write(CloneLimit);
|
||||
|
||||
writer.Write(ReputationMultiplier);
|
||||
|
||||
writer.Write((int) TimeUnit);
|
||||
|
||||
writer.Write((int) Achievement);
|
||||
|
||||
writer.Write(PlayerZonePoint);
|
||||
|
||||
writer.Write(MaxBuildHeight);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
UnknownInt0 = reader.Read<int>();
|
||||
|
||||
Price = reader.Read<int>();
|
||||
|
||||
RentalTime = reader.Read<int>();
|
||||
|
||||
AssociatedZone = reader.Read<ulong>();
|
||||
|
||||
DisplayName = reader.ReadNiString(true, true);
|
||||
|
||||
DisplayDescription = reader.ReadNiString(true);
|
||||
|
||||
UnknownInt1 = reader.Read<int>();
|
||||
|
||||
CloneLimit = reader.Read<int>();
|
||||
|
||||
ReputationMultiplier = reader.Read<float>();
|
||||
|
||||
TimeUnit = (RentalTimeUnit) reader.Read<int>();
|
||||
|
||||
Achievement = (AchievementRequired) reader.Read<int>();
|
||||
|
||||
PlayerZonePoint = reader.Read<Vector3>();
|
||||
|
||||
MaxBuildHeight = reader.Read<float>();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
InfectedRose.Luz/LuzRaceWaypoint.cs
Normal file
42
InfectedRose.Luz/LuzRaceWaypoint.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzRaceWaypoint : LuzPathWaypoint
|
||||
{
|
||||
public Quaternion Rotation { get; set; }
|
||||
|
||||
public byte[] UnknownBytes { get; set; }
|
||||
|
||||
public Vector3 UnknownVector { get; set; }
|
||||
|
||||
public LuzRaceWaypoint(uint version) : base(version)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteNiQuaternion(Rotation);
|
||||
|
||||
writer.Write(UnknownBytes);
|
||||
|
||||
writer.Write(UnknownVector);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
Rotation = reader.ReadNiQuaternion();
|
||||
|
||||
UnknownBytes = reader.ReadBuffer(2);
|
||||
|
||||
UnknownVector = reader.Read<Vector3>();
|
||||
}
|
||||
}
|
||||
}
|
||||
60
InfectedRose.Luz/LuzRailWaypoint.cs
Normal file
60
InfectedRose.Luz/LuzRailWaypoint.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzRailWaypoint : LuzPathWaypoint
|
||||
{
|
||||
public LuzPathConfig[] Configs { get; set; }
|
||||
|
||||
public Quaternion UnknownQuaternion { get; set; }
|
||||
|
||||
public float Speed { get; set; }
|
||||
|
||||
public LuzRailWaypoint(uint version) : base(version)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteNiQuaternion(UnknownQuaternion);
|
||||
|
||||
if (Version >= 17)
|
||||
{
|
||||
writer.Write(Speed);
|
||||
}
|
||||
|
||||
writer.Write((uint) Configs.Length);
|
||||
|
||||
foreach (var config in Configs)
|
||||
{
|
||||
config.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
UnknownQuaternion = reader.ReadNiQuaternion();
|
||||
|
||||
if (Version >= 17)
|
||||
{
|
||||
Speed = reader.Read<float>();
|
||||
}
|
||||
|
||||
var configCount = reader.Read<uint>();
|
||||
Configs = new LuzPathConfig[configCount];
|
||||
|
||||
for (var i = 0; i < configCount; i++)
|
||||
{
|
||||
Configs[i] = new LuzPathConfig();
|
||||
Configs[i].Deserialize(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
64
InfectedRose.Luz/LuzScene.cs
Normal file
64
InfectedRose.Luz/LuzScene.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
[Serializable]
|
||||
public class LuzScene : IConstruct
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
|
||||
public byte SceneId { get; set; }
|
||||
|
||||
public bool IsAudioScene { get; set; }
|
||||
|
||||
public string SceneName { get; set; }
|
||||
|
||||
public byte[] UnknownByteArray0 { get; set; } = new byte[3];
|
||||
|
||||
public byte[] UnknownByteArray1 { get; set; } = new byte[3];
|
||||
|
||||
public byte[] UnknownByteArray2 { get; set; } = new byte[3];
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.WriteNiString(FileName, false, true);
|
||||
|
||||
writer.Write(SceneId);
|
||||
|
||||
writer.Write(UnknownByteArray0);
|
||||
|
||||
writer.Write((byte) (IsAudioScene ? 1 : 0));
|
||||
|
||||
writer.Write(UnknownByteArray1);
|
||||
|
||||
writer.WriteNiString(SceneName, false, true);
|
||||
|
||||
writer.Write(UnknownByteArray2);
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
FileName = reader.ReadNiString(false, true);
|
||||
|
||||
SceneId = reader.Read<byte>();
|
||||
|
||||
UnknownByteArray0 = reader.ReadBuffer(3);
|
||||
|
||||
IsAudioScene = reader.Read<byte>() != 0;
|
||||
|
||||
UnknownByteArray1 = reader.ReadBuffer(3);
|
||||
|
||||
SceneName = reader.ReadNiString(false, true);
|
||||
|
||||
UnknownByteArray2 = reader.ReadBuffer(3);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return FileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
InfectedRose.Luz/LuzSceneTransition.cs
Normal file
53
InfectedRose.Luz/LuzSceneTransition.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
[Serializable]
|
||||
public class LuzSceneTransition : IConstruct
|
||||
{
|
||||
public string SceneTransitionName { get; set; }
|
||||
|
||||
public LuzSceneTransitionPoint[] TransitionPoints { get; set; }
|
||||
|
||||
public uint Version { get; set; }
|
||||
|
||||
public LuzSceneTransition(uint version)
|
||||
{
|
||||
Version = version;
|
||||
}
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
if (Version < 0x25)
|
||||
{
|
||||
writer.WriteNiString(SceneTransitionName, false, true);
|
||||
}
|
||||
|
||||
foreach (var transitionPoint in TransitionPoints)
|
||||
{
|
||||
transitionPoint.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
if (Version < 0x25)
|
||||
{
|
||||
SceneTransitionName = reader.ReadNiString(false, true);
|
||||
}
|
||||
|
||||
var pointCount = Version <= 21 || Version >= 0x27 ? 2 : 5;
|
||||
|
||||
TransitionPoints = new LuzSceneTransitionPoint[pointCount];
|
||||
|
||||
for (var i = 0; i < pointCount; i++)
|
||||
{
|
||||
TransitionPoints[i] = new LuzSceneTransitionPoint();
|
||||
TransitionPoints[i].Deserialize(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
InfectedRose.Luz/LuzSceneTransitionPoint.cs
Normal file
30
InfectedRose.Luz/LuzSceneTransitionPoint.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
[Serializable]
|
||||
public class LuzSceneTransitionPoint : IConstruct
|
||||
{
|
||||
public ulong SceneId { get; set; }
|
||||
|
||||
public Vector3 Point { get; set; }
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(SceneId);
|
||||
|
||||
writer.Write(Point);
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
SceneId = reader.Read<ulong>();
|
||||
|
||||
Point = reader.Read<Vector3>();
|
||||
}
|
||||
}
|
||||
}
|
||||
60
InfectedRose.Luz/LuzSpawnerPath.cs
Normal file
60
InfectedRose.Luz/LuzSpawnerPath.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System.IO;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzSpawnerPath : LuzPathData
|
||||
{
|
||||
public uint SpawnedLot { get; set; }
|
||||
|
||||
public uint RespawnTime { get; set; }
|
||||
|
||||
public int MaxSpawnCount { get; set; }
|
||||
|
||||
public uint NumberToMaintain { get; set; }
|
||||
|
||||
public long SpawnerObjectId { get; set; }
|
||||
|
||||
public bool ActivateSpawnerNetworkOnLoad { get; set; }
|
||||
|
||||
public LuzSpawnerPath(uint version) : base(version)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(SpawnedLot);
|
||||
|
||||
writer.Write(RespawnTime);
|
||||
|
||||
writer.Write(MaxSpawnCount);
|
||||
|
||||
writer.Write(NumberToMaintain);
|
||||
|
||||
writer.Write(SpawnerObjectId);
|
||||
|
||||
if (Version > 8)
|
||||
writer.Write((byte) (ActivateSpawnerNetworkOnLoad ? 1 : 0));
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
SpawnedLot = reader.Read<uint>();
|
||||
|
||||
RespawnTime = reader.Read<uint>();
|
||||
|
||||
MaxSpawnCount = reader.Read<int>();
|
||||
|
||||
NumberToMaintain = reader.Read<uint>();
|
||||
|
||||
SpawnerObjectId = reader.Read<long>();
|
||||
|
||||
if (Version > 8)
|
||||
ActivateSpawnerNetworkOnLoad = reader.Read<byte>() != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
InfectedRose.Luz/LuzSpawnerWaypoint.cs
Normal file
48
InfectedRose.Luz/LuzSpawnerWaypoint.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Numerics;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Luz
|
||||
{
|
||||
public class LuzSpawnerWaypoint : LuzPathWaypoint
|
||||
{
|
||||
public Quaternion Rotation { get; set; }
|
||||
|
||||
public LuzPathConfig[] Configs { get; set; }
|
||||
|
||||
public LuzSpawnerWaypoint(uint version) : base(version)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteNiQuaternion(Quaternion.Identity);
|
||||
|
||||
writer.Write((uint) Configs.Length);
|
||||
|
||||
foreach (var config in Configs)
|
||||
{
|
||||
config.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
Rotation = reader.ReadNiQuaternion();
|
||||
|
||||
var configCount = reader.Read<uint>();
|
||||
|
||||
Configs = new LuzPathConfig[configCount];
|
||||
|
||||
for (var i = 0; i < configCount; i++)
|
||||
{
|
||||
Configs[i] = new LuzPathConfig();
|
||||
Configs[i].Deserialize(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
InfectedRose.Lvl/ChunkBase.cs
Normal file
16
InfectedRose.Lvl/ChunkBase.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Lvl
|
||||
{
|
||||
public abstract class ChunkBase : IConstruct
|
||||
{
|
||||
public ushort Index { get; set; }
|
||||
|
||||
public abstract uint ChunkType { get; }
|
||||
|
||||
public abstract void Serialize(BitWriter writer);
|
||||
|
||||
public abstract void Deserialize(BitReader reader);
|
||||
}
|
||||
}
|
||||
33
InfectedRose.Lvl/IdStruct.cs
Normal file
33
InfectedRose.Lvl/IdStruct.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.IO;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Lvl
|
||||
{
|
||||
public class IdStruct : IConstruct
|
||||
{
|
||||
public uint Id { get; set; }
|
||||
|
||||
public float UnknownFloat0 { get; set; }
|
||||
|
||||
public float UnknownFloat1 { get; set; }
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(Id);
|
||||
|
||||
writer.Write(UnknownFloat0);
|
||||
|
||||
writer.Write(UnknownFloat1);
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
Id = reader.Read<uint>();
|
||||
|
||||
UnknownFloat0 = reader.Read<float>();
|
||||
|
||||
UnknownFloat1 = reader.Read<float>();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
InfectedRose.Lvl/InfectedRose.Lvl.csproj
Normal file
11
InfectedRose.Lvl/InfectedRose.Lvl.csproj
Normal file
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\InfectedRose.Core\InfectedRose.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
234
InfectedRose.Lvl/LegoDataDictionary.cs
Normal file
234
InfectedRose.Lvl/LegoDataDictionary.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
||||
namespace Lvl
|
||||
{
|
||||
public class LegoDataDictionary : IDictionary<string, object>
|
||||
{
|
||||
public const char InfoSeparator = '\u001F';
|
||||
private readonly Dictionary<string, (byte, object)> _map;
|
||||
|
||||
public int Count => _map.Count;
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public ICollection<string> Keys => _map.Keys;
|
||||
public ICollection<object> Values => _map.Values.Select(v => v.Item2).ToArray();
|
||||
|
||||
public object this[string key]
|
||||
{
|
||||
get => _map[key].Item2;
|
||||
set => Add(key, value);
|
||||
}
|
||||
|
||||
public object this[string key, byte type]
|
||||
{
|
||||
get => _map[key].Item2;
|
||||
set => Add(key, value, type);
|
||||
}
|
||||
|
||||
public LegoDataDictionary()
|
||||
{
|
||||
_map = new Dictionary<string, (byte, object)>();
|
||||
}
|
||||
|
||||
public void Add(string key, object value, byte type)
|
||||
=> _map[key] = (type, value);
|
||||
|
||||
public void Add(string key, object value)
|
||||
{
|
||||
var type =
|
||||
value is int ? 1 :
|
||||
value is float ? 3 :
|
||||
value is double ? 4 :
|
||||
value is uint ? 5 :
|
||||
value is bool ? 7 :
|
||||
value is long ? 8 :
|
||||
value is byte[] ? 13 : 0;
|
||||
|
||||
Add(key, value, (byte) type);
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<string, object> item)
|
||||
=> Add(item.Key, item.Value);
|
||||
|
||||
public void Clear()
|
||||
=> _map.Clear();
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
=> _map.ContainsKey(key);
|
||||
|
||||
public bool Contains(KeyValuePair<string, object> item)
|
||||
=> _map.ContainsKey(item.Key) && _map[item.Key].Item2 == item.Value;
|
||||
|
||||
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Remove(string key)
|
||||
=> _map.Remove(key);
|
||||
|
||||
public bool Remove(KeyValuePair<string, object> item)
|
||||
=> _map.Remove(item.Key);
|
||||
|
||||
public bool TryGetValue(string key, out object value)
|
||||
{
|
||||
if (_map.TryGetValue(key, out var temp))
|
||||
{
|
||||
value = temp.Item2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
value = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
|
||||
{
|
||||
foreach (var k in _map)
|
||||
{
|
||||
yield return new KeyValuePair<string, object>(k.Key, k.Value.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
public override string ToString()
|
||||
=> ToString("\r\n");
|
||||
|
||||
public string ToString(string separator)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
foreach (var k in _map)
|
||||
{
|
||||
string val;
|
||||
|
||||
switch (k.Value.Item2)
|
||||
{
|
||||
case Vector2 vec2:
|
||||
val = $"{vec2.X}{InfoSeparator}{vec2.Y}";
|
||||
break;
|
||||
|
||||
case Vector3 vec3:
|
||||
val = $"{vec3.X}{InfoSeparator}{vec3.Z}{InfoSeparator}{vec3.Y}";
|
||||
break;
|
||||
|
||||
case Vector4 vec4:
|
||||
val = $"{vec4.X}{InfoSeparator}{vec4.Z}{InfoSeparator}{vec4.Y}{InfoSeparator}{vec4.W}";
|
||||
break;
|
||||
|
||||
case LegoDataList list:
|
||||
val = list.ToString();
|
||||
break;
|
||||
|
||||
default:
|
||||
val = k.Value.Item2.ToString();
|
||||
break;
|
||||
}
|
||||
|
||||
str.Append($"{k}={k.Value.Item1}:{val}");
|
||||
|
||||
var i = _map.Keys.ToList().IndexOf(k.Key);
|
||||
|
||||
if (i + 1 < Count)
|
||||
str.Append(separator);
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
public static LegoDataDictionary FromDictionary<T>(Dictionary<string, T> dict)
|
||||
{
|
||||
var ldd = new LegoDataDictionary();
|
||||
|
||||
foreach (var k in dict)
|
||||
{
|
||||
ldd[k.Key] = k.Value;
|
||||
}
|
||||
|
||||
return ldd;
|
||||
}
|
||||
|
||||
public static LegoDataDictionary FromString(string text, char separator = '\n')
|
||||
{
|
||||
var dict = new LegoDataDictionary();
|
||||
var lines = text.Replace("\r", "").Split(separator);
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var firstEqual = line.IndexOf('=');
|
||||
var firstColon = line.IndexOf(':');
|
||||
var key = line.Substring(0, firstEqual);
|
||||
var type = int.Parse(line.Substring(firstEqual + 1, firstColon - firstEqual - 1));
|
||||
var val = line.Substring(firstColon + 1);
|
||||
|
||||
object v;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
v = int.Parse(val);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
v = float.Parse(val, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
v = double.Parse(val);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
case 6:
|
||||
v = uint.Parse(val);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
v = int.Parse(val) == 1;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
case 9:
|
||||
v = long.Parse(val);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (val.Contains('+'))
|
||||
{
|
||||
v = LegoDataList.FromString(val);
|
||||
}
|
||||
else if (val.Contains('\u001F'))
|
||||
{
|
||||
var floats = val.Split('\u001F').Select(s => float.Parse(s, CultureInfo.InvariantCulture)).ToArray();
|
||||
|
||||
v =
|
||||
floats.Length == 1 ? floats[0] :
|
||||
floats.Length == 2 ? new Vector2(floats[0], floats[1]) :
|
||||
floats.Length == 3 ? new Vector3(floats[0], floats[1], floats[2]) :
|
||||
floats.Length == 4 ? new Vector4(floats[0], floats[1], floats[2], floats[3]) :
|
||||
(object) val;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dict[key, (byte) type] = v;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
}
|
||||
222
InfectedRose.Lvl/LegoDataList.cs
Normal file
222
InfectedRose.Lvl/LegoDataList.cs
Normal file
@@ -0,0 +1,222 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
||||
namespace Lvl
|
||||
{
|
||||
public class LegoDataList : IList<object>
|
||||
{
|
||||
public const char InfoSeparator = '\u001F';
|
||||
private readonly List<(byte, object)> _list;
|
||||
|
||||
public int Count => _list.Count;
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public object this[int index]
|
||||
{
|
||||
get => _list[index].Item2;
|
||||
set => Insert(index, value);
|
||||
}
|
||||
|
||||
public object this[int index, byte type]
|
||||
{
|
||||
get => _list[index].Item2;
|
||||
set => Insert(index, value, type);
|
||||
}
|
||||
|
||||
public LegoDataList()
|
||||
{
|
||||
_list = new List<(byte, object)>();
|
||||
}
|
||||
|
||||
public void Add(object item, byte type)
|
||||
=> _list.Add((type, item));
|
||||
|
||||
public void Add(object item)
|
||||
{
|
||||
var type =
|
||||
item is int ? 1 :
|
||||
item is float ? 3 :
|
||||
item is double ? 4 :
|
||||
item is uint ? 5 :
|
||||
item is bool ? 7 :
|
||||
item is long ? 8 :
|
||||
item is byte[] ? 13 : 0;
|
||||
|
||||
Add(item, (byte) type);
|
||||
}
|
||||
|
||||
public void Insert(int index, object item, byte type)
|
||||
=> _list.Insert(index, (type, item));
|
||||
|
||||
public void Insert(int index, object item)
|
||||
{
|
||||
var type =
|
||||
item is int ? 1 :
|
||||
item is float ? 3 :
|
||||
item is double ? 4 :
|
||||
item is uint ? 5 :
|
||||
item is bool ? 7 :
|
||||
item is long ? 8 :
|
||||
item is byte[] ? 13 : 0;
|
||||
|
||||
Insert(index, item, (byte) type);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
=> _list.Clear();
|
||||
|
||||
public bool Contains(object item)
|
||||
=> _list.Exists(i => i.Item2 == item);
|
||||
|
||||
public void RemoveAt(int index)
|
||||
=> _list.RemoveAt(index);
|
||||
|
||||
public bool Remove(object item)
|
||||
=> _list.Remove(_list.Find(i => i.Item2 == item));
|
||||
|
||||
public int IndexOf(object item)
|
||||
=> _list.FindIndex(i => i.Item2 == item);
|
||||
|
||||
public void CopyTo(object[] array, int arrayIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerator<object> GetEnumerator()
|
||||
{
|
||||
foreach (var (_, v) in _list) yield return v;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
public override string ToString()
|
||||
=> ToString("+");
|
||||
|
||||
public string ToString(string separator)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
foreach (var (t, v) in _list)
|
||||
{
|
||||
string val;
|
||||
|
||||
switch (v)
|
||||
{
|
||||
case Vector2 vec2:
|
||||
val = $"{vec2.X}{InfoSeparator}{vec2.Y}";
|
||||
break;
|
||||
|
||||
case Vector3 vec3:
|
||||
val = $"{vec3.X}{InfoSeparator}{vec3.Z}{InfoSeparator}{vec3.Y}";
|
||||
break;
|
||||
|
||||
case Vector4 vec4:
|
||||
val = $"{vec4.X}{InfoSeparator}{vec4.Z}{InfoSeparator}{vec4.Y}{InfoSeparator}{vec4.W}";
|
||||
break;
|
||||
|
||||
case LegoDataList list:
|
||||
val = list.ToString();
|
||||
break;
|
||||
|
||||
default:
|
||||
val = v.ToString();
|
||||
break;
|
||||
}
|
||||
|
||||
str.Append($"{t}:{val}");
|
||||
|
||||
if (IndexOf(v) + 1 < Count)
|
||||
str.Append(separator);
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
public static LegoDataList FromEnumerable<T>(IEnumerable<T> list)
|
||||
{
|
||||
var ldl = new LegoDataList();
|
||||
|
||||
foreach (var item in list) ldl.Add(item);
|
||||
|
||||
return ldl;
|
||||
}
|
||||
|
||||
public static LegoDataList FromString(string text)
|
||||
{
|
||||
var list = new LegoDataList();
|
||||
var entries = text.Split('+');
|
||||
|
||||
for (var i = 0; i < entries.Length; i++)
|
||||
{
|
||||
var entry = entries[i];
|
||||
var firstColon = entry.IndexOf(':');
|
||||
var type = int.Parse(entry.Substring(0, firstColon));
|
||||
var val = entry.Substring(firstColon + 1);
|
||||
|
||||
object v = null;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
v = int.Parse(val);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
v = float.Parse(val, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
v = double.Parse(val);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
case 6:
|
||||
v = uint.Parse(val);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
v = int.Parse(val) == 1;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
case 9:
|
||||
v = long.Parse(val);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (val.Contains('+'))
|
||||
{
|
||||
v = FromString(val);
|
||||
}
|
||||
else if (val.Contains('\u001F'))
|
||||
{
|
||||
var floats = val.Split('\u001F').Select(s => float.Parse(s, CultureInfo.InvariantCulture)).ToArray();
|
||||
|
||||
v =
|
||||
floats.Length == 1 ? floats[0] :
|
||||
floats.Length == 2 ? new Vector2(floats[0], floats[1]) :
|
||||
floats.Length == 3 ? new Vector3(floats[0], floats[1], floats[2]) :
|
||||
floats.Length == 4 ? new Vector4(floats[0], floats[1], floats[2], floats[3]) :
|
||||
(object) val;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
list[i, (byte) type] = v;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
InfectedRose.Lvl/LevelEnvironmentConfig.cs
Normal file
35
InfectedRose.Lvl/LevelEnvironmentConfig.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.IO;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Lvl
|
||||
{
|
||||
public class LevelEnvironmentConfig : ChunkBase
|
||||
{
|
||||
public ParticleStruct[] ParticleStructs { get; set; }
|
||||
|
||||
public override uint ChunkType => 2002;
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write((uint) ParticleStructs.Length);
|
||||
|
||||
foreach (var particleStruct in ParticleStructs)
|
||||
{
|
||||
particleStruct.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
ParticleStructs = new ParticleStruct[reader.Read<uint>()];
|
||||
|
||||
for (var i = 0; i < ParticleStructs.Length; i++)
|
||||
{
|
||||
var particle = new ParticleStruct();
|
||||
particle.Deserialize(reader);
|
||||
|
||||
ParticleStructs[i] = particle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
46
InfectedRose.Lvl/LevelInfo.cs
Normal file
46
InfectedRose.Lvl/LevelInfo.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.IO;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Lvl
|
||||
{
|
||||
public class LevelInfo : ChunkBase
|
||||
{
|
||||
public uint LvlVersion { get; set; }
|
||||
|
||||
public uint RevisionNumber { get; set; }
|
||||
|
||||
public uint AddressChunk2000 { get; set; }
|
||||
|
||||
public uint AddressChunk2001 { get; set; }
|
||||
|
||||
public uint AddressChunk2002 { get; set; }
|
||||
|
||||
public override uint ChunkType => 1000;
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(LvlVersion);
|
||||
|
||||
writer.Write(RevisionNumber);
|
||||
|
||||
writer.Write(AddressChunk2000);
|
||||
|
||||
writer.Write(AddressChunk2001);
|
||||
|
||||
writer.Write(AddressChunk2002);
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
LvlVersion = reader.Read<uint>();
|
||||
|
||||
RevisionNumber = reader.Read<uint>();
|
||||
|
||||
AddressChunk2000 = reader.Read<uint>();
|
||||
|
||||
AddressChunk2001 = reader.Read<uint>();
|
||||
|
||||
AddressChunk2002 = reader.Read<uint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
84
InfectedRose.Lvl/LevelObjectTemplate.cs
Normal file
84
InfectedRose.Lvl/LevelObjectTemplate.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using InfectedRose.Core;
|
||||
using Lvl;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Lvl
|
||||
{
|
||||
public class LevelObjectTemplate : IConstruct
|
||||
{
|
||||
public ulong ObjectId { get; set; }
|
||||
|
||||
public int Lot { get; set; }
|
||||
|
||||
public uint AssetType { get; set; }
|
||||
|
||||
public uint UnknownInt { get; set; }
|
||||
|
||||
public Vector3 Position { get; set; }
|
||||
|
||||
public Quaternion Rotation { get; set; }
|
||||
|
||||
public float Scale { get; set; }
|
||||
|
||||
public LegoDataDictionary LegoInfo { get; set; }
|
||||
|
||||
public uint LvlVersion { get; set; }
|
||||
|
||||
public LevelObjectTemplate(uint lvlVersion)
|
||||
{
|
||||
LvlVersion = lvlVersion;
|
||||
}
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(ObjectId);
|
||||
|
||||
writer.Write(Lot);
|
||||
|
||||
if (LvlVersion >= 0x26)
|
||||
writer.Write(AssetType);
|
||||
|
||||
if (LvlVersion >= 0x20)
|
||||
writer.Write(UnknownInt);
|
||||
|
||||
writer.Write(Position);
|
||||
|
||||
writer.WriteNiQuaternion(Rotation);
|
||||
|
||||
writer.Write(Scale);
|
||||
|
||||
writer.WriteNiString(LegoInfo.ToString(), true);
|
||||
|
||||
if (LvlVersion >= 0x7)
|
||||
writer.Write(0u);
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
ObjectId = reader.Read<ulong>();
|
||||
|
||||
Lot = reader.Read<int>();
|
||||
|
||||
if (LvlVersion >= 0x26)
|
||||
AssetType = reader.Read<uint>();
|
||||
|
||||
if (LvlVersion >= 0x20)
|
||||
UnknownInt = reader.Read<uint>();
|
||||
|
||||
Position = reader.Read<Vector3>();
|
||||
|
||||
Rotation = reader.ReadNiQuaternion();
|
||||
|
||||
Scale = reader.Read<float>();
|
||||
|
||||
var legoInfo = reader.ReadNiString(true);
|
||||
|
||||
LegoInfo = LegoDataDictionary.FromString(legoInfo);
|
||||
|
||||
if (LvlVersion >= 0x7)
|
||||
reader.Read<uint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
InfectedRose.Lvl/LevelObjects.cs
Normal file
42
InfectedRose.Lvl/LevelObjects.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.IO;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Lvl
|
||||
{
|
||||
public class LevelObjects : ChunkBase
|
||||
{
|
||||
public LevelObjectTemplate[] Templates { get; set; }
|
||||
|
||||
public uint LvlVersion { get; set; }
|
||||
|
||||
public override uint ChunkType => 2001;
|
||||
|
||||
public LevelObjects(uint lvlVersion)
|
||||
{
|
||||
LvlVersion = lvlVersion;
|
||||
}
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write((uint) Templates.Length);
|
||||
|
||||
foreach (var template in Templates)
|
||||
{
|
||||
template.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
Templates = new LevelObjectTemplate[reader.Read<uint>()];
|
||||
|
||||
for (var i = 0; i < Templates.Length; i++)
|
||||
{
|
||||
var template = new LevelObjectTemplate(LvlVersion);
|
||||
template.Deserialize(reader);
|
||||
|
||||
Templates[i] = template;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
138
InfectedRose.Lvl/LevelSkyConfig.cs
Normal file
138
InfectedRose.Lvl/LevelSkyConfig.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Lvl
|
||||
{
|
||||
public class LevelSkyConfig : ChunkBase
|
||||
{
|
||||
public IdStruct[] Identifiers { get; set; }
|
||||
|
||||
public string[] SkyFilesPaths { get; set; } = new string[6];
|
||||
|
||||
public float[] UnknownFloatArray0 { get; set; }
|
||||
|
||||
public float[] UnknownFloatArray1 { get; set; } = new float[3];
|
||||
|
||||
public float[] UnknownFloatArray2 { get; set; } = new float[3];
|
||||
|
||||
public byte[] UnknownSectionData { get; set; }
|
||||
|
||||
public override uint ChunkType => 2000;
|
||||
|
||||
public override void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(8);
|
||||
|
||||
// TODO: Add UnknownFloatArray0?
|
||||
|
||||
var addressPosition = writer.BaseStream.Position;
|
||||
|
||||
writer.BaseStream.Position += 8;
|
||||
|
||||
writer.Write((uint) Identifiers.Length);
|
||||
|
||||
foreach (var identifier in Identifiers)
|
||||
{
|
||||
identifier.Serialize(writer);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
writer.Write(UnknownFloatArray1[i]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
writer.Write(UnknownFloatArray2[i]);
|
||||
}
|
||||
|
||||
var skySectionAddress = writer.BaseStream.Position;
|
||||
|
||||
writer.Write(WriteSkySection());
|
||||
|
||||
var otherSectionAddress = writer.BaseStream.Position;
|
||||
|
||||
writer.Write(WriteOtherSection());
|
||||
|
||||
writer.BaseStream.Position = addressPosition;
|
||||
|
||||
writer.Write((uint) skySectionAddress);
|
||||
|
||||
writer.Write((uint) otherSectionAddress);
|
||||
|
||||
writer.BaseStream.Position = otherSectionAddress + 4;
|
||||
}
|
||||
|
||||
private byte[] WriteSkySection()
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
using var writer = new BitWriter(stream);
|
||||
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
writer.WriteNiString(SkyFilesPaths[i]);
|
||||
}
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
private byte[] WriteOtherSection()
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
using var writer = new BinaryWriter(stream);
|
||||
|
||||
writer.Write(0u);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
public override void Deserialize(BitReader reader)
|
||||
{
|
||||
var sizeOfData = reader.Read<uint>();
|
||||
|
||||
var skySectionAddress = reader.Read<uint>();
|
||||
|
||||
var otherSectionAddress = reader.Read<uint>();
|
||||
|
||||
UnknownFloatArray0 = new float[(sizeOfData - 8) / 4];
|
||||
|
||||
for (var i = 0; i < UnknownFloatArray0.Length; i++)
|
||||
{
|
||||
UnknownFloatArray0[i] = reader.Read<float>();
|
||||
}
|
||||
|
||||
Identifiers = new IdStruct[reader.Read<uint>()];
|
||||
|
||||
for (var i = 0; i < Identifiers.Length; i++)
|
||||
{
|
||||
var idStruct = new IdStruct();
|
||||
idStruct.Deserialize(reader);
|
||||
|
||||
Identifiers[i] = idStruct;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
UnknownFloatArray1[i] = reader.Read<float>();
|
||||
}
|
||||
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
UnknownFloatArray2[i] = reader.Read<float>();
|
||||
}
|
||||
|
||||
reader.BaseStream.Position = skySectionAddress;
|
||||
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
SkyFilesPaths[i] = reader.ReadNiString();
|
||||
}
|
||||
|
||||
reader.BaseStream.Position = otherSectionAddress;
|
||||
|
||||
UnknownSectionData = reader.ReadBuffer(reader.Read<uint>());
|
||||
}
|
||||
}
|
||||
}
|
||||
141
InfectedRose.Lvl/LvlFile.cs
Normal file
141
InfectedRose.Lvl/LvlFile.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Lvl
|
||||
{
|
||||
public class LvlFile : IConstruct
|
||||
{
|
||||
public uint LvlVersion { get; set; }
|
||||
|
||||
public LevelInfo LevelInfo;
|
||||
|
||||
public LevelSkyConfig LevelSkyConfig;
|
||||
|
||||
public LevelObjects LevelObjects;
|
||||
|
||||
public LevelEnvironmentConfig LevelEnvironmentConfig;
|
||||
|
||||
private static readonly byte[] ChunkHeader = "CHNK".Select(c => (byte) c).ToArray();
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
var levelInfoData = WriteChunk(LevelInfo);
|
||||
var levelSkyData = WriteChunk(LevelSkyConfig);
|
||||
var levelObjectsData = WriteChunk(LevelObjects);
|
||||
var levelEnvData = WriteChunk(LevelEnvironmentConfig);
|
||||
|
||||
Console.WriteLine($"{levelInfoData.Length} - {levelSkyData.Length} - {levelObjectsData.Length} - {levelEnvData.Length}");
|
||||
}
|
||||
|
||||
private static byte[] WriteChunk(IConstruct chunk)
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
using var writer = new BitWriter(stream);
|
||||
|
||||
chunk.Serialize(writer);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
var magic = new string(reader.ReadBuffer(4).Select(s => (char) s).ToArray());
|
||||
|
||||
if (magic != "CHNK")
|
||||
{
|
||||
Console.WriteLine(new NotImplementedException("Older LVL files not yet supported."));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
reader.BaseStream.Position = 0;
|
||||
|
||||
while (reader.BaseStream.Position != reader.BaseStream.Length)
|
||||
{
|
||||
var startPosition = reader.BaseStream.Position;
|
||||
|
||||
magic = new string(reader.ReadBuffer(4).Select(s => (char) s).ToArray());
|
||||
|
||||
if (startPosition % 16 != 0 || magic != "CHNK")
|
||||
{
|
||||
throw new Exception($"{startPosition} % 16 = {startPosition % 16} | {magic}");
|
||||
}
|
||||
|
||||
var chunkType = reader.Read<uint>();
|
||||
|
||||
reader.Read<ushort>();
|
||||
|
||||
var index = reader.Read<ushort>();
|
||||
|
||||
var chunkLength = reader.Read<uint>();
|
||||
|
||||
var chunkAddress = reader.Read<uint>();
|
||||
|
||||
reader.BaseStream.Position = chunkAddress;
|
||||
|
||||
if (reader.BaseStream.Position % 16 != 0) break;
|
||||
|
||||
switch (chunkType)
|
||||
{
|
||||
case 1000:
|
||||
var chunk1000 = new LevelInfo
|
||||
{
|
||||
Index = index
|
||||
};
|
||||
|
||||
chunk1000.Deserialize(reader);
|
||||
|
||||
LvlVersion = chunk1000.LvlVersion;
|
||||
|
||||
LevelInfo = chunk1000;
|
||||
break;
|
||||
case 2000:
|
||||
var chunk2000 = new LevelSkyConfig
|
||||
{
|
||||
Index = index
|
||||
};
|
||||
|
||||
chunk2000.Deserialize(reader);
|
||||
|
||||
LevelSkyConfig = chunk2000;
|
||||
break;
|
||||
case 2001:
|
||||
var chunk2001 = new LevelObjects(LvlVersion)
|
||||
{
|
||||
Index = index
|
||||
};
|
||||
|
||||
chunk2001.Deserialize(reader);
|
||||
|
||||
LevelObjects = chunk2001;
|
||||
break;
|
||||
case 2002:
|
||||
var chunk2002 = new LevelEnvironmentConfig
|
||||
{
|
||||
Index = index
|
||||
};
|
||||
|
||||
chunk2002.Deserialize(reader);
|
||||
|
||||
LevelEnvironmentConfig = chunk2002;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException($"{chunkType} is not a valid chunk type.");
|
||||
}
|
||||
|
||||
while (reader.BaseStream.Position != startPosition + chunkLength)
|
||||
{
|
||||
reader.Read<byte>();
|
||||
}
|
||||
|
||||
reader.BaseStream.Position = startPosition + chunkLength;
|
||||
|
||||
Console.WriteLine($"[END] -> {reader.BaseStream.Position}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
InfectedRose.Lvl/ParticleStruct.cs
Normal file
57
InfectedRose.Lvl/ParticleStruct.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Lvl
|
||||
{
|
||||
public class ParticleStruct : IConstruct
|
||||
{
|
||||
public byte[] UnknownByteArray0 { get; set; } = new byte[2];
|
||||
|
||||
public Vector3 Position { get; set; }
|
||||
|
||||
public Quaternion Rotation { get; set; }
|
||||
|
||||
public string ParticleName { get; set; }
|
||||
|
||||
public byte[] UnknownByteArray1 { get; set; } = new byte[4];
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(UnknownByteArray0);
|
||||
|
||||
writer.Write(Position);
|
||||
|
||||
writer.WriteNiQuaternion(Rotation);
|
||||
|
||||
writer.WriteNiString(ParticleName, true);
|
||||
|
||||
writer.Write(UnknownByteArray1);
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
UnknownByteArray0 = reader.ReadBuffer(2);
|
||||
|
||||
Position = reader.Read<Vector3>();
|
||||
|
||||
Rotation = reader.ReadNiQuaternion();
|
||||
|
||||
var position = reader.BaseStream.Position;
|
||||
|
||||
try
|
||||
{
|
||||
ParticleName = reader.ReadNiString(true);
|
||||
|
||||
Console.WriteLine(ParticleName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
reader.BaseStream.Position = position + 4;
|
||||
}
|
||||
|
||||
UnknownByteArray1 = reader.ReadBuffer(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
InfectedRose.Nif/BlockInfo.cs
Normal file
9
InfectedRose.Nif/BlockInfo.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace InfectedRose.Nif
|
||||
{
|
||||
public class BlockInfo
|
||||
{
|
||||
public ushort TypeIndex { get; set; }
|
||||
|
||||
public uint Size { get; set; }
|
||||
}
|
||||
}
|
||||
8
InfectedRose.Nif/Enums/Endian.cs
Normal file
8
InfectedRose.Nif/Enums/Endian.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace InfectedRose.Nif
|
||||
{
|
||||
public enum Endian : byte
|
||||
{
|
||||
EndianBig,
|
||||
EndianLittle
|
||||
}
|
||||
}
|
||||
170
InfectedRose.Nif/Enums/NifVersion.cs
Normal file
170
InfectedRose.Nif/Enums/NifVersion.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
namespace InfectedRose.Nif
|
||||
{
|
||||
public enum NifVersion : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// The ve R_2_3
|
||||
/// </summary>
|
||||
Ver23 = 33751040u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_3_0
|
||||
/// </summary>
|
||||
Ver30 = 50331648u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_3_03
|
||||
/// </summary>
|
||||
Ver303 = 50332416u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_3_1
|
||||
/// </summary>
|
||||
Ver31 = 50397184u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_3_3_0_13
|
||||
/// </summary>
|
||||
Ver33013 = 50528269u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_4_0_0_0
|
||||
/// </summary>
|
||||
Ver4000 = 67108864u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_4_0_0_2
|
||||
/// </summary>
|
||||
Ver4002 = 67108866u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_4_1_0_12
|
||||
/// </summary>
|
||||
Ver4101 = 0x04010001,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_4_1_0_12
|
||||
/// </summary>
|
||||
Ver41012 = 67174412u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_4_2_0_2
|
||||
/// </summary>
|
||||
Ver4202 = 67239938u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_4_2_1_0
|
||||
/// </summary>
|
||||
Ver4210 = 67240192u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_4_2_2_0
|
||||
/// </summary>
|
||||
Ver4220 = 67240448u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_5_0_0_1
|
||||
/// </summary>
|
||||
Ver5001 = 83886081u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_10_0_1_0
|
||||
/// </summary>
|
||||
Ver10010 = 167772416u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_10_0_1_2
|
||||
/// </summary>
|
||||
Ver10012 = 167772418u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_10_0_1_3
|
||||
/// </summary>
|
||||
Ver10013,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_10_1_0_0
|
||||
/// </summary>
|
||||
Ver10100 = 167837696u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_10_1_0_101
|
||||
/// </summary>
|
||||
Ver1010101 = 167837797u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_10_1_0_106
|
||||
/// </summary>
|
||||
Ver1010106 = 167837802u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_10_2_0_0
|
||||
/// </summary>
|
||||
Ver10200 = 167903232u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_10_4_0_1
|
||||
/// </summary>
|
||||
Ver10401 = 168034305u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_20_0_0_4
|
||||
/// </summary>
|
||||
Ver20004 = 335544324u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_20_0_0_5
|
||||
/// </summary>
|
||||
Ver20005,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_20_1_0_3
|
||||
/// </summary>
|
||||
Ver20103 = 335609859u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_20_2_0_7
|
||||
/// </summary>
|
||||
Ver20207 = 335675399u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_20_2_0_8
|
||||
/// </summary>
|
||||
Ver20208,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_20_3_0_1
|
||||
/// </summary>
|
||||
Ver20301 = 335740929u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_20_3_0_2
|
||||
/// </summary>
|
||||
Ver20302,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_20_3_0_3
|
||||
/// </summary>
|
||||
Ver20303,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_20_3_0_6
|
||||
/// </summary>
|
||||
Ver20306 = 335740934u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve R_20_3_0_9
|
||||
/// </summary>
|
||||
Ver20309 = 335740937u, // LEGO Universe
|
||||
|
||||
/// <summary>
|
||||
/// The ve r_ unsupported
|
||||
/// </summary>
|
||||
VerUnsupported = 4294967295u,
|
||||
|
||||
/// <summary>
|
||||
/// The ve r_ invalid
|
||||
/// </summary>
|
||||
VerInvalid = 4294967294u
|
||||
}
|
||||
}
|
||||
82
InfectedRose.Nif/Header.cs
Normal file
82
InfectedRose.Nif/Header.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Nif
|
||||
{
|
||||
public class Header : IConstruct
|
||||
{
|
||||
public string HeaderString { get; set; }
|
||||
|
||||
public NifVersion Version { get; set; }
|
||||
|
||||
public Endian Endian { get; set; }
|
||||
|
||||
public string VersionString { get; set; }
|
||||
|
||||
public uint UserVersion { get; set; }
|
||||
|
||||
public BlockInfo[] NodeInfo { get; set; }
|
||||
|
||||
public NifString[] NodeTypes { get; set; }
|
||||
|
||||
public uint MaxStringLength { get; set; }
|
||||
|
||||
public uint[] Groups { get; set; }
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
var versionStringBuilder = new StringBuilder();
|
||||
|
||||
var character = reader.Read<byte>();
|
||||
while (character != 0xA)
|
||||
{
|
||||
versionStringBuilder.Append((char) character);
|
||||
|
||||
character = reader.Read<byte>();
|
||||
}
|
||||
|
||||
VersionString = versionStringBuilder.ToString();
|
||||
|
||||
reader.Read<byte>();
|
||||
|
||||
Version = (NifVersion) reader.Read<uint>();
|
||||
|
||||
Endian = (Endian) reader.Read<byte>();
|
||||
|
||||
UserVersion = reader.Read<uint>();
|
||||
|
||||
NodeInfo = new BlockInfo[reader.Read<uint>()];
|
||||
|
||||
NodeTypes = new NifString[reader.Read<uint>()];
|
||||
|
||||
for (var i = 0; i < NodeTypes.Length; i++)
|
||||
{
|
||||
var str = new NifString();
|
||||
|
||||
str.Deserialize(reader);
|
||||
|
||||
NodeTypes[i] = str;
|
||||
}
|
||||
|
||||
for (var i = 0; i < NodeInfo.Length; i++)
|
||||
{
|
||||
NodeInfo[i] = new BlockInfo
|
||||
{
|
||||
TypeIndex = reader.Read<ushort>()
|
||||
};
|
||||
}
|
||||
|
||||
foreach (var info in NodeInfo)
|
||||
{
|
||||
info.Size = reader.Read<uint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
InfectedRose.Nif/InfectedRose.Nif.csproj
Normal file
15
InfectedRose.Nif/InfectedRose.Nif.csproj
Normal file
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\InfectedRose.Core\InfectedRose.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Nodes" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
18
InfectedRose.Nif/NifFile.cs
Normal file
18
InfectedRose.Nif/NifFile.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Nif
|
||||
{
|
||||
public class NifFile : IConstruct
|
||||
{
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
40
InfectedRose.Nif/NifString.cs
Normal file
40
InfectedRose.Nif/NifString.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Nif
|
||||
{
|
||||
public class NifString : IConstruct
|
||||
{
|
||||
public string Value { get; set; }
|
||||
|
||||
public bool Wide { get; set; }
|
||||
|
||||
public bool Small { get; set; }
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
if (Small) writer.Write((byte) Value.Length);
|
||||
else writer.Write((uint) Value.Length);
|
||||
|
||||
foreach (var character in Value)
|
||||
{
|
||||
if (Wide) writer.Write((ushort) character);
|
||||
else writer.Write((byte) character);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
var length = Small ? reader.Read<byte>() : reader.Read<uint>();
|
||||
|
||||
var chars = new char[length];
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
chars[i] = (char) (Wide ? reader.Read<ushort>() : reader.Read<byte>());
|
||||
}
|
||||
|
||||
Value = new string(chars);
|
||||
}
|
||||
}
|
||||
}
|
||||
134
InfectedRose.Terrain/Chunk.cs
Normal file
134
InfectedRose.Terrain/Chunk.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Terrain
|
||||
{
|
||||
public class Chunk : IConstruct
|
||||
{
|
||||
public int ChunkIndex { get; set; }
|
||||
|
||||
public HeightMap HeightMap { get; set; }
|
||||
|
||||
public ColorMap Colormap0 { get; set; }
|
||||
|
||||
public TerrainDirectDraw Lightmap { get; set; }
|
||||
|
||||
public ColorMap Colormap1 { get; set; }
|
||||
|
||||
public byte UnknownByte { get; set; }
|
||||
|
||||
public TerrainDirectDraw Blendmap { get; set; }
|
||||
|
||||
public WeirdStruct[] WeirdStructs { get; set; }
|
||||
|
||||
public byte[] UnknownByteArray0 { get; set; }
|
||||
|
||||
public ShortMap ShortMap { get; set; }
|
||||
|
||||
public short[][] UnknownShortArray { get; set; }
|
||||
|
||||
public byte[] UnknownByteArray1 { get; set; }
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(ChunkIndex);
|
||||
|
||||
HeightMap.Serialize(writer);
|
||||
|
||||
Colormap0.Serialize(writer);
|
||||
|
||||
Lightmap.Serialize(writer);
|
||||
|
||||
Colormap1.Serialize(writer);
|
||||
|
||||
writer.Write(UnknownByte);
|
||||
|
||||
Blendmap.Serialize(writer);
|
||||
|
||||
writer.Write(WeirdStructs.Length);
|
||||
|
||||
foreach (var weirdStruct in WeirdStructs)
|
||||
{
|
||||
weirdStruct.Serialize(writer);
|
||||
}
|
||||
|
||||
foreach (var unknownByte in UnknownByteArray0)
|
||||
{
|
||||
writer.Write(unknownByte);
|
||||
}
|
||||
|
||||
ShortMap.Serialize(writer);
|
||||
|
||||
if (ShortMap.Data.Length == default) return;
|
||||
|
||||
for (var i = 0; i < 32; i++)
|
||||
{
|
||||
writer.Write(UnknownByteArray1[i]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
writer.Write((short) UnknownShortArray[i].Length);
|
||||
|
||||
for (var j = 0; j < UnknownShortArray[i].Length; j++)
|
||||
{
|
||||
writer.Write(UnknownShortArray[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
ChunkIndex = reader.Read<int>();
|
||||
|
||||
HeightMap = new HeightMap();
|
||||
HeightMap.Deserialize(reader);
|
||||
|
||||
Colormap0 = new ColorMap();
|
||||
Colormap0.Deserialize(reader);
|
||||
|
||||
Lightmap = new TerrainDirectDraw();
|
||||
Lightmap.Deserialize(reader);
|
||||
|
||||
Colormap1 = new ColorMap();
|
||||
Colormap1.Deserialize(reader);
|
||||
|
||||
UnknownByte = reader.Read<byte>();
|
||||
|
||||
Blendmap = new TerrainDirectDraw();
|
||||
Blendmap.Deserialize(reader);
|
||||
|
||||
WeirdStructs = new WeirdStruct[reader.Read<int>()];
|
||||
|
||||
for (var i = 0; i < WeirdStructs.Length; i++)
|
||||
{
|
||||
var weirdStruct = new WeirdStruct();
|
||||
weirdStruct.Deserialize(reader);
|
||||
|
||||
WeirdStructs[i] = weirdStruct;
|
||||
}
|
||||
|
||||
UnknownByteArray0 = reader.ReadBuffer((uint) (Colormap0.Width * Colormap0.Height));
|
||||
|
||||
ShortMap = new ShortMap();
|
||||
ShortMap.Deserialize(reader);
|
||||
|
||||
if (ShortMap.Data.Length == default) return;
|
||||
|
||||
UnknownByteArray1 = reader.ReadBuffer(32);
|
||||
|
||||
UnknownShortArray = new short[16][];
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
var length = reader.Read<short>();
|
||||
UnknownShortArray[i] = new short[length];
|
||||
|
||||
for (var j = 0; j < length; j++)
|
||||
{
|
||||
UnknownShortArray[i][j] = reader.Read<short>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
41
InfectedRose.Terrain/ColorMap.cs
Normal file
41
InfectedRose.Terrain/ColorMap.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Terrain
|
||||
{
|
||||
public class ColorMap : IConstruct
|
||||
{
|
||||
public int Width { get; set; }
|
||||
|
||||
public int Height { get; set; }
|
||||
|
||||
public uint[] Data { get; set; }
|
||||
|
||||
public uint GetValue(int x, int y)
|
||||
{
|
||||
return Data[y * Width + x];
|
||||
}
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(Width);
|
||||
|
||||
for (var i = 0; i < Width * Height; i++)
|
||||
{
|
||||
writer.Write(Data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
Width = Height = reader.Read<int>();
|
||||
|
||||
Data = new uint[Width * Height];
|
||||
|
||||
for (var i = 0; i < Data.Length; i++)
|
||||
{
|
||||
Data[i] = reader.Read<uint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
InfectedRose.Terrain/HeightMap.cs
Normal file
66
InfectedRose.Terrain/HeightMap.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Terrain
|
||||
{
|
||||
public class HeightMap : IConstruct
|
||||
{
|
||||
public int Width { get; set; }
|
||||
|
||||
public int Height { get; set; }
|
||||
|
||||
public float UnknownFloat0 { get; set; }
|
||||
public float UnknownFloat1 { get; set; }
|
||||
public float UnknownFloat2 { get; set; }
|
||||
|
||||
public int[] UnknownIntArray { get; set; }
|
||||
|
||||
public float[] Data { get; set; }
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(Width);
|
||||
writer.Write(Height);
|
||||
|
||||
writer.Write(UnknownFloat0);
|
||||
writer.Write(UnknownFloat1);
|
||||
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
writer.Write(UnknownIntArray[i]);
|
||||
}
|
||||
|
||||
writer.Write(UnknownFloat2);
|
||||
|
||||
for (var i = 0; i < Width * Height; i++)
|
||||
{
|
||||
writer.Write(Data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
Width = reader.Read<int>();
|
||||
Height = reader.Read<int>();
|
||||
|
||||
UnknownFloat0 = reader.Read<float>();
|
||||
UnknownFloat1 = reader.Read<float>();
|
||||
|
||||
UnknownIntArray = new int[4];
|
||||
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
UnknownIntArray[i] = reader.Read<int>();
|
||||
}
|
||||
|
||||
UnknownFloat2 = reader.Read<float>();
|
||||
|
||||
Data = new float[Width * Height];
|
||||
|
||||
for (var i = 0; i < Data.Length; i++)
|
||||
{
|
||||
Data[i] = reader.Read<float>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
InfectedRose.Terrain/InfectedRose.Terrain.csproj
Normal file
11
InfectedRose.Terrain/InfectedRose.Terrain.csproj
Normal file
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\InfectedRose.Core\InfectedRose.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
30
InfectedRose.Terrain/ShortMap.cs
Normal file
30
InfectedRose.Terrain/ShortMap.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Terrain
|
||||
{
|
||||
public class ShortMap : IConstruct
|
||||
{
|
||||
public short[] Data { get; set; }
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(Data.Length);
|
||||
|
||||
foreach (var data in Data)
|
||||
{
|
||||
writer.Write(data);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
Data = new short[reader.Read<int>()];
|
||||
|
||||
for (var i = 0; i < Data.Length; i++)
|
||||
{
|
||||
Data[i] = reader.Read<short>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
InfectedRose.Terrain/TerrainDirectDraw.cs
Normal file
25
InfectedRose.Terrain/TerrainDirectDraw.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Terrain
|
||||
{
|
||||
public class TerrainDirectDraw : IConstruct
|
||||
{
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(Data.Length);
|
||||
|
||||
foreach (var data in Data)
|
||||
{
|
||||
writer.Write(data);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
Data = reader.ReadBuffer((uint) reader.Read<int>());
|
||||
}
|
||||
}
|
||||
}
|
||||
7
InfectedRose.Terrain/TerrainEditor.cs
Normal file
7
InfectedRose.Terrain/TerrainEditor.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace InfectedRose.Terrain
|
||||
{
|
||||
public class TerrainEditor
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
52
InfectedRose.Terrain/TerrainFile.cs
Normal file
52
InfectedRose.Terrain/TerrainFile.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Collections.Generic;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Terrain
|
||||
{
|
||||
public class TerrainFile : IConstruct
|
||||
{
|
||||
public List<Chunk> Chunks;
|
||||
|
||||
public int ChunkTotalCount { get; set; }
|
||||
|
||||
public int ChunkCountX { get; set; }
|
||||
|
||||
public int ChunkCountY { get; set; }
|
||||
|
||||
public byte[] UnknownHeader { get; set; }
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(UnknownHeader);
|
||||
|
||||
writer.Write(ChunkTotalCount);
|
||||
writer.Write(ChunkCountX);
|
||||
writer.Write(ChunkCountY);
|
||||
|
||||
foreach (var chunk in Chunks)
|
||||
{
|
||||
chunk.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
Chunks = new List<Chunk>();
|
||||
|
||||
UnknownHeader = reader.ReadBuffer(3);
|
||||
|
||||
ChunkTotalCount = reader.Read<int>();
|
||||
ChunkCountX = reader.Read<int>();
|
||||
ChunkCountY = reader.Read<int>();
|
||||
|
||||
for (var i = 0; i < ChunkTotalCount; i++)
|
||||
{
|
||||
var chunk = new Chunk();
|
||||
chunk.Deserialize(reader);
|
||||
|
||||
Chunks.Add(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
InfectedRose.Terrain/WeirdStruct.cs
Normal file
51
InfectedRose.Terrain/WeirdStruct.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Numerics;
|
||||
using InfectedRose.Core;
|
||||
using RakDotNet.IO;
|
||||
|
||||
namespace InfectedRose.Terrain
|
||||
{
|
||||
public class WeirdStruct : IConstruct
|
||||
{
|
||||
public int Type { get; set; }
|
||||
|
||||
public Vector3 Position { get; set; }
|
||||
|
||||
public Quaternion Rotation { get; set; }
|
||||
|
||||
public uint UnknownInt { get; set; }
|
||||
|
||||
public void Serialize(BitWriter writer)
|
||||
{
|
||||
writer.Write(Type);
|
||||
|
||||
writer.Write(Rotation.W);
|
||||
|
||||
writer.Write(Position);
|
||||
|
||||
writer.Write(Rotation.X);
|
||||
writer.Write(Rotation.Y);
|
||||
writer.Write(Rotation.Z);
|
||||
|
||||
writer.Write(UnknownInt);
|
||||
}
|
||||
|
||||
public void Deserialize(BitReader reader)
|
||||
{
|
||||
Type = reader.Read<int>();
|
||||
|
||||
var rotW = reader.Read<float>();
|
||||
|
||||
Position = reader.Read<Vector3>();
|
||||
|
||||
Rotation = new Quaternion
|
||||
{
|
||||
X = reader.Read<float>(),
|
||||
Y = reader.Read<float>(),
|
||||
Z = reader.Read<float>(),
|
||||
W = rotW
|
||||
};
|
||||
|
||||
UnknownInt = reader.Read<uint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
58
InfectedRose.sln
Normal file
58
InfectedRose.sln
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfectedRose.Terrain", "InfectedRose.Terrain\InfectedRose.Terrain.csproj", "{C5948668-31F0-457F-A1D7-A32DB85A6A5D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfectedRose.Examples", "InfectedRose.Examples\InfectedRose.Examples.csproj", "{135A3A1D-3C81-45AB-9195-DEB44D2581F4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfectedRose.Core", "InfectedRose.Core\InfectedRose.Core.csproj", "{2D0A3B97-ACED-487E-AF18-F6E81627D0F6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfectedRose.Luz", "InfectedRose.Luz\InfectedRose.Luz.csproj", "{0C38A6FC-7EF9-4B97-B767-6A2F40962D29}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfectedRose.Lvl", "InfectedRose.Lvl\InfectedRose.Lvl.csproj", "{8BC6E972-A4B6-4D79-9948-A3265FAAF2FC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfectedRose.Database", "InfectedRose.Database\InfectedRose.Database.csproj", "{94A2F951-BA5B-4C51-9EC5-C909D97D30A3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RakDotNet.IO", "RakDotNet.IO\RakDotNet.IO\RakDotNet.IO.csproj", "{C5BEDCE5-382D-4963-B68F-F098A9EB3CA8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfectedRose.Nif", "InfectedRose.Nif\InfectedRose.Nif.csproj", "{BDCD4970-7BFF-4C69-B866-F022583D9E18}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C5948668-31F0-457F-A1D7-A32DB85A6A5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5948668-31F0-457F-A1D7-A32DB85A6A5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5948668-31F0-457F-A1D7-A32DB85A6A5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5948668-31F0-457F-A1D7-A32DB85A6A5D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{135A3A1D-3C81-45AB-9195-DEB44D2581F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{135A3A1D-3C81-45AB-9195-DEB44D2581F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{135A3A1D-3C81-45AB-9195-DEB44D2581F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{135A3A1D-3C81-45AB-9195-DEB44D2581F4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2D0A3B97-ACED-487E-AF18-F6E81627D0F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2D0A3B97-ACED-487E-AF18-F6E81627D0F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2D0A3B97-ACED-487E-AF18-F6E81627D0F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2D0A3B97-ACED-487E-AF18-F6E81627D0F6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0C38A6FC-7EF9-4B97-B767-6A2F40962D29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0C38A6FC-7EF9-4B97-B767-6A2F40962D29}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0C38A6FC-7EF9-4B97-B767-6A2F40962D29}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0C38A6FC-7EF9-4B97-B767-6A2F40962D29}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8BC6E972-A4B6-4D79-9948-A3265FAAF2FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8BC6E972-A4B6-4D79-9948-A3265FAAF2FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8BC6E972-A4B6-4D79-9948-A3265FAAF2FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8BC6E972-A4B6-4D79-9948-A3265FAAF2FC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{94A2F951-BA5B-4C51-9EC5-C909D97D30A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{94A2F951-BA5B-4C51-9EC5-C909D97D30A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{94A2F951-BA5B-4C51-9EC5-C909D97D30A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{94A2F951-BA5B-4C51-9EC5-C909D97D30A3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C5BEDCE5-382D-4963-B68F-F098A9EB3CA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5BEDCE5-382D-4963-B68F-F098A9EB3CA8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5BEDCE5-382D-4963-B68F-F098A9EB3CA8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5BEDCE5-382D-4963-B68F-F098A9EB3CA8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BDCD4970-7BFF-4C69-B866-F022583D9E18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BDCD4970-7BFF-4C69-B866-F022583D9E18}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BDCD4970-7BFF-4C69-B866-F022583D9E18}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BDCD4970-7BFF-4C69-B866-F022583D9E18}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Reference in New Issue
Block a user