first commit

This commit is contained in:
yyc12345 2023-02-02 12:01:28 +08:00
commit 0c107b74b0
10 changed files with 942 additions and 0 deletions

364
.gitignore vendored Normal file
View File

@ -0,0 +1,364 @@
## my ban
*.nmo
*.cmo
*.nms
*.vmo
## 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
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
Temp/
# 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
nunit-*.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/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# 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
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*[.json, .xml, .info]
# 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
# NuGet Symbol Packages
*.snupkg
# 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
*.appxbundle
*.appxupload
# 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
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# 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/
# 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/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/

6
PyCmo/PyCmo.py Normal file
View File

@ -0,0 +1,6 @@
import VirtoolsReader
import VirtoolsStruct
with open("D:\\libcmo21\\PyCmo\\Gameplay.nmo", 'rb') as fs:
composition = VirtoolsReader.ReadCKComposition(fs)
print(str(composition.Header))

50
PyCmo/PyCmo.pyproj Normal file
View File

@ -0,0 +1,50 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>adc519e8-5f1b-427d-8e5c-1fabcb6147fb</ProjectGuid>
<ProjectHome>.</ProjectHome>
<StartupFile>PyCmo.py</StartupFile>
<SearchPath>
</SearchPath>
<WorkingDirectory>.</WorkingDirectory>
<OutputPath>.</OutputPath>
<Name>PyCmo</Name>
<RootNamespace>PyCmo</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>true</DebugSymbols>
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
</PropertyGroup>
<ItemGroup>
<Compile Include="PyCmo.py" />
<Compile Include="PyCmoMisc.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="VirtoolsConstants.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="VirtoolsReader.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="VirtoolsStruct.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="VirtoolsUtils.py">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets" />
<!-- Uncomment the CoreCompile target to enable the Build command in
Visual Studio and specify your pre- and post-build commands in
the BeforeBuild and AfterBuild targets below. -->
<!--<Target Name="CoreCompile" />-->
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
</Project>

32
PyCmo/PyCmoMisc.py Normal file
View File

@ -0,0 +1,32 @@
def OutputSizeHumanReadable(storage_size: int):
probe = storage_size
# check Bytes
if (probe >> 10) == 0:
return f"{storage_size:d}Bytes"
probe >>= 10
# check KiB
if (probe >> 10) == 0:
return f"{(storage_size / (1 << 10)):.2f}KiB"
probe >>= 10
# check MiB
if (probe >> 10) == 0:
return f"{(storage_size / (1 << 20)):.2f}MiB"
probe >>= 10
# otherwise GiB
return f"{(storage_size / (1 << 30)):.2f}GiB"
def BcdCodeToDecCode(bcd_num: int):
result = 0
pow = 1
while bcd_num != 0:
result += (bcd_num & 0xf) * pow
bcd_num >>= 4
pow *= 10
return result

320
PyCmo/VirtoolsConstants.py Normal file
View File

@ -0,0 +1,320 @@
import enum
class PyEnum(object):
@staticmethod
def Contain(val: int, probe: int):
return bool(val & probe)
@staticmethod
def Add(val: int, data: int):
return val | data
@staticmethod
def PrintEnum(val: int, _enum: enum.IntEnum):
for i in _enum:
if i.value == val:
return i.name
return ""
@staticmethod
def PrintEnumFlag(val: int, _enum: enum.IntEnum):
pending = []
for i in _enum:
# if it have exactly same entry, return directly
if i.value == val:
return i.name
# check exist
if bool(val & i.value):
pending.append(i.name)
return ', '.join(pending)
class CK_FILE_WRITEMODE(enum.IntEnum):
CKFILE_UNCOMPRESSED =0 # Save data uncompressed
CKFILE_CHUNKCOMPRESSED_OLD =1 # Obsolete
CKFILE_EXTERNALTEXTURES_OLD=2 # Obsolete : use CKContext::SetGlobalImagesSaveOptions instead.
CKFILE_FORVIEWER =4 # Don't save Interface Data within the file, the level won't be editable anymore in the interface
CKFILE_WHOLECOMPRESSED =8 # Compress the whole file
class CK_LOAD_FLAGS(enum.IntEnum):
CK_LOAD_ANIMATION =1<<0 # Load animations
CK_LOAD_GEOMETRY =1<<1 # Load geometry.
CK_LOAD_DEFAULT =CK_LOAD_GEOMETRY|CK_LOAD_ANIMATION # Load animations & geometry
CK_LOAD_ASCHARACTER =1<<2 # Load all the objects and create a character that contains them all .
CK_LOAD_DODIALOG =1<<3 # Check object name unicity and warns the user with a dialog box when duplicate names are found.
CK_LOAD_AS_DYNAMIC_OBJECT =1<<4 # Objects loaded from this file may be deleted at run-time or are temporary
CK_LOAD_AUTOMATICMODE =1<<5 # Check object name unicity and automatically rename or replace according to the options specified in CKContext::SetAutomaticLoadMode
CK_LOAD_CHECKDUPLICATES =1<<6 # Check object name unicity (The list of duplicates is stored in the CKFile class after a OpenFile call
CK_LOAD_CHECKDEPENDENCIES =1<<7 # Check if every plugins needed are availables
CK_LOAD_ONLYBEHAVIORS =1<<8 #
CK_CLASSID = int
class CKCID(enum.IntEnum):
CKCID_OBJECT = 1
CKCID_PARAMETERIN = 2
CKCID_PARAMETEROPERATION = 4
CKCID_STATE = 5
CKCID_BEHAVIORLINK = 6
CKCID_BEHAVIOR = 8
CKCID_BEHAVIORIO = 9
CKCID_RENDERCONTEXT = 12
CKCID_KINEMATICCHAIN = 13
CKCID_SCENEOBJECT = 11
CKCID_OBJECTANIMATION = 15
CKCID_ANIMATION = 16
CKCID_KEYEDANIMATION = 18
CKCID_BEOBJECT = 19
CKCID_DATAARRAY = 52
CKCID_SCENE = 10
CKCID_LEVEL = 21
CKCID_PLACE = 22
CKCID_GROUP = 23
CKCID_SOUND = 24
CKCID_WAVESOUND = 25
CKCID_MIDISOUND = 26
CKCID_MATERIAL = 30
CKCID_TEXTURE = 31
CKCID_MESH = 32
CKCID_PATCHMESH = 53
CKCID_RENDEROBJECT = 47
CKCID_2DENTITY = 27
CKCID_SPRITE = 28
CKCID_SPRITETEXT = 29
CKCID_3DENTITY = 33
CKCID_GRID = 50
CKCID_CURVEPOINT = 36
CKCID_SPRITE3D = 37
CKCID_CURVE = 43
CKCID_CAMERA = 34
CKCID_TARGETCAMERA = 35
CKCID_LIGHT = 38
CKCID_TARGETLIGHT = 39
CKCID_CHARACTER = 40
CKCID_3DOBJECT = 41
CKCID_BODYPART = 42
CKCID_PARAMETER = 46
CKCID_PARAMETERLOCAL = 45
CKCID_PARAMETERVARIABLE = 55
CKCID_PARAMETEROUT = 3
CKCID_INTERFACEOBJECTMANAGER = 48
CKCID_CRITICALSECTION = 49
CKCID_LAYER = 51
CKCID_PROGRESSIVEMESH = 54
CKCID_SYNCHRO = 20
CKCID_OBJECTARRAY = 80
CKCID_SCENEOBJECTDESC = 81
CKCID_ATTRIBUTEMANAGER = 82
CKCID_MESSAGEMANAGER = 83
CKCID_COLLISIONMANAGER = 84
CKCID_OBJECTMANAGER = 85
CKCID_FLOORMANAGER = 86
CKCID_RENDERMANAGER = 87
CKCID_BEHAVIORMANAGER = 88
CKCID_INPUTMANAGER = 89
CKCID_PARAMETERMANAGER = 90
CKCID_GRIDMANAGER = 91
CKCID_SOUNDMANAGER = 92
CKCID_TIMEMANAGER = 93
CKCID_CUIKBEHDATA = -1
CKCID_MAXCLASSID = 56
CKCID_MAXMAXCLASSID = 128
__ClassHierarchy = {
1: ("CKCID_OBJECT", ),
2: ("CKCID_OBJECT", "CKCID_PARAMETERIN", ),
4: ("CKCID_OBJECT", "CKCID_PARAMETEROPERATION", ),
5: ("CKCID_OBJECT", "CKCID_STATE", ),
6: ("CKCID_OBJECT", "CKCID_BEHAVIORLINK", ),
8: ("CKCID_OBJECT", "CKCID_BEHAVIOR", ),
9: ("CKCID_OBJECT", "CKCID_BEHAVIORIO", ),
12: ("CKCID_OBJECT", "CKCID_RENDERCONTEXT", ),
13: ("CKCID_OBJECT", "CKCID_KINEMATICCHAIN", ),
11: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", ),
15: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_OBJECTANIMATION", ),
16: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_ANIMATION", ),
18: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_ANIMATION", "CKCID_KEYEDANIMATION", ),
19: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", ),
52: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_DATAARRAY", ),
10: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_SCENE", ),
21: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_LEVEL", ),
22: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_PLACE", ),
23: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_GROUP", ),
24: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_SOUND", ),
25: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_SOUND", "CKCID_WAVESOUND", ),
26: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_SOUND", "CKCID_MIDISOUND", ),
30: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_MATERIAL", ),
31: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_TEXTURE", ),
32: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_MESH", ),
53: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_MESH", "CKCID_PATCHMESH", ),
47: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_RENDEROBJECT", ),
27: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_RENDEROBJECT", "CKCID_2DENTITY", ),
28: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_RENDEROBJECT", "CKCID_2DENTITY", "CKCID_SPRITE", ),
29: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_RENDEROBJECT", "CKCID_2DENTITY", "CKCID_SPRITETEXT", ),
33: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_3DENTITY", ),
50: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_3DENTITY", "CKCID_GRID", ),
36: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_3DENTITY", "CKCID_CURVEPOINT", ),
37: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_3DENTITY", "CKCID_SPRITE3D", ),
43: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_3DENTITY", "CKCID_CURVE", ),
34: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_3DENTITY", "CKCID_CAMERA", ),
35: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_3DENTITY", "CKCID_CAMERA", "CKCID_TARGETCAMERA", ),
38: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_3DENTITY", "CKCID_LIGHT", ),
39: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_3DENTITY", "CKCID_LIGHT", "CKCID_TARGETLIGHT", ),
40: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_3DENTITY", "CKCID_CHARACTER", ),
41: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_3DENTITY", "CKCID_3DOBJECT", ),
42: ("CKCID_OBJECT", "CKCID_SCENEOBJECT", "CKCID_BEOBJECT", "CKCID_3DENTITY", "CKCID_3DOBJECT", "CKCID_BODYPART", ),
46: ("CKCID_OBJECT", "CKCID_PARAMETER", ),
45: ("CKCID_OBJECT", "CKCID_PARAMETER", "CKCID_PARAMETERLOCAL", ),
55: ("CKCID_OBJECT", "CKCID_PARAMETER", "CKCID_PARAMETERLOCAL", "CKCID_PARAMETERVARIABLE", ),
3: ("CKCID_OBJECT", "CKCID_PARAMETER", "CKCID_PARAMETEROUT", ),
48: ("CKCID_OBJECT", "CKCID_INTERFACEOBJECTMANAGER", ),
49: ("CKCID_OBJECT", "CKCID_CRITICALSECTION", ),
51: ("CKCID_OBJECT", "CKCID_LAYER", ),
54: ("CKCID_OBJECT", "CKCID_PROGRESSIVEMESH", ),
20: ("CKCID_OBJECT", "CKCID_SYNCHRO", ),
80: ("CKCID_OBJECTARRAY", ),
81: ("CKCID_SCENEOBJECTDESC", ),
82: ("CKCID_ATTRIBUTEMANAGER", ),
83: ("CKCID_MESSAGEMANAGER", ),
84: ("CKCID_COLLISIONMANAGER", ),
85: ("CKCID_OBJECTMANAGER", ),
86: ("CKCID_FLOORMANAGER", ),
87: ("CKCID_RENDERMANAGER", ),
88: ("CKCID_BEHAVIORMANAGER", ),
89: ("CKCID_INPUTMANAGER", ),
90: ("CKCID_PARAMETERMANAGER", ),
91: ("CKCID_GRIDMANAGER", ),
92: ("CKCID_SOUNDMANAGER", ),
93: ("CKCID_TIMEMANAGER", ),
-1: ("CKCID_CUIKBEHDATA", ),
56: ("CKCID_MAXCLASSID", ),
128: ("CKCID_MAXMAXCLASSID", ),
}
def __init__(self, code: CK_CLASSID):
self.code: CK_CLASSID = code
def __repr__(self):
hierarchy = self.__ClassHierarchy.get(self.code, None)
if hierarchy is None:
return "[Undefined]"
return "{} ({})".format(
hierarchy[-1],
' -> '.join(hierarchy)
)
CKERROR = int
class CKERR():
CKERR_OK = 0
CKERR_INVALIDPARAMETER = -1
CKERR_INVALIDPARAMETERTYPE = -2
CKERR_INVALIDSIZE = -3
CKERR_INVALIDOPERATION = -4
CKERR_OPERATIONNOTIMPLEMENTED = -5
CKERR_OUTOFMEMORY = -6
CKERR_NOTIMPLEMENTED = -7
CKERR_NOTFOUND = -11
CKERR_NOLEVEL = -13
CKERR_CANCREATERENDERCONTEXT = -14
CKERR_NOTIFICATIONNOTHANDLED = -16
CKERR_ALREADYPRESENT = -17
CKERR_INVALIDRENDERCONTEXT = -18
CKERR_RENDERCONTEXTINACTIVE = -19
CKERR_NOLOADPLUGINS = -20
CKERR_NOSAVEPLUGINS = -21
CKERR_INVALIDFILE = -22
CKERR_INVALIDPLUGIN = -23
CKERR_NOTINITIALIZED = -24
CKERR_INVALIDMESSAGE = -25
CKERR_NODLLFOUND = -29
CKERR_ALREADYREGISTREDDLL = -30
CKERR_INVALIDDLL = -31
CKERR_INVALIDOBJECT = -34
CKERR_INVALIDCONDSOLEWINDOW = -35
CKERR_INVALIDKINEMATICCHAIN = -36
CKERR_NOKEYBOARD = -37
CKERR_NOMOUSE = -38
CKERR_NOJOYSTICK = -39
CKERR_INCOMPATIBLEPARAMETERS = -40
CKERR_NORENDERENGINE = -44
CKERR_NOCURRENTLEVEL = -45
CKERR_SOUNDDISABLED = -46
CKERR_DINPUTDISABLED = -47
CKERR_INVALIDGUID = -48
CKERR_NOTENOUGHDISKPLACE = -49
CKERR_CANTWRITETOFILE = -50
CKERR_BEHAVIORADDDENIEDBYCB = -51
CKERR_INCOMPATIBLECLASSID = -52
CKERR_MANAGERALREADYEXISTS = -53
CKERR_PAUSED = -54
CKERR_PLUGINSMISSING = -55
CKERR_OBSOLETEVIRTOOLS = -56
CKERR_FILECRCERROR = -57
CKERR_ALREADYFULLSCREEN = -58
CKERR_CANCELLED = -59
CKERR_NOANIMATIONKEY = -121
CKERR_INVALIDINDEX = -122
CKERR_INVALIDANIMATION = -123
__ErrorDescription = {
0: "Operation successful",
-1: "One of the parameter passed to the function was invalid",
-2: "One of the parameter passed to the function was invalid",
-3: "The parameter size was invalid",
-4: "The operation type didn't exist",
-5: "The function used to execute the operation is not yet implemented",
-6: "There was not enough memory to perform the action",
-7: "The function is not yet implemented",
-11: "There was an attempt to remove something not present",
-13: "There is no level currently created",
-14: "There is no level currently created",
-16: "The notification message was not used",
-17: "Attempt to add an item that was already present",
-18: "the render context is not valid",
-19: "the render context is not activated for rendering",
-20: "there was no plugins to load this kind of file",
-21: "there was no plugins to save this kind of file",
-22: "attempt to load an invalid file",
-23: "attempt to load with an invalid plugin",
-24: "attempt use an object that wasnt initialized",
-25: "attempt use a message type that wasn't registred",
-29: "No dll file found in the parse directory",
-30: "this dll has already been registred",
-31: "this dll does not contain information to create the prototype",
-34: "Invalid Object (attempt to Get an object from an invalid ID)",
-35: "Invalid window was provided as console window",
-36: "Invalid kinematic chain ( end and start effector may not be part of the same hierarchy )",
-37: "Keyboard not attached or not working properly",
-38: "Mouse not attached or not working properly",
-39: "Joystick not attached or not working properly",
-40: "Try to link imcompatible Parameters",
-44: "There is no render engine dll",
-45: "There is no current level (use CKSetCurrentLevel )",
-46: "Sound Management has been disabled",
-47: "DirectInput Management has been disabled",
-48: "Guid is already in use or invalid",
-49: "There was no more free space on disk when trying to save a file",
-50: "Impossible to write to file (write-protection ?)",
-51: "The behavior cannnot be added to this entity",
-52: "The behavior cannnot be added to this entity",
-53: "A manager was registered more than once",
-54: "CKprocess or TimeManager process while CK is paused will fail",
-55: "Some plugins were missing whileloading a file",
-56: "Virtools version too old to load this file",
-57: "CRC Error while loading file",
-58: "A Render context is already in Fullscreen Mode",
-59: "Operation was cancelled by user",
-121: "there were no animation key at the given index",
-122: "attemp to acces an animation key with an invalid index",
-123: "the animation is invalid (no entity associated or zero length)",
}
def __init__(self, code: CKERROR):
self.code: CKERROR = code
def __repr__(self):
return self.__ErrorDescription.get(self.code, "[Undefined]")

47
PyCmo/VirtoolsReader.py Normal file
View File

@ -0,0 +1,47 @@
import VirtoolsStruct
import VirtoolsUtils
import PyCmoMisc
import struct, io, datetime, zlib
g_dword = struct.Struct("<I")
def ReadCKFileHeader(fs: io.BufferedReader):
header = VirtoolsStruct.CKFileHeader()
# check magic words
magic_words = fs.read(8)
if magic_words != b'Nemo Fi\0':
raise Exception("Fail to read file header magic words")
header.Signature = magic_words
# assign data
(header.Crc, raw_date, header.FileVersion, header.FileVersion2, header.SaveFlags, header.PrewHdrPackSize,
header.DataPackSize, header.DataUnpackSize, header.ManagerCount, header.ObjectCount, header.MaxIDSaved,
header.ProductVersion, header.ProductBuild, header.PrewHdrUnpackSize) = struct.unpack("<14I", fs.read(14 * 4))
# process date independently
# date is in BCD code
day = PyCmoMisc.BcdCodeToDecCode((raw_date >> 24) & 0xff)
month = PyCmoMisc.BcdCodeToDecCode((raw_date >> 16) & 0xff - 1)
month = (month % 12) + 1
year = PyCmoMisc.BcdCodeToDecCode(raw_date & 0xffff)
header.Timestamp = datetime.date(year, month, day)
if header.FileVersion >= 8:
# check crc
gotten_crc = zlib.adler32(b'Nemo Fi\0', 0)
gotten_crc = zlib.adler32(struct.pack("<6I", 0, raw_date, header.FileVersion, header.FileVersion2, header.SaveFlags, header.PrewHdrPackSize), gotten_crc) # reset crc as zero
gotten_crc = zlib.adler32(struct.pack("<8I", header.DataPackSize, header.DataUnpackSize, header.ManagerCount, header.ObjectCount, header.MaxIDSaved, header.ProductVersion, header.ProductBuild, header.PrewHdrUnpackSize), gotten_crc)
gotten_crc = zlib.adler32(fs.read(header.PrewHdrPackSize), gotten_crc)
gotten_crc = zlib.adler32(fs.read(header.DataPackSize), gotten_crc)
if gotten_crc != header.Crc:
raise Exception("Crc Error")
return header
def ReadCKComposition(fs: io.BufferedReader):
composition = VirtoolsStruct.CKComposition()
composition.Header = ReadCKFileHeader(fs)
return composition

43
PyCmo/VirtoolsStruct.py Normal file
View File

@ -0,0 +1,43 @@
import VirtoolsConstants
import datetime
import PyCmoMisc
class CKFileHeader:
def __init__(self):
self.Signature: bytes = b'Nemo Fi\0'
self.Crc: int = 0
self.Timestamp: datetime.date = datetime.date.today()
self.FileVersion: int = 0
self.FileVersion2: int = 0
self.SaveFlags: int = 0
self.PrewHdrPackSize: int = 0
self.DataPackSize: int = 0
self.DataUnpackSize: int = 0
self.ManagerCount: int = 0
self.ObjectCount: int = 0
self.MaxIDSaved: int = 0
self.ProductVersion: int = 0
self.ProductBuild: int = 0
self.PrewHdrUnpackSize: int = 0
def __str__(self):
return f"""File Version: {self.FileVersion:d} / {self.FileVersion2:d}
Production (Version / Build): {self.ProductVersion:d} / {(self.ProductBuild >> 24) & 0xff:d}.{(self.ProductBuild >> 16) & 0xff:d}.{(self.ProductBuild >> 8) & 0xff:d}.{self.ProductBuild & 0xff:d}
Crc: 0x{self.Crc:08X}
Timestamp: {str(self.Timestamp)}
Save Flags: {VirtoolsConstants.PyEnum.PrintEnumFlag(self.SaveFlags, VirtoolsConstants.CK_FILE_WRITEMODE)}
Preview Header (Pack / Unpack): {PyCmoMisc.OutputSizeHumanReadable(self.PrewHdrPackSize)} / {PyCmoMisc.OutputSizeHumanReadable(self.PrewHdrUnpackSize)}
Data (Pack / Unpack): {PyCmoMisc.OutputSizeHumanReadable(self.DataPackSize)} / {PyCmoMisc.OutputSizeHumanReadable(self.DataUnpackSize)}
Manager Count: {self.ManagerCount:d}
Object Count: {self.ObjectCount:d}
Max ID Saved: {self.MaxIDSaved:d}
"""
class CKComposition(object):
def __init__(self):
self.Header: CKFileHeader = None

48
PyCmo/VirtoolsUtils.py Normal file
View File

@ -0,0 +1,48 @@
import zlib
import io
class ZlibDecompressBuffer(object):
def __init__(self, _fs: io.BufferedReader, _len: int, _is_compressed: bool):
self.__fs: io.BufferedReader = _fs
self.__len: int = _len
self.__compressed: bool = _is_compressed
self.__pos: int = 0
self.__parser: zlib._Decompress = zlib.decompressobj()
self.__cache: bytes = b''
self.__cachelen: int = 0
def __ParseOnce(self) -> bytes:
# check remain
remain: int = self.__len - self.__pos
if remain <= 0:
return None
# read it and increase pos
read_count: int = min(remain, 1024)
gotten_uncompressed: bytes = self.__parser.decompress(self.__fs.read(read_count))
self.__pos += read_count
# everything has done, no more data, flush it and get it remained data
if self.__pos >= self.__len:
gotten_uncompressed += self.__parser.flush()
return gotten_uncompressed
def Read(self, expected: int):
# try enrich cache
while self.__cachelen < expected:
new_data = self.__ParseOnce()
if new_data is None:
# no more data
raise Exception("No more data.")
else:
self.__cache += new_data
self.__cachelen += len(new_data)
# change data
returned_data = self.__cache[:expected]
self.__cache = self.__cache[expected:]
self.__cachelen -= expected
return returned_data

9
README.md Normal file
View File

@ -0,0 +1,9 @@
# libcmo21
The aim of this project is creating a universal library which can read / write CMO files or any other Virtools files without any Virtools dependencies.
This project will not link any original Virtools dynamic library. So this project can run on both of x64 and x86 platform.
This project only involving specific Virtools version, 2.1. Other Virtools version are not considered by this project.
This project is based on reverse work of CK2.dll, VxMath.dll and CK2_3D.dll. The program [unvirt](https://aluigi.altervista.org/papers.htm#unvirt) created by Luigi Auriemma, which is licensed by GPL-v2, also help my work.
For some personal reason, this project will keep a clean room with all doyaGu's projects. All variables and logic are based on my understanding and reversed code. This is my personal behavior, please forgive my decision if you dislike it.

23
libcmo21.sln Normal file
View File

@ -0,0 +1,23 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31702.278
MinimumVisualStudioVersion = 10.0.40219.1
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "PyCmo", "PyCmo\PyCmo.pyproj", "{ADC519E8-5F1B-427D-8E5C-1FABCB6147FB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ADC519E8-5F1B-427D-8E5C-1FABCB6147FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADC519E8-5F1B-427D-8E5C-1FABCB6147FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7C36D9F6-B130-4675-A20E-CE3523231D08}
EndGlobalSection
EndGlobal