nickhugi / pykotor Goto Github PK
View Code? Open in Web Editor NEWA Python library that can read and modify most file formats used by the game Knights of the Old Republic and its sequel.
License: GNU General Public License v3.0
A Python library that can read and modify most file formats used by the game Knights of the Old Republic and its sequel.
License: GNU General Public License v3.0
[gff_hk47_RepliesList_6]
FieldType=List
Label=RepliesList
AddField0=gff_hk47_RepliesList_0_6
[gff_hk47_RepliesList_0_6]
FieldType=Struct
Label=
TypeId=0
AddField0=gff_hk47_Index_8
[gff_hk47_Index_8]
FieldType=DWORD
Label=Index
Value=2DAMEMORY42
2DAMEMORY55=!FieldPath
Again from RepairHK47. Seems to need some inner way to connect all the nodes when a Path or a Label isn't provided as both of those seem to be optional for this syntax
more info: https://github.com/NickHugi/PyKotor/actions/runs/8128969560/job/22215485694
have tried different versions of pyinstaller to no avail. May need to use mlocate
or something to determine if the libs actually exist but not on $PATH
Doesn't happen in release. Not sure what's causing it. Things like textboxes in the Scripts tab will be empty, checkboxes etc
Since TSLPatcher was written for windows, nobody uses case-insensitive filenames especially in the inis. This causes problems when attempting patches with PyKotor on Unix.
e.g. 2DAMEMORY#/StrRef#
This is fixed on master and will be addressed in v1.5.3
The correct definition for GFFList patches is:
capsule = None
if is_capsule_file(gff_patch.destination.name):
capsule = Capsule(gff_output_container_path)
# TSLPatcher follows the following behavior:
# if !ReplaceFile=0:
# 1. Get the resource from the Modules (if we're patching to one).
# 2. Get the resource from Override (if we're patching there).
# 3. If still not found, get it from tslpatchdata
# if !ReplaceFile=1:
# 1. Get the resource from tslpatchdata.
# 2. If not found, get the resource from the Module we're patching (if we're patching to one).
# 3. If still not found, get the resource from Override (if we're patching there)
game_resource_location = SearchLocation.OVERRIDE if capsule is None else SearchLocation.CUSTOM_MODULES
if gff_patch.replace_file:
search_order = [
SearchLocation.CUSTOM_FOLDERS,
game_resource_location,
]
else:
search_order = [
game_resource_location,
SearchLocation.CUSTOM_FOLDERS,
]
resname, restype = ResourceIdentifier.from_path(gff_patch.filename)
search = installation.resource(
resname,
restype,
search_order,
folders=[self.mod_path],
capsules=[] if capsule is None else [capsule],
)
if search is None or search.data is None:
self.log.add_error(
f"Didn't patch '{gff_patch.filename}' because search data is `None`.",
)
continue
Had this error just a few times but for multiple mods:
[7/2/2023 7:10:11 PM] Using changes.ini path: C:\Users\*****\Documents\k1 mods\KillCzerkaJerk\tslpatchdata\changes.ini
[7/2/2023 7:10:12 PM] Traceback (most recent call last):
File "pykotorcli.py", line 66, in <module>
File "pykotor\tslpatcher\config.py", line 118, in install
File "pykotor\tslpatcher\config.py", line 113, in config
File "pykotor\tslpatcher\config.py", line 77, in load
File "pykotor\tslpatcher\reader.py", line 57, in load
File "pykotor\tslpatcher\reader.py", line 202, in load_nss
File "configparser.py", line 979, in __getitem__
KeyError: 'kas22_attack.nss'
Relevant changes.ini
example that'll reproduce:
; =====================================================[v1.0.5b1]====
; TSLPATCHER - GENERATED MODIFICATIONS FILE (25/03/2021)
; ===================================================================
; This file is automatically generated and as such has no formatting
; to speak of. You can insert blank lines between sections (but NOT
; between keys within a section!) and add comment lines starting
; with semicolon to make it more readable without breaking anything.
; -------------------------------------------------------------------
[Settings]
FileExists=1
WindowCaption=Request: Kill the Czerka jerk on Kashyyyk
ConfirmMessage=N/A
LogLevel=3
InstallerMode=1
BackupFiles=1
PlaintextLog=0
LookupGameFolder=0
LookupGameNumber=2
SaveProcessedScripts=0
[TLKList]
[InstallList]
install_folder0=Override
[2DAList]
[GFFList]
[CompileList]
Replace0=kas22_attack.nss
[SSFList]
; ===================================================================
[install_folder0]
Replace0=kas22_czerkag_01.dlg
Replace1=kas22_czerkag_01.utc
Replace2=kas22_czerkag_02.utc
Replace3=kas22_czerkag_03.utc
Replace4=kas22_czerkag_04.utc
Replace5=kas22_czerka2_01.utc
I am trying to batch convert KOTOR models to ASCII format. I executed pip install pykotor and wrote the following application(reduced)
from pykotor.resource.formats.mdl import read_mdl, write_mdl
from pykotor.resource.type import ResourceType
model = read_mdl(original_files_folder + file_name)
write_mdl(model, converted_files_folder + converted_file_name, ResourceType.MDL_ASCII)
but unfortunatelly around 30% of files from models.bif archite are failed with some errors.
For example:
write_mdl list index out of range
Files: dor_lhr02.mdl, dor_lma01.mdl, c_drdwar.mdl, c_drdastro.mdl ...
read_mdl 501 is not a valid SurfaceMaterial
Files: c_dewback.mdl,lqa_dewback.mdl, m01aa_c01_char02.mdl, m08aa_05a.mdl ...
read_mdl 38 is not a valid SurfaceMaterial
Files: m12aa_c03_char02.mdl, m12aa_c04_char01.mdl ...
read_mdl 8195 is not a valid SurfaceMaterial
Files: m02aa_09b.mdl...
read_mdl unpack requires a buffer of 4 bytes
Files: m12aa_c04_cam.mdl, m12ab_mgt02.mdl, m12ab_mgt05.mdl
From the TSLPatcher docs:
When NWNNSSComp.exe decompiles a ncs, it'll look for the game install based on what's in the registry. So if I have another htinstallation that's currently selected and that htinstallation does not point to a path that's mirrored in the registry, nwnnsscomp will fail with:
Lookup path root set to: C:\Program Files (x86)\Steam\steamapps\common\Knights of the Old Republic II\
Error: Couldn't initialize the NwnStdLoader
this happened when my installation was set to C:\Program Files (x86)\Steam\steamapps\common\Knights of the Old Republic II - TSLRCM
Nesting a .git in a subfolder of our main repo creates a submodule. This strategy allows us to point to another repository, enabling these repositories to connect and interact more efficiently. PyKotor has become a giant monster of a project, and it's been difficult to organize things with our current system. This is why I recommend the feature: sub-modules
BWM
or PyKotor.Extract.Installation
, avoiding unnecessary downloads.In tslpatcher/config.py line 186, the patcher will crash if search is None. Which seems to happen a lot with files inside mod archives. I am trying to install K1CP (admittedly an unfair test as most builds of TSLPatcher fail with it, but still one of the most popular mods)
This is the relevant section of the output prior to an unrelated crash (which is almost certainly a macOS compatibility issue-- double backslashes getting a FileNotFoundError). I had added a check which prints the "because it is None" message whenever search is None
Patching czerkasoldier.utc in the modules\korr_m33aa.mod archive.
Didn't patch czerkasoldier.utc because it is None.
Patching dan13_ahlan.dlg in the modules\danm13.mod archive.
Didn't patch dan13_ahlan.dlg because it is None.
Patching dan13_bluecryst.uti in the modules\danm13.mod archive.
Didn't patch dan13_bluecryst.uti because it is None.
Patching dan13_goldcryst.uti in the modules\danm13.mod archive.
Didn't patch dan13_goldcryst.uti because it is None.
Patching dan13_grncryst.uti in the modules\danm13.mod archive.
Didn't patch dan13_grncryst.uti because it is None.
Patching dan13_vandar.dlg in the modules\danm13.mod archive.
Didn't patch dan13_vandar.dlg because it is None.
Patching dan13_vrook.utc in the modules\danm13.mod archive.
Didn't patch dan13_vrook.utc because it is None.
Patching dan13_zhar.dlg in the modules\danm13.mod archive.
Didn't patch dan13_zhar.dlg because it is None.
Patching dan13_zhar.utc in the modules\danm13.mod archive.
Didn't patch dan13_zhar.utc because it is None.
Patching dan14_bolook.dlg in the modules\danm14ac.mod archive.
Didn't patch dan14_bolook.dlg because it is None.
Patching dan14_bolook.utc in the modules\danm14ac.mod archive.
Didn't patch dan14_bolook.utc because it is None.
Patching dan14_bolook02.utc in the modules\danm14ac.mod archive.
Didn't patch dan14_bolook02.utc because it is None.
Patching dan14_corpse.utp in the modules\danm14ac.mod archive.
Didn't patch dan14_corpse.utp because it is None.
Patching dan14_cutscene.dlg in the modules\danm14ad.mod archive.
Didn't patch dan14_cutscene.dlg because it is None.
Patching dan14_elise.dlg in the modules\danm14aa.mod archive.
Didn't patch dan14_elise.dlg because it is None.
Patching dan14_handon.utc in the modules\danm14ac.mod archive.
Didn't patch dan14_handon.utc because it is None.
Patching dan14_jedi.dlg in the modules\danm13.mod archive.
Didn't patch dan14_jedi.dlg because it is None.
Patching dan14_juhani.utc in the modules\danm14ac.mod archive.
Didn't patch dan14_juhani.utc because it is None.
Patching dan14_rickard.utc in the modules\danm14ac.mod archive.
Didn't patch dan14_rickard.utc because it is None.
Patching dan14_sdroid.utc in the modules\danm14ad.mod archive.
Didn't patch dan14_sdroid.utc because it is None.
Patching dan14_sherruk.dlg in the modules\danm14ac.mod archive.
Didn't patch dan14_sherruk.dlg because it is None.
Patching dan14aa_casus.utp in the modules\danm14ab.mod archive.
Didn't patch dan14aa_casus.utp because it is None.
Patching dan14ab_duros01.utc in the modules\danm14ab.mod archive.
Didn't patch dan14ab_duros01.utc because it is None.
Patching dan14ab_duros02.utc in the modules\danm14ab.mod archive.
Didn't patch dan14ab_duros02.utc because it is None.
Patching dan14ab_duros03.utc in the modules\danm14ab.mod archive.
Didn't patch dan14ab_duros03.utc because it is None.
Patching dan14ac_duros01.utc in the modules\danm14ac.mod archive.
Didn't patch dan14ac_duros01.utc because it is None.
Patching dan14ac_duros02.utc in the modules\danm14ac.mod archive.
Didn't patch dan14ac_duros02.utc because it is None.
Patching dan15_ancientdrd.dlg in the modules\danm15.mod archive.
Didn't patch dan15_ancientdrd.dlg because it is None.
Patching dan16_nurik.dlg in the modules\danm16.mod archive.
Didn't patch dan16_nurik.dlg because it is None.
Patching dan16_nurik.utc in the modules\danm16.mod archive.
Didn't patch dan16_nurik.utc because it is None.
Patching ebo_bast_vision.dlg in the modules\ebo_m12aa.mod archive.
Didn't patch ebo_bast_vision.dlg because it is None.
Patching ebo_carth.dlg in the modules\ebo_m40ad.mod archive.
Didn't patch ebo_carth.dlg because it is None.
Patching m12aa.git in the modules\ebo_m41aa.mod archive.
Didn't patch m12aa.git because it is None.
Patching end_cut01.dlg in the modules\end_m01aa.mod archive.
Didn't patch end_cut01.dlg because it is None.
Patching end_door19.utd in the modules\end_m01aa.mod archive.
Didn't patch end_door19.utd because it is None.
Patching footlker003.utp in the modules\manm27aa.mod archive.
Didn't patch footlker003.utp because it is None.
Looking at PyKotor you have the following:
for name, value in modifications_ini.items():
if name.lower() == "!destination":
modificaitons.destination = value
elif name.lower() == "!replacefile":
modificaitons.replace_file = bool(int(value))
elif name.lower() == "!filename":
modificaitons.filename = value
elif name.lower().startswith("addfield"):
modifier = self.add_field_gff(value, dict(self.ini[value]))
modificaitons.modifiers.append(modifier)
else:
modifier = self.modify_field_gff(name, value)
modificaitons.modifiers.append(modifier)
TSLPatcher has another field less known called !SaveAs
:
My impression was that Fair Strides added !Filename without realizing !SaveAs was already there, maybe because she was working from the original release that didn't have it, I dunno.
From the TSLPatcher readme it says:
"Added the HackList modifiers to the Configuration Summary display. Added
name of source file if different from the destination file name (configured with
the new !SourceFile and !SaveAs keys)."
"Added an optional !DefaultDestination key to the [CompileList] section
which will determine where the NCS files should be put if no specific
destination has been set. Default value if the key is left out is the override
folder as before. In addition to override it can be set the the relative path (from
the game folder) and name of an ERF or RIM file to insert the scripts into. This
value can then be overridden with the !Destination key for individual files as
before."
Relevant changes.ini snippet:
[man_calo.utc]
!Destination=modules\manm28aa.mod
!SaveAs=n_calonord001.utc
GoodEvil=25
!ReplaceFile=0
Expected TSLPatcher output:
• Modifying GFF format files...
• GFF FILE: man_calo.utc and man_calo.utc.
• GFF FILE: man_calo.utc and man_calo.utc.
• GFF Check: 1_man_calo.utc.
• GFF Check: 2_C:\Users\boden\Desktop\KotOR1\modules\manm28aa.mod.
• GFF Check: 3.
• GFF Check: 4_C:\Users\boden\Documents\k1 mods\NPC_Alignment_Fix_v1_1\tslpatchdata\_erfpath_temp.
• GFF Check: 5_n_calonord001.utc man_calo.utc..
PyKotor throws some red herring of an error due to this.
When installing: https://deadlystream.com/files/file/312-gaffi-stick-improvement/
It looks like some of the bits of the rtf README are throwing parsing errors in HoloPatcher, this is benign as far as I can tell, but interrupts an automated install (like with KOTORModSync).
Here's the stack trace: let me know if I can give you anything else :)
An unexpected error occurred while loading the patcher namespace. Exception ''utf-8' codec can't decode byte 0xbb in position 36: invalid start byte' of type '<class 'UnicodeDecodeError'>' occurred.
Stack Trace Variables:
Function 'on_namespace_option_chosen' at /tmp/_MEI9fHypt/__main__.py:863:
self = App(
browse_button=<tkinter.ttk.Button object .!frame.!button>,
exit_button=<tkinter.ttk.Button object .!frame4.!button>,
expand_namespace_description_button=<tkinter.ttk.Button object .!frame.!button2>,
gamepaths=<tkinter.ttk.Combobox object .!frame.!combobox2>,
gamepaths_browse_button=<tkinter.ttk.Button object .!frame.!button3>,
install_button=<tkinter.ttk.Button object .!frame4.!button2>,
install_running=False,
log_file_path=PosixPath(/home/synchro/Games/Modding/kotormods...<truncated>
event = Event(
<tkinter.Event object at 0x7fa0328a3aa0>
config_reader = ConfigReader(
config=PatcherConfig(
confirm_message='N/A',
game_number=1,
ignore_file_extensions=False,
install_list=[],
log_level=<LogLevel.WARNINGS: 3>,
patches_2da...,
ini=ConfigParser(
BOOLEAN_STATES={'1': True, 'yes': True, 'true': True, 'on': True, '0': False, 'no': False, 'false': False, 'off': False},
NONSPACECRE=re.compile('\\S'),
OPTCR...,
log=PatchLogger(
all_logs=[<pykotor.tslpatcher.logger.PatchLog object at 0x7fa0328a3b90>],
error_observable=Observable(
callbacks=[]
),
errors=[],
n...,
mod_path=CaseAwarePath("//home/synchro/Games/Modding/kotormods/mods/Gaffi Stick Improvement/Gaffi Stick Improvement/tslpatchdata"),
previously_parsed_sections={'Settings'}
)
namespace_option = PatcherNamespace(
DEFAULT_INFO_FILENAME='info.rtf',
DEFAULT_INI_FILENAME='changes.ini',
data_folderpath=PurePosixPath(.),
description='',
info_filename='info.rtf',
ini_filename='changes.ini',
name='Gaffi Stick Improvement - KotOR 1',
namespace_id=''
)
changes_ini_path = CaseAwarePath("//home/synchro/Games/Modding/kotormods/mods/Gaffi Stick Improvement/Gaffi Stick Improvement/tslpatchdata/changes.ini")
reader = ConfigReader(
config=PatcherConfig(
confirm_message='N/A',
game_number=1,
ignore_file_extensions=False,
install_list=[],
log_level=<LogLevel.WARNINGS: 3>,
patches_2da...,
ini=ConfigParser(
BOOLEAN_STATES={'1': True, 'yes': True, 'true': True, 'on': True, '0': False, 'no': False, 'false': False, 'off': False},
NONSPACECRE=re.compile('\\S'),
OPTCR...,
log=PatchLogger(
all_logs=[<pykotor.tslpatcher.logger.PatchLog object at 0x7fa0328a3b90>],
error_observable=Observable(
callbacks=[]
),
errors=[],
n...,
mod_path=CaseAwarePath("//home/synchro/Games/Modding/kotormods/mods/Gaffi Stick Improvement/Gaffi Stick Improvement/tslpatchdata"),
previously_parsed_sections={'Settings'}
)
game_number = 1
game = <Game.K1: 1>
info_rtf_path = CaseAwarePath("//home/synchro/Games/Modding/kotormods/mods/Gaffi Stick Improvement/Gaffi Stick Improvement/tslpatchdata/info.rtf")
info_rte_path = CaseAwarePath("//home/synchro/Games/Modding/kotormods/mods/Gaffi Stick Improvement/Gaffi Stick Improvement/tslpatchdata/info.rte")
data = b'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n\xbb Gaffi Stick Improvement ReadMe\r\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\nAUTHOR: Fallen Guardian\r\nNAME: Gaffi Stick Improvement\r\nTYPE: Modification\r\nV...
e = UnicodeDecodeError('utf-8', b'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n\xbb Gaffi Stick Improvement ReadMe\r\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\nAUTHOR: Fallen Guardian\r\nNAME: Gaffi Stick Improvemen...
Function 'decode_bytes_with_fallbacks' at /tmp/_MEI9fHypt/pykotor/tools/encoding.pyc:61:
byte_content = b'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n\xbb Gaffi Stick Improvement ReadMe\r\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\nAUTHOR: Fallen Guardian\r\nNAME: Gaffi Stick Improvement\r\nTYPE: Modification\r\nV...
errors = 'strict'
encoding = None
lang = None
only_8bit_encodings = False
provided_encoding = 'utf-8'
Traceback (most recent call last):
File "__main__.py", line 863, in on_namespace_option_chosen
File "pykotor/tools/encoding.py", line 61, in decode_bytes_with_fallbacks
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbb in position 36: invalid start byte
I fixed a bug recently where the compiled file would end in .nss extension instead of .ncs.
I am uncertain whether this bug manifested in the code before or after the release of holopatcher v1.4.3. Both master and bleeding-edge have this fixed.
The NSS editor will open with the filename set to foo_s.rim/a_script.ncs. (Either it'll have the decompiled source of a_script.ncs, or it'll be blank. Doesn't matter either way.)
The new script will be compiled to an NCS resource and saved over a_script in foo_s.rim, even though "allow saving resources to RIM files" is disabled.
There's a forwards-compatibility issue with glibc that I've observed on some linux systems during testing. This issue applies directly to our releases, and directly applies to our PyInstaller publish workflow. Their FAQ explains the problem better than I can:
Under Linux, I get runtime dynamic linker errors, related to libc. What should I do?
The executable that PyInstaller builds is not fully static, in that it still depends on the system libc. Under Linux, the ABI of GLIBC is backward compatible, but not forward compatible. So if you link against a newer GLIBC, you can't run the resulting executable on an older system. The supplied binary bootloader should work with older GLIBC. However, the libpython.so and other dynamic libraries still depends on the newer GLIBC. The solution is to compile the Python interpreter with its modules (and also probably bootloader) on the oldest system you have around, so that it gets linked with the oldest version of GLIBC.
Another solution is to use a tool like StaticX to create a fully-static bundled version of your PyInstaller application. StaticX bundles all dependencies, including libc and ld.so. (Python code ➡️ PyInstaller ➡️ StaticX ➡️ Fully-static application)
To be clear: this a problem specific to building binaries with a tool like PyInstaller for a public release. Building from src or running the python scripts directly on Linux does not have any issues.
The polish version of the game has two TalkTable files - a dialog.tlk
and a dialogf.tlk
. I believe the latter is for female entries and the former is for male/nongendered. Would need to modify ModificationsTLK class and update the reader.py code in load_tlk_list
I don't know of or have access to the Polish version of the game to do any testing with this.
So in a usual [CompileList] section TSLPatcher does the following:
Version 1.4.3 of holopatcher fails step 3, it currently isolates the processed scripts from the others making memory token replacement in include scripts impossible.
Version 1.4.3 also fails to set the include directory (the library_lookup list argument) when compiling with the built-in. So the built-in compiler currently does not work with include scripts.
Master branch has all of the above fixed, but a bug still remains: step 4 is not observed by the built-in compiler.
Problem is perhaps in the pathlib overrides but further research must be done. Shouldn't have to worry about this until we eventually start releasing with python 3.13.
See the conversation around here for details.
There seem to be major discrepancies in what TSLPatcher is doing with 2da files vs PyKotor. Nothing specifically looks off in Holocron Toolset but Winmerge spots dozens and dozens of bytes that differ. Here are both appearance.2da files after installing the TSLRCM Tweak Pack:
Tested at commit ebcd217 on Windows:
Open any .nss file (I used Vanilla_KOTOR_Script_Source\TSL\Vanilla\Modules\001EBO_Ebon_Hawk_(prologue_interior)\a_end_001.nss
) and then use "Save As" and choose an output file with the .ncs file name.
It should pop up a dialog to select a compiler, and then invoke the chosen compiler to save the script as an NCS.
There are 5 cases:
For case 2 and 5, I added a call UndefinedFunction();
to the start of the script, which should fail to compile since, you know, the function's undefined.
user exited
compiling script from nsseditor
user cancelled the compilation
Failed to write to file
and message ('ValueError', ''Could not convert to bytes - nsseditor.build()')
.stdout says:
user chose No, compiling with nwnnsscomp
Compiling: C:\Users\JoeNotCharles\temp\tempscript_243ff0.nss
Total Execution time = 15 ms
compiling script from nsseditor
errorlog.txt contains:
Assertion with Exception Trace: Exception 'Could not convert to bytes - nsseditor.build()' of type '<class 'ValueError'>' occurred.
Formatted Traceback:
Traceback (most recent call last):
File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py", line 247, in save
data, data_ext = self.build()
File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py", line 193, in build
raise ValueError(msg)
ValueError: Could not convert to bytes - nsseditor.build()
Stack Trace Variables:
Function 'save' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py:247:
self = <toolset.gui.editors.nss.NSSEditor object at 0x00000186F02DFEB0>
e = ValueError('Could not convert to bytes - nsseditor.build()')
file = <_io.TextIOWrapper name='errorlog.txt' mode='a' encoding='utf-8'>
Function 'build' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py:193:
self = <toolset.gui.editors.nss.NSSEditor object at 0x00000186F02DFEB0>
compiled_bytes = b'NCS V1.0B\x00\x00\x04H\x1e\x00\x00\x00\x00\x08
\x00\x02\x03\x04\x03\x00\x00\x00\x01\x05\x00\x03\x00\x01\x01\x01\xff\xff\xff\xf8\x00\x04\x1b\x00\xff\xff\xff\xfc\x03\x01\xff\xff\xff\xfc\x00\x04\x1f\x00\x00\x00\x00o\x04\x05\x00\x10001EBO_Movie_End\x05\x00\x02D\x01\x04\x03\x00\x00\x00\x00\x0b \x1f\x00\x00\x00\x00B\x04\x03\x00\x00\x00\x01\x04\x05\x00\x10001EBO_Movie_End\x05\x00\x02E\x02\x04\x03\x00\x00\x00\x00\x04\x05\x00\x08permov02\x05\x00\x02\xdd\x02\x1d\x00\x00\x00\x00\x06\x1d\x00\x00\x00\x00\x06\x05\x00\x...<truncated>
msg = 'Could not convert to bytes - nsseditor.build()'
----------------------
Failed to write to file
and message (FileNotFoundError', "Could not find temp compiled script at 'C:\\Users\\JoeNotCharles\\temp\\tempscript_089466.ncs'")
.stdout says:
user chose No, compiling with nwnnsscomp
Compiling: C:\Users\JoeNotCharles\temp\tempscript_089466.nss
Compilation aborted with errors
Total Execution time = 0 ms
C:\Users\JoeNotCharles\temp\tempscript_089466.nss(3): Error: Undeclared identifier "UndefinedFunction"
errorlog.txt contains:
----------------------
Assertion with Exception Trace: Exception 'Could not find temp compiled script at 'C:\Users\JoeNotCharles\temp\tempscript_089466.ncs'' of type '<class 'FileNotFoundError'>' occurred.
Formatted Traceback:
Traceback (most recent call last):
File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py", line 247, in save
data, data_ext = self.build()
File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py", line 186, in build
compiled_bytes: bytes | None = compileScript(self.ui.codeEdit.toPlainText(), self._installation.tsl, self._installation.path())
File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py", line 181, in compileScript
return _compile_windows(global_settings, extract_path, source, tsl, installation_path)
File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py", line 299, in _compile_windows
raise FileNotFoundError(f"Could not find temp compiled script at '{tempCompiledPath}'") # noqa: TRY003, EM102
FileNotFoundError: Could not find temp compiled script at 'C:\Users\JoeNotCharles\temp\tempscript_089466.ncs'
Stack Trace Variables:
Function 'save' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py:247:
self = <toolset.gui.editors.nss.NSSEditor object at 0x00000186F02DFEB0>
e = FileNotFoundError("Could not find temp compiled script at 'C:\\Users\\JoeNotCharles\\temp\\tempscript_089466.ncs'")
file = <_io.TextIOWrapper name='errorlog.txt' mode='a' encoding='utf-8'>
Function 'build' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py:186:
self = <toolset.gui.editors.nss.NSSEditor object at 0x00000186F02DFEB0>
Function 'compileScript' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py:181:
source = 'void main() {\n\tint nParam1 = GetScriptParameter(1);\n UndefinedFunction();\n\tif (nParam1) {\n\t\tif ((GetGlobalNumber("001EBO_Movie_End") == 0)) {\n\t\t\tSetGlobalNumber("001EBO_Movie_End", 1);\n\t\t\tPlayMovie("permov02", 0);\n\t\t}\n\t}\n\tif ((!GetIsXBox())) {\n\t\tSetPlanetAvailable(11, 0);\n\t\tSetPlanetSelectable(11, 0);\n\t}\n\tint int5 = 88;\n\tif ((!GetIsXBox())) {\n\t\tint5 = 89;\n\t}\n\tif (((GetJournalEntry("tutorial_3CFD") > 0) && (GetJournalEntry("tutorial_3CFD") < 90))) {\n\t\tAurPostS...<truncated>
tsl = True
installation_path = CaseAwarePath("C:\"\"Program Files (x86)"\"Steam"\"steamapps"\"common"\"Knights of the Old Republic II")
global_settings = <toolset.gui.widgets.settings.installations.GlobalSettings object at 0x00000186ED2F4820>
extract_path = WindowsPath(C:\Users\JoeNotCharles\temp)
returnValue = 65536
Function '_compile_windows' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py:299:
global_settings = <toolset.gui.widgets.settings.installations.GlobalSettings object at 0x00000186ED2F4820>
extract_path = WindowsPath(C:\Users\JoeNotCharles\temp)
source = 'void main() {\n\tint nParam1 = GetScriptParameter(1);\n UndefinedFunction();\n\tif (nParam1) {\n\t\tif ((GetGlobalNumber("001EBO_Movie_End") == 0)) {\n\t\t\tSetGlobalNumber("001EBO_Movie_End", 1);\n\t\t\tPlayMovie("permov02", 0);\n\t\t}\n\t}\n\tif ((!GetIsXBox())) {\n\t\tSetPlanetAvailable(11, 0);\n\t\tSetPlanetSelectable(11, 0);\n\t}\n\tint int5 = 88;\n\tif ((!GetIsXBox())) {\n\t\tint5 = 89;\n\t}\n\tif (((GetJournalEntry("tutorial_3CFD") > 0) && (GetJournalEntry("tutorial_3CFD") < 90))) {\n\t\tAurPostS...<truncated>
tsl = True
installation_path = CaseAwarePath("C:\"\"Program Files (x86)"\"Steam"\"steamapps"\"common"\"Knights of the Old Republic II")
nss_compiler_path = WindowsPath(C:\src\gamedev\kotor\Streamlined Peragus\tslpatchdata\nwnnsscomp.exe)
rand_id = '089466'
tempscript_filestem = 'tempscript_089466'
tempSourcePath = WindowsPath(C:\Users\JoeNotCharles\temp\tempscript_089466.nss)
tempCompiledPath = WindowsPath(C:\Users\JoeNotCharles\temp\tempscript_089466.ncs)
gameEnum = <Game.K2: 2>
extCompiler = <pykotor.resource.formats.ncs.compilers.ExternalNCSCompiler object at 0x00000186ED2F41E0>
orig_regkey_path = None
orig_regkey_value = None
stdout = 'Compiling: C:\\Users\\JoeNotCharles\\temp\\tempscript_089466.nss\nCompilation aborted with errors\nTotal Execution time = 0 ms\n'
stderr = '\nC:\\Users\\JoeNotCharles\\temp\\tempscript_089466.nss(3): Error: Undeclared identifier "UndefinedFunction"'
pattern = 'Unable to open the include file "([^"\\n]*)"'
----------------------
Failed to write to file
and message ('error, 'argument out of range')
.stdout says:
user chose Yes, compiling with builtin
errorlog.txt contains:
Assertion with Exception Trace: Exception 'argument out of range' of type '<class 'struct.error'>' occurred.
Formatted Traceback:
Traceback (most recent call last):
File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py", line 247, in save
data, data_ext = self.build()
File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py", line 186, in build
compiled_bytes: bytes | None = compileScript(self.ui.codeEdit.toPlainText(), self._installation.tsl, self._installation.path())
File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py", line 178, in compileScript
return bytes_ncs(compile_nss(source, Game.K2 if tsl else Game.K1, library_lookup=[CaseAwarePath(extract_path)]))
File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\ncs_auto.py", line 91, in bytes_ncs
write_ncs(ncs, data, file_format)
File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\ncs_auto.py", line 63, in write_ncs
NCSBinaryWriter(ncs, target).write()
File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\type.py", line 392, in _autoclose
resource: R = func(self, auto_close)
File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\io_ncs.py", line 358, in write
self._write_instruction(instruction)
File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\io_ncs.py", line 463, in _write_instruction
self._writer.write_int32(instruction.args[0], big=True)
File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\common\stream.py", line 1762, in write_int32
self._ba[self._position : self._position + 4] = struct.pack(
struct.error: argument out of range
Stack Trace Variables:
Function 'save' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py:247:
self = <toolset.gui.editors.nss.NSSEditor object at 0x00000186F02DFEB0>
e = error('argument out of range')
file = <_io.TextIOWrapper name='errorlog.txt' mode='a' encoding='utf-8'>
Function 'build' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py:186:
self = <toolset.gui.editors.nss.NSSEditor object at 0x00000186F02DFEB0>
Function 'compileScript' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py:178:
source = 'void main() {\n\tint nParam1 = GetScriptParameter(1);\n\tif (nParam1) {\n\t\tif ((GetGlobalNumber("001EBO_Movie_End") == 0)) {\n\t\t\tSetGlobalNumber("001EBO_Movie_End", 1);\n\t\t\tPlayMovie("permov02", 0);\n\t\t}\n\t}\n\tif ((!GetIsXBox())) {\n\t\tSetPlanetAvailable(11, 0);\n\t\tSetPlanetSelectable(11, 0);\n\t}\n\tint int5 = 88;\n\tif ((!GetIsXBox())) {\n\t\tint5 = 89;\n\t}\n\tif (((GetJournalEntry("tutorial_3CFD") > 0) && (GetJournalEntry("tutorial_3CFD") < 90))) {\n\t\tAurPostString("Completing tutorial...<truncated>
tsl = True
installation_path = CaseAwarePath("C:\"\"Program Files (x86)"\"Steam"\"steamapps"\"common"\"Knights of the Old Republic II")
global_settings = <toolset.gui.widgets.settings.installations.GlobalSettings object at 0x00000186ED114F50>
extract_path = WindowsPath(C:\Users\JoeNotCharles\temp)
returnValue = 16384
Function 'bytes_ncs' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\ncs_auto.py:91:
ncs = <pykotor.resource.formats.ncs.ncs_data.NCS object at 0x00000186ED114AF0>
file_format = ResourceType.NCS
data = bytearray(b'NCS V1.0B\x00\x00\x04\xb8\x1e\x00\x00\x00\x00\x08 \x00\x04\x03\x00\x00\x00\x01\x05\x00\x03\x00\x01\x03\x01\xff\xff\xff\xfc\x00\x04\x1f\x00\x00\x00\x00\x93\x04\x05\x00\x10001EBO_Movie_End\x05\x00\x02D\x01\x04\x03\x00\x00\x00\x00\x0b \x1f\x00\x00\x00\x00Z\x04\x03\x00\x00\x00\x01\x04\x05\x00\x10001EBO_Movie_End\x05\x00\x02E\x02\x1b\x00\x00\x00\x00\x00\x04\x03\x00\x00\x00\x00\x04\x05\x00\x08permov02\x05\x00\x02\xdd\x02\x1b\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x00\x00\x1d\x00\x...<truncated>
Function 'write_ncs' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\ncs_auto.py:63:
ncs = <pykotor.resource.formats.ncs.ncs_data.NCS object at 0x00000186ED114AF0>
target = bytearray(b'NCS V1.0B\x00\x00\x04\xb8\x1e\x00\x00\x00\x00\x08 \x00\x04\x03\x00\x00\x00\x01\x05\x00\x03\x00\x01\x03\x01\xff\xff\xff\xfc\x00\x04\x1f\x00\x00\x00\x00\x93\x04\x05\x00\x10001EBO_Movie_End\x05\x00\x02D\x01\x04\x03\x00\x00\x00\x00\x0b \x1f\x00\x00\x00\x00Z\x04\x03\x00\x00\x00\x01\x04\x05\x00\x10001EBO_Movie_End\x05\x00\x02E\x02\x1b\x00\x00\x00\x00\x00\x04\x03\x00\x00\x00\x00\x04\x05\x00\x08permov02\x05\x00\x02\xdd\x02\x1b\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x00\x00\x1d\x00\x...<truncated>
file_format = ResourceType.NCS
Function '_autoclose' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\type.py:392:
self = <pykotor.resource.formats.ncs.io_ncs.NCSBinaryWriter object at 0x00000186ED221050>
auto_close = True
func = <function NCSBinaryWriter.write at 0x00000186DDA3C5F0>
Function 'write' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\io_ncs.py:358:
self = <pykotor.resource.formats.ncs.io_ncs.NCSBinaryWriter object at 0x00000186ED221050>
auto_close = True
offset = 1208
instruction = NCSInstruction(NCSInstructionType.CONSTI, None, [4294967295])
Function '_write_instruction' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\io_ncs.py:463:
self = <pykotor.resource.formats.ncs.io_ncs.NCSBinaryWriter object at 0x00000186ED221050>
instruction = NCSInstruction(NCSInstructionType.CONSTI, None, [4294967295])
to_signed_32bit = <function NCSBinaryWriter._write_instruction.<locals>.to_signed_32bit at 0x00000186F03CEEB0>
to_signed_16bit = <function NCSBinaryWriter._write_instruction.<locals>.to_signed_16bit at 0x00000186F03CECD0>
Function 'write_int32' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\common\stream.py:1762:
self = <pykotor.common.stream.BinaryWriterBytearray object at 0x00000186ED196AA0>
value = 4294967295
big = True
----------------------
Failed to write to file
and message ('CompileError', "Function 'UndefinedFunction' has not been defined.")
.stdout says:
user chose Yes, compiling with builtin
errorlog.txt contains:
Assertion with Exception Trace: Exception 'Function 'UndefinedFunction' has not been defined.' of type '<class 'pykotor.resource.formats.ncs.compiler.classes.CompileError'>' occurred.
Formatted Traceback:
Traceback (most recent call last):
File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py", line 247, in save
data, data_ext = self.build()
File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py", line 186, in build
compiled_bytes: bytes | None = compileScript(self.ui.codeEdit.toPlainText(), self._installation.tsl, self._installation.path())
File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py", line 178, in compileScript
return bytes_ncs(compile_nss(source, Game.K2 if tsl else Game.K1, library_lookup=[CaseAwarePath(extract_path)]))
File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\ncs_auto.py", line 125, in compile_nss
block.compile(ncs)
File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py", line 309, in compile
obj.compile(ncs, self)
File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py", line 591, in compile
self.block.compile(ncs, root, None, retn, None, None)
File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py", line 435, in compile
statement.compile(
File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py", line 1392, in compile
expression_type = self.expression.compile(ncs, root, block)
File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py", line 1033, in compile
raise CompileError(msg)
pykotor.resource.formats.ncs.compiler.classes.CompileError: Function 'UndefinedFunction' has not been defined.
Stack Trace Variables:
Function 'save' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py:247:
self = <toolset.gui.editors.nss.NSSEditor object at 0x00000186F02DFEB0>
e = CompileError("Function 'UndefinedFunction' has not been defined.")
file = <_io.TextIOWrapper name='errorlog.txt' mode='a' encoding='utf-8'>
Function 'build' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py:186:
self = <toolset.gui.editors.nss.NSSEditor object at 0x00000186F02DFEB0>
Function 'compileScript' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py:178:
source = 'void main() {\n UndefinedFunction();\n\tint nParam1 = GetScriptParameter(1);\n\tif (nParam1) {\n\t\tif ((GetGlobalNumber("001EBO_Movie_End") == 0)) {\n\t\t\tSetGlobalNumber("001EBO_Movie_End", 1);\n\t\t\tPlayMovie("permov02", 0);\n\t\t}\n\t}\n\tif ((!GetIsXBox())) {\n\t\tSetPlanetAvailable(11, 0);\n\t\tSetPlanetSelectable(11, 0);\n\t}\n\tint int5 = 88;\n\tif ((!GetIsXBox())) {\n\t\tint5 = 89;\n\t}\n\tif (((GetJournalEntry("tutorial_3CFD") > 0) && (GetJournalEntry("tutorial_3CFD") < 90))) {\n\t\tAurPostS...<truncated>
tsl = True
installation_path = CaseAwarePath("C:\"\"Program Files (x86)"\"Steam"\"steamapps"\"common"\"Knights of the Old Republic II")
global_settings = <toolset.gui.widgets.settings.installations.GlobalSettings object at 0x00000186ED196140>
extract_path = WindowsPath(C:\Users\JoeNotCharles\temp)
returnValue = 16384
Function 'compile_nss' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\ncs_auto.py:125:
source = 'void main() {\n UndefinedFunction();\n\tint nParam1 = GetScriptParameter(1);\n\tif (nParam1) {\n\t\tif ((GetGlobalNumber("001EBO_Movie_End") == 0)) {\n\t\t\tSetGlobalNumber("001EBO_Movie_End", 1);\n\t\t\tPlayMovie("permov02", 0);\n\t\t}\n\t}\n\tif ((!GetIsXBox())) {\n\t\tSetPlanetAvailable(11, 0);\n\t\tSetPlanetSelectable(11, 0);\n\t}\n\tint int5 = 88;\n\tif ((!GetIsXBox())) {\n\t\tint5 = 89;\n\t}\n\tif (((GetJournalEntry("tutorial_3CFD") > 0) && (GetJournalEntry("tutorial_3CFD") < 90))) {\n\t\tAurPostS...<truncated>
game = <Game.K2: 2>
optimizers = None
library_lookup = [CaseAwarePath("C:\"\"Users"\"JoeNotCharles"\"temp")]
errorlog = None
debug = False
nss_parser = <pykotor.resource.formats.ncs.compiler.parser.NssParser object at 0x00000186ED30C230>
ncs = <pykotor.resource.formats.ncs.ncs_data.NCS object at 0x00000186ED3EBF50>
block = <pykotor.resource.formats.ncs.compiler.classes.CodeRoot object at 0x00000186ED4039B0>
Function 'compile' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py:309:
self = <pykotor.resource.formats.ncs.compiler.classes.CodeRoot object at 0x00000186ED4039B0>
ncs = <pykotor.resource.formats.ncs.ncs_data.NCS object at 0x00000186ED3EBF50>
others = [<pykotor.resource.formats.ncs.compiler.classes.FunctionDefinition object at 0x00000186ED331A00>]
entry_index = 0
obj = <pykotor.resource.formats.ncs.compiler.classes.FunctionDefinition object at 0x00000186ED331A00>
included = []
script_globals = []
Function 'compile' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py:591:
self = <pykotor.resource.formats.ncs.compiler.classes.FunctionDefinition object at 0x00000186ED331A00>
ncs = <pykotor.resource.formats.ncs.ncs_data.NCS object at 0x00000186ED3EBF50>
root = <pykotor.resource.formats.ncs.compiler.classes.CodeRoot object at 0x00000186ED4039B0>
name = 'main'
previous_is_default = False
retn = NCSInstruction(NCSInstructionType.RETN, None, [])
function_start = NCSInstruction(NCSInstructionType.NOP, None, [])
Function 'compile' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py:435:
self = <pykotor.resource.formats.ncs.compiler.classes.CodeBlock object at 0x00000186ED31ACD0>
ncs = <pykotor.resource.formats.ncs.ncs_data.NCS object at 0x00000186ED3EBF50>
root = <pykotor.resource.formats.ncs.compiler.classes.CodeRoot object at 0x00000186ED4039B0>
block = None
return_instruction = NCSInstruction(NCSInstructionType.RETN, None, [])
break_instruction = None
continue_instruction = None
statement = <pykotor.resource.formats.ncs.compiler.classes.ExpressionStatement object at 0x00000186ED407140>
Function 'compile' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py:1392:
self = <pykotor.resource.formats.ncs.compiler.classes.ExpressionStatement object at 0x00000186ED407140>
ncs = <pykotor.resource.formats.ncs.ncs_data.NCS object at 0x00000186ED3EBF50>
root = <pykotor.resource.formats.ncs.compiler.classes.CodeRoot object at 0x00000186ED4039B0>
block = <pykotor.resource.formats.ncs.compiler.classes.CodeBlock object at 0x00000186ED31ACD0>
return_instruction = NCSInstruction(NCSInstructionType.RETN, None, [])
break_instruction = None
continue_instruction = None
Function 'compile' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py:1033:
self = <pykotor.resource.formats.ncs.compiler.classes.FunctionCallExpression object at 0x00000186ED403A50>
ncs = <pykotor.resource.formats.ncs.ncs_data.NCS object at 0x00000186ED3EBF50>
root = <pykotor.resource.formats.ncs.compiler.classes.CodeRoot object at 0x00000186ED4039B0>
block = <pykotor.resource.formats.ncs.compiler.classes.CodeBlock object at 0x00000186ED31ACD0>
msg = "Function 'UndefinedFunction' has not been defined."
----------------------
[Note] Adding file plc_hotelscomp.utp in the manm26ae.MOD archive...
[Note] Patching m26ae.git in the modules\manm26ae.MOD folder.
[7/1/2023 10:03:34 PM] Traceback (most recent call last):
File "pykotorcli.py", line 66, in <module>
File "pykotor\tslpatcher\config.py", line 186, in install
AttributeError: 'NoneType' object has no attribute 'data'
config.ini:
; =====================================================[v1.0.5b1]====
; TSLPATCHER - GENERATED MODIFICATIONS FILE (1/27/2009)
; ===================================================================
; This file is automatically generated and as such has no formatting
; to speak of. You can insert blank lines between sections (but NOT
; between keys within a section!) and add comment lines starting
; with semicolon to make it more readable without breaking anything.
; -------------------------------------------------------------------
[Settings]
FileExists=1
WindowCaption=K1 Utility Armbands
ConfirmMessage=Did you read the ReadMe carefully?
LogLevel=3
InstallerMode=1
BackupFiles=1
PlaintextLog=0
LookupGameFolder=0
LookupGameNumber=1
SaveProcessedScripts=0
[TLKList]
[InstallList]
install_folder0=Modules
install_folder1=Modules\manm26ae.MOD
[2DAList]
[GFFList]
File0=m26ae.git
[CompileList]
[SSFList]
; ===================================================================
[gff_sa_ope_doo_PropertiesList_0_0]
FieldType=Struct
Path=PropertiesList
Label=
TypeId=0
AddField0=gff_sa_ope_doo_PropertyName_0
AddField1=gff_sa_ope_doo_Subtype_0
AddField2=gff_sa_ope_doo_CostTable_0
AddField3=gff_sa_ope_doo_CostValue_0
AddField4=gff_sa_ope_doo_Param1_0
AddField5=gff_sa_ope_doo_Param1Value_0
AddField6=gff_sa_ope_doo_ChanceAppear_0
[gff_sa_ope_doo_PropertyName_0]
FieldType=Word
Label=PropertyName
Value=10
[gff_sa_ope_doo_Subtype_0]
FieldType=Word
Label=Subtype
Value=2DAMEMORY1
[gff_sa_ope_doo_CostTable_0]
FieldType=Byte
Label=CostTable
Value=3
[gff_sa_ope_doo_CostValue_0]
FieldType=Word
Label=CostValue
Value=13
[gff_sa_ope_doo_Param1_0]
FieldType=Byte
Label=Param1
Value=255
[gff_sa_ope_doo_Param1Value_0]
FieldType=Byte
Label=Param1Value
Value=0
[gff_sa_ope_doo_ChanceAppear_0]
FieldType=Byte
Label=ChanceAppear
Value=100
[gff_sa_ori_arm_PropertiesList_0_0]
FieldType=Struct
Path=PropertiesList
Label=
TypeId=0
AddField0=gff_sa_ori_arm_PropertyName_0
AddField1=gff_sa_ori_arm_Subtype_0
AddField2=gff_sa_ori_arm_CostTable_0
AddField3=gff_sa_ori_arm_CostValue_0
AddField4=gff_sa_ori_arm_Param1_0
AddField5=gff_sa_ori_arm_Param1Value_0
AddField6=gff_sa_ori_arm_ChanceAppear_0
[gff_sa_ori_arm_PropertyName_0]
FieldType=Word
Label=PropertyName
Value=10
[gff_sa_ori_arm_Subtype_0]
FieldType=Word
Label=Subtype
Value=2DAMEMORY2
[gff_sa_ori_arm_CostTable_0]
FieldType=Byte
Label=CostTable
Value=3
[gff_sa_ori_arm_CostValue_0]
FieldType=Word
Label=CostValue
Value=13
[gff_sa_ori_arm_Param1_0]
FieldType=Byte
Label=Param1
Value=255
[gff_sa_ori_arm_Param1Value_0]
FieldType=Byte
Label=Param1Value
Value=0
[gff_sa_ori_arm_ChanceAppear_0]
FieldType=Byte
Label=ChanceAppear
Value=100
[gff_m01aa_Placeable List_60_0]
FieldType=Struct
Path=Placeable List
Label=
TypeId=9
AddField0=gff_m01aa_TemplateResRef_0
AddField1=gff_m01aa_X_0
AddField2=gff_m01aa_Y_0
AddField3=gff_m01aa_Z_0
AddField4=gff_m01aa_Bearing_0
[gff_m01aa_TemplateResRef_0]
FieldType=ResRef
Label=TemplateResRef
Value=sa_uti_arm
[gff_m01aa_X_0]
FieldType=Float
Label=X
Value=11.8500003814697
[gff_m01aa_Y_0]
FieldType=Float
Label=Y
Value=15.9099998474121
[gff_m01aa_Z_0]
FieldType=Float
Label=Z
Value=-1.26999998092651
[gff_m01aa_Bearing_0]
FieldType=Float
Label=Bearing
Value=0
[m26ae.git]
AddField0=gff_m26ae_Placeable List_43_0
AddField1=gff_m26ae_Placeable List_44_0
AddField2=gff_m26ae_Placeable List_45_0
AddField3=gff_m26ae_Placeable List_46_0
CameraList\16\Orientation=0.122737869620323|0|0|0.992439150810242
AddField4=gff_m26ae_CameraList_19_0
!Destination=modules\manm26ae.MOD
[gff_m26ae_Placeable List_43_0]
FieldType=Struct
Path=Placeable List
Label=
TypeId=9
AddField0=gff_m26ae_TemplateResRef_0
AddField1=gff_m26ae_X_0
AddField2=gff_m26ae_Y_0
AddField3=gff_m26ae_Z_0
AddField4=gff_m26ae_Bearing_0
[gff_m26ae_TemplateResRef_0]
FieldType=ResRef
Label=TemplateResRef
Value=plc_hotelscomp
[gff_m26ae_X_0]
FieldType=Float
Label=X
Value=21
[gff_m26ae_Y_0]
FieldType=Float
Label=Y
Value=37.422420501709
[gff_m26ae_Z_0]
FieldType=Float
Label=Z
Value=57.5034408569336
[gff_m26ae_Bearing_0]
FieldType=Float
Label=Bearing
Value=1.57878005504608
[gff_m26ae_Placeable List_44_0]
FieldType=Struct
Path=Placeable List
Label=
TypeId=9
AddField0=gff_m26ae_TemplateResRef_1
AddField1=gff_m26ae_X_1
AddField2=gff_m26ae_Y_1
AddField3=gff_m26ae_Z_1
AddField4=gff_m26ae_Bearing_1
[gff_m26ae_TemplateResRef_1]
FieldType=ResRef
Label=TemplateResRef
Value=plc_hotelcomp
[gff_m26ae_X_1]
FieldType=Float
Label=X
Value=5.44999980926514
[gff_m26ae_Y_1]
FieldType=Float
Label=Y
Value=36.8073883056641
[gff_m26ae_Z_1]
FieldType=Float
Label=Z
Value=57.5034408569336
[gff_m26ae_Bearing_1]
FieldType=Float
Label=Bearing
Value=4.69497013092041
[gff_m26ae_Placeable List_45_0]
FieldType=Struct
Path=Placeable List
Label=
TypeId=9
AddField0=gff_m26ae_TemplateResRef_2
AddField1=gff_m26ae_X_2
AddField2=gff_m26ae_Y_2
AddField3=gff_m26ae_Z_2
AddField4=gff_m26ae_Bearing_2
[gff_m26ae_TemplateResRef_2]
FieldType=ResRef
Label=TemplateResRef
Value=plc_hotelcomp
[gff_m26ae_X_2]
FieldType=Float
Label=X
Value=21
[gff_m26ae_Y_2]
FieldType=Float
Label=Y
Value=47.3524208068848
[gff_m26ae_Z_2]
FieldType=Float
Label=Z
Value=57.5034408569336
[gff_m26ae_Bearing_2]
FieldType=Float
Label=Bearing
Value=1.57878005504608
[gff_m26ae_Placeable List_46_0]
FieldType=Struct
Path=Placeable List
Label=
TypeId=9
AddField0=gff_m26ae_TemplateResRef_3
AddField1=gff_m26ae_X_3
AddField2=gff_m26ae_Y_3
AddField3=gff_m26ae_Z_3
AddField4=gff_m26ae_Bearing_3
[gff_m26ae_TemplateResRef_3]
FieldType=ResRef
Label=TemplateResRef
Value=plc_hotelcomp
[gff_m26ae_X_3]
FieldType=Float
Label=X
Value=19.5557098388672
[gff_m26ae_Y_3]
FieldType=Float
Label=Y
Value=65.870002746582
[gff_m26ae_Z_3]
FieldType=Float
Label=Z
Value=57.5034408569336
[gff_m26ae_Bearing_3]
FieldType=Float
Label=Bearing
Value=0.00441000005230308
[gff_m26ae_CameraList_19_0]
FieldType=Struct
Path=CameraList
Label=
TypeId=14
AddField0=gff_m26ae_CameraID_0
AddField1=gff_m26ae_Position_0
AddField2=gff_m26ae_Pitch_0
AddField3=gff_m26ae_MicRange_0
AddField4=gff_m26ae_Orientation_0
AddField5=gff_m26ae_Height_0
AddField6=gff_m26ae_FieldOfView_0
[gff_m26ae_CameraID_0]
FieldType=Int
Label=CameraID
Value=21
[gff_m26ae_Position_0]
FieldType=Position
Label=Position
Value=21.3220901489258|40.1263618469238|57.5034408569336
[gff_m26ae_Pitch_0]
FieldType=Float
Label=Pitch
Value=80
[gff_m26ae_MicRange_0]
FieldType=Float
Label=MicRange
Value=0
[gff_m26ae_Orientation_0]
FieldType=Orientation
Label=Orientation
Value=0.145659998059273|0|0|-0.989340007305145
[gff_m26ae_Height_0]
FieldType=Float
Label=Height
Value=1.5
[gff_m26ae_FieldOfView_0]
FieldType=Float
Label=FieldOfView
Value=55
[install_folder0]
File0=manm26ae.mod
[install_folder1]
Replace0=k_pman_planet43.ncs
Replace1=man26_bigcomp.dlg
Replace2=plc_hotelcomp.dlg
Replace3=smre_closesunrydor.ncs
Replace4=smre_elassa.utc
Replace5=smre_fadein.ncs
Replace6=smre_fadeout.ncs
Replace7=smre_kill.ncs
Replace8=smre_killelassa.ncs
Replace9=smre_opendoor.ncs
Replace10=smre_opendoor2.ncs
Replace11=smre_rec_c.ncs
Replace12=smre_spawn_elas.ncs
Replace13=smre_spawn_sunry.ncs
Replace14=smre_sun_fin.dlg
Replace15=smre_sun_rec.dlg
Replace16=smre_sun_rec.ncs
Replace17=smre_sunry.utc
Replace18=smre_term_conv.ncs
Replace19=smre_wait1.ncs
Replace20=plc_hotelcomp.utp
Replace21=plc_hotelscomp.utp
[gff_m26ae_Placeable List_43_1]
FieldType=Struct
Path=Placeable List
Label=
TypeId=9
AddField0=gff_m26ae_TemplateResRef_4
AddField1=gff_m26ae_X_4
AddField2=gff_m26ae_Y_4
AddField3=gff_m26ae_Z_4
AddField4=gff_m26ae_Bearing_4
[gff_m26ae_TemplateResRef_4]
FieldType=ResRef
Label=TemplateResRef
Value=plc_hotelscomp
[gff_m26ae_X_4]
FieldType=Float
Label=X
Value=21
[gff_m26ae_Y_4]
FieldType=Float
Label=Y
Value=37.422420501709
[gff_m26ae_Z_4]
FieldType=Float
Label=Z
Value=57.5034408569336
[gff_m26ae_Bearing_4]
FieldType=Float
Label=Bearing
Value=1.57878005504608
[gff_m26ae_Placeable List_44_1]
FieldType=Struct
Path=Placeable List
Label=
TypeId=9
AddField0=gff_m26ae_TemplateResRef_5
AddField1=gff_m26ae_X_5
AddField2=gff_m26ae_Y_5
AddField3=gff_m26ae_Z_5
AddField4=gff_m26ae_Bearing_5
[gff_m26ae_TemplateResRef_5]
FieldType=ResRef
Label=TemplateResRef
Value=plc_hotelcomp
[gff_m26ae_X_5]
FieldType=Float
Label=X
Value=5.44999980926514
[gff_m26ae_Y_5]
FieldType=Float
Label=Y
Value=36.8073883056641
[gff_m26ae_Z_5]
FieldType=Float
Label=Z
Value=57.5034408569336
[gff_m26ae_Bearing_5]
FieldType=Float
Label=Bearing
Value=4.69497013092041
[gff_m26ae_Placeable List_45_1]
FieldType=Struct
Path=Placeable List
Label=
TypeId=9
AddField0=gff_m26ae_TemplateResRef_6
AddField1=gff_m26ae_X_6
AddField2=gff_m26ae_Y_6
AddField3=gff_m26ae_Z_6
AddField4=gff_m26ae_Bearing_6
[gff_m26ae_TemplateResRef_6]
FieldType=ResRef
Label=TemplateResRef
Value=plc_hotelcomp
[gff_m26ae_X_6]
FieldType=Float
Label=X
Value=21
[gff_m26ae_Y_6]
FieldType=Float
Label=Y
Value=47.3524208068848
[gff_m26ae_Z_6]
FieldType=Float
Label=Z
Value=57.5034408569336
[gff_m26ae_Bearing_6]
FieldType=Float
Label=Bearing
Value=1.57878005504608
[gff_m26ae_Placeable List_46_1]
FieldType=Struct
Path=Placeable List
Label=
TypeId=9
AddField0=gff_m26ae_TemplateResRef_7
AddField1=gff_m26ae_X_7
AddField2=gff_m26ae_Y_7
AddField3=gff_m26ae_Z_7
AddField4=gff_m26ae_Bearing_7
[gff_m26ae_TemplateResRef_7]
FieldType=ResRef
Label=TemplateResRef
Value=plc_hotelcomp
[gff_m26ae_X_7]
FieldType=Float
Label=X
Value=19.5557098388672
[gff_m26ae_Y_7]
FieldType=Float
Label=Y
Value=65.870002746582
[gff_m26ae_Z_7]
FieldType=Float
Label=Z
Value=57.5034408569336
[gff_m26ae_Bearing_7]
FieldType=Float
Label=Bearing
Value=0.00441000005230308
[gff_m26ae_CameraList_19_1]
FieldType=Struct
Path=CameraList
Label=
TypeId=14
AddField0=gff_m26ae_CameraID_1
AddField1=gff_m26ae_Position_1
AddField2=gff_m26ae_Pitch_1
AddField3=gff_m26ae_MicRange_1
AddField4=gff_m26ae_Orientation_1
AddField5=gff_m26ae_Height_1
AddField6=gff_m26ae_FieldOfView_1
[gff_m26ae_CameraID_1]
FieldType=Int
Label=CameraID
Value=21
[gff_m26ae_Position_1]
FieldType=Position
Label=Position
Value=21.3220901489258|40.1263618469238|57.5034408569336
[gff_m26ae_Pitch_1]
FieldType=Float
Label=Pitch
Value=80
[gff_m26ae_MicRange_1]
FieldType=Float
Label=MicRange
Value=0
[gff_m26ae_Orientation_1]
FieldType=Orientation
Label=Orientation
Value=0.145659998059273|0|0|-0.989340007305145
[gff_m26ae_Height_1]
FieldType=Float
Label=Height
Value=1.5
[gff_m26ae_FieldOfView_1]
FieldType=Float
Label=FieldOfView
Value=55
The tests/common/test_get_case_sensitive_path.py::TestCaseAwarePath::test_make_and_parse_uri
and test_relative_to
tests are failing on macOS, but not linux. Very bizarre. Is happening on all tested python versions.
Love seeing a decently written cross-platform GUI toolkit for KotOR 👍
I see some reuse potential between HT and KotorBlender, which has complete support for binary MDL and BWM in Python. reone too, as a source of knowledge on graphics and possibly NCS.
Let me know what you think about that. I totally get if you don't want to touch any of that and just do your own thing.
When launching these HoloPatcher releases on Linux I get the following error:
[81862] Module object for struct is NULL!
Traceback (most recent call last):
File "struct.py", line 13, in <module>
ModuleNotFoundError: No module named '_struct'
To my ignorant self it looks like there is a missing python module during your packaging process, but I am not all too familiar with the packaging process for python apps.
This is reproducable for all of the 1.6.0 beta releases of holopatcher so far.
[8/4/2023 2:15:19 PM] [Error] Traceback (most recent call last):
[8/4/2023 2:15:19 PM] Warning: A file named manm26ae.mod already exists in the Modules folder. Skipping file...
[8/4/2023 2:15:19 PM] Note: Replacing file k_pman_planet43.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file man26_bigcomp.dlg in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file plc_hotelcomp.dlg in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Adding file smre_closesunrydor.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_elassa.utc in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_fadein.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_fadeout.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_kill.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_killelassa.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_opendoor.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_opendoor2.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_rec_c.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_spawn_elas.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_spawn_sunry.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_sun_fin.dlg in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_sun_rec.dlg in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_sun_rec.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_sunry.utc in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file smre_term_conv.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] [Error] File "pykotorcli.py", line 80, in <module>
[8/4/2023 2:15:19 PM] Note: Replacing file smre_wait1.ncs in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] [Error] File "pykotor\tslpatcher\config.py", line 187, in install
[8/4/2023 2:15:19 PM] Note: Replacing file plc_hotelcomp.utp in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Replacing file plc_hotelscomp.utp in the manm26ae.MOD archive...
[8/4/2023 2:15:19 PM] Note: Patching m26ae.git in the modules\manm26ae.MOD folder.
[8/4/2023 2:15:19 PM] [Error] AttributeError: 'NoneType' object has no attribute 'data'
[8/4/2023 2:15:19 PM] [Error] [20572] Failed to execute script 'pykotorcli' due to unhandled exception!
See the test test_gff_add_inside_list
for why this is broken.
https://github.com/NickHugi/PyKotor/blob/master/tests/tslpatcher/test_reader.py
Logs:
Note: Patching drdparts.dlg in the \override\ folder.
Note: apply in ModifyFieldGFF: add value({1: '725'}, 2)
Note: apply in ModifyFieldGFF: add value({1: '725'}, 2)
relevant changes.ini snippet:
[GFFList]
File1=drdparts.dlg
[drdparts.dlg]
AddField0=gff_drdparts_EntryList_14_0
AddField1=gff_drdparts_EntriesList_2_0
AddField2=gff_drdparts_ReplyList_11_0
ReplyList\7\EntriesList\0\ParamStrA=HK_REPAIR_STATE
ReplyList\7\EntriesList\0\Index=2DAMEMORY2
...omitted for brevity...
ReplyList\7\EntriesList\1\ParamStrA=000_HK_Total_Parts
[gff_drdparts_EntryList_14_0]
FieldType=Struct
Path=EntryList
Label=
TypeId=14
AddField0=gff_drdparts_Speaker_0
...omitted for brevity...
AddField42=gff_drdparts_RecordNoVOOverri_0
2DAMEMORY2=ListIndex
The issue is due to a lack of support for the syntax The problem is caused by missing support for adding structs to GFF lists. The struct is never added, therefore it can never be found in patcher memory, thus the KeyError.2DAMEMORY2=ListIndex
and then referencing the value 2DAMEMORY2
later in the GFFList.
I've noticed the mod Visually Repair HK-47 is one of the only ones to have this error.
Using PyKotor to attempt to install the Juhani Romance Enhancement mod, I get this error:
[7/2/2023 6:59:31 PM] Using changes.ini path: C:\Users\*****\Documents\k1 mods\Juhani_Romance_Enhancement\tslpatchdata\changes.ini
[7/2/2023 6:59:32 PM] Traceback (most recent call last):
File "pykotorcli.py", line 66, in <module>
File "pykotor\tslpatcher\config.py", line 118, in install
File "pykotor\tslpatcher\config.py", line 113, in config
File "pykotor\tslpatcher\config.py", line 77, in load
File "pykotor\tslpatcher\reader.py", line 56, in load
File "pykotor\tslpatcher\reader.py", line 189, in load_gff
File "pykotor\tslpatcher\reader.py", line 331, in add_field_gff
File "pykotor\tslpatcher\reader.py", line 294, in add_field_gff
ValueError: could not convert string to float: '113,430000305176'
Relevant changes.ini
snippet:
[m44ac.git]
AddField0=gff_m44ac_TriggerList_18_0
AddField1=gff_m44ac_CameraList_22_0
AddField2=gff_m44ac_CameraList_23_0
!Destination=Modules\unk_m44ac.mod
[gff_m44ac_TriggerList_18_0]
FieldType=Struct
Path=TriggerList
Label=
TypeId=1
AddField0=gff_m44ac_TemplateResRef_0
AddField1=gff_m44ac_XPosition_0
AddField2=gff_m44ac_YPosition_0
AddField3=gff_m44ac_ZPosition_0
AddField4=gff_m44ac_XOrientation_0
AddField5=gff_m44ac_YOrientation_0
AddField6=gff_m44ac_ZOrientation_0
AddField7=gff_m44ac_Geometry_0
[gff_m44ac_TemplateResRef_0]
FieldType=ResRef
Label=TemplateResRef
Value=jre_trigger
[gff_m44ac_XPosition_0]
FieldType=Float
Label=XPosition
Value=113,430000305176
[gff_m44ac_YPosition_0]
FieldType=Float
Label=YPosition
Value=69,6999969482422
[gff_m44ac_ZPosition_0]
FieldType=Float
Label=ZPosition
Value=13,7505826950073
Perhaps the comma simply needs to be treated as a dot and handle both cases?
I try to install your project using Pip. I found that your project will depend on the project "PyKotor==1.5.4". After installing the dependencies, some of the files in your project will overwrite some of the files in PyKotor. This includes mainly the modules in the "pykotor" root directory and the "venv" root directory.
Not sure what the cause is, but installing both the K1 and K2 modbuild with PyKotor results in all characters having no dialogue (you try to talk to them and they say nothing). Doesn't affect playable characters in the party.
Loading into a new zone (walking through a door into a new area) causes the game to return to the main menu with all buttons there disabled. This is an instantaneous action. Attempting to alt+f4 does not even bring up the confirmation 'are you sure' screen.
I'm attempting to compare the .mod files as I think it is a lip problem, I will post my results here.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.