-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- testing_1.3.4.4
- testing_1.3.4.3
- testing_1.3.4.2
- testing_1.3.4.1
- testing_1.3.3.10
- testing_1.3.3.9
- testing_1.3.3.8
- testing_1.3.3.7
- testing_1.3.3.6
- testing_1.3.3.5
- testing_1.3.3.4
- testing_1.3.3.3
- testing_1.3.3.2
- testing_1.3.2.2
- testing_1.3.2.1
- testing_1.3.1.6
- testing_1.3.1.5
- testing_1.3.1.4
- testing_1.3.0.4
- testing_1.3.0.3
- testing_1.3.0.2
- testing_1.3.0.1
- testing_1.2.1.9
- testing_1.2.1.8
- testing_1.2.1.7
- testing_1.2.1.6
- testing_1.2.1.5
- testing_1.2.1.4
- testing_1.2.1.3
- testing_1.2.1.2
- testing_1.2.0.23
- testing_1.2.0.22
- testing_1.2.0.21
- testing_1.2.0.20
- testing_1.2.0.19
- testing_1.2.0.18
- testing_1.2.0.17
- testing_1.2.0.16
- testing_1.2.0.15
- testing_1.2.0.14
- testing_1.2.0.13
- testing_1.2.0.12
- testing_1.2.0.11
- testing_1.2.0.10
- testing_1.2.0.9
- testing_1.2.0.8
- testing_1.2.0.7
- testing_1.2.0.6
- testing_1.2.0.5
- testing_1.2.0.4
- testing_1.2.0.3
- testing_1.2.0.2
- testing_1.2.0.1
- testing_1.2.0.0
- testing_1.1.1.5
- testing_1.1.1.4
- testing_1.1.1.3
- testing_1.1.0.3
- testing_1.0.3.2
- testing_1.0.3.1
- testing_1.0.3.0
- testing_1.0.2.6
- testing_1.0.2.5
- testing_1.0.2.4
- testing_1.0.2.3
- testing_1.0.2.2
- testing_1.0.2.1
- testing_1.0.2.0
- testing_1.0.0.8
- testing_0.8.3.7
- testing_0.8.3.6
- testing_0.8.3.5
- testing_0.8.3.4
- testing_0.8.3.3
- testing_0.8.3.2
- testing_0.8.2.3
- testing_0.8.2.2
- testing_0.8.1.10
- testing_0.8.1.9
- testing_0.8.0.4
- testing_0.8.0.3
- testing_0.8.0.2
- testing_0.8.0.1
- testing_0.7.3.13
- testing_0.7.3.12
- testing_0.7.3.11
- testing_0.7.3.10
- testing_0.7.3.9
- testing_0.7.3.8
- testing_0.7.3.7
- testing_0.7.3.6
- testing_0.7.3.5
- testing_0.7.3.4
- testing_0.7.3.3
- testing_0.7.2.7
- testing_0.7.2.6
- testing_0.7.2.5
- testing_0.7.2.4
- testing_0.7.2.3
- testing_0.7.1.11
- testing_0.7.1.10
- testing_0.7.1.9
- t0.7.1.8
- t0.7.1.7
- t0.7.1.6
- t0.7.1.5
- t0.7.0.15
- t0.7.0.14
- t0.7.0.13
- t0.7.0.12
- t0.7.0.11
- t0.6.6.10
- t0.6.6.9
- t0.6.6.8
- t0.6.6.7
- t0.6.6.6
- t0.6.6.2
- t0.6.5.5
- t0.6.5.4
- t0.6.5.3
- t0.6.5.1
- t0.6.4.1
- t0.6.3.3
- t0.6.3.2
- t0.6.1.6
- t0.6.1.5
- t0.6.1.4
- t0.6.0.15
- t0.6.0.14
- t0.6.0.13
- t0.6.0.12
- t0.6.0.11
- t0.6.0.10
- t0.6.0.9
- t0.6.0.8
- t0.6.0.7
- t0.5.11.7
- t0.5.11.6
- t0.5.11.5
- t0.5.11.4
- t0.5.11.3
- t0.5.11.2
- t0.5.10.3
- t0.5.10.2
- t0.5.10.1
- t0.5.9.1
- t0.5.8.8
- t0.5.7.6
- t0.5.7.5
- t0.5.7.4
- t0.5.7.3
- t0.5.7.2
- t0.5.6.8
- t0.5.6.7
- t0.5.6.6
- t0.5.6.5
- t0.5.6.4
- t0.5.6.3
- t0.5.4.9
- t0.5.4.7
- t0.5.4.5
- t0.5.3.9
- t0.5.3.8
- t0.5.2.6
- t0.5.2.5
- t0.5.2.4
- t0.5.2.3
- t0.5.2.2
- t0.5.2.1
- t0.5.1.6
- t0.5.1.5
- t0.5.1.4
- t0.5.1.3
- t0.5.0.8
- t0.5.0.7
- t0.5.0.6
- 1.3.4.0
- 1.3.3.1
- 1.3.3.0
- 1.3.2.0
- 1.3.1.3
- 1.3.1.2
- 1.3.1.1
- 1.3.1.0
- 1.3.0.0
- 1.2.1.1
- 1.2.1.0
- 1.1.1.2
- 1.1.1.1
- 1.1.1.0
- 1.1.0.2
- 1.1.0.1
- 1.1.0.0
- 1.0.1.0
- 1.0.0.7
- 1.0.0.6
- 1.0.0.5
- 1.0.0.4
- 1.0.0.3
- 1.0.0.2
- 1.0.0.1
- 1.0.0.0
- 0.8.3.1
- 0.8.3.0
- 0.8.2.1
- 0.8.2.0
- 0.8.1.8
- 0.8.1.7
- 0.8.1.6
- 0.8.1.5
- 0.8.1.4
- 0.8.1.3
- 0.8.1.2
- 0.8.1.1
- 0.8.1.0
- 0.8.0.0
- 0.7.3.2
- 0.7.3.1
- 0.7.3.0
- 0.7.2.2
- 0.7.2.1
- 0.7.2.0
- 0.7.1.4
- 0.7.1.3
- 0.7.1.2
- 0.7.1.1
- 0.7.1.0
- 0.7.0.10
- 0.7.0.9
- 0.7.0.8
- 0.7.0.7
- 0.7.0.6
- 0.7.0.5
- 0.7.0.4
- 0.7.0.3
- 0.7.0.2
- 0.7.0.1
- 0.7.0.0
- 0.6.6.5
- 0.6.6.4
- 0.6.6.3
- 0.6.6.2
- 0.6.6.1
- 0.6.6.0
- 0.6.5.2
- 0.6.5.0
- 0.6.4.0
- 0.6.3.1
- 0.6.3.0
- 0.6.2.1
- 0.6.2.0
- 0.6.1.3
- 0.6.1.2
- 0.6.1.1
- 0.6.1.0
- 0.6.0.6
- 0.6.0.5
- 0.6.0.4
- 0.6.0.3
- 0.6.0.2
- 0.6.0.1
- 0.6.0.0
- 0.5.11.1
- 0.5.11.0
- 0.5.10.0
- 0.5.9.0
- 0.5.8.7
- 0.5.8.6
- 0.5.8.5
- 0.5.8.3
- 0.5.8.2
- 0.5.8.1
- 0.5.8.0
- 0.5.7.1
- 0.5.7.0
- 0.5.6.3
- 0.5.6.2
- 0.5.6.1
- 0.5.6.0
- 0.5.5.0
- 0.5.4.8
- 0.5.4.6
- 0.5.4.4
- 0.5.4.1
- 0.5.4.0
- 0.5.3.7
- 0.5.3.6
- 0.5.3.5
- 0.5.3.4
- 0.5.3.3
- 0.5.3.2
- 0.5.3.1
- 0.5.3.0
- 0.5.2.0
- 0.5.1.2
- 0.5.1.1
- 0.5.1.0
- 0.5.0.5
- 0.5.0.4
- 0.5.0.3
- 0.5.0.2
- 0.5.0.1
- 0.5.0.0
- 0.4.8.2
- 0.4.8.1
- 0.4.8.0
- 0.4.7.7
- 0.4.7.6
- 0.4.7.5
- 0.4.7.4
- 0.4.7.3
- 0.4.7.2
- 0.4.7.1
- 0.4.7.0
- 0.4.6.9
- 0.4.6.8
- 0.4.6.7
- 0.4.6.6
- 0.4.6.5
- 0.4.6.4
- 0.4.6.3
- 0.4.6.2
- 0.4.6.1
- 0.4.6.0
- 0.4.5.0
- 0.4.4.9
- 0.4.4.8
- 0.4.4.7
- 0.4.4.6
- 0.4.4.5
- 0.4.4.4
- 0.4.2.7
- 0.4.2.6
- 0.4.2.5
- 0.4.2.4
- 0.4.2.3
- 0.4.2.2
- 0.4.2.1
- 0.4.2.0
- 0.4.1.0
- 0.4.0.3
- 0.4.0.2
- 0.4.0.1
- 0.4.0.0
- 0.3.5.2
- 0.3.5.1
- 0.3.5.0
- 0.3.4.3
- 0.3.4.2
- 0.3.4.1
- 0.3.4.0
- 0.3.3.3
- 0.3.3.2
- 0.3.3.1
- 0.3.3.0
- 0.3.2.0
- 0.3.1.0
- 0.3.0.0
- 0.2.2.0
- 0.2.1.0
- 0.2.0.1
- 0.2.0.0
- 0.1.6.1
- 0.1.6.0
0 parents
commit 0e7650f
Showing
27 changed files
with
1,596 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
|
||
[*] | ||
charset=utf-8 | ||
end_of_line=crlf | ||
trim_trailing_whitespace=false | ||
insert_final_newline=false | ||
indent_style=space | ||
indent_size=4 | ||
|
||
# Microsoft .NET properties | ||
csharp_new_line_before_members_in_object_initializers=false | ||
csharp_preferred_modifier_order=public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion | ||
csharp_space_after_cast=false | ||
csharp_space_after_keywords_in_control_flow_statements=false | ||
csharp_space_between_method_call_parameter_list_parentheses=true | ||
csharp_space_between_method_declaration_parameter_list_parentheses=true | ||
csharp_space_between_parentheses=control_flow_statements,expressions,type_casts | ||
csharp_style_var_elsewhere=true:suggestion | ||
csharp_style_var_for_built_in_types=true:suggestion | ||
csharp_style_var_when_type_is_apparent=true:suggestion | ||
dotnet_style_parentheses_in_arithmetic_binary_operators=never_if_unnecessary:none | ||
dotnet_style_parentheses_in_other_binary_operators=never_if_unnecessary:none | ||
dotnet_style_parentheses_in_relational_binary_operators=never_if_unnecessary:none | ||
dotnet_style_predefined_type_for_locals_parameters_members=true:suggestion | ||
dotnet_style_predefined_type_for_member_access=true:suggestion | ||
dotnet_style_qualification_for_event=false:suggestion | ||
dotnet_style_qualification_for_field=false:suggestion | ||
dotnet_style_qualification_for_method=false:suggestion | ||
dotnet_style_qualification_for_property=false:suggestion | ||
dotnet_style_require_accessibility_modifiers=for_non_interface_members:suggestion | ||
|
||
# ReSharper properties | ||
resharper_autodetect_indent_settings=true | ||
resharper_csharp_space_within_array_access_brackets=true | ||
resharper_enforce_line_ending_style=true | ||
resharper_place_attribute_on_same_line=false | ||
resharper_space_after_cast=false | ||
resharper_space_within_checked_parentheses=true | ||
resharper_space_within_default_parentheses=true | ||
resharper_space_within_nameof_parentheses=true | ||
resharper_space_within_single_line_array_initializer_braces=true | ||
resharper_space_within_sizeof_parentheses=true | ||
resharper_space_within_typeof_parentheses=true | ||
resharper_space_within_type_argument_angles=true | ||
resharper_space_within_type_parameter_angles=true | ||
resharper_use_indent_from_vs=false | ||
resharper_wrap_lines=true | ||
|
||
# ReSharper inspection severities | ||
resharper_arrange_redundant_parentheses_highlighting=hint | ||
resharper_arrange_this_qualifier_highlighting=hint | ||
resharper_arrange_type_member_modifiers_highlighting=hint | ||
resharper_arrange_type_modifiers_highlighting=hint | ||
resharper_built_in_type_reference_style_for_member_access_highlighting=hint | ||
resharper_built_in_type_reference_style_highlighting=hint | ||
resharper_redundant_base_qualifier_highlighting=warning | ||
resharper_suggest_var_or_type_built_in_types_highlighting=hint | ||
resharper_suggest_var_or_type_elsewhere_highlighting=hint | ||
resharper_suggest_var_or_type_simple_types_highlighting=hint | ||
resharper_web_config_module_not_resolved_highlighting=warning | ||
resharper_web_config_type_not_resolved_highlighting=warning | ||
resharper_web_config_wrong_module_highlighting=warning | ||
|
||
[*.{appxmanifest,asax,ascx,aspx,build,cg,cginc,compute,cs,cshtml,dtd,hlsl,hlsli,hlslinc,master,nuspec,razor,resw,resx,shader,skin,usf,ush,vb,xaml,xamlx,xoml,xsd}] | ||
indent_style=space | ||
indent_size=4 | ||
tab_width=4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.vs/ | ||
obj/ | ||
bin/ | ||
*.user |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 16 | ||
VisualStudioVersion = 16.0.29709.97 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Penumbra", "Penumbra\Penumbra.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}" | ||
EndProject | ||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F89C9EAE-25C8-43BE-8108-5921E5A93502}" | ||
ProjectSection(SolutionItems) = preProject | ||
.editorconfig = .editorconfig | ||
EndProjectSection | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {B17E85B1-5F60-4440-9F9A-3DDE877E8CDF} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
using Dalamud.Configuration; | ||
using Dalamud.Plugin; | ||
using System; | ||
|
||
namespace Penumbra | ||
{ | ||
[Serializable] | ||
public class Configuration : IPluginConfiguration | ||
{ | ||
public int Version { get; set; } = 0; | ||
|
||
public bool IsEnabled { get; set; } = true; | ||
|
||
public string BaseFolder { get; set; } = @"D:/ffxiv/fs_mods/"; | ||
|
||
// the below exist just to make saving less cumbersome | ||
|
||
[NonSerialized] | ||
private DalamudPluginInterface _pluginInterface; | ||
|
||
public void Initialize( DalamudPluginInterface pluginInterface ) | ||
{ | ||
_pluginInterface = pluginInterface; | ||
} | ||
|
||
public void Save() | ||
{ | ||
_pluginInterface.SavePluginConfig( this ); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Drawing; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using System.Windows.Forms; | ||
|
||
namespace Penumbra | ||
{ | ||
public static class DialogExtensions | ||
{ | ||
public static Task< DialogResult > ShowDialogAsync( this CommonDialog form ) | ||
{ | ||
using var process = Process.GetCurrentProcess(); | ||
return form.ShowDialogAsync( new DialogHandle( process.MainWindowHandle ) ); | ||
} | ||
|
||
public static Task< DialogResult > ShowDialogAsync( this CommonDialog form, IWin32Window owner ) | ||
{ | ||
var taskSource = new TaskCompletionSource< DialogResult >(); | ||
var th = new Thread( () => DialogThread( form, owner, taskSource ) ); | ||
th.Start(); | ||
return taskSource.Task; | ||
} | ||
|
||
[STAThread] | ||
private static void DialogThread( CommonDialog form, IWin32Window owner, | ||
TaskCompletionSource< DialogResult > taskSource ) | ||
{ | ||
Application.SetCompatibleTextRenderingDefault( false ); | ||
Application.EnableVisualStyles(); | ||
using var hiddenForm = new HiddenForm( form, owner, taskSource ); | ||
Application.Run( hiddenForm ); | ||
Application.ExitThread(); | ||
} | ||
|
||
public class DialogHandle : IWin32Window | ||
{ | ||
public IntPtr Handle { get; set; } | ||
|
||
public DialogHandle( IntPtr handle ) | ||
{ | ||
Handle = handle; | ||
} | ||
} | ||
|
||
public class HiddenForm : Form | ||
{ | ||
private readonly CommonDialog form; | ||
private readonly IWin32Window owner; | ||
private readonly TaskCompletionSource< DialogResult > taskSource; | ||
|
||
public HiddenForm( CommonDialog form, IWin32Window owner, TaskCompletionSource< DialogResult > taskSource ) | ||
{ | ||
this.form = form; | ||
this.owner = owner; | ||
this.taskSource = taskSource; | ||
|
||
Opacity = 0; | ||
FormBorderStyle = FormBorderStyle.None; | ||
ShowInTaskbar = false; | ||
Size = new Size( 0, 0 ); | ||
|
||
Shown += HiddenForm_Shown; | ||
} | ||
|
||
private void HiddenForm_Shown( object sender, EventArgs _ ) | ||
{ | ||
Hide(); | ||
try | ||
{ | ||
var result = form.ShowDialog( owner ); | ||
taskSource.SetResult( result ); | ||
} | ||
catch( Exception e ) | ||
{ | ||
taskSource.SetException( e ); | ||
} | ||
|
||
Close(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
using System; | ||
using System.Reflection; | ||
using System.Reflection.Emit; | ||
|
||
namespace Penumbra.Extensions | ||
{ | ||
public static class FuckedExtensions | ||
{ | ||
private delegate ref TFieldType RefGet< in TObject, TFieldType >( TObject obj ); | ||
|
||
/// <summary> | ||
/// Create a delegate which will return a zero-copy reference to a given field in a manner that's fucked tiers of quick and | ||
/// fucked tiers of stupid, but hey, why not? | ||
/// </summary> | ||
/// <remarks> | ||
/// The only thing that this can't do is inline, this always ends up as a call instruction because we're generating code at | ||
/// runtime and need to jump to it. That said, this is still super quick and provides a convenient and type safe shim around | ||
/// a primitive type | ||
/// | ||
/// You can use the resultant <see cref="RefGet{TObject,TFieldType}"/> to access a ref to a field on an object without invoking any | ||
/// unsafe code too. | ||
/// </remarks> | ||
/// <param name="fieldName">The name of the field to grab a reference to</param> | ||
/// <typeparam name="TObject">The object that holds the field</typeparam> | ||
/// <typeparam name="TField">The type of the underlying field</typeparam> | ||
/// <returns>A delegate that will return a reference to a particular field - zero copy</returns> | ||
/// <exception cref="MissingFieldException"></exception> | ||
private static RefGet< TObject, TField > CreateRefGetter< TObject, TField >( string fieldName ) where TField : unmanaged | ||
{ | ||
const BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; | ||
|
||
var fieldInfo = typeof( TObject ).GetField( fieldName, flags ); | ||
if( fieldInfo == null ) | ||
{ | ||
throw new MissingFieldException( typeof( TObject ).Name, fieldName ); | ||
} | ||
|
||
var dm = new DynamicMethod( | ||
$"__refget_{typeof( TObject ).Name}_{fieldInfo.Name}", | ||
typeof( TField ).MakeByRefType(), | ||
new[] { typeof( TObject ) }, | ||
typeof( TObject ), | ||
true | ||
); | ||
|
||
var il = dm.GetILGenerator(); | ||
|
||
il.Emit( OpCodes.Ldarg_0 ); | ||
il.Emit( OpCodes.Ldflda, fieldInfo ); | ||
il.Emit( OpCodes.Ret ); | ||
|
||
return ( RefGet< TObject, TField > )dm.CreateDelegate( typeof( RefGet< TObject, TField > ) ); | ||
} | ||
|
||
private static readonly RefGet< string, byte > StringRefGet = CreateRefGetter< string, byte >( "_firstChar" ); | ||
|
||
public static unsafe IntPtr UnsafePtr( this string str ) | ||
{ | ||
// nb: you can do it without __makeref but the code becomes way shittier because the way of getting the ptr | ||
// is more fucked up so it's easier to just abuse __makeref | ||
// but you can just use the StringRefGet func to get a `ref byte` too, though you'll probs want a better delegate so it's | ||
// actually usable, lol | ||
var fieldRef = __makeref( StringRefGet( str ) ); | ||
|
||
return *( IntPtr* )&fieldRef; | ||
} | ||
|
||
public static unsafe int UnsafeLength( this string str ) | ||
{ | ||
var fieldRef = __makeref( StringRefGet( str ) ); | ||
|
||
// c# strings are utf16 so we just multiply len by 2 to get the total byte count + 2 for null terminator (:D) | ||
// very simple and intuitive | ||
|
||
// this also maps to a defined structure, so you can just move the pointer backwards to read from the native string struct | ||
// see: https://github.com/dotnet/coreclr/blob/master/src/vm/object.h#L897-L909 | ||
return *( int* )( *( IntPtr* )&fieldRef - 4 ) * 2 + 2; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace Penumbra.Importer.Models | ||
{ | ||
internal class OptionList | ||
{ | ||
public string Name { get; set; } | ||
public object Description { get; set; } | ||
public string ImagePath { get; set; } | ||
public List< SimpleMod > ModsJsons { get; set; } | ||
public string GroupName { get; set; } | ||
public string SelectionType { get; set; } | ||
public bool IsChecked { get; set; } | ||
} | ||
|
||
internal class ModGroup | ||
{ | ||
public string GroupName { get; set; } | ||
public string SelectionType { get; set; } | ||
public List< OptionList > OptionList { get; set; } | ||
} | ||
|
||
internal class ModPackPage | ||
{ | ||
public int PageIndex { get; set; } | ||
public List< ModGroup > ModGroups { get; set; } | ||
} | ||
|
||
internal class ExtendedModPack | ||
{ | ||
public string TTMPVersion { get; set; } | ||
public string Name { get; set; } | ||
public string Author { get; set; } | ||
public string Version { get; set; } | ||
public string Description { get; set; } | ||
public List< ModPackPage > ModPackPages { get; set; } | ||
public List< SimpleMod > SimpleModsList { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace Penumbra.Importer.Models | ||
{ | ||
internal class SimpleModPack | ||
{ | ||
public string TTMPVersion { get; set; } | ||
public string Name { get; set; } | ||
public string Author { get; set; } | ||
public string Version { get; set; } | ||
public string Description { get; set; } | ||
public List< SimpleMod > SimpleModsList { get; set; } | ||
} | ||
|
||
internal class SimpleMod | ||
{ | ||
public string Name { get; set; } | ||
public string Category { get; set; } | ||
public string FullPath { get; set; } | ||
public int ModOffset { get; set; } | ||
public int ModSize { get; set; } | ||
public string DatFile { get; set; } | ||
public object ModPackEntry { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
using Dalamud.Plugin; | ||
using Ionic.Zip; | ||
using Lumina.Data; | ||
using Newtonsoft.Json; | ||
using Penumbra.Importer.Models; | ||
using Penumbra.Models; | ||
|
||
namespace Penumbra.Importer | ||
{ | ||
internal class TexToolsImport | ||
{ | ||
private readonly DirectoryInfo _outDirectory; | ||
|
||
public TexToolsImport( DirectoryInfo outDirectory ) | ||
{ | ||
_outDirectory = outDirectory; | ||
} | ||
|
||
public void ImportModPack( FileInfo modPackFile ) | ||
{ | ||
switch( modPackFile.Extension ) | ||
{ | ||
case ".ttmp": | ||
ImportV1ModPack( modPackFile ); | ||
return; | ||
|
||
case ".ttmp2": | ||
ImportV2ModPack( modPackFile ); | ||
return; | ||
} | ||
} | ||
|
||
private void ImportV1ModPack( FileInfo modPackFile ) | ||
{ | ||
PluginLog.Log( " -> Importing V1 ModPack" ); | ||
|
||
using var extractedModPack = ZipFile.Read( modPackFile.OpenRead() ); | ||
|
||
var modListRaw = GetStringFromZipEntry( extractedModPack[ "TTMPL.mpl" ], Encoding.UTF8 ).Split( | ||
new[] { "\r\n", "\r", "\n" }, | ||
StringSplitOptions.None | ||
); | ||
|
||
var modList = modListRaw.Select( JsonConvert.DeserializeObject< SimpleMod > ); | ||
|
||
// Create a new ModMeta from the TTMP modlist info | ||
var modMeta = new ModMeta | ||
{ | ||
Author = "Unknown", | ||
Name = modPackFile.Name, | ||
Description = "Mod imported from TexTools mod pack" | ||
}; | ||
|
||
// Open the mod data file from the modpack as a SqPackStream | ||
var modData = GetSqPackStreamFromZipEntry( extractedModPack[ "TTMPD.mpd" ] ); | ||
|
||
var newModFolder = new DirectoryInfo( Path.Combine( _outDirectory.FullName, | ||
Path.GetFileNameWithoutExtension( modPackFile.Name ) ) ); | ||
newModFolder.Create(); | ||
|
||
File.WriteAllText( Path.Combine( newModFolder.FullName, "meta.json" ), | ||
JsonConvert.SerializeObject( modMeta ) ); | ||
|
||
ExtractSimpleModList( newModFolder, modList, modData ); | ||
} | ||
|
||
private void ImportV2ModPack( FileInfo modPackFile ) | ||
{ | ||
using var extractedModPack = ZipFile.Read( modPackFile.OpenRead() ); | ||
|
||
var modList = | ||
JsonConvert.DeserializeObject< SimpleModPack >( GetStringFromZipEntry( extractedModPack[ "TTMPL.mpl" ], | ||
Encoding.UTF8 ) ); | ||
|
||
if( modList.TTMPVersion.EndsWith( "s" ) ) | ||
{ | ||
ImportSimpleV2ModPack( extractedModPack ); | ||
return; | ||
} | ||
|
||
if( modList.TTMPVersion.EndsWith( "w" ) ) | ||
{ | ||
ImportExtendedV2ModPack( extractedModPack ); | ||
} | ||
} | ||
|
||
private void ImportSimpleV2ModPack( ZipFile extractedModPack ) | ||
{ | ||
PluginLog.Log( " -> Importing Simple V2 ModPack" ); | ||
|
||
var modList = | ||
JsonConvert.DeserializeObject< SimpleModPack >( GetStringFromZipEntry( extractedModPack[ "TTMPL.mpl" ], | ||
Encoding.UTF8 ) ); | ||
|
||
// Create a new ModMeta from the TTMP modlist info | ||
var modMeta = new ModMeta | ||
{ | ||
Author = modList.Author, | ||
Name = modList.Name, | ||
Description = string.IsNullOrEmpty( modList.Description ) | ||
? "Mod imported from TexTools mod pack" | ||
: modList.Description | ||
}; | ||
|
||
// Open the mod data file from the modpack as a SqPackStream | ||
var modData = GetSqPackStreamFromZipEntry( extractedModPack[ "TTMPD.mpd" ] ); | ||
|
||
var newModFolder = new DirectoryInfo( Path.Combine( _outDirectory.FullName, | ||
Path.GetFileNameWithoutExtension( modList.Name ) ) ); | ||
newModFolder.Create(); | ||
|
||
File.WriteAllText( Path.Combine( newModFolder.FullName, "meta.json" ), | ||
JsonConvert.SerializeObject( modMeta ) ); | ||
|
||
ExtractSimpleModList( newModFolder, modList.SimpleModsList, modData ); | ||
} | ||
|
||
private void ImportExtendedV2ModPack( ZipFile extractedModPack ) | ||
{ | ||
PluginLog.Log( " -> Importing Extended V2 ModPack" ); | ||
|
||
var modList = | ||
JsonConvert.DeserializeObject< ExtendedModPack >( GetStringFromZipEntry( extractedModPack[ "TTMPL.mpl" ], | ||
Encoding.UTF8 ) ); | ||
|
||
// Create a new ModMeta from the TTMP modlist info | ||
var modMeta = new ModMeta | ||
{ | ||
Author = modList.Author, | ||
Name = modList.Name, | ||
Description = string.IsNullOrEmpty( modList.Description ) | ||
? "Mod imported from TexTools mod pack" | ||
: modList.Description | ||
}; | ||
|
||
// Open the mod data file from the modpack as a SqPackStream | ||
var modData = GetSqPackStreamFromZipEntry( extractedModPack[ "TTMPD.mpd" ] ); | ||
|
||
var newModFolder = new DirectoryInfo( Path.Combine( _outDirectory.FullName, | ||
Path.GetFileNameWithoutExtension( modList.Name ) ) ); | ||
newModFolder.Create(); | ||
|
||
File.WriteAllText( Path.Combine( newModFolder.FullName, "meta.json" ), | ||
JsonConvert.SerializeObject( modMeta ) ); | ||
|
||
if( modList.SimpleModsList != null ) | ||
ExtractSimpleModList( newModFolder, modList.SimpleModsList, modData ); | ||
|
||
if( modList.ModPackPages == null ) | ||
return; | ||
|
||
// Iterate through all pages | ||
// For now, we are just going to import the default selections | ||
// TODO: implement such a system in resrep? | ||
foreach( var option in from modPackPage in modList.ModPackPages | ||
from modGroup in modPackPage.ModGroups | ||
from option in modGroup.OptionList | ||
where option.IsChecked | ||
select option ) | ||
{ | ||
ExtractSimpleModList( newModFolder, option.ModsJsons, modData ); | ||
} | ||
} | ||
|
||
private void ImportMetaModPack( FileInfo file ) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
private void ExtractSimpleModList( DirectoryInfo outDirectory, IEnumerable< SimpleMod > mods, SqPackStream dataStream ) | ||
{ | ||
// Extract each SimpleMod into the new mod folder | ||
foreach( var simpleMod in mods ) | ||
{ | ||
if( simpleMod == null ) | ||
continue; | ||
|
||
ExtractMod( outDirectory, simpleMod, dataStream ); | ||
} | ||
} | ||
|
||
private void ExtractMod( DirectoryInfo outDirectory, SimpleMod mod, SqPackStream dataStream ) | ||
{ | ||
PluginLog.Log( " -> Extracting {0} at {1}", mod.FullPath, mod.ModOffset.ToString( "X" ) ); | ||
|
||
try | ||
{ | ||
var data = dataStream.ReadFile< FileResource >( mod.ModOffset ); | ||
|
||
var extractedFile = new FileInfo( Path.Combine( outDirectory.FullName, mod.FullPath ) ); | ||
extractedFile.Directory?.Create(); | ||
|
||
File.WriteAllBytes( extractedFile.FullName, data.Data ); | ||
} | ||
catch( Exception ex ) | ||
{ | ||
PluginLog.LogError( ex, "Could not export mod." ); | ||
} | ||
} | ||
|
||
private static MemoryStream GetStreamFromZipEntry( ZipEntry entry ) | ||
{ | ||
var stream = new MemoryStream(); | ||
entry.Extract( stream ); | ||
return stream; | ||
} | ||
|
||
private static string GetStringFromZipEntry( ZipEntry entry, Encoding encoding ) | ||
{ | ||
return encoding.GetString( GetStreamFromZipEntry( entry ).ToArray() ); | ||
} | ||
|
||
private static SqPackStream GetSqPackStreamFromZipEntry( ZipEntry entry ) | ||
{ | ||
return new SqPackStream( GetStreamFromZipEntry( entry ) ); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using Dalamud.Plugin; | ||
using Penumbra.Models; | ||
using Newtonsoft.Json; | ||
|
||
namespace Penumbra | ||
{ | ||
public class ModManager | ||
{ | ||
public DirectoryInfo BasePath { get; set; } | ||
|
||
public readonly Dictionary< string, ResourceMod > AvailableMods = new Dictionary< string, ResourceMod >(); | ||
|
||
public readonly Dictionary< string, FileInfo > ResolvedFiles = new Dictionary< string, FileInfo >(); | ||
|
||
public ModManager( DirectoryInfo basePath ) | ||
{ | ||
BasePath = basePath; | ||
} | ||
|
||
public ModManager() | ||
{ | ||
} | ||
|
||
public void DiscoverMods() | ||
{ | ||
if( BasePath == null ) | ||
{ | ||
return; | ||
} | ||
|
||
if( !BasePath.Exists ) | ||
{ | ||
return; | ||
} | ||
|
||
AvailableMods.Clear(); | ||
ResolvedFiles.Clear(); | ||
|
||
// get all mod dirs | ||
foreach( var modDir in BasePath.EnumerateDirectories() ) | ||
{ | ||
var metaFile = modDir.EnumerateFiles().FirstOrDefault( f => f.Name == "meta.json" ); | ||
|
||
if( metaFile == null ) | ||
{ | ||
PluginLog.LogError( "mod meta is missing for resource mod: {ResourceModLocation}", modDir ); | ||
continue; | ||
} | ||
|
||
var meta = JsonConvert.DeserializeObject< Models.ModMeta >( File.ReadAllText( metaFile.FullName ) ); | ||
|
||
var mod = new ResourceMod | ||
{ | ||
Meta = meta, | ||
ModBasePath = modDir | ||
}; | ||
|
||
AvailableMods[ modDir.Name ] = mod; | ||
mod.RefreshModFiles(); | ||
} | ||
|
||
// todo: sort the mods by priority here so that the file discovery works correctly | ||
|
||
foreach( var mod in AvailableMods.Select( m => m.Value ) ) | ||
{ | ||
// fixup path | ||
var baseDir = mod.ModBasePath.FullName; | ||
|
||
foreach( var file in mod.ModFiles ) | ||
{ | ||
var path = file.FullName.Substring( baseDir.Length ).ToLowerInvariant() | ||
.TrimStart( '\\' ).Replace( '\\', '/' ); | ||
|
||
// todo: notify when collisions happen? or some extra state on the file? not sure yet | ||
// this code is shit all the same | ||
|
||
if( !ResolvedFiles.ContainsKey( path ) ) | ||
{ | ||
ResolvedFiles[ path ] = file; | ||
} | ||
else | ||
{ | ||
PluginLog.LogError( | ||
"a different mod already fucks this file: {FilePath}", | ||
ResolvedFiles[ path ].FullName | ||
); | ||
} | ||
} | ||
} | ||
} | ||
|
||
public FileInfo GetCandidateForGameFile( string resourcePath ) | ||
{ | ||
return ResolvedFiles.TryGetValue( resourcePath.ToLowerInvariant(), out var fileInfo ) ? fileInfo : null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace Penumbra.Models | ||
{ | ||
public class ModMeta | ||
{ | ||
public string Name { get; set; } | ||
public string Author { get; set; } | ||
public string Description { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
using System; | ||
using System.IO; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
using Dalamud.Hooking; | ||
using Dalamud.Plugin; | ||
using Penumbra.Structs; | ||
using Penumbra.Util; | ||
using FileMode = Penumbra.Structs.FileMode; | ||
using Penumbra.Extensions; | ||
|
||
namespace Penumbra | ||
{ | ||
public class Penumbra : IDisposable | ||
{ | ||
public Plugin Plugin { get; set; } | ||
|
||
public bool IsEnabled { get; set; } | ||
|
||
public Crc32 Crc32 { get; } | ||
|
||
|
||
// Delegate prototypes | ||
public unsafe delegate byte ReadFilePrototype( IntPtr pFileHandler, SeFileDescriptor* pFileDesc, int priority, bool isSync ); | ||
|
||
public unsafe delegate byte ReadSqpackPrototype( IntPtr pFileHandler, SeFileDescriptor* pFileDesc, int priority, bool isSync ); | ||
|
||
public unsafe delegate void* GetResourceSyncPrototype( IntPtr pFileManager, uint* pCategoryId, char* pResourceType, | ||
uint* pResourceHash, char* pPath, void* pUnknown ); | ||
|
||
public unsafe delegate void* GetResourceAsyncPrototype( IntPtr pFileManager, uint* pCategoryId, char* pResourceType, | ||
uint* pResourceHash, char* pPath, void* pUnknown, bool isUnknown ); | ||
|
||
|
||
// Hooks | ||
public Hook< GetResourceSyncPrototype > GetResourceSyncHook { get; private set; } | ||
public Hook< GetResourceAsyncPrototype > GetResourceAsyncHook { get; private set; } | ||
public Hook< ReadSqpackPrototype > ReadSqpackHook { get; private set; } | ||
|
||
// Unmanaged functions | ||
public ReadFilePrototype ReadFile { get; private set; } | ||
|
||
|
||
public Penumbra( Plugin plugin ) | ||
{ | ||
Plugin = plugin; | ||
Crc32 = new Crc32(); | ||
} | ||
|
||
public unsafe void Init() | ||
{ | ||
var scanner = Plugin.PluginInterface.TargetModuleScanner; | ||
|
||
var readFileAddress = | ||
scanner.ScanText( "E8 ?? ?? ?? ?? 84 C0 0F 84 ?? 00 00 00 4C 8B C3 BA 05" ); | ||
|
||
var readSqpackAddress = | ||
scanner.ScanText( "E8 ?? ?? ?? ?? EB 05 E8 ?? ?? ?? ?? 84 C0 0F 84 ?? 00 00 00 4C 8B C3" ); | ||
|
||
var getResourceSyncAddress = | ||
scanner.ScanText( "E8 ?? ?? 00 00 48 8D 4F ?? 48 89 87 ?? ?? 00 00" ); | ||
|
||
var getResourceAsyncAddress = | ||
scanner.ScanText( "E8 ?? ?? ?? 00 48 8B D8 EB ?? F0 FF 83 ?? ?? 00 00" ); | ||
|
||
|
||
ReadSqpackHook = new Hook< ReadSqpackPrototype >( readSqpackAddress, new ReadSqpackPrototype( ReadSqpackHandler ) ); | ||
|
||
GetResourceSyncHook = new Hook< GetResourceSyncPrototype >( getResourceSyncAddress, | ||
new GetResourceSyncPrototype( GetResourceSyncHandler ) ); | ||
|
||
GetResourceAsyncHook = new Hook< GetResourceAsyncPrototype >( getResourceAsyncAddress, | ||
new GetResourceAsyncPrototype( GetResourceAsyncHandler ) ); | ||
|
||
ReadFile = Marshal.GetDelegateForFunctionPointer< ReadFilePrototype >( readFileAddress ); | ||
} | ||
|
||
|
||
public unsafe void* GetResourceSyncHandler( IntPtr pFileManager, uint* pCategoryId, | ||
char* pResourceType, uint* pResourceHash, char* pPath, void* pUnknown ) | ||
{ | ||
return GetResourceHandler( true, pFileManager, pCategoryId, pResourceType, | ||
pResourceHash, pPath, pUnknown, false ); | ||
} | ||
|
||
public unsafe void* GetResourceAsyncHandler( IntPtr pFileManager, uint* pCategoryId, | ||
char* pResourceType, uint* pResourceHash, char* pPath, void* pUnknown, bool isUnknown ) | ||
{ | ||
return GetResourceHandler( false, pFileManager, pCategoryId, pResourceType, | ||
pResourceHash, pPath, pUnknown, isUnknown ); | ||
} | ||
|
||
private unsafe void* GetResourceHandler( bool isSync, IntPtr pFileManager, uint* pCategoryId, | ||
char* pResourceType, uint* pResourceHash, char* pPath, void* pUnknown, bool isUnknown ) | ||
{ | ||
var gameFsPath = Marshal.PtrToStringAnsi( new IntPtr( pPath ) ); | ||
|
||
var candidate = Plugin.ModManager.GetCandidateForGameFile( gameFsPath ); | ||
|
||
// path must be < 260 because statically defined array length :( | ||
if( candidate == null || candidate.FullName.Length >= 260 || !candidate.Exists ) | ||
{ | ||
return isSync | ||
? GetResourceSyncHook.Original( pFileManager, pCategoryId, pResourceType, | ||
pResourceHash, pPath, pUnknown ) | ||
: GetResourceAsyncHook.Original( pFileManager, pCategoryId, pResourceType, | ||
pResourceHash, pPath, pUnknown, isUnknown ); | ||
} | ||
|
||
var cleanPath = candidate.FullName.Replace( '\\', '/' ); | ||
var asciiPath = Encoding.ASCII.GetBytes( cleanPath ); | ||
|
||
var bPath = stackalloc byte[asciiPath.Length + 1]; | ||
Marshal.Copy( asciiPath, 0, new IntPtr( bPath ), asciiPath.Length ); | ||
pPath = ( char* )bPath; | ||
|
||
Crc32.Init(); | ||
Crc32.Update( asciiPath ); | ||
*pResourceHash = Crc32.Checksum; | ||
|
||
return isSync | ||
? GetResourceSyncHook.Original( pFileManager, pCategoryId, pResourceType, | ||
pResourceHash, pPath, pUnknown ) | ||
: GetResourceAsyncHook.Original( pFileManager, pCategoryId, pResourceType, | ||
pResourceHash, pPath, pUnknown, isUnknown ); | ||
} | ||
|
||
|
||
public unsafe byte ReadSqpackHandler( IntPtr pFileHandler, SeFileDescriptor* pFileDesc, int priority, bool isSync ) | ||
{ | ||
var gameFsPath = Marshal.PtrToStringAnsi( new IntPtr( pFileDesc->ResourceHandle->FileName ) ); | ||
|
||
var isRooted = Path.IsPathRooted( gameFsPath ); | ||
|
||
if( gameFsPath == null || gameFsPath.Length >= 260 || !isRooted ) | ||
{ | ||
return ReadSqpackHook.Original( pFileHandler, pFileDesc, priority, isSync ); | ||
} | ||
|
||
#if DEBUG | ||
PluginLog.Log( "loading modded file: {GameFsPath}", gameFsPath ); | ||
#endif | ||
|
||
pFileDesc->FileMode = FileMode.LoadUnpackedResource; | ||
|
||
var utfPath = Encoding.Unicode.GetBytes( gameFsPath ); | ||
|
||
Marshal.Copy( utfPath, 0, new IntPtr( &pFileDesc->UtfFileName ), utfPath.Length ); | ||
|
||
var fd = stackalloc byte[0x20 + utfPath.Length + 0x16]; | ||
Marshal.Copy( utfPath, 0, new IntPtr( fd + 0x21 ), utfPath.Length ); | ||
|
||
pFileDesc->FileDescriptor = fd; | ||
|
||
|
||
return ReadFile( pFileHandler, pFileDesc, priority, isSync ); | ||
} | ||
|
||
public void Enable() | ||
{ | ||
if( IsEnabled ) | ||
return; | ||
|
||
ReadSqpackHook.Enable(); | ||
GetResourceSyncHook.Enable(); | ||
GetResourceAsyncHook.Enable(); | ||
|
||
IsEnabled = true; | ||
} | ||
|
||
public void Disable() | ||
{ | ||
if( !IsEnabled ) | ||
return; | ||
|
||
ReadSqpackHook.Disable(); | ||
GetResourceSyncHook.Disable(); | ||
GetResourceAsyncHook.Disable(); | ||
|
||
IsEnabled = false; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
if( IsEnabled ) | ||
Disable(); | ||
|
||
ReadSqpackHook.Dispose(); | ||
GetResourceSyncHook.Dispose(); | ||
GetResourceAsyncHook.Dispose(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | ||
<PropertyGroup> | ||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
<ProjectGuid>{13C812E9-0D42-4B95-8646-40EEBF30636F}</ProjectGuid> | ||
<OutputType>Library</OutputType> | ||
<AppDesignerFolder>Properties</AppDesignerFolder> | ||
<RootNamespace>Penumbra</RootNamespace> | ||
<AssemblyName>Penumbra</AssemblyName> | ||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion> | ||
<FileAlignment>512</FileAlignment> | ||
<Deterministic>true</Deterministic> | ||
<LangVersion>8</LangVersion> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||
<DebugSymbols>true</DebugSymbols> | ||
<DebugType>full</DebugType> | ||
<Optimize>false</Optimize> | ||
<OutputPath>bin\Debug\</OutputPath> | ||
<DefineConstants>DEBUG;TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||
<DebugType>pdbonly</DebugType> | ||
<Optimize>true</Optimize> | ||
<OutputPath>bin\Release\</OutputPath> | ||
<DefineConstants>TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Reference Include="Dalamud"> | ||
<HintPath>..\libs\Dalamud.dll</HintPath> | ||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Dalamud.dll</HintPath> | ||
<Private>False</Private> | ||
</Reference> | ||
<Reference Include="ImGui.NET"> | ||
<HintPath>..\libs\ImGui.NET.dll</HintPath> | ||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGui.NET.dll</HintPath> | ||
<Private>False</Private> | ||
</Reference> | ||
<Reference Include="ImGuiScene"> | ||
<HintPath>..\libs\ImGuiScene.dll</HintPath> | ||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGuiScene.dll</HintPath> | ||
<Private>False</Private> | ||
</Reference> | ||
<Reference Include="Lumina"> | ||
<HintPath>..\libs\Lumina.dll</HintPath> | ||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Lumina.dll</HintPath> | ||
<Private>False</Private> | ||
</Reference> | ||
<Reference Include="System" /> | ||
<Reference Include="System.Core" /> | ||
<Reference Include="System.Drawing" /> | ||
<Reference Include="System.Numerics" /> | ||
<Reference Include="System.Windows.Forms" /> | ||
<Reference Include="System.Xml.Linq" /> | ||
<Reference Include="System.Data.DataSetExtensions" /> | ||
<Reference Include="Microsoft.CSharp" /> | ||
<Reference Include="System.Data" /> | ||
<Reference Include="System.Net.Http" /> | ||
<Reference Include="System.Xml" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Compile Include="Configuration.cs" /> | ||
<Compile Include="DialogExtensions.cs" /> | ||
<Compile Include="Importer\Models\ExtendedModPack.cs" /> | ||
<Compile Include="Importer\Models\SimpleModPack.cs" /> | ||
<Compile Include="Importer\TexToolsImport.cs" /> | ||
<Compile Include="Extensions\FuckedExtensions.cs" /> | ||
<Compile Include="Models\ModMeta.cs" /> | ||
<Compile Include="ModManager.cs" /> | ||
<Compile Include="Plugin.cs" /> | ||
<Compile Include="Properties\AssemblyInfo.cs" /> | ||
<Compile Include="Structs\FileMode.cs" /> | ||
<Compile Include="Structs\SeFileDescriptor.cs" /> | ||
<Compile Include="ResourceMod.cs" /> | ||
<Compile Include="Penumbra.cs" /> | ||
<Compile Include="Structs\ResourceHandle.cs" /> | ||
<Compile Include="SettingsInterface.cs" /> | ||
<Compile Include="Util\Crc32.cs" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<PackageReference Include="DotNetZip"> | ||
<Version>1.13.8</Version> | ||
</PackageReference> | ||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | ||
</ItemGroup> | ||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
using System.IO; | ||
using Dalamud.Game.Command; | ||
using Dalamud.Plugin; | ||
|
||
namespace Penumbra | ||
{ | ||
public class Plugin : IDalamudPlugin | ||
{ | ||
public string Name => "Penumbra"; | ||
|
||
private const string CommandName = "/penumbra"; | ||
|
||
public DalamudPluginInterface PluginInterface { get; set; } | ||
public Configuration Configuration { get; set; } | ||
|
||
public Penumbra Penumbra { get; set; } | ||
|
||
public ModManager ModManager { get; set; } | ||
|
||
public SettingsInterface SettingsInterface { get; set; } | ||
|
||
public void Initialize( DalamudPluginInterface pluginInterface ) | ||
{ | ||
PluginInterface = pluginInterface; | ||
|
||
Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration(); | ||
Configuration.Initialize( PluginInterface ); | ||
|
||
SettingsInterface = new SettingsInterface( this ); | ||
PluginInterface.UiBuilder.OnBuildUi += SettingsInterface.Draw; | ||
|
||
ModManager = new ModManager( new DirectoryInfo( Configuration.BaseFolder ) ); | ||
ModManager.DiscoverMods(); | ||
|
||
Penumbra = new Penumbra( this ); | ||
|
||
|
||
PluginInterface.CommandManager.AddHandler( CommandName, new CommandInfo( OnCommand ) | ||
{ | ||
HelpMessage = "/penumbra 0 will disable penumbra, /penumbra 1 will enable it." | ||
} ); | ||
|
||
Penumbra.Init(); | ||
Penumbra.Enable(); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
PluginInterface.UiBuilder.OnBuildUi -= SettingsInterface.Draw; | ||
|
||
PluginInterface.CommandManager.RemoveHandler( CommandName ); | ||
PluginInterface.Dispose(); | ||
|
||
Penumbra.Dispose(); | ||
} | ||
|
||
private void OnCommand( string command, string args ) | ||
{ | ||
if( args.Length > 0 ) | ||
Configuration.IsEnabled = args[ 0 ] == '1'; | ||
|
||
if( Configuration.IsEnabled ) | ||
Penumbra.Enable(); | ||
else | ||
Penumbra.Disable(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
using System.Reflection; | ||
using System.Runtime.InteropServices; | ||
|
||
// General Information about an assembly is controlled through the following | ||
// set of attributes. Change these attribute values to modify the information | ||
// associated with an assembly. | ||
[assembly: AssemblyTitle("Penumbra")] | ||
[assembly: AssemblyDescription("")] | ||
[assembly: AssemblyConfiguration("")] | ||
[assembly: AssemblyCompany("absolute gangstas")] | ||
[assembly: AssemblyProduct("Penumbra")] | ||
[assembly: AssemblyCopyright("Copyright © 2020")] | ||
[assembly: AssemblyTrademark("")] | ||
[assembly: AssemblyCulture("")] | ||
|
||
// Setting ComVisible to false makes the types in this assembly not visible | ||
// to COM components. If you need to access a type in this assembly from | ||
// COM, set the ComVisible attribute to true on that type. | ||
[assembly: ComVisible(false)] | ||
|
||
// The following GUID is for the ID of the typelib if this project is exposed to COM | ||
[assembly: Guid("13c812e9-0d42-4b95-8646-40eebf30636f")] | ||
|
||
// Version information for an assembly consists of the following four values: | ||
// | ||
// Major Version | ||
// Minor Version | ||
// Build Number | ||
// Revision | ||
// | ||
// You can specify all the values or you can default the Build and Revision Numbers | ||
// by using the '*' as shown below: | ||
// [assembly: AssemblyVersion("1.0.*")] | ||
[assembly: AssemblyVersion("1.0.0.0")] | ||
[assembly: AssemblyFileVersion("1.0.0.0")] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using Dalamud.Plugin; | ||
using Penumbra.Models; | ||
|
||
namespace Penumbra | ||
{ | ||
public class ResourceMod | ||
{ | ||
public ModMeta Meta { get; set; } | ||
|
||
public DirectoryInfo ModBasePath { get; set; } | ||
|
||
public List< FileInfo > ModFiles { get; } = new List< FileInfo >(); | ||
|
||
public void RefreshModFiles() | ||
{ | ||
if( ModBasePath == null ) | ||
{ | ||
PluginLog.LogError( "no basepath has been set on {ResourceModName}", Meta.Name ); | ||
return; | ||
} | ||
|
||
// we don't care about any _files_ in the root dir, but any folders should be a game folder/file combo | ||
foreach( var dir in ModBasePath.EnumerateDirectories() ) | ||
{ | ||
foreach( var file in dir.EnumerateFiles( "*.*", SearchOption.AllDirectories ) ) | ||
{ | ||
ModFiles.Add( file ); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,316 @@ | ||
using System; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Numerics; | ||
using System.Runtime.Remoting.Messaging; | ||
using System.Threading.Tasks; | ||
using System.Windows.Forms; | ||
using Dalamud.Interface; | ||
using Dalamud.Plugin; | ||
using ImGuiNET; | ||
using Penumbra.Importer; | ||
|
||
namespace Penumbra | ||
{ | ||
public class SettingsInterface | ||
{ | ||
private readonly Plugin _plugin; | ||
|
||
public bool Visible { get; set; } = true; | ||
|
||
private static readonly Vector2 AutoFillSize = new Vector2( -1, -1 ); | ||
private static readonly Vector2 ModListSize = new Vector2( 200, -1 ); | ||
|
||
private static readonly Vector2 MinSettingsSize = new Vector2( 650, 450 ); | ||
private static readonly Vector2 MaxSettingsSize = new Vector2( 69420, 42069 ); | ||
|
||
private int _selectedModIndex; | ||
private ResourceMod _selectedMod; | ||
|
||
private bool _isImportRunning = false; | ||
|
||
public SettingsInterface( Plugin plugin ) | ||
{ | ||
_plugin = plugin; | ||
} | ||
|
||
public void Draw() | ||
{ | ||
ImGui.SetNextWindowSizeConstraints( MinSettingsSize, MaxSettingsSize ); | ||
var ret = ImGui.Begin( _plugin.Name ); | ||
if( !ret ) | ||
{ | ||
return; | ||
} | ||
|
||
ImGui.BeginTabBar( "PenumbraSettings" ); | ||
|
||
DrawSettingsTab(); | ||
DrawResourceMods(); | ||
DrawEffectiveFileList(); | ||
|
||
ImGui.EndTabBar(); | ||
|
||
ImGui.End(); | ||
} | ||
|
||
void DrawSettingsTab() | ||
{ | ||
var ret = ImGui.BeginTabItem( "Settings" ); | ||
if( !ret ) | ||
{ | ||
return; | ||
} | ||
|
||
// FUCKKKKK | ||
var basePath = _plugin.Configuration.BaseFolder; | ||
if( ImGui.InputText( "Root Folder", ref basePath, 255 ) ) | ||
{ | ||
_plugin.Configuration.BaseFolder = basePath; | ||
} | ||
|
||
if( ImGui.Button( "Rediscover Mods" ) ) | ||
{ | ||
ReloadMods(); | ||
} | ||
|
||
if( !_isImportRunning ) | ||
{ | ||
if( ImGui.Button( "Import TexTools Modpacks" ) ) | ||
{ | ||
_isImportRunning = true; | ||
|
||
Task.Run( async () => | ||
{ | ||
var picker = new OpenFileDialog | ||
{ | ||
Multiselect = true, | ||
Filter = "TexTools TTMP Modpack (*.ttmp2)|*.ttmp*|All files (*.*)|*.*", | ||
CheckFileExists = true, | ||
Title = "Pick one or more modpacks." | ||
}; | ||
|
||
var result = await picker.ShowDialogAsync(); | ||
|
||
if( result == DialogResult.OK ) | ||
{ | ||
try | ||
{ | ||
var importer = | ||
new TexToolsImport( new DirectoryInfo( _plugin.Configuration.BaseFolder ) ); | ||
|
||
foreach( var fileName in picker.FileNames ) | ||
{ | ||
PluginLog.Log( "-> {0} START", fileName ); | ||
|
||
importer.ImportModPack( new FileInfo( fileName ) ); | ||
|
||
PluginLog.Log( "-> {0} OK!", fileName ); | ||
} | ||
|
||
ReloadMods(); | ||
} | ||
catch( Exception ex ) | ||
{ | ||
PluginLog.LogError( ex, "Could not import one or more modpacks." ); | ||
} | ||
} | ||
|
||
_isImportRunning = false; | ||
} ); | ||
} | ||
} | ||
else | ||
{ | ||
ImGui.Button( "Import in progress..." ); | ||
} | ||
|
||
if( ImGui.Button( "Save Settings" ) ) | ||
_plugin.Configuration.Save(); | ||
|
||
ImGui.EndTabItem(); | ||
} | ||
|
||
void DrawModsSelector() | ||
{ | ||
// Selector pane | ||
ImGui.BeginGroup(); | ||
ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, new Vector2( 0, 0 ) ); | ||
|
||
// Inlay selector list | ||
ImGui.BeginChild( "availableModList", new Vector2( 180, -ImGui.GetFrameHeightWithSpacing() ), true ); | ||
|
||
for( var modIndex = 0; modIndex < _plugin.ModManager.AvailableMods.Count; modIndex++ ) | ||
{ | ||
var mod = _plugin.ModManager.AvailableMods.ElementAt( modIndex ); | ||
|
||
if( ImGui.Selectable( mod.Value.Meta.Name, modIndex == _selectedModIndex ) ) | ||
{ | ||
_selectedModIndex = modIndex; | ||
_selectedMod = mod.Value; | ||
} | ||
} | ||
|
||
ImGui.EndChild(); | ||
|
||
// Selector controls | ||
ImGui.PushStyleVar( ImGuiStyleVar.WindowPadding, new Vector2( 0, 0 ) ); | ||
ImGui.PushStyleVar( ImGuiStyleVar.FrameRounding, 0 ); | ||
ImGui.PushFont( UiBuilder.IconFont ); | ||
if( _selectedModIndex != 0 ) | ||
{ | ||
if( ImGui.Button( FontAwesomeIcon.ArrowUp.ToIconString(), new Vector2( 45, 0 ) ) ) | ||
{ | ||
} | ||
} | ||
else | ||
{ | ||
ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f ); | ||
ImGui.Button( FontAwesomeIcon.ArrowUp.ToIconString(), new Vector2( 45, 0 ) ); | ||
ImGui.PopStyleVar(); | ||
} | ||
|
||
ImGui.PopFont(); | ||
|
||
if( ImGui.IsItemHovered() ) | ||
ImGui.SetTooltip( "Move the selected mod up in priority" ); | ||
|
||
ImGui.PushFont( UiBuilder.IconFont ); | ||
|
||
ImGui.SameLine(); | ||
|
||
if( _selectedModIndex != _plugin.ModManager.AvailableMods.Count - 1 ) | ||
{ | ||
if( ImGui.Button( FontAwesomeIcon.ArrowDown.ToIconString(), new Vector2( 45, 0 ) ) ) | ||
{ | ||
} | ||
} | ||
else | ||
{ | ||
ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f ); | ||
ImGui.Button( FontAwesomeIcon.ArrowDown.ToIconString(), new Vector2( 45, 0 ) ); | ||
ImGui.PopStyleVar(); | ||
} | ||
|
||
|
||
ImGui.PopFont(); | ||
|
||
if( ImGui.IsItemHovered() ) | ||
ImGui.SetTooltip( "Move the selected mod down in priority" ); | ||
|
||
ImGui.PushFont( UiBuilder.IconFont ); | ||
|
||
ImGui.SameLine(); | ||
|
||
if( ImGui.Button( FontAwesomeIcon.Trash.ToIconString(), new Vector2( 45, 0 ) ) ) | ||
{ | ||
} | ||
|
||
ImGui.PopFont(); | ||
|
||
if( ImGui.IsItemHovered() ) | ||
ImGui.SetTooltip( "Delete the selected mod" ); | ||
|
||
ImGui.PushFont( UiBuilder.IconFont ); | ||
|
||
ImGui.SameLine(); | ||
|
||
if( ImGui.Button( FontAwesomeIcon.Plus.ToIconString(), new Vector2( 45, 0 ) ) ) | ||
{ | ||
} | ||
|
||
ImGui.PopFont(); | ||
|
||
if( ImGui.IsItemHovered() ) | ||
ImGui.SetTooltip( "Add an empty mod" ); | ||
|
||
ImGui.PopStyleVar( 3 ); | ||
|
||
ImGui.EndGroup(); | ||
} | ||
|
||
void DrawResourceMods() | ||
{ | ||
var ret = ImGui.BeginTabItem( "Resource Mods" ); | ||
if( !ret ) | ||
{ | ||
return; | ||
} | ||
|
||
DrawModsSelector(); | ||
|
||
ImGui.SameLine(); | ||
|
||
if( _selectedMod != null ) | ||
{ | ||
try | ||
{ | ||
ImGui.BeginChild( "selectedModInfo", AutoFillSize, true ); | ||
|
||
ImGui.Text( _selectedMod.Meta.Name ); | ||
ImGui.SameLine(); | ||
ImGui.TextColored( new Vector4( 1f, 1f, 1f, 0.66f ), "by" ); | ||
ImGui.SameLine(); | ||
ImGui.Text( _selectedMod.Meta.Author ); | ||
|
||
ImGui.TextWrapped( _selectedMod.Meta.Description ?? "" ); | ||
|
||
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + 12 ); | ||
|
||
// list files | ||
ImGui.Text( "Files:" ); | ||
ImGui.SetNextItemWidth( -1 ); | ||
if( ImGui.ListBoxHeader( "##", AutoFillSize ) ) | ||
{ | ||
foreach( var file in _selectedMod.ModFiles ) | ||
{ | ||
ImGui.Selectable( file.FullName ); | ||
} | ||
} | ||
|
||
ImGui.ListBoxFooter(); | ||
|
||
ImGui.EndChild(); | ||
} | ||
catch( Exception ex ) | ||
{ | ||
PluginLog.LogError( ex, "fuck" ); | ||
} | ||
} | ||
|
||
ImGui.EndTabItem(); | ||
} | ||
|
||
void DrawEffectiveFileList() | ||
{ | ||
var ret = ImGui.BeginTabItem( "Effective File List" ); | ||
if( !ret ) | ||
{ | ||
return; | ||
} | ||
|
||
if( ImGui.ListBoxHeader( "##", AutoFillSize ) ) | ||
{ | ||
// todo: virtualise this | ||
foreach( var file in _plugin.ModManager.ResolvedFiles ) | ||
{ | ||
ImGui.Selectable( file.Value.FullName ); | ||
} | ||
} | ||
|
||
ImGui.ListBoxFooter(); | ||
|
||
ImGui.EndTabItem(); | ||
} | ||
|
||
private void ReloadMods() | ||
{ | ||
_selectedMod = null; | ||
|
||
// haha yikes | ||
_plugin.ModManager = new ModManager( new DirectoryInfo( _plugin.Configuration.BaseFolder ) ); | ||
_plugin.ModManager.DiscoverMods(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace Penumbra.Structs | ||
{ | ||
public enum FileMode : uint | ||
{ | ||
LoadUnpackedResource = 0, | ||
LoadFileResource = 1, // Shit in My Games uses this | ||
LoadSqpackResource = 0x0B | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using System.Runtime.InteropServices; | ||
|
||
namespace Penumbra.Structs | ||
{ | ||
[StructLayout( LayoutKind.Explicit )] | ||
public unsafe struct ResourceHandle | ||
{ | ||
[FieldOffset( 0x48 )] | ||
public byte* FileName; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System.Runtime.InteropServices; | ||
|
||
namespace Penumbra.Structs | ||
{ | ||
[StructLayout( LayoutKind.Explicit )] | ||
public unsafe struct SeFileDescriptor | ||
{ | ||
[FieldOffset( 0x00 )] | ||
public FileMode FileMode; | ||
|
||
[FieldOffset( 0x30 )] | ||
public void* FileDescriptor; // | ||
|
||
[FieldOffset( 0x50 )] | ||
public ResourceHandle* ResourceHandle; // | ||
|
||
|
||
[FieldOffset( 0x68 )] | ||
public byte UtfFileName; // | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Runtime.CompilerServices; | ||
using Penumbra.Extensions; | ||
|
||
namespace Penumbra.Util | ||
{ | ||
/// <summary> | ||
/// Performs the 32-bit reversed variant of the cyclic redundancy check algorithm | ||
/// </summary> | ||
public class Crc32 | ||
{ | ||
private const uint POLY = 0xedb88320; | ||
|
||
private static readonly uint[] CrcArray = | ||
Enumerable.Range( 0, 256 ).Select( i => | ||
{ | ||
var k = ( uint )i; | ||
for( var j = 0; j < 8; j++ ) | ||
k = ( k & 1 ) != 0 ? ( k >> 1 ) ^ POLY : k >> 1; | ||
|
||
return k; | ||
} ).ToArray(); | ||
|
||
public uint Checksum => ~_crc32; | ||
|
||
private uint _crc32 = 0xFFFFFFFF; | ||
|
||
/// <summary> | ||
/// Initializes Crc32's state | ||
/// </summary> | ||
public void Init() | ||
{ | ||
_crc32 = 0xFFFFFFFF; | ||
} | ||
|
||
/// <summary> | ||
/// Updates Crc32's state with new data | ||
/// </summary> | ||
/// <param name="data">Data to calculate the new CRC from</param> | ||
[MethodImpl( MethodImplOptions.AggressiveInlining )] | ||
public void Update( byte[] data ) | ||
{ | ||
foreach( var b in data ) | ||
Update( b ); | ||
} | ||
|
||
[MethodImpl( MethodImplOptions.AggressiveInlining )] | ||
public void Update( byte b ) | ||
{ | ||
_crc32 = CrcArray[ ( _crc32 ^ b ) & 0xFF ] ^ | ||
( ( _crc32 >> 8 ) & 0x00FFFFFF ); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Penumbra | ||
|
||
Penumbra is a runtime mod loader for FINAL FANTASY XIV, with a bunch of other useful features baked in: | ||
|
||
* No need to back up your install - mods don't touch game files | ||
* Disable and enable mods without restarting the game | ||
* Resolve conflicts between mods by changing mod order | ||
* Files can be edited and are often replicated in-game after a map change or closing and reopening a window | ||
|
||
## Current Status | ||
Penumbra, in its current state, is not intended for widespread use. It is mainly aimed at developers and people who don't need their hands held (for now). | ||
|
||
We're working towards a 1.0 release, and you can follow it's progress [here](https://github.com/xivdev/Penumbra/projects/1). | ||
|
||
## Contributing | ||
Contributions are welcome, but please make an issue first before writing any code. It's possible what you want to implement is out of scope for this project, or could be reworked so that it would provide greater benefit. | ||
|
||
## TexTools Mods | ||
Penumbra has support for TexTools modpacks, however no support will be given. This is aimed as an interim measure while better tooling is developed, but note that there is no ETA for this. | ||
|
||
### Why not support TexTools? | ||
|
||
Because it sucks. It's slow to use, the workflow is awful and the codebase is so far gone any notable improvements or support for new features would mean throwing out significant portions of the existing codebase. If you're interested in helping build new tooling, or are just curious about what's available, you can check out Umbra [here](https://github.com/NotAdam/Lumina/tree/master/src/Umbra). |