diff --git a/Next.Api/Attributes/IsUnmanagedAttribute.cs b/Next.Api/Attributes/IsUnmanagedAttribute.cs
new file mode 100644
index 0000000..e6c01e3
--- /dev/null
+++ b/Next.Api/Attributes/IsUnmanagedAttribute.cs
@@ -0,0 +1,13 @@
+// ReSharper disable CheckNamespace
+
+namespace System.Runtime.CompilerServices;
+
+///
+/// This attribute is required by the compiler for the "unmanaged" generic type constraint.
+/// It should be generated automatically, but for whatever reason its not.
+///
+[Obsolete("Do not use directly.", true)]
+[AttributeUsage(AttributeTargets.All)]
+internal sealed class IsUnmanagedAttribute : Attribute
+{
+}
\ No newline at end of file
diff --git a/Next.Api/Bases/LanguageLoaderBase.cs b/Next.Api/Bases/LanguageLoaderBase.cs
new file mode 100644
index 0000000..1c2c52e
--- /dev/null
+++ b/Next.Api/Bases/LanguageLoaderBase.cs
@@ -0,0 +1,10 @@
+using Next.Api.Interfaces;
+
+namespace Next.Api.Bases;
+
+public abstract class LanguageLoaderBase(string[] filter)
+{
+ public string[] Filter { get; protected set; } = filter;
+
+ public abstract void Load(ILanguageManager _manager, Stream stream, string FileName);
+}
\ No newline at end of file
diff --git a/Next.Api/Interfaces/ILanguageManager.cs b/Next.Api/Interfaces/ILanguageManager.cs
new file mode 100644
index 0000000..fd4bb00
--- /dev/null
+++ b/Next.Api/Interfaces/ILanguageManager.cs
@@ -0,0 +1,12 @@
+using Next.Api.Bases;
+
+namespace Next.Api.Interfaces;
+
+public interface ILanguageManager
+{
+ public void AddLoader(LanguageLoaderBase _loader);
+
+ public LanguageLoaderBase? GetLoader(string extensionName);
+
+ public void AddToMap(SupportedLangs lang, string key, string value, string loaderName);
+}
\ No newline at end of file
diff --git a/Next.Api/Logs/LocalWriter.cs b/Next.Api/Logs/LocalWriter.cs
new file mode 100644
index 0000000..72f41e8
--- /dev/null
+++ b/Next.Api/Logs/LocalWriter.cs
@@ -0,0 +1,30 @@
+using BepInEx;
+using BepInEx.Core;
+
+namespace Next.Api.Logs;
+
+public class LocalWriter
+{
+ public LocalWriter(NextLog log)
+ {
+ if (!Directory.Exists(LogDir))
+ Directory.CreateDirectory(LogDir);
+
+ LogFileWriter = new StreamWriter(File.Open(Path.Combine(LogDir, log.LogSource.SourceName), FileMode.OpenOrCreate, FileAccess.Write))
+ {
+ AutoFlush = true,
+ };
+
+ LogFileWriter.WriteLine("NextLog Listener Start");
+ LogFileWriter.WriteLine($"CurrentTime: {DateTime.Now:g}");
+ }
+
+ public static readonly string LogDir = Path.Combine(Paths.GameRootPath, "NextLogs");
+ private readonly StreamWriter LogFileWriter;
+
+ public LocalWriter Write(string str)
+ {
+ LogFileWriter.WriteLine(str);
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/Next.Api/Logs/LogConfigInfo.cs b/Next.Api/Logs/LogConfigInfo.cs
new file mode 100644
index 0000000..50e38f6
--- /dev/null
+++ b/Next.Api/Logs/LogConfigInfo.cs
@@ -0,0 +1,11 @@
+using System.Reflection;
+
+namespace Next.Api.Logs;
+
+public class LogConfigInfo(Assembly assembly, NextLog log)
+{
+ public readonly Assembly Assembly = assembly;
+ public string LogName { get; set; } = string.Empty;
+ public NextLog _Log { get; set; } = log;
+ public readonly List UseAssembly = [assembly];
+}
\ No newline at end of file
diff --git a/Next.Api/Logs/LogHelper.cs b/Next.Api/Logs/LogHelper.cs
new file mode 100644
index 0000000..a64d867
--- /dev/null
+++ b/Next.Api/Logs/LogHelper.cs
@@ -0,0 +1,95 @@
+using System.Reflection;
+using BepInEx.Logging;
+
+
+namespace Next.Api.Logs;
+
+public static class LogHelper
+{
+ /*
+ 各消息作用:
+
+ 发生了致命错误,无法从中恢复 : A fatal error has occurred, which cannot be recovered from
+ Fatal
+
+ 发生错误,但可以从中恢复 : An error has occured, but can be recovered from
+ Error
+
+ 已发出警告,但并不一定意味着发生了错误 : A warning has been produced, but does not necessarily mean that something wrong has happened
+ Warning
+
+ 应向用户显示的重要消息 : An important message that should be displayed to the user
+ Message
+
+ 重要性较低的消息 : A message of low importance
+ Info
+
+ 可能只有开发人员感兴趣的消息 : A message that would likely only interest a developer
+ Debug,
+ */
+
+
+ ///
+ /// 一般信息
+ ///
+ ///
+ public static void Info(string Message)
+ {
+ Log(Message, LogLevel.Info, Assembly.GetCallingAssembly());
+ }
+
+ ///
+ /// 报错
+ ///
+ ///
+ public static void Error(string Message)
+ {
+ Log(Message, LogLevel.Error, Assembly.GetCallingAssembly());
+ }
+
+ ///
+ /// 测试
+ ///
+ ///
+ public static void Debug(string Message)
+ {
+ Log(Message, LogLevel.Debug, Assembly.GetCallingAssembly());
+ }
+
+ public static void Fatal(string Message)
+ {
+ Log(Message, LogLevel.Fatal, Assembly.GetCallingAssembly());
+ }
+
+ ///
+ /// 警告
+ ///
+ ///
+ public static void Warn(string Message)
+ {
+ Log(Message, LogLevel.Warning, Assembly.GetCallingAssembly());
+ }
+
+
+ public static void Message(string Message)
+ {
+ Log(Message, LogLevel.Message, Assembly.GetCallingAssembly());
+ }
+
+ public static void Exception(Exception exception)
+ {
+ Error(exception.ToString());
+ }
+
+ public static void Log(object @object, LogLevel errorLevel = LogLevel.None, Assembly? assembly = null)
+ {
+ var _assembly = assembly ?? Assembly.GetCallingAssembly();
+ var log = NextLog.GetUseLog(_assembly);
+ log.WriteToFile(@object, errorLevel);
+ }
+
+ public static void LogObject(object @object)
+ {
+ Log(@object, LogLevel.Error, Assembly.GetCallingAssembly());
+ }
+}
\ No newline at end of file
diff --git a/Next.Api/Logs/NextLog.cs b/Next.Api/Logs/NextLog.cs
new file mode 100644
index 0000000..0cedaf8
--- /dev/null
+++ b/Next.Api/Logs/NextLog.cs
@@ -0,0 +1,110 @@
+using System.Reflection;
+using System.Text;
+using BepInEx;
+using BepInEx.Logging;
+
+namespace Next.Api.Logs;
+
+public class NextLog(Assembly _assembly, ManualLogSource logSource)
+{
+ public Assembly Assembly = _assembly;
+ public ManualLogSource LogSource = logSource;
+ public bool UseLocalWrite { get; set; } = false;
+ private LocalWriter? _writer;
+ public LocalWriter? Writer
+ {
+ get
+ {
+ if (UseLocalWrite)
+ {
+ return _writer ??= new LocalWriter(this);
+ }
+
+ return null;
+ }
+ }
+
+ public static List LogConfigInfos = [];
+ public static NextLog? MainLog { get; private set; }
+
+ public static void RemoveLog(Assembly? assembly = null)
+ {
+ var _assembly = assembly ?? Assembly.GetCallingAssembly();
+ foreach (var info in LogConfigInfos.Where(n => n.UseAssembly.Contains(_assembly)))
+ info.UseAssembly.Remove(_assembly);
+ }
+
+ public static NextLog? SetLog(Assembly assembly)
+ {
+ if (LogConfigInfos.All(n => n.Assembly != assembly))
+ return null;
+
+ var info = LogConfigInfos.First(n => n.Assembly == assembly);
+ info.UseAssembly.Add(assembly);
+
+ return info._Log;
+ }
+
+ public static NextLog CreateMainLog(ManualLogSource logSource)
+ {
+ if (ConsoleManager.ConsoleEnabled)
+ System.Console.OutputEncoding = Encoding.UTF8;
+
+ var assembly = Assembly.GetCallingAssembly();
+ MainLog = new NextLog(assembly, logSource);
+ RemoveLog(assembly);
+
+ LogConfigInfos.Add(new LogConfigInfo(assembly, MainLog)
+ {
+ LogName = logSource.SourceName
+ });
+ return MainLog;
+ }
+
+ public static NextLog GetUseLog(Assembly? assembly = null)
+ {
+ var _assembly = assembly ?? Assembly.GetCallingAssembly();
+ var log = LogConfigInfos.FirstOrDefault(n => n.UseAssembly.Contains(_assembly))?._Log;
+ if (log != null)
+ return log;
+
+ if (MainLog == null) return CreateMainLog(_assembly.GetLogSource());
+
+ LogConfigInfos.First(n => n._Log == MainLog).UseAssembly.Add(_assembly);
+ return MainLog;
+ }
+
+ public NextLog WriteToFile(object @object, LogLevel errorLevel = LogLevel.None)
+ {
+ var Message = @object as string;
+ switch (errorLevel)
+ {
+ case LogLevel.Message:
+ LogSource.LogMessage(Message);
+ break;
+ case LogLevel.Error:
+ LogSource.LogError(Message);
+ break;
+ case LogLevel.Warning:
+ LogSource.LogWarning(Message);
+ break;
+ case LogLevel.Fatal:
+ LogSource.LogFatal(Message);
+ break;
+ case LogLevel.Info:
+ LogSource.LogInfo(Message);
+ break;
+ case LogLevel.Debug:
+ LogSource.LogDebug(Message);
+ break;
+ case LogLevel.None:
+ case LogLevel.All:
+ default:
+ LogSource.LogInfo(Message);
+ goto Writer;
+ }
+ Writer:
+ Writer?.Write($"[FastLog, Level: {errorLevel}] {Message}");
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/Next.Api/Utils/BepInExUtils.cs b/Next.Api/Utils/BepInExUtils.cs
new file mode 100644
index 0000000..851305f
--- /dev/null
+++ b/Next.Api/Utils/BepInExUtils.cs
@@ -0,0 +1,25 @@
+using System.Reflection;
+using BepInEx;
+using BepInEx.Configuration;
+using BepInEx.Logging;
+using BepInEx.Unity.IL2CPP;
+
+namespace Next.Api.Utils;
+
+public static class BepInExUtils
+{
+ public static PluginInfo GetPlugin(this Assembly assembly)
+ {
+ return IL2CPPChainloader.Instance.Plugins.FirstOrDefault(n => n.Value.Location == assembly.Location).Value;
+ }
+
+ public static ConfigFile GetConfig(this Assembly assembly) => assembly.GetBaseInstance().Config;
+
+ public static ManualLogSource GetLogSource(this Assembly assembly) => assembly.GetBaseInstance().Log;
+
+ public static BasePlugin GetBaseInstance(this Assembly assembly) => (BasePlugin)assembly.GetPlugin().Instance;
+
+ public static T? GetInstance(this PluginInfo info) where T : BasePlugin => info.Instance as T;
+
+ public static BepInPlugin GetMetadata(this Assembly assembly) => assembly.GetPlugin().Metadata;
+}
\ No newline at end of file