Skip to content

Commit

Permalink
feat: init
Browse files Browse the repository at this point in the history
  • Loading branch information
EonZeNx committed Dec 11, 2024
1 parent 58da409 commit 156bc3f
Show file tree
Hide file tree
Showing 13 changed files with 512 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.idea
.venv
__pycache__

test

py_atl/dll/**.dll
py_atl/dll/**.json

**.db
17 changes: 17 additions & 0 deletions blender_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
if __name__ == '__main__':
try:
import clr_loader
except ImportError:
import pip
pip.main(['install', 'clr-loader'])
import clr_loader

try:
import pythonnet
except ImportError:
import pip
pip.main(["install", "pythonnet"])
import pythonnet

from main import setup_dll
setup_dll()
30 changes: 30 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import os
import pythonnet
from py_atl import database

PROJECT_DIRECTORY: str = r"D:\Projects\Various\pysharp"
DLL_DIRECTORY: str = os.path.join(PROJECT_DIRECTORY, "dll")
DB_PATH: str = os.path.join(PROJECT_DIRECTORY, "database", "atl.jc3.db")


def setup_dll():
global DLL_DIRECTORY

from os import listdir
from os.path import isfile, join

pythonnet.load("coreclr")

import clr

dll_files: list[str] = [f.removesuffix(".dll") for f in listdir(DLL_DIRECTORY) if isfile(join(DLL_DIRECTORY, f)) and f.endswith(".dll")]
for dll_file in dll_files:
clr.AddReference(dll_file)

import pysharp
pysharp.main()


if __name__ == '__main__':
setup_dll()
database.setup(DB_PATH)
47 changes: 47 additions & 0 deletions py_atl/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
bl_info = {
"name": "PyAtl",
"blender": (4, 3, 0),
"category": "Import-Export",
"description": "Interfaces with ATL",
"author": "EonZeNx",
"version": (0, 1, 0),
}

from py_atl import utils, dll
import bpy
from bpy.props import StringProperty
from bpy.types import AddonPreferences


class PyAtlPreferences(AddonPreferences):
bl_idname = __name__

project_path: StringProperty(
name="Project Base Path",
description="Base path for dll files, database files, and more",
default="",
subtype='DIR_PATH',
update=lambda self, context: self.on_preference_update(context)
)

def draw(self, context):
layout = self.layout
layout.prop(self, "project_path")

def on_preference_update(self, context):
dll.setup_dll(self.project_path)


def register():
bpy.utils.register_class(PyAtlPreferences)

from py_atl import utils, dll
dll.setup_dll(utils.project_path(), True)


def unregister():
bpy.utils.unregister_class(PyAtlPreferences)


if __name__ == "__main__":
register()
38 changes: 38 additions & 0 deletions py_atl/database/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from ApexToolsLauncher.Core.Hash import HashDatabase, EHashType

DB_CONNECTION = None


def setup(db_path: str) -> None:
global DB_CONNECTION

if DB_CONNECTION is not None:
return

option_database = HashDatabase.Create(db_path)
if option_database.IsNone:
print(f"failed to setup hash database")
return

DB_CONNECTION = option_database.Unwrap()
DB_CONNECTION.OpenConnection()


def lookup(game_hash: int):
global DB_CONNECTION

if DB_CONNECTION is None:
print(f"lookup_filepath : DB_CONNECTION is None")
return None

return DB_CONNECTION.Lookup(game_hash)


def lookup_filepath(game_hash: int):
global DB_CONNECTION

if DB_CONNECTION is None:
print(f"lookup_filepath : DB_CONNECTION is None")
return None

return DB_CONNECTION.Lookup(game_hash, EHashType.FilePath)
17 changes: 17 additions & 0 deletions py_atl/database/query.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from py_atl.database import DB_CONNECTION
from ApexToolsLauncher.Core.Hash import HashDatabase, EHashType


def lookup(game_hash: int):
if DB_CONNECTION is None:
return None

return DB_CONNECTION.Lookup(game_hash)


def lookup_filepath(game_hash: int):
if DB_CONNECTION is None:
print(f"lookup_filepath : DB_CONNECTION is None")
return None

return DB_CONNECTION.Lookup(game_hash, EHashType.FilePath)
6 changes: 6 additions & 0 deletions py_atl/development.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

DLL_FILES: list[str] = []


def log(msg: str) -> None:
print(f"PyAtl: {msg}")
41 changes: 41 additions & 0 deletions py_atl/dll/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import pythonnet
if pythonnet.get_runtime_info() is not None:
pythonnet.unload()

pythonnet.load("coreclr")
import clr

from py_atl import development, utils
from os import path, listdir


def setup_dll(project_path: str, log_result: bool = False):
if len(project_path) == 0 or not path.exists(project_path):
return

dll_directory: str = path.join(project_path, "dll")
development.DLL_FILES = [path.join(dll_directory, f).removesuffix(".dll")
for f in listdir(dll_directory)
if path.isfile(path.join(dll_directory, f)) and f.endswith(".dll")]

loaded_dlls: list[str] = []
failed_dlls: list[str] = []
for dll_file in development.DLL_FILES:
try:
clr.AddReference(dll_file)
loaded_dlls.append(dll_file)
except (Exception,) as e:
development.log(e)
failed_dlls.append(dll_file)

if log_result:
development.log(f"Successfully loaded {len(loaded_dlls)} dll files")
for dll in loaded_dlls:
development.log(f"\t- {dll}")

development.log(f"Failed to load {len(failed_dlls)}")
for dll in failed_dlls:
development.log(f"\t- {dll}")


setup_dll(utils.project_path())
21 changes: 21 additions & 0 deletions py_atl/dll/cs_to.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
functions to convert objects from c# to python
"""

from System import Array, Single

from mathutils import Matrix


def bpy_matrix(mat4: Array[Single]) -> Matrix:
if len(mat4) != 16:
raise ValueError(f"Expected 16 elements, got {len(mat4)}")

matrix: Matrix = Matrix((
(mat4[0], mat4[1], mat4[2], mat4[3]),
(mat4[4], mat4[5], mat4[6], mat4[7]),
(mat4[8], mat4[9], mat4[10], mat4[11]),
(mat4[12], mat4[13], mat4[14], mat4[15])
))

return matrix
19 changes: 19 additions & 0 deletions py_atl/rtpc_v01/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from System.IO import FileStream, FileMode
from System import Array, String
from System.Collections.Generic import Dictionary
from ApexFormat.RTPC.V01.Class import RtpcV01HeaderExtensions, RtpcV01ContainerExtensions, RtpcV01Container, IRtpcV01Filter, RtpcV01Filter, RtpcV01FilterString


def filter_by(filters: list[IRtpcV01Filter]):
for each in filters:
print(each)


def filter_by_test():
rigid_object: RtpcV01FilterString = RtpcV01FilterString("_class", "CRigidObject")
rigid_object.SubFilters = [
RtpcV01Filter("filename"),
RtpcV01Filter("world")
]

filter_by([rigid_object])
55 changes: 55 additions & 0 deletions py_atl/rtpc_v01/containers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from dataclasses import dataclass, field
from typing import Self


@dataclass(slots=True)
class RtpcObject:
init_value: str | int | None = field(init=True, default=None)
name: str | None = field(init=False, default=None)
name_hash: int | None = field(init=False, default=None)
containers: list[Self] = field(init=False, default_factory=list)

def __post_init__(self):
if type(self.init_value) is str:
self.name = self.init_value
elif type(self.init_value) is int:
self.name_hash = self.init_value
else:
raise ValueError(f"{type(self).__name__} initialised with invalid type, {type(self.init_value)}")

if self.name is None and self.name_hash is None:
raise ValueError(f"{type(self).__name__} must have name or name_hash")

def __repr__(self):
name_or_hash: str = self.name if self.name is not None else f"{self.name_hash:08X}"
containers_str: str = f"containers: {self.containers}" if len(self.containers) > 0 else ""
containers_prefix: str = ", " if len(containers_str) > 0 else ""

return f"{type(self).__name__}({name_or_hash}{containers_prefix}{containers_str})"


@dataclass(slots=True)
class RtpcWorldObject(RtpcObject):
world: str = field(init=False, default=None)

def __repr__(self):
name_or_hash: str = self.name if self.name is not None else f"{self.name_hash:08X}"
containers_str: str = f"containers: {self.containers}" if len(self.containers) > 0 else ""
containers_prefix: str = ", " if len(containers_str) > 0 else ""

return f"{type(self).__name__}({name_or_hash}, world: {self.world}{containers_prefix}{containers_str})"


@dataclass(slots=True)
class RtpcRigidObject(RtpcWorldObject):
filename: str | None = field(init=False, default=None)
filename_hash: int | None = field(init=False, default=None)

def __repr__(self):
name_or_hash: str = self.name if self.name is not None else f"{self.name_hash:08X}"
containers_str: str = f"containers: {self.containers}" if len(self.containers) > 0 else ""
containers_prefix: str = ", " if len(containers_str) > 0 else ""
filename_or_hash: str = self.filename if self.filename is not None else f"{self.filename_hash:08X}"

return f"{type(self).__name__}({name_or_hash}, filename: {filename_or_hash}, world: {self.world}{containers_prefix}{containers_str})"

17 changes: 17 additions & 0 deletions py_atl/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import bpy


def project_path() -> str:
addon = bpy.context.preferences.addons.get("py_atl", None)
if addon is None:
return ""

preferences = addon.preferences
if preferences is None:
return ""

project_path = preferences.project_path
if project_path is None:
return ""

return project_path
Loading

0 comments on commit 156bc3f

Please sign in to comment.