- Joined
- Sep 15, 2009
- Messages
- 143
- Reaction score
- 50
复制这段内容后打开百度网盘App,操作更方便哦。
链接:
提取码:9F1w --来自百度网盘超级会员V3的分享
链接:
You must be registered to see links
提取码:9F1w --来自百度网盘超级会员V3的分享
Last edited by a moderator:
Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!
Join Today!Would take some time, but yeahWould anyone be able to re-upload to google drive/mega/mediafire?
/notice
/summon
/bookset
/teleport
/transfer
/enterHome
/leaveHome
/run
/startQuest
/cancelQuest
/addToFinishedQuests
/removeFromFinishedQuests
/questStates
/test_menu_selection_marker
/testload
/move
/whereami
/action
/getProperty
/setProperty
/resetCutscene
/item
/uncarve
/batch
/forcetransfer
/whereis
/playerlist
/checkmemory
/behaviortree
/kickout
/kickoutAll
/stamina
/refreshkiranaconditionz
/refreshkc
/time
/dump
/resetZone
/resetTerrain
/controlZoneEnter
/getRelationship
/setRelationship
/level
/emptyinven
/loot
/hottimez
/ho
/spmaxz
/sp
/kimaxz
/ki
/giveItem
/ban
/account
/character
/server
/debugAI
/dumpuser
/resetNPC
Would take some time, but yeah
You must be registered to see links
You must be registered to see links
GM Commands
Code:/notice /summon /bookset /teleport /transfer /enterHome /leaveHome /run /startQuest /cancelQuest /addToFinishedQuests /removeFromFinishedQuests /questStates /test_menu_selection_marker /testload /move /whereami /action /getProperty /setProperty /resetCutscene /item /uncarve /batch /forcetransfer /whereis /playerlist /checkmemory /behaviortree /kickout /kickoutAll /stamina /refreshkiranaconditionz /refreshkc /time /dump /resetZone /resetTerrain /controlZoneEnter /getRelationship /setRelationship /level /emptyinven /loot /hottimez /ho /spmaxz /sp /kimaxz /ki /giveItem /ban /account /character /server /debugAI /dumpuser /resetNPC
Hope this helps out.
if currentLocale != 'cp949':
if self.Renderer.NativeWindowHandle:
text = 'Unsupported system locale : {}'.format(currentLocale)
text += '\n\nTo execute the client, change system locale to cp949 (Korean)'
self.showWindowsMessageBox(text)
self.nxlog = None
self.quit(0)
return
It does have a messagebox yes, I also found it in decompiled app.py
Code:if currentLocale != 'cp949': if self.Renderer.NativeWindowHandle: text = 'Unsupported system locale : {}'.format(currentLocale) text += '\n\nTo execute the client, change system locale to cp949 (Korean)' self.showWindowsMessageBox(text) self.nxlog = None self.quit(0) return
issue is that the decompilation failed half way down the file :S and its not possible to just replace the app.pyc with app.py because of this.
# uncompyle6 version 3.7.4
# Python bytecode 3.7 (3394)
# Decompiled from: Python 2.7.17 (default, Sep 30 2020, 13:38:04)
# [GCC 7.5.0]
# Warning: this version of Python has problems handling the Python 3 "byte" type in constants properly.
# Embedded file name: C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\client\app.py
# Compiled at: 2019-05-10 19:51:18
# Size of source mod 2**32: 69315 bytes
import collections, logging, os, sys, weakref, time, datetime, platform, enum, locale, thing.accessor
import thing.asyncio as asyncio
import thing.system
from natuum.activeobjects import ApartmentActiveObject
import natuum.apartment, natuum.app, natuum.builder, natuum.renderer, natuum.jobQueue, natuum.configuration, natuum.client.action, natuum.client.pager, natuum.client.resource, natuum.client.craft, natuum.client.logic, natuum.util, natuum.variation, natuum.indexBook, natuum.reward, natuum.growth, natuum.emotionCutscene, natuum.client.synergy, natuum.client.contract, natuum.client.relationship, natuum._entity.apartmentEvents, natuum._entity.framework.cluster
import natuum._entity.messageRPC as messageRPC
from natuum.nexon import NXLogClient
from natuum._entity.interfaces.clientSubscriber import IGatewaySubscriber
import natuum.gameService.wordFilter
if __thing_can_get_zcom_objects__:
import multiprocessing
if not __final__:
import natuum.objects
DEFAULT_CLIENT_RESOLUTION = (1920, 1080)
if not __final__:
LOG_DEBUG = natuum.getLogger('client.app').debug
LOG_WARNING = natuum.getLogger('client.app').warning
import socket
def callbackBeforeDump():
if natuum.client.app.Instance:
natuum.client.app.Instance.nxlog.stageLog(1020, 'crash')
natuum.flushLog()
def callbackAfterDump():
pass
TEXT_FORMAT_TO_PRELOAD = ((0, '2002', 24.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 12.0, 3, 0, 5, 1.0),
(0, 'KoPubDotum', 13.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 13.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 14.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 14.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 15.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 15.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 17.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 17.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 18.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 18.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 21.0, 5, 0, 5, 1.0), (0, 'KoPubDotum', 22.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 23.0, 5, 0, 5, 1.0), (0, 'KoPubDotum', 24.0, 3, 0, 5, 1.0),
(0, 'KoPubDotum', 26.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 27.36, 3, 0, 5, 1.0),
(0, 'KoPubDotum', 27.6, 5, 0, 5, 1.0), (0, 'KoPubDotum', 33.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 34.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 50.0, 5, 0, 5, 1.0),
(0, 'NanumSquare', 12.0, 5, 0, 5, 1.0), (0, 'NanumSquare', 14.0, 3, 0, 5, 1.0),
(0, 'NanumSquare', 14.0, 5, 0, 5, 1.0), (0, 'NanumSquare', 15.0, 5, 0, 5, 1.0),
(0, 'NanumSquare', 16.0, 5, 2, 5, 1.0), (0, 'NanumSquare', 17.0, 5, 0, 5, 1.0),
(0, 'NanumSquare', 40.0, 5, 0, 5, 1.0))
SIDEMENU_HTMLIVEWS = ('sideMenu_page_collection', 'sideMenu_page_map', 'sideMenu_page_present',
'sideMenuAvatar_editor')
Instance = None
class ListenerType(enum.IntEnum):
ZONE = 0
PERSON = 1
class App(natuum.app.App):
_App__LONG_TIME_PLAY_WARNING_INTERVAL = 3600000
def __init__(self):
global Instance
super().__init__()
Instance = self
self.RealTimeClock = thing.Value.RealTimeClock()
self.RunOptions = self._getRunOptions('Natuum Client', '', (self._App__RunOptionHandler(),), sys.argv[1:])
now = time.clock()
self._App__clientTime = now
self._App__serverTime = now
self._App__fps = 60
self.nxlog = None
[USER=1333341624]Property[/USER]
def FPS(self):
return self._App__fps
@FPS.setter
def FPS(self, fps):
self._App__fps = fps
def __sendPacket(self, blob):
pass
Resolution = thing.accessor.ri(doc=u'\ud074\ub77c\uc774\uc5b8\ud2b8 \ud574\uc0c1\ub3c4')
Renderer = thing.accessor.ri(doc=u'\ub80c\ub354\ub7ec \uac1d\uccb4')
RPCManager = thing.accessor.ri(doc=u'RPC \uad00\ub9ac\uc790 \uac1d\uccb4')
SoundManager = thing.accessor.ri(None, doc=u'\uc74c\ud5a5 \uad00\ub9ac\uc790 \uac1d\uccb4')
Apartment = thing.accessor.ri(doc=u'\ud074\ub77c\uc774\uc5b8\ud2b8 \uc544\ud30c\ud2b8\uba3c\ud2b8')
EventLoop = thing.accessor.ri(None, doc=u'\ud074\ub77c\uc774\uc5b8\ud2b8 \uc774\ubca4\ud2b8\ub8e8\ud504')
ClusterGuestNode = thing.accessor.ri(doc=u'\ud074\ub77c\uc774\uc5b8\ud2b8 \ud074\ub7ec\uc2a4\ud130 \ub178\ub4dc')
ClientZone = thing.accessor.rw(None)
QuitOnRendererShutdown = thing.accessor.ri(True, doc=u'\ub80c\ub354\ub7ec \uc167\ub2e4\uc6b4\uc2dc \ud504\ub85c\uadf8\ub7a8 \uc885\ub8cc')
Platform = thing.accessor.ri(doc=u'\ud50c\ub7ab\ud3fc \uac1d\uccb4')
GatewayEntityID = thing.accessor.rw(None, doc=u'\uac8c\uc774\ud2b8\uc6e8\uc774\uc5d4\ud2f0\ud2f0 ID')
ChatManagerEntityID = thing.accessor.rw(None, doc=u'\ucc44\ud305\uad00\ub9ac\uc790\uc5d4\ud2f0\ud2f0 ID')
ItemDesignLibraryEntityID = thing.accessor.rw(None, doc=u'\uc544\uc774\ud15c\uc124\uacc4\uad00\ub9ac\uc790\uc5d4\ud2f0\ud2f0 ID')
DocumentContentLibraryEntityID = thing.accessor.rw(None, doc=u'\ubb38\uc11c\ub0b4\uc6a9\uad00\ub9ac\uc790\uc5d4\ud2f0\ud2f0 ID')
ServerHostAddress = thing.accessor.ri(None, doc=u'\uac8c\uc784 \uc11c\ubc84 \uc8fc\uc18c')
LoaderThreadCount = thing.accessor.ri(1, doc=u'\ub85c\ub354 \uc2a4\ub808\ub4dc \uac2f\uc218')
RealTimeClock = thing.accessor.ri(None, doc='RealTimeClock')
EngineConfig = thing.accessor.rw({}, doc='EngineConfig')
ServerConfig = thing.accessor.rw({}, doc='ServerConfig')
ControlModeParams = thing.accessor.ri({}, doc='ControlModeParams')
PlayerInitConfig = thing.accessor.ri({}, doc='PlayerInitConfig')
MaxFPS = thing.accessor.rw(None, doc='MaxFPS')
AccountSession = thing.accessor.ri(None, doc='AccountSession')
ClientSpace = thing.accessor.ri(None, doc='ClientSpace')
GameLogic = thing.accessor.ri(None, doc='GameLogic')
Context = thing.accessor.ri(None, doc='Context')
DummyAvatarSceneObjectData = thing.accessor.ri(None, doc='DummyAvatarSceneObjectData')
IsPreloading = thing.accessor.ri(True, doc=u'\uc120\ub85c\ub529 \uc5ec\ubd80')
UserConfig = thing.accessor.ri(None, doc='UserConfig')
InitialSplashLoadTask = thing.accessor.ri(None, doc='InitialSplashLoadTask')
_App__SERVER_EPOCH = datetime.datetime(2018, 1, 1)
def __setup(self) -> 'int, exit code':
if not __final__:
thing.system.setQuietMode(self.RunOptions.Quiet)
DebugLogCategories = '*,-action,-builder,-cutscene,' if self.RunOptions.SSOAuthToken is not None else ''
DebugLogCategories += os.environ.get('NT_DEBUG_LOG', '*') + ',' + self.RunOptions.DebugLogCategories
for category in DebugLogCategories.split(','):
if not category:
continue
if category.startswith('-'):
logger = natuum.getLogger(category[1:])
logger.setLevel(logging.INFO)
LOG_INFO('Log category [{}] level=debug was disabled'.format(logger.name))
from thing.changeset import changeset, NexonCrashReporterVersion
LOG_INFO('Changeset for Code:{}'.format(changeset))
LOG_INFO('BuildVersion:{}'.format(NexonCrashReporterVersion))
LOG_INFO('LauncherVer:{}, NGM Param:{}, NexonSN:{}, NexonSID:{}'.format(self.RunOptions.LauncherBuildVersion, self.RunOptions.LauncherOptionalParam, self.RunOptions.NexonSN, self.RunOptions.NexonSID))
self.Platform = platform = thing.Platform.Platform()
self.ETWSession_findObjects = platform.createETWSession('findObjects')
if self.RunOptions.SendCrashReport:
installed = platform.installCrashReporter(self.RunOptions.ProjectID)
installed or LOG_WARNING('exception handler is not installed')
else:
platform.setCrashReporterInformation('ProcessType', self.RunOptions.ProductName)
from thing.changeset import NexonCrashReporterVersion
platform.setCrashReporterInformation('ProjectVersion', NexonCrashReporterVersion)
if natuum.m_logFilePath:
relPath = os.path.relpath(natuum.m_logFilePath, os.path.dirname(sys.executable))
platform.setCrashReporterAuxFile(relPath)
if __thing_supports_gc__:
if natuum.objects.m_refCycleFilePath:
relPath = os.path.relpath(natuum.objects.m_refCycleFilePath, os.path.dirname(sys.executable))
platform.setCrashReporterAuxFile(relPath)
platform.registerCrashReporterCallbackBeforeDump(callbackBeforeDump)
thing.system._installExceptHook(fromInit=False)
else:
__final__ or self._App__initConsoleCtrlHandler()
if not __final__:
platform.listenEasyProfileGUI(28077)
else:
self._App__thMan, self.RPCManager, self._App__chMan, self._App__chManThread = self._App__setupRPCManager()
self._App__clientLoaderApartments = self._App__createLoaderApartments()
rootFS = thing.FileSystem.FileSystem(natuum.getRootPath())
dataFS = rootFS['data']
try:
resourcesFS = rootFS['resources']
except Exception:
resourcesFS = rootFS.createDirectory('resources')
rm = natuum.client.resource.Manager(dataFS, resourcesFS)
rm.IsPreloading = self.IsPreloading
self._App__clientLoaderRegisterTokens = self._App__setupResourceManager(rm, self._App__clientLoaderApartments)
self.JobQueue = natuum.jobQueue.JobQueue()
self.EngineConfig = engineConfig = rm.load(natuum.builder.combineID('_', 'EngineConfig')).lockForReading().Data
self.ServerConfig = rm.load(natuum.builder.combineID('_', 'ServerConfig')).lockForReading().Data[self.RunOptions.ClusterID]
self.GatewayEntityID = self.ServerConfig['GatewayEntityID']
self.ChatManagerEntityID = self.ServerConfig['ChatManagerEntityID']
self.ItemDesignLibraryEntityID = self.ServerConfig['ItemDesignLibraryEntityID']
self.DocumentContentLibraryEntityID = self.ServerConfig['DocumentContentLibraryEntityID']
self.ServerHostAddress = self.RunOptions.Host
self.ControlModeParams = rm.ensureResource('controlModeParams@GameSetting')
self.PlayerInitConfig = rm.ensureResource('playerInitialization@GameSetting')
fullScreen = self.RunOptions.FullScreen
if fullScreen:
import ctypes
user32 = ctypes.windll.user32
screenWidth = user32.GetSystemMetrics(0)
screenHeight = user32.GetSystemMetrics(1)
screenRatio = screenWidth / screenHeight
if screenRatio > 1.7777777777777777:
width, height = (2400, 1080)
else:
if screenRatio > 1.6:
if screenWidth == 2048 and screenHeight == 1152:
width, height = screenWidth, screenHeight
else:
width, height = (1920, 1080)
else:
if screenRatio > 1.3333333333333333:
width, height = (1920, 1200)
else:
width, height = (1600, 1200)
else:
width, height = DEFAULT_CLIENT_RESOLUTION
self.AspectRatio = thing.Dirp.Dirp_Static(thing.system.vec(width / height, 1))
self.MaxFPS = max(int(engineConfig.Config.get('maxFPS', 60)), 1)
rendererMode = thing.Renderer.RendererManager().createRendererMode(fullScreen, width, height, 32)
self.Renderer = self._App__Renderer(rendererMode, engineConfig.Config)
self.Renderer.TerrainTessellationQueueLength = 3
self.Renderer.HangDetector = thing.ToolHelpers.HangDetector(self._App__onHangDetected)
self.PropCanvasMipHeadCutCountOnLoad = 0
userConfig = self._loadUserConfig()
if userConfig is not None:
self.UserConfig = userConfig
self._refreshCanvasLoadQuality(userConfig)
self.Renderer.UserConfig = userConfig
else:
self.UserConfig = self.Renderer.UserConfigValue['']
currentLocale = locale.getdefaultlocale()[1]
# if currentLocale != 'cp949':
# if self.Renderer.NativeWindowHandle:
# text = 'Unsupported system locale : {}'.format(currentLocale)
# text += '\n\nTo execute the client, change system locale to cp949 (Korean)'
# self.showWindowsMessageBox(text)
# self.nxlog = None
# self.quit(0)
# return
self._App__rendererModeWatchToken = self.Renderer.ModeVersion.addWatcher(self._App__onRendererModeChangedEntry, '__call__', weakref.ref(self))
self.nxlog = NXLogClient(self.RunOptions.NexonSN, self.RunOptions.NexonSID)
self.nxlog.stageLog(420, '__setup')
self._App__rendererReadyAtom = rendererReadyAtom = thing.Thread.Atom()
self._App__pagerThread = thread = self._App__thMan.createThread(thing.system.nativeThreadEntry, '__call__', self._App__pagerThreadEntry, rendererReadyAtom)
thread.Name = 'Main Updater'
thread.run()
_App__settingsDirName = 'settings'
_App__userConfigFileName = 'userConfig.nothing'
def _loadUserConfig(self):
settingsDirPath = os.path.join(natuum.getRootPath(), 'storage', __class__._App__settingsDirName)
try:
if os.path.exists(settingsDirPath):
fs = thing.FileSystem.FileSystem(settingsDirPath)
else:
raise KeyError
f = fs[__class__._App__userConfigFileName]
ra = thing.Archive.ReadingArchive_FromFile(f)
userConfig = thing.Collection.Dict()
userConfig.load(ra)
LOG_INFO('user config loaded')
except KeyError:
LOG_WARNING('cannot load user config')
userConfig = None
return userConfig
def _saveUserConfig(self, userConfig):
settingsDirPath = os.path.join(natuum.getRootPath(), 'storage', __class__._App__settingsDirName)
try:
os.makedirs(settingsDirPath)
except OSError:
pass
try:
fs = thing.FileSystem.FileSystem(settingsDirPath)
f = fs.createFile(__class__._App__userConfigFileName, True)
wa = thing.Archive.WritingArchive_FromFile(f)
userConfig.save(wa)
wa.flush()
LOG_INFO('user config saved')
except:
LOG_WARNING('cannot save user config')
def _refreshCanvasLoadQuality(self, userConfig):
propTexQuality = userConfig.get('PropTextureQuality', -1)
if propTexQuality >= 0:
propTexQuality = min(2, propTexQuality)
oldValue = self.PropCanvasMipHeadCutCountOnLoad
newValue = (2, 1, 0)[propTexQuality]
if oldValue != newValue:
self.PropCanvasMipHeadCutCountOnLoad = newValue
return True
return False
def __preload(self):
markerResourceIDs = self._App__collectMarkerResources()
effectPreloadList = tuple(markerResourceIDs.get('Effect', set()) | set(self._App__PRELOAD_EFFECTS))
rm = natuum.client.resource.Manager.Instance
rm.preload('Avatar', preloadList=('AT099800(man_default)', 'AT099900(woman_default)'))
rm.preload('Effect', preloadList=effectPreloadList)
rm.preload('CameraAngle')
rm.preload('CameraAngleBlender')
rm.preload('CameraAngleBlenderSet')
rm.preload('HTMLView', preloadList=SIDEMENU_HTMLIVEWS)
rm.preload('HTML', preloadList=('sideMenu', 'sideMenuAvatar'))
rm.preload('ItemDesign')
rm.preload('ItemIO')
rm.preload('MeshSet', preloadList=(self._App__DUMMY_AVATAR_MESHSETS))
rm.preload('PropPart', preloadList=(self._App__PRELOAD_PROPPARTS))
rm.preload('Quest')
rm.preload('VueApp', preloadList=('app', ))
rm.preload('Zone', preloadList=('ZR0000(carveKiranaArea)', ))
for typeName, resourceIDs in markerResourceIDs.items():
if typeName in ('Effect', 'ItemDesign'):
continue
rm.preload(typeName, preloadList=(tuple(resourceIDs)))
rm.preload('GameSetting')
def __collectMarkerResources(self):
def collectResourceIDs--- This code section failed: ---
L. 433 0 LOAD_GLOBAL isinstance
2 LOAD_FAST 'value'
4 LOAD_GLOBAL str
6 CALL_FUNCTION_2 2 '2 positional arguments'
8 POP_JUMP_IF_FALSE 56 'to 56'
10 LOAD_GLOBAL natuum
12 LOAD_ATTR builder
14 LOAD_METHOD isResourceID
16 LOAD_FAST 'value'
18 CALL_METHOD_1 1 '1 positional argument'
20 POP_JUMP_IF_FALSE 56 'to 56'
L. 434 22 LOAD_GLOBAL natuum
24 LOAD_ATTR builder
26 LOAD_METHOD splitID
28 LOAD_FAST 'value'
30 CALL_METHOD_1 1 '1 positional argument'
32 UNPACK_SEQUENCE_3 3
34 STORE_FAST 'name'
36 STORE_FAST 'typeName'
38 STORE_FAST '_'
L. 435 40 LOAD_FAST 'resourceIDs_'
42 LOAD_FAST 'typeName'
44 BINARY_SUBSCR
46 LOAD_METHOD add
48 LOAD_FAST 'name'
50 CALL_METHOD_1 1 '1 positional argument'
52 POP_TOP
54 JUMP_FORWARD 144 'to 144'
56_0 COME_FROM 20 '20'
56_1 COME_FROM 8 '8'
L. 436 56 LOAD_GLOBAL isinstance
58 LOAD_FAST 'value'
60 LOAD_GLOBAL str
62 CALL_FUNCTION_2 2 '2 positional arguments'
64 POP_JUMP_IF_TRUE 104 'to 104'
66 LOAD_GLOBAL isinstance
68 LOAD_FAST 'value'
70 LOAD_GLOBAL collections
72 LOAD_ATTR Sequence
74 CALL_FUNCTION_2 2 '2 positional arguments'
76 POP_JUMP_IF_FALSE 104 'to 104'
L. 437 78 SETUP_LOOP 144 'to 144'
80 LOAD_FAST 'value'
82 GET_ITER
84 FOR_ITER 100 'to 100'
86 STORE_FAST 'value_'
L. 438 88 LOAD_DEREF 'collectResourceIDs'
90 LOAD_FAST 'value_'
92 LOAD_FAST 'resourceIDs_'
94 CALL_FUNCTION_2 2 '2 positional arguments'
96 POP_TOP
98 JUMP_BACK 84 'to 84'
100 POP_BLOCK
102 JUMP_FORWARD 144 'to 144'
104_0 COME_FROM 76 '76'
104_1 COME_FROM 64 '64'
L. 439 104 LOAD_GLOBAL isinstance
106 LOAD_FAST 'value'
108 LOAD_GLOBAL collections
110 LOAD_ATTR Mapping
112 CALL_FUNCTION_2 2 '2 positional arguments'
114 POP_JUMP_IF_FALSE 144 'to 144'
L. 440 116 SETUP_LOOP 144 'to 144'
118 LOAD_FAST 'value'
120 LOAD_METHOD values
122 CALL_METHOD_0 0 '0 positional arguments'
124 GET_ITER
126 FOR_ITER 142 'to 142'
128 STORE_FAST 'value_'
L. 441 130 LOAD_DEREF 'collectResourceIDs'
132 LOAD_FAST 'value_'
134 LOAD_FAST 'resourceIDs_'
136 CALL_FUNCTION_2 2 '2 positional arguments'
138 POP_TOP
140 JUMP_BACK 126 'to 126'
142 POP_BLOCK
144_0 COME_FROM_LOOP 116 '116'
144_1 COME_FROM 114 '114'
144_2 COME_FROM 102 '102'
144_3 COME_FROM_LOOP 78 '78'
144_4 COME_FROM 54 '54'
Parse error at or near `COME_FROM_LOOP' instruction at offset 144_3
def collectMarkerClasses(marker, markerClasses_):
markerClasses.add(marker)
for marker_ in marker.__subclasses__():
collectMarkerClasses(marker_, markerClasses_)
markerResourceIDs = collections.defaultdict(set)
markerClasses = set()
collectMarkerClasses(natuum.client.clientSpace.marker.Marker, markerClasses)
for arranger in natuum.client.clientSpace.arranger.__dict__.values():
if isinstance(arranger, type):
collectMarkerClasses(arranger, markerClasses)
for marker in markerClasses:
for attribute in marker.__dict__.values():
collectResourceIDs(attribute, markerResourceIDs)
collectMarkerClasses = None
collectResourceIDs = None
return markerResourceIDs
def __run(self) -> 'int, exit code':
if not __final__:
if not self.RunOptions.NoUsageReport:
self._App__sendUsageReport()
windowTitle = 'Peria Chronicles{}'.format(natuum.util.getBuildVersion())
rendererExitCode = self.Renderer.start(windowTitle, thing.system.ICanvas.PIXEL_FORMAT_R8G8B8A8, self._App__rendererReadyAtom, self.QuitOnRendererShutdown)
return self._App__exitCode
def __cleanup(self) -> None:
global Instance
if not __final__:
for i in range(5):
if self._App__pagerThread.wait(1):
break
(LOG_DEBUG if i <= 2 else LOG_WARNING)(u'Pager \uc2a4\ub808\ub4dc \uc885\ub8cc \ub300\uae30\uc911 (%d\ucd08)', i + 1)
else:
self._App__pagerThread.wait(5)
del self._App__pagerThread
self.JobQueue.shutdown()
self._App__clientLoaderRegisterTokens.clear()
for apartment in self._App__clientLoaderApartments.values():
apartment.shutdown()
self._App__shutdownTableManagers()
self._App__cleanupResourceManager()
if self._App__chMan is not None:
self._App__chMan.shutdown()
VERIFY(self._App__chManThread.wait(5))
del self._App__chManThread
del self._App__mainApartment
self.RPCManager.shutdown()
Instance = None
[USER=186209]Thing[/USER].overrides(natuum.app.App)
def run(self) -> 'int, exit code':
self._App__setup()
ret = self._App__run()
self._App__cleanup()
return ret
[USER=186209]Thing[/USER].overrides(natuum.app.App)
def quit(self, exitCode):
LOG_INFO('client quit called')
self.Renderer.shutdown()
curPage = natuum.client.pager.CurPage
if curPage is not None:
if not natuum.client.pager.command((curPage.canQuitApp), wait=True):
return
super().quit()
self._App__exitCode = exitCode
if self.RunOptions.SendCrashReport:
self.Platform.setCrashReporterClientExit(exitCode)
if natuum.client.app.Instance.nxlog is not None:
natuum.client.app.Instance.nxlog.stageLog(1010, str(exitCode))
self.Renderer.quit(True)
def isInRendererThreadGroup(self, threadID):
return threadID == self.Renderer.ThreadID
def collectZcomObjects(self, showBackrefsOfIDs=False):
if not __thing_can_get_zcom_objects__:
return
createdZcomObjects = self._App__createdZcomObjects
if createdZcomObjects is None:
self._App__createdZcomObjects = thing.ToolHelpers.CreatedObjects()
else:
self._App__createdZcomObjects = None
objs = None
try:
backrefsDir = os.path.join(natuum.getLogPath(), 'backrefs')
os.makedirs(backrefsDir, exist_ok=True)
today = datetime.datetime.today()
timestamp = '%4d%02d%02d_%02d%02d%02d' % (today.year, today.month, today.day, today.hour, today.minute, today.second)
graphFilePath = os.path.join(backrefsDir, 'graph_c{}.txt'.format(timestamp))
with open(graphFilePath, 'w', encoding='utf_8-sig') as (file):
natuum.objects.Graph.collectToFile(file)
objs = list(createdZcomObjects)
objectIDsFilePath = os.path.join(backrefsDir, 'objects_c{}.txt'.format(timestamp))
with open(objectIDsFilePath, 'w') as (file):
natuum.objects.saveObjectIDsToFile(file, objs)
if showBackrefsOfIDs:
multiprocessing.Process(target=(natuum.objects.showBackrefsOfIDs),
args=(
backrefsDir, graphFilePath, objectIDsFilePath)).start()
thing.system._debugBreak()
objs.clear()
finally:
if objs is not None:
objs.clear()
def checkMemory(self):
if __final__ or self._App__memoryReclaimer is None:
return
for i in range(10):
self._App__memoryReclaimer.reclaimAll()
natuum.objects.GarbageCollector().collect(-1, True)
trendsCollector = self._App__objectCountTrendsCollector
if trendsCollector is None:
self._App__objectCountTrendsCollector = trendsCollector = natuum.objects.CountTrendsCollector()
trendsCollector.collect()
trends = [(v, trendsCollector.getCount(k), k) for k, v in trendsCollector.items()]
trends.sort(reverse=True)
tracker = self._App__memoryTracker
lines = []
lines.append('**** object count trend log start ****')
for trend, count, typeName in trends:
countList = tracker.get(typeName, None)
if countList is None:
countList = list()
tracker[typeName] = countList
countList.append(count)
lines.append('{:G}\t{}\t{}'.format(trend, typeName, '\t'.join([str(i) for i in countList])))
lines.append('**** object count trend log end ****')
def getRoughServerTime(self) -> 'int. milliseconds':
passed = int(time.time() - self._App__clientTime) * 1000
return (self._App__serverTime + passed) % 2147483647
def setListener(self, flag, position) -> None:
soundManager = self.SoundManager
if soundManager is not None:
configuration = self.ControlModeParams.get('sound')
if configuration is None:
if ListenerType.ZONE == flag:
soundManager.Listener = position
elif configuration['listener'] == flag:
soundManager.Listener = thing.Dirp.Dirp_FromLocal(configuration['local'], thing.math.ROT_IDENTITY, position)
def _setServerTime(self, serverNow):
self._App__clientTime = time.time()
self._App__serverTime = int(serverNow * 1000)
class __Renderer(natuum.renderer.Renderer):
[USER=186209]Thing[/USER].overrides(natuum.renderer.Renderer)
def onRendererCloseButton(self, renderer: 'thing.system.IRenderer', private) -> None:
Instance.quit(0)
[USER=186209]Thing[/USER].overrides(natuum.renderer.Renderer)
def onRendererConfigChange(self, renderer: 'thing.system.IRenderer', private) -> None:
if isinstance(private, thing.system.IMutableMapping):
userConfig = private
natuum.client.app.Instance._saveUserConfig(userConfig)
if natuum.client.app.Instance._refreshCanvasLoadQuality(userConfig):
natuum.client.pager.command(natuum.client.app.Instance.GameLogic.onCanvasLoadQualityChange)
def _registerLayerCategories(self) -> None:
self.registerLayerCategory('UI').forget()
class __RunOptionHandler(natuum.runOptions.IHandler):
def fillDefaults(self, options):
options.Host = None
options.Quiet = False
options.InfuseActor = None
options.CrashReportURL = 'http://socorro.thingsoft.com:8882/submit'
options.ProductName = 'client'
options.ProductVersion = '0.8.1'
options.NoUsageReport = False
options.NoEffect = False
options.BatchJob = None
options.Locale = None
options.ClusterID = 'default'
options.SSOAuthToken = None
options.FullScreen = False
options.DebugLogCategories = '*,-action,-builder,-cutscene' if __final__ else ''
options.ProjectID = 'peria_dev'
options.LauncherBuildVersion = -1
options.LauncherOptionalParam = ''
options.NexonSN = 0
options.NexonSID = None
options.disableNXLog = False
crashReport = os.environ.get('NT_NO_CRASH_REPORT', '0')
options.SendCrashReport = crashReport == '0'
def buildParser(self, parser: 'optparse.OptionParser', options) -> None:
parser.add_option('-a', '--address', dest='Host', help='server address')
parser.add_option('-q', '--quiet', dest='Quiet', default=False, action='store_true', help='quiet mode')
parser.add_option('-i', '--infuseActor', dest='InfuseActor', help='auto infuse actor')
parser.add_option('-b', '--batch', dest='BatchJob', help='batch job file')
parser.add_option('-l', '--locale', dest='Locale', help='locale')
parser.add_option('-C', '--cluster', dest='ClusterID', help='cluster id')
parser.add_option('--crashreport-url', dest='CrashReportURL', help='crash report url')
parser.add_option('--product-name', dest='ProductName', help='product name')
parser.add_option('--product-version', dest='ProductVersion', help='product version')
parser.add_option('--nousagereport', dest='NoUsageReport', default=False, action='store_true', help="don't send usage report")
parser.add_option('-t', '--auth', dest='SSOAuthToken', help='auth token')
parser.add_option('-f', '--fullScreen', dest='FullScreen', default=False, action='store_true', help='full screen mode')
parser.add_option('--debugLog', type='str', dest='DebugLogCategories', help='comma seperated log categories')
parser.add_option('--projectid', dest='ProjectID', help='crash reporter project id')
parser.add_option('--launcherBuildVersion', dest='LauncherBuildVersion', help='launcher build version')
parser.add_option('--launcherParam', dest='LauncherOptionalParam', default='', help='argument from NexonGameManager')
parser.add_option('--nexonsn', dest='NexonSN', default=0, help='argument from NexonGameManager')
parser.add_option('--nexonsid', dest='NexonSID', default='', help='argument from NexonGameManager')
parser.add_option('--disableNXLog', dest='disableNXLog', default=False, action='store_true', help='disable NXLOG')
def onParsed(self, parser: 'optparse.OptionParser', options, args: tuple) -> None:
if options.BatchJob is not None:
batchJobPath = os.path.join(natuum.getRootPath(), 'settings', options.BatchJob)
options.BatchJob = natuum.util.readXDF(batchJobPath)
if options.Locale is not None:
if options.Locale in ('ko', 'ja', 'zh', 'en'):
natuum.util.DefaultLocale = options.Locale
def __createLoaderApartments(self) -> '{ str: thing.system.IApartment }':
apartments = {}
for i in range(self.LoaderThreadCount):
name = 'Loader{}'.format(i)
apartmentObject = ApartmentActiveObject(self._App__thMan, self.RPCManager)
apartmentObject.start(name, -0.13333333333333333)
apartments[name] = apartmentObject.Apartment
return apartments
if not __final__:
def __initConsoleCtrlHandler(self):
def _terminateProcess(ctrlType):
thing.system._TerminateProcess()
thing.system.setConsoleCtrlHandler(_terminateProcess)
def __setupRPCManager(self):
thMan = thing.Thread.ThreadManager()
rpcManager = thing.RPC.RPCManager(thMan)
self._App__mainApartment = natuum.apartment.Apartment()
return (
thMan, rpcManager, None, None)
def __setupResourceManager(self, rm, loaderApartments) -> '{ str : thing.system.IForgettableToken }':
tokens = {}
for name, apartment in loaderApartments.items():
token = rm.CacheManager.registerDelayedLoaderApartment(name, apartment.Inner)
tokens[name] = token
return tokens
def __cleanupResourceManager(self) -> None:
natuum.client.resource.Manager.Instance.shutdown()
@staticmethod
def __onRendererModeChangedEntry(watched, weakSelf, hint, funcName) -> None:
self = weakSelf()
if self is not None:
clientSpace = self.ClientSpace
if clientSpace is not None:
natuum.client.pager.command(clientSpace.onRendererModeChanged)
def __pagerThreadEntry(self, rendererReadyAtom: 'thing.system.IAtom') -> None:
self.Context = thing.Common.Sites()
self.EventLoop = loop = natuum._entity.apartmentEvents.EventLoop()
asyncio.set_event_loop(loop)
self.Apartment = loop.Apartment
thing.system.setSwitchIntervalForCurrentThread(1)
rendererReadyAtom.wait()
inputManager = natuum.client.input.Manager()
self._App__initFontManager()
self.showInitialSplash(True)
if self.InitialSplashLoadTask:
loop.run_until_complete(self.InitialSplashLoadTask)
_ = self.Platform.disableAccessibility()
self.GUI = guiSystem = thing.Renderer.GUISystem()
self.Renderer.GUISystem = guiSystem
self.SoundManager = soundManager = self._App__createSoundManager(parameters=(self.ControlModeParams))
try:
soundManager.setVolume('music', self.UserConfig['BGMVolume'])
soundFXVol = self.UserConfig['SoundEffectVolume']
for bus in ('effect', 'voice', 'environment', 'kiranaContract'):
soundManager.setVolume(bus, soundFXVol)
except KeyError:
pass
natuum.configuration.Configuration.initialize()
self.ClusterGuestNode = node = natuum._entity.framework.cluster.setup_guest(self.ServerConfig['GatewayServers'])
if self.ServerHostAddress is not None:
node.overrideConnectingtHost(self.ServerHostAddress)
self.AccountSession = natuum.client.app.AccountSession()
self.ZoneChanged = natuum.signal.Signal(natuum.client.zone.Zone)
self._App__initClassTables()
if self.IsPreloading:
self._App__preload()
self._App__initTableManagers()
clientSpace = natuum.client.clientSpace.ClientSpace()
clientSpace.onRendererModeChanged()
clientSpace.addDesktop()
clientSpace.addDesktop()
clientSpace.addInventory()
self.ClientSpace = clientSpace
inputManager.setEventHandler(clientSpace)
self.GameLogic = gameLogic = natuum.client.logic.GameLogic(clientSpace)
gameLogic.SyncClock.defer(App._App__LONG_TIME_PLAY_WARNING_INTERVAL, App._App__warnLongTimePlay, 1).forget()
self._App__setupIDE()
self._App__buildDummyAvatar()
self._App__processorToken = thing.Thread.Processor().addTask(0, self.MaxFPS)
self._App__memoryReclaimer = memoryReclaimer = thing.Common.MemoryReclaimer()
memoryReclaimer.clearPolicies()
memoryReclaimer.appendPolicy(memoryReclaimer.MEMORY_RECLAIMER_CRITERION_AVAILABLE_PHYSICAL_MB_LESS_THAN, 100, 209715200, 5)
memoryReclaimer.appendPolicy(memoryReclaimer.MEMORY_RECLAIMER_CRITERION_AVAILABLE_PHYSICAL_MB_LESS_THAN, 500, 104857600, 10)
memoryReclaimer.appendPolicy(memoryReclaimer.MEMORY_RECLAIMER_CRITERION_AVAILABLE_PHYSICAL_MB_LESS_THAN, 1000, 1, 15)
memoryReclaimer.appendPolicy(memoryReclaimer.MEMORY_RECLAIMER_CRITERION_PAGE_FILE_USAGE_MB_GREATER_THAN, 7168, 102400, 15)
natuum.apartment.getCurrentApartment().Alarm.postTask(self._App__reclaimMemory, 0).forget()
if not __final__:
natuum.apartment.getCurrentApartment().Alarm.postTask(self._App__logMemoryReclaimer, 60000).forget()
self._App__memoryTracker = {}
loop.call_soon(natuum.client.pager.enter)
loop.run_forever()
loop.run_until_complete(node.shutdown())
loop.close()
gameLogic.shutdown()
thing.Client.EffectManager().terminate()
soundManager.shutdown()
guiSystem.shutdown()
self.Renderer.GUISystem = None
def __initClassTables(self) -> None:
rm = natuum.client.resource.Manager.Instance
natuum.client.action.ActionTableManager.ensureInstance()
rawClassTables = rm.load(natuum.gameClass.CLASS_TABLE).lockForReading().Data
natuum.gameClass.initManager(rawClassTables)
if self.IsPreloading:
natuum.gameClass.getManagerInstance().preloadClasses()
def __initTableManagers(self) -> None:
rm = natuum.client.resource.Manager.Instance
natuum.emotionCutscene.initManager(rm)
natuum.client.craft.initManager(rm)
natuum.variation.initManager(rm)
natuum.indexBook.initManager(rm)
natuum.client.contract.initManager(rm)
natuum.reward.initManager(rm)
natuum.growth.initManager(rm)
natuum.actor.initManager(rm)
natuum.client.quest.initManager(rm)
natuum.town.initManager(rm)
natuum.client.relationship.initManager(rm)
natuum.client.synergy.initManager(rm)
natuum.gameService.wordFilter.initManager(rm)
def __initFontManager(self) -> None:
fontManager = thing.Renderer.FontManager()
rm = natuum.client.resource.Manager.Instance
rm.preload('Font', preloadList=(natuum.util.FontNames))
for fontName in natuum.util.FontNames:
fontID = natuum.builder.combineID(fontName, 'Font')
fontData = rm.ensureResource(fontID)
fontManager.registerFontData(fontData[0], fontData[1])
for info in TEXT_FORMAT_TO_PRELOAD:
(fontManager.createRasterTextFormat)(self.Renderer, *info)
def __setupIDE(self) -> None:
pass
def __buildDummyAvatar(self) -> None:
rm = natuum.client.resource.Manager.Instance
meshSet = rm.ensureResource('AP7250@MeshSet')
sceneObjectData = thing.Scene.SceneObjectData_Mesh()
sceneObjectData.ShaderFlags = thing.system.IShader.SHADER_SHADOW_MAP | thing.system.IShader.SHADER_REALISTIC
for meshName, meshAndBone in meshSet.items():
sceneObjectMeshElementData = thing.Scene.SceneObjectMeshElementData()
sceneObjectMeshElementData.Mesh = meshAndBone['mesh']
sceneObjectData.Elements[meshName] = sceneObjectMeshElementData
self.Renderer.warm(sceneObjectData, 0)
self.DummyAvatarSceneObjectData = sceneObjectData
def __shutdownTableManagers(self) -> None:
natuum.client.craft.shutdownManager()
natuum.client.action.ActionTableManager.shutdown()
natuum.gameClass.shutdownManager()
def __reclaimMemory(self) -> None:
if self.IsQuitting:
return
waitDuration = self._App__memoryReclaimer.reclaim()
natuum.apartment.getCurrentApartment().Alarm.postTask(self._App__reclaimMemory, waitDuration).forget()
if not __final__:
def __logMemoryReclaimer(self) -> None:
if self.IsQuitting:
return
memoryReclaimer = self._App__memoryReclaimer
LOG_INFO('available physical memory: {} GB'.format(memoryReclaimer.AvailablePhysicalMemoryGB))
LOG_INFO('page file usage: {} GB'.format(memoryReclaimer.PageFileUsageGB))
natuum.apartment.getCurrentApartment().Alarm.postTask(self._App__logMemoryReclaimer, 60000).forget()
def __sendUsageReport(self) -> None:
def sendReport(info: 'sequence of ( str, str )') -> str:
tokenDelim = '_TDELIM_'
emptyToken = '_EMPTY'
stream = tokenDelim.join([value if value != '' else emptyToken for value in info])
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(stream.encode('utf-8'), ('wild.thingsoft.com', 8025))
LOG_INFO('Usage report sent..')
except socket.error:
pass
sock.close()
rendererManager = thing.Renderer.RendererManager()
usageInfo = (
'{}'.format(platform.node()),
'{} {}'.format(platform.system(), platform.version()),
'{}'.format(platform.processor()),
'{}'.format(self.Platform.MemorySize),
'{}'.format(self.Platform.HardDiskSize),
'{}'.format(rendererManager.DeviceDescription.split('\x00')[0].strip()),
'{}'.format(natuum.util.getBuildVersion()))
sendReport(usageInfo)
sendReport = None
[USER=437263]clas[/USER]smethod
def __createSoundManager(cls, parameters=None, liveUpdate=False) -> 'thing.system.ISoundManager':
rm = natuum.client.resource.Manager.Instance
masterBank = rm.load(cls._App__masterBankResourceID)
masterBank = masterBank.lockForReading().Data
try:
masterBank = masterBank.SoundData
except KeyError:
LOG_WARNING(u'{}\ub97c \uc77d\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. \uc774\ubca4\ud2b8 \uacbd\ub85c\ub97c \uc77d\uc9c0 \ubabb\ud574 \uc18c\ub9ac\uac00 \ub098\uc624\uc9c0 ' + (u'\uc54a\uc2b5\ub2c8\ub2e4.').format(cls._App__masterBankResourceID))
return
else:
masterStringBank = rm.load(cls._App__masterStringBankResourceID)
try:
masterStringBank = masterStringBank.lockForReading().Data.SoundData
except KeyError:
LOG_WARNING(u'{}\ub97c \uc77d\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. \uc774\ubca4\ud2b8 \uacbd\ub85c\ub97c \uc77d\uc9c0 \ubabb\ud574 \uc18c\ub9ac\uac00 \ub098\uc624\uc9c0 ' + (u'\uc54a\uc2b5\ub2c8\ub2e4.').format(cls._App__masterStringBankResourceID))
return
else:
busGroups = cls._App__getBusGroups(parameters)
return thing.Sound.SoundManager(masterBank, masterStringBank, liveUpdate, natuum.getRootPath(), busGroups)
def __closeSplashZoneViewerMarker(self):
self._App__splashZoneViewerMarker.close()
self._App__splashZoneViewerMarker = None
def showInitialSplash(self, show):
self._App__splashNoticeLayer = None
self._App__splashLayer = None
if self._App__splashZoneViewerMarker:
self.Renderer.Timer.defer(0, self._App__closeSplashZoneViewerMarker).forget()
if show:
rm = natuum.client.resource.Manager.Instance
canvas = rm.load('ui_title_booting@Canvas').lockForReading().Data
self._App__splashLayer = self.Renderer.createOverlayLayer(thing.Dirp.Dirp_Static(), thing.Dirp.Dirp_Static(self.AspectRatio), canvas)
self.Renderer.updateLayers()
@staticmethod
def __onSplashZoneLoaded(fut_) -> None:
app = natuum.client.app.Instance
canvas = app._App__splashZoneViewerMarker.getViewCanvas()
app._App__splashLayer = app.Renderer.createOverlayLayer(thing.Dirp.Dirp_Static(), thing.Dirp.Dirp_Static(app.AspectRatio), canvas)
text = natuum.client.text.Text(u'\ub85c\ub529 \uc911\uc785\ub2c8\ub2e4. \uae30\ub2e4\ub9ac\ub294 \ub3d9\uc548 \uc9c0\ud615 \ud3b8\uc9d1\uc744 \uc5f0\uc2b5\ud574 \ubcf4\uc138\uc694.', 22, 'NanumSquare', thing.system.vec(xyzw=1), thing.system.vec(a=1), 'bold', 0.0)
app._App__splashNoticeLayer = app.Renderer.createOverlayLayer(thing.Dirp.Dirp_Static(thing.system.vec(0.5, 0.8)), thing.Dirp.Dirp_Static(thing.system.vec(text.getWidth(), text.getHeight()) / text.getHeight() * 0.04), text.getCanvas())
app.Renderer.updateLayers()
def showWindowsMessageBox(self, text, title='Peria Chronicles', uType=0, quit=False):
import ctypes
MessageBox = ctypes.windll.user32.MessageBoxW
ret = None
if natuum.client.app.Instance.Renderer.NativeWindowHandle:
ret = MessageBox(natuum.client.app.Instance.Renderer.NativeWindowHandle, text, 'Peria Chronicles', uType)
if quit:
self.GameLogic.turnOffGame()
return ret
@staticmethod
def __warnLongTimePlay(count):
app = Instance
if app is None:
return
gameLogic = app.GameLogic
if gameLogic is None:
return
getLocalString = natuum.action.ActionTableManager.getInstance().getLocalString
author = getLocalString('NoticeAuthor')
longTimePlayWarning = getLocalString('LongTimePlayWarning').format(N=count)
ageRatingInformation = getLocalString('AgeRatingInformation')
gameLogic.createMarker('message', ((u'(\uc0c9\uc0c1:\ube68\uac15)(\ud06c\uae30:\ud06c\uac8c){}(/\ud06c\uae30)(/\uc0c9\uc0c1)').format(longTimePlayWarning)), forced=True)
gameLogic.SyncClock.addWork(5000, (gameLogic.createMarker), 'message', ((u'(\uc0c9\uc0c1:\ube68\uac15)(\ud06c\uae30:\ud06c\uac8c){}(/\ud06c\uae30)(/\uc0c9\uc0c1)').format(ageRatingInformation)), forced=True).forget()
gameLogic.vueUiController.ChattingView.addChatText('notice', author, longTimePlayWarning)
gameLogic.vueUiController.ChattingView.addChatText('notice', author, ageRatingInformation)
gameLogic.SyncClock.defer(App._App__LONG_TIME_PLAY_WARNING_INTERVAL, App._App__warnLongTimePlay, count + 1).forget()
@staticmethod
def __getBusGroups(parameters) -> '{ str : var }':
if parameters is None:
return {}
try:
return parameters['sound']['bus']['groups']
except KeyError:
return {}
@staticmethod
def __onHangDetected(detected: 'thing.system.IHangDetector') -> None:
if not __final__:
import thing.debugger
if thing.debugger.checkAttached():
LOG_WARNING('hang detected')
thing.debugger.breakIfAttached()
return
try:
raise RuntimeError('hang detected')
except Exception as e:
try:
sys.excepthook(type(e), e, e.__traceback__)
finally:
e = None
del e
_App__thMan = None
_App__chMan = None
_App__clientLoaderApartments = None
_App__clientLoaderRegisterTokens = None
_App__chManThread = None
_App__pagerThread = None
_App__rendererReadyAtom = None
_App__exitCode = 0
_App__serverPort = 9999
_App__server = None
_App__memoryReclaimer = None
_App__memoryChecker = None
if not __final__:
_App__objectCountTrendsCollector = None
if __thing_can_get_zcom_objects__:
_App__createdZcomObjects = None
_App__actionTableManager = None
_App__masterBankResourceID = natuum.builder.combineID('MasterBank', 'Sound')
_App__masterStringBankResourceID = natuum.builder.combineID('MasterBankstrings', 'Sound')
_App__splashLayer = None
_App__splashNoticeLayer = None
_App__splashZoneViewerMarker = None
_App__PRELOAD_EFFECTS = ('EF7000', 'EF7000_lumi', 'EF7001', 'EF7002', 'EF7003',
'EF7004', 'EF7006', 'EF7007', 'EF7010', 'EF7012', 'EF7013',
'EF7016', 'EF7019', 'EF7020', 'EF7022', 'EF7024', 'EF7033',
'EF7050', 'EF7051', 'EF7052', 'EF7053', 'EF7054', 'EF7058',
'EF7074', 'EF7075', 'EF7080', 'EF7081', 'EF7082', 'EF7083',
'EF7084', 'EF7093', 'EF7094', 'EF7095', 'EF7096', 'EF7098',
'EF7099', 'EF8000', 'EF8001', 'EF8002', 'EF8003', 'EF8003',
'EF8004', 'EF8008', 'EF8010', 'EF8011', 'EF8012', 'EF8013',
'EF8015', 'EF8016', 'EF8017', 'EF8020', 'EF8021', 'EF8022',
'EF8030', 'EF8031', 'EF8040', 'EF8041', 'EF8050', 'EF8051',
'EF8100', 'EF8100a', 'EF8100b', 'EF8100d', 'EF8107',
'EF8130', 'EF8131', 'EF8132', 'EF8133', 'EF8134', 'EF8135',
'EF8136', 'EF8137', 'EF8139', 'EF8142', 'EF8142', 'EF8143',
'EF8144', 'EF8145', 'EF8146', 'EF8147', 'EF8148', 'EF8149',
'EF8149', 'EF8149', 'EF8150', 'EF8151', 'EF8152', 'EF8153',
'EF8154', 'EF8156', 'EF8159', 'EF8160', 'EF8162', 'EF8165',
'EF8167', 'EF8168', 'EF8170', 'EF8171', 'EF8172', 'EF8173',
'EF8174', 'EF8175', 'EF8176', 'EF8179', 'EF8182', 'EF8184',
'EF8186', 'EF8187', 'EF8188', 'EF8189', 'EF8191', 'EF8192',
'EF8194', 'EF8196', 'EF8197', 'EF8198', 'EF8199', 'EF8200',
'EF8201', 'EF8205', 'EF8207', 'EF8210', 'EF8211', 'EF8212',
'EF8213', 'EF8216', 'EF8217', 'EF8218', 'EF8219', 'EF8220',
'EF8158a', 'EF8158b', 'EF8158c', 'EF8224', 'EF8233',
'EF8234', 'EF8236', 'EF8237', 'SEF(warning_01)', 'SEF1018(world_map)',
'SEF1020(marker_open)', 'SEF1023(guardian_qattack_ready)',
'SEF1025(guardian_qattack_fire)', 'SEF1026(guardian_qattack_targeting)',
'SEF1028(actionmaker_click)', 'SEF1029(actionmaker_hover)',
'SEF1030(actionmaker_open)', 'SEF1031(actionmaker_release)',
'SEF1032(conversation_click)', 'SEF1033(conversation_hover)',
'SEF1034(f_key_to_continue_conversation)', 'SEF1035(f_key_to_start_conversation)',
'SEF1036(general_button_click)', 'SEF1037(general_button_release)',
'SEF1038(changing_tab)', 'SEF1043(list_open)', 'SEF1044(list_close)',
'SEF1045(Xbutton)', 'SEF1046(popup_window)', 'SEF1047(conversation_release)',
'SEF1048(f_key_hover)', 'SEF1049(general_button_hover)',
'SEF1050(tab_hover)', 'SEF1051(small_button_click)',
'SEF1052(small_button_hover)', 'SEF1053(small_button_release)',
'SEF1054(kirana_listup_hover)', 'SEF1055(kirana_listup_click)',
'SEF1057(kirana_listup_release)', 'SEF1058(kirana_listup_release_cancel)',
'SEF1063(f_key_click)', 'SEF1065(battle_book_use)',
'SEF1066(inventory_hover)', 'SEF1067(inventory_click)',
'SEF1068(inventory_block)', 'SEF1069(inventory_release)',
'SEF1070(tab_release)', 'SEF1071(battle_book_hover)',
'SEF1075(battle_book_appearance)', 'SEF1076(battle_book_disappearance)',
'UI_deliveryRangeSphere', 'balloon_marker', 'button_marker',
'caption_marker', 'close_marker', 'coordinates_marker',
'gauge_marker', 'label', 'list_marker', 'list_marker3',
'text_balloon_marker', 'text_edit_marker', 'tooltip_marker',
'window', 'window2')
_App__PRELOAD_PROPPARTS = ('PP6954', 'PP6366(blue)', 'PP6366(green)', 'PP6366(purple)',
'PP6366(red)', 'PP6366(white)', 'PP6366(yellow)',
'PP6851', 'PP8200', 'PP8201', 'PP8202', 'PP8203',
'PP8204', 'PP8205', 'PP8206', 'PP8207', 'PP8208',
'PP8209', 'PP8210', 'PP8211', 'PP8212', 'PP8213',
'PP8214')
_App__DUMMY_AVATAR_MESHSETS = ('AP7250', )
class AccountSession(natuum._entity.IEntitySubscriber, IGatewaySubscriber):
def __init__(self):
self._AccountSession__connected = False
self._AccountSession__gatewaySubscription = None
self._AccountSession__NGSClient = None
self._AccountSession__JYPClient = None
self._AccountSession__accountID = None
self._AccountSession__kickoutMessage = None
self._AccountSession__weakOnConntionQueueChangedCallback = None
self._AccountSession__weakOnAccountAuthenticatedAfterWaitingQueueCallback = None
self.OnDisconnected = natuum.signal.Signal(bool, str)
self.OnBeginTransferMessage = natuum.signal.Signal(bool)
self.OnPrepareTransferMessage = natuum.signal.Signal(str)
self.OnFinishTransferMessage = natuum.signal.Signal(thing.system.uuid, str, bool)
async def connect(self, callback=None, maxTryCount=-1):
if self._AccountSession__connected:
return
await natuum.client.app.Instance.ClusterGuestNode.start()
apartment = asyncio.get_event_loop().Apartment
tryCount = 0
entity = None
while maxTryCount < 0 or maxTryCount > tryCount:
try:
entity = await apartment.EntityManager.findEntity(natuum.client.app.Instance.GatewayEntityID)
break
except natuum._entity.error.RemoteEntityServerNotFound:
LOG_WARNING('RemoteEntityServer not found')
return
except natuum._entity.error.EntityNotExist:
LOG_WARNING('GatewayEntity not exist')
return
except natuum._entity.error.EntityNotRestored:
LOG_WARNING('GatewayEntity not restored. try after 5 seconds. try count : {}'.format(tryCount))
tryCount += 1
await asyncio.sleep(5)
except natuum._entity.error.SubscriptionChannelClosed:
tryCount += 1
await asyncio.sleep(5)
except asyncio.TimeoutError:
return
except asyncio.CancelledError:
return
if entity is None:
return
try:
subscription = await natuum._entity.subscribeEntity(entity, 'hello', None, self)
except natuum._entity.error.SubscribeFailed:
return
else:
self._AccountSession__gatewaySubscription = subscription
self._AccountSession__connected = True
LOG_INFO('Connection to game server established')
async def disconnect(self, forced=True):
if not self._AccountSession__connected:
return
LOG_INFO('Connection to game server closed')
self._AccountSession__connected = False
self._AccountSession__gatewaySubscription = None
self._AccountSession__NGSClient = None
self._AccountSession__JYPClient = None
await natuum.client.app.Instance.ClusterGuestNode.shutdown()
self.OnDisconnected.emit(forced, self.KickOutMessage)
self.KickOutMessage = None
def setAuthenticationWaitingCallback(self, onConntionQueueChanged, onAccountAuthenticatedAfterWaitingQueue):
self._AccountSession__weakOnConntionQueueChangedCallback = weakref.WeakMethod(onConntionQueueChanged) if onConntionQueueChanged is not None else None
self._AccountSession__weakOnAccountAuthenticatedAfterWaitingQueueCallback = weakref.WeakMethod(onAccountAuthenticatedAfterWaitingQueue) if onAccountAuthenticatedAfterWaitingQueue is not None else None
[USER=1333341624]Property[/USER]
def Connected(self) -> 'bool':
return self._AccountSession__connected
[USER=1333341624]Property[/USER]
def AccountID(self) -> 'str':
return self._AccountSession__accountID
[USER=162874]account[/USER]ID.setter
def AccountID(self, accountID: 'str'):
self._AccountSession__accountID = accountID
[USER=1333341624]Property[/USER]
def KickOutMessage(self) -> 'str':
return self._AccountSession__kickoutMessage
[USER=2000007488]KickOut[/USER]Message.setter
def KickOutMessage(self, msg: 'str'):
self._AccountSession__kickoutMessage = msg
[USER=1333341624]Property[/USER]
def GatewaySubscription(self):
return self._AccountSession__gatewaySubscription
def setupNGS(self):
LOG_INFO('NGS:setupNGS')
if self._AccountSession__NGSClient is not None:
return
natuum.client.app.Instance.nxlog.stageLog(510, 'setupNGS')
def _sendMessage(weakSubscription, data):
subscription = weakSubscription()
if subscription is not None:
_data = data.tobytes()
subscription.MessageProxy.onNGSMessageReceived(_data, nowait=True)
def _callSendMessage(loop, weakSelf, data):
loop.call_soon_threadsafe(_sendMessage, weakSelf, data)
callableFactory = thing.Common.CallableFactory()
args = thing.Collection.Array()
args.append(asyncio.get_event_loop())
args.append(weakref.ref(self._AccountSession__gatewaySubscription))
args.append(callableFactory.PlaceHolder[1])
sendNGSMessage = callableFactory.bind(_callSendMessage, '__call__', args.iterate())
self._AccountSession__NGSClient = thing.NGSClient.NGSClient(sendNGSMessage)
if not self._AccountSession__NGSClient.isInitialized():
natuum.client.app.Instance.showWindowsMessageBox(u'NGS \ucd08\uae30\ud654\uc5d0 \uc2e4\ud328\ud558\uc5ec \ud504\ub85c\uadf8\ub7a8\uc744 \uc885\ub8cc\ud569\ub2c8\ub2e4.')
natuum.client.app.Instance.GameLogic.turnOffGame()
natuum.client.app.Instance.nxlog.stageLog(520, 'setupNGS')
def setupJYP(self, nexonID):
LOG_INFO('NGS:setupJYP')
if self._AccountSession__JYPClient is not None:
return
self._AccountSession__JYPClient = thing.JYP.JYPClient(nexonID)
self._AccountSession__JYPClient.collectThisThread()
def onFrameRenderForJYP(self):
if self._AccountSession__JYPClient is not None:
self._AccountSession__JYPClient.onFrameRender()
def onZoneEnterForJYP(self, zoneID):
if self._AccountSession__JYPClient is not None:
self._AccountSession__JYPClient.onSetZone(zoneID)
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
def doAnything(self, *args, **kwds):
pass
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
def onBeginTransfer(self, targetZoneName: str):
self.OnBeginTransferMessage.emit(targetZoneName)
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
def onPrepareTransfer(self, zoneStyle: str):
self.OnPrepareTransferMessage.emit(zoneStyle)
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
async def onFinishTransfer(self, zoneEntityID: 'thing.system.uuid or None', reason: str, isTimeout: bool):
self.OnFinishTransferMessage.emit(zoneEntityID, reason, isTimeout)
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
def onNGSMessageReceivedFromServer(self, data):
if self._AccountSession__NGSClient is not None:
self._AccountSession__NGSClient.onReceive(data)
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
async def notifyKickOut(self, type, errorCode):
LOG_INFO((u'\uc11c\ubc84\uc5d0 \uc758\ud574 \uac8c\uc784\uc744 \uac15\uc81c \uc885\ub8cc:{},{}.').format(type, errorCode))
text = (u'\uc11c\ubc84\uc5d0 \uc758\ud574 \ud504\ub85c\uadf8\ub7a8\uc774 \uc885\ub8cc\ub429\ub2c8\ub2e4.\n\n\uc0ac\uc720 : {}\n\uc5d0\ub7ec \ucf54\ub4dc :{}').format(type, errorCode)
self._AccountSession__kickoutMessage = text
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
async def notifyServerClock(self, now):
Instance._setServerTime(now)
[USER=186209]Thing[/USER].overrides(natuum._entity.IEntitySubscriber)
def onMessage(self, serial: 'int', message: 'var'):
pass
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
async def checkAlive(self, channelID=None):
pass
[USER=186209]Thing[/USER].overrides(natuum._entity.IEntitySubscriber)
def onChannelStatusChanged(self, status: 'int', detailedStatus: 'str'):
asyncio.ensure_future_and_forget(self.disconnect())
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
def onConnectionQueueChanged(self, left: 'int'):
callback = self._AccountSession__weakOnConntionQueueChangedCallback()
if callback is not None:
callback(left)
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
def onAccountAuthenticatedAfterWaitingQueue(self, userID: 'str', actors: 'collections.Sequence'):
callback = self._AccountSession__weakOnAccountAuthenticatedAfterWaitingQueueCallback()
if callback is not None:
callback(userID, actors)
_AccountSession__connected = None
class EngineConfig:
def __init__(self, id: 'str', config: 'collisions.Mapping'):
self._EngineConfig__id = id
self._EngineConfig__config = config
[USER=1333341624]Property[/USER]
def ID(self):
return self._EngineConfig__id
[USER=1333341624]Property[/USER]
def Config(self):
return self._EngineConfig__config
def apply(self):
pass
def onReload(self, newFactory):
self._EngineConfig__config = newFactory._EngineConfig__config
self.apply()
_EngineConfig__id = None
_EngineConfig__config = None
import collections, logging, os, sys, weakref, time, datetime, platform, enum, locale, thing.accessor
import thing.asyncio as asyncio
import thing.system
from natuum.activeobjects import ApartmentActiveObject
import natuum.apartment, natuum.app, natuum.builder, natuum.renderer, natuum.jobQueue, natuum.configuration, natuum.client.action, natuum.client.pager, natuum.client.resource, natuum.client.craft, natuum.client.logic, natuum.util,
natuum.variation, natuum.indexBook, natuum.reward, natuum.growth, natuum.emotionCutscene, natuum.client.synergy, natuum.client.contract, natuum.client.relationship, natuum._entity.apartmentEvents, natuum._entity.framework.cluster
import natuum._entity.messageRPC as messageRPC
from natuum.nexon import NXLogClient
from natuum._entity.interfaces.clientSubscriber import IGatewaySubscriber
import natuum.gameService.wordFilter
if __thing_can_get_zcom_objects__:
import multiprocessing
if not __final__:
import natuum.objects
DEFAULT_CLIENT_RESOLUTION = (1920, 1080)
if not __final__:
LOG_DEBUG = natuum.getLogger('client.app').debug
LOG_WARNING = natuum.getLogger('client.app').warning
import socket
def callbackBeforeDump():
if natuum.client.app.Instance:
natuum.client.app.Instance.nxlog.stageLog(1020, 'crash')
natuum.flushLog()
def callbackAfterDump():
pass
TEXT_FORMAT_TO_PRELOAD = ((0, '2002', 24.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 12.0, 3, 0, 5, 1.0),
(0, 'KoPubDotum', 13.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 13.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 14.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 14.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 15.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 15.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 17.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 17.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 18.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 18.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 21.0, 5, 0, 5, 1.0), (0, 'KoPubDotum', 22.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 23.0, 5, 0, 5, 1.0), (0, 'KoPubDotum', 24.0, 3, 0, 5, 1.0),
(0, 'KoPubDotum', 26.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 27.36, 3, 0, 5, 1.0),
(0, 'KoPubDotum', 27.6, 5, 0, 5, 1.0), (0, 'KoPubDotum', 33.0, 5, 0, 5, 1.0),
(0, 'KoPubDotum', 34.0, 3, 0, 5, 1.0), (0, 'KoPubDotum', 50.0, 5, 0, 5, 1.0),
(0, 'NanumSquare', 12.0, 5, 0, 5, 1.0), (0, 'NanumSquare', 14.0, 3, 0, 5, 1.0),
(0, 'NanumSquare', 14.0, 5, 0, 5, 1.0), (0, 'NanumSquare', 15.0, 5, 0, 5, 1.0),
(0, 'NanumSquare', 16.0, 5, 2, 5, 1.0), (0, 'NanumSquare', 17.0, 5, 0, 5, 1.0),
(0, 'NanumSquare', 40.0, 5, 0, 5, 1.0))
SIDEMENU_HTMLIVEWS = ('sideMenu_page_collection', 'sideMenu_page_map', 'sideMenu_page_present',
'sideMenuAvatar_editor')
Instance = None
class ListenerType(enum.IntEnum):
ZONE = 0
PERSON = 1
class App(natuum.app.App):
_App__LONG_TIME_PLAY_WARNING_INTERVAL = 3600000
def __init__(self):
global Instance
super().__init__()
Instance = self
self.RealTimeClock = thing.Value.RealTimeClock()
self.RunOptions = self._getRunOptions('Natuum Client', '', (self._App__RunOptionHandler(),), sys.argv[1:])
now = time.clock()
self._App__clientTime = now
self._App__serverTime = now
self._App__fps = 60
self.nxlog = None
[USER=1333341624]Property[/USER]
def FPS(self):
return self._App__fps
@FPS.setter
def FPS(self, fps):
self._App__fps = fps
def __sendPacket(self, blob):
pass
Resolution = thing.accessor.ri(doc='클라이언트 해상도')
Renderer = thing.accessor.ri(doc='렌더러 객체')
RPCManager = thing.accessor.ri(doc='RPC 관리자 객체')
SoundManager = thing.accessor.ri(None, doc='음향 관리자 객체')
Apartment = thing.accessor.ri(doc='클라이언트 아파트먼트')
EventLoop = thing.accessor.ri(None, doc='클라이언트 이벤트루프')
ClusterGuestNode = thing.accessor.ri(doc='클라이언트 클러스터 노드')
ClientZone = thing.accessor.rw(None)
QuitOnRendererShutdown = thing.accessor.ri(True, doc='렌더러 셧다운시 프로그램 종료')
Platform = thing.accessor.ri(doc='플랫폼 객체')
GatewayEntityID = thing.accessor.rw(None, doc='게이트웨이엔티티 ID')
ChatManagerEntityID = thing.accessor.rw(None, doc='채팅관리자엔티티 ID')
ItemDesignLibraryEntityID = thing.accessor.rw(None, doc='아이템설계관리자엔티티 ID')
DocumentContentLibraryEntityID = thing.accessor.rw(None, doc='문서내용관리자엔티티 ID')
ServerHostAddress = thing.accessor.ri(None, doc='게임 서버 주소')
LoaderThreadCount = thing.accessor.ri(1, doc='로더 스레드 갯수')
RealTimeClock = thing.accessor.ri(None, doc='RealTimeClock')
EngineConfig = thing.accessor.rw({}, doc='EngineConfig')
ServerConfig = thing.accessor.rw({}, doc='ServerConfig')
ControlModeParams = thing.accessor.ri({}, doc='ControlModeParams')
PlayerInitConfig = thing.accessor.ri({}, doc='PlayerInitConfig')
MaxFPS = thing.accessor.rw(None, doc='MaxFPS')
AccountSession = thing.accessor.ri(None, doc='AccountSession')
ClientSpace = thing.accessor.ri(None, doc='ClientSpace')
GameLogic = thing.accessor.ri(None, doc='GameLogic')
Context = thing.accessor.ri(None, doc='Context')
DummyAvatarSceneObjectData = thing.accessor.ri(None, doc='DummyAvatarSceneObjectData')
IsPreloading = thing.accessor.ri(True, doc='선로딩 여부')
UserConfig = thing.accessor.ri(None, doc='UserConfig')
InitialSplashLoadTask = thing.accessor.ri(None, doc='InitialSplashLoadTask')
_App__SERVER_EPOCH = datetime.datetime(2018, 1, 1)
def __setup(self) -> 'int, exit code':
if not __final__:
thing.system.setQuietMode(self.RunOptions.Quiet)
DebugLogCategories = '*,-action,-builder,-cutscene,' if self.RunOptions.SSOAuthToken is not None else ''
DebugLogCategories += os.environ.get('NT_DEBUG_LOG', '*') + ',' + self.RunOptions.DebugLogCategories
for category in DebugLogCategories.split(','):
if not category:
continue
if category.startswith('-'):
logger = natuum.getLogger(category[1:])
logger.setLevel(logging.INFO)
LOG_INFO('Log category [{}] level=debug was disabled'.format(logger.name))
from thing.changeset import changeset, NexonCrashReporterVersion
LOG_INFO('Changeset for Code:{}'.format(changeset))
LOG_INFO('BuildVersion:{}'.format(NexonCrashReporterVersion))
LOG_INFO('LauncherVer:{}, NGM Param:{}, NexonSN:{}, NexonSID:{}'.format(self.RunOptions.LauncherBuildVersion, self.RunOptions.LauncherOptionalParam, self.RunOptions.NexonSN, self.RunOptions.NexonSID))
self.Platform = platform = thing.Platform.Platform()
self.ETWSession_findObjects = platform.createETWSession('findObjects')
if self.RunOptions.SendCrashReport:
installed = platform.installCrashReporter(self.RunOptions.ProjectID)
if not installed:
LOG_WARNING('exception handler is not installed')
else:
platform.setCrashReporterInformation('ProcessType', self.RunOptions.ProductName)
from thing.changeset import NexonCrashReporterVersion
platform.setCrashReporterInformation('ProjectVersion', NexonCrashReporterVersion)
if natuum.m_logFilePath:
relPath = os.path.relpath(natuum.m_logFilePath, os.path.dirname(sys.executable))
platform.setCrashReporterAuxFile(relPath)
if __thing_supports_gc__:
if natuum.objects.m_refCycleFilePath:
relPath = os.path.relpath(natuum.objects.m_refCycleFilePath, os.path.dirname(sys.executable))
platform.setCrashReporterAuxFile(relPath)
platform.registerCrashReporterCallbackBeforeDump(callbackBeforeDump)
thing.system._installExceptHook(fromInit=False)
if not __final__:
self._App__initConsoleCtrlHandler()
if not __final__:
platform.listenEasyProfileGUI(28077)
self._App__thMan, self.RPCManager, self._App__chMan, self._App__chManThread = self._App__setupRPCManager()
self._App__clientLoaderApartments = self._App__createLoaderApartments()
rootFS = thing.FileSystem.FileSystem(natuum.getRootPath())
dataFS = rootFS['data']
try:
resourcesFS = rootFS['resources']
except Exception:
resourcesFS = rootFS.createDirectory('resources')
rm = natuum.client.resource.Manager(dataFS, resourcesFS)
rm.IsPreloading = self.IsPreloading
self._App__clientLoaderRegisterTokens = self._App__setupResourceManager(rm, self._App__clientLoaderApartments)
self.JobQueue = natuum.jobQueue.JobQueue()
self.EngineConfig = engineConfig = rm.load(natuum.builder.combineID('_', 'EngineConfig')).lockForReading().Data
self.ServerConfig = rm.load(natuum.builder.combineID('_', 'ServerConfig')).lockForReading().Data[self.RunOptions.ClusterID]
self.GatewayEntityID = self.ServerConfig['GatewayEntityID']
self.ChatManagerEntityID = self.ServerConfig['ChatManagerEntityID']
self.ItemDesignLibraryEntityID = self.ServerConfig['ItemDesignLibraryEntityID']
self.DocumentContentLibraryEntityID = self.ServerConfig['DocumentContentLibraryEntityID']
self.ServerHostAddress = self.RunOptions.Host
self.ControlModeParams = rm.ensureResource('controlModeParams@GameSetting')
self.PlayerInitConfig = rm.ensureResource('playerInitialization@GameSetting')
fullScreen = self.RunOptions.FullScreen
if fullScreen:
import ctypes
user32 = ctypes.windll.user32
screenWidth = user32.GetSystemMetrics(0)
screenHeight = user32.GetSystemMetrics(1)
screenRatio = screenWidth / screenHeight
if screenRatio > 1.7777777777777777:
width, height = (2400, 1080)
elif screenRatio > 1.6:
if screenWidth == 2048 and screenHeight == 1152:
width, height = screenWidth, screenHeight
else:
width, height = (1920, 1080)
elif screenRatio > 1.3333333333333333:
width, height = (1920, 1200)
else:
width, height = (1600, 1200)
else:
width, height = DEFAULT_CLIENT_RESOLUTION
self.AspectRatio = thing.Dirp.Dirp_Static(thing.system.vec(width / height, 1))
self.MaxFPS = max(int(engineConfig.Config.get('maxFPS', 60)), 1)
rendererMode = thing.Renderer.RendererManager().createRendererMode(fullScreen, width, height, 32)
self.Renderer = self._App__Renderer(rendererMode, engineConfig.Config)
self.Renderer.TerrainTessellationQueueLength = 3
self.Renderer.HangDetector = thing.ToolHelpers.HangDetector(self._App__onHangDetected)
self.PropCanvasMipHeadCutCountOnLoad = 0
userConfig = self._loadUserConfig()
if userConfig is not None:
self.UserConfig = userConfig
self._refreshCanvasLoadQuality(userConfig)
self.Renderer.UserConfig = userConfig
else:
self.UserConfig = self.Renderer.UserConfigValue['']
currentLocale = locale.getdefaultlocale()[1]
if currentLocale != 'cp949':
if self.Renderer.NativeWindowHandle:
text = 'Unsupported system locale : {}'.format(currentLocale)
text += '\n\nTo execute the client, change system locale to cp949 (Korean)'
self.showWindowsMessageBox(text)
self.nxlog = None
self.quit(0)
return
self._App__rendererModeWatchToken = self.Renderer.ModeVersion.addWatcher(self._App__onRendererModeChangedEntry, '__call__', weakref.ref(self))
self.nxlog = NXLogClient(self.RunOptions.NexonSN, self.RunOptions.NexonSID)
self.nxlog.stageLog(420, '__setup')
self._App__rendererReadyAtom = rendererReadyAtom = thing.Thread.Atom()
self._App__pagerThread = thread = self._App__thMan.createThread(thing.system.nativeThreadEntry, '__call__', self._App__pagerThreadEntry, rendererReadyAtom)
thread.Name = 'Main Updater'
thread.run()
_App__settingsDirName = 'settings'
_App__userConfigFileName = 'userConfig.nothing'
def _loadUserConfig(self):
settingsDirPath = os.path.join(natuum.getRootPath(), 'storage', __class__._App__settingsDirName)
try:
if os.path.exists(settingsDirPath):
fs = thing.FileSystem.FileSystem(settingsDirPath)
else:
raise KeyError
f = fs[__class__._App__userConfigFileName]
ra = thing.Archive.ReadingArchive_FromFile(f)
userConfig = thing.Collection.Dict()
userConfig.load(ra)
LOG_INFO('user config loaded')
except KeyError:
LOG_WARNING('cannot load user config')
userConfig = None
return userConfig
def _saveUserConfig(self, userConfig):
settingsDirPath = os.path.join(natuum.getRootPath(), 'storage', __class__._App__settingsDirName)
try:
os.makedirs(settingsDirPath)
except OSError:
pass
try:
fs = thing.FileSystem.FileSystem(settingsDirPath)
f = fs.createFile(__class__._App__userConfigFileName, True)
wa = thing.Archive.WritingArchive_FromFile(f)
userConfig.save(wa)
wa.flush()
LOG_INFO('user config saved')
except:
LOG_WARNING('cannot save user config')
def _refreshCanvasLoadQuality(self, userConfig):
propTexQuality = userConfig.get('PropTextureQuality', -1)
if propTexQuality >= 0:
propTexQuality = min(2, propTexQuality)
oldValue = self.PropCanvasMipHeadCutCountOnLoad
newValue = (2, 1, 0)[propTexQuality]
if oldValue != newValue:
self.PropCanvasMipHeadCutCountOnLoad = newValue
return True
return False
def __preload(self):
markerResourceIDs = self._App__collectMarkerResources()
effectPreloadList = tuple(markerResourceIDs.get('Effect', set()) | set(self._App__PRELOAD_EFFECTS))
rm = natuum.client.resource.Manager.Instance
rm.preload('Avatar', preloadList=('AT099800(man_default)', 'AT099900(woman_default)'))
rm.preload('Effect', preloadList=effectPreloadList)
rm.preload('CameraAngle')
rm.preload('CameraAngleBlender')
rm.preload('CameraAngleBlenderSet')
rm.preload('HTMLView', preloadList=SIDEMENU_HTMLIVEWS)
rm.preload('HTML', preloadList=('sideMenu', 'sideMenuAvatar'))
rm.preload('ItemDesign')
rm.preload('ItemIO')
rm.preload('MeshSet', preloadList=(self._App__DUMMY_AVATAR_MESHSETS))
rm.preload('PropPart', preloadList=(self._App__PRELOAD_PROPPARTS))
rm.preload('Quest')
rm.preload('VueApp', preloadList=('app', ))
rm.preload('Zone', preloadList=('ZR0000(carveKiranaArea)', ))
for typeName, resourceIDs in markerResourceIDs.items():
if typeName in ('Effect', 'ItemDesign'):
continue
else:
rm.preload(typeName, preloadList=(tuple(resourceIDs)))
rm.preload('GameSetting')
def __collectMarkerResources(self):
def collectResourceIDs(value, resourceIDs_):
if isinstance(value, str) and natuum.builder.isResourceID(value):
name, typeName, _ = natuum.builder.splitID(value)
resourceIDs_[typeName].add(name)
elif not isinstance(value, str) or isinstance(value, collections.Sequence):
for value_ in value:
collectResourceIDs(value_, resourceIDs_)
elif isinstance(value, collections.Mapping):
for value_ in value.values():
collectResourceIDs(value_, resourceIDs_)
def collectMarkerClasses(marker, markerClasses_):
markerClasses.add(marker)
for marker_ in marker.__subclasses__():
collectMarkerClasses(marker_, markerClasses_)
markerResourceIDs = collections.defaultdict(set)
markerClasses = set()
collectMarkerClasses(natuum.client.clientSpace.marker.Marker, markerClasses)
for arranger in natuum.client.clientSpace.arranger.__dict__.values():
if isinstance(arranger, type):
collectMarkerClasses(arranger, markerClasses)
for marker in markerClasses:
for attribute in marker.__dict__.values():
collectResourceIDs(attribute, markerResourceIDs)
collectMarkerClasses = None
collectResourceIDs = None
return markerResourceIDs
def __run(self) -> 'int, exit code':
if not __final__:
if not self.RunOptions.NoUsageReport:
self._App__sendUsageReport()
windowTitle = 'Peria Chronicles{}'.format(natuum.util.getBuildVersion())
rendererExitCode = self.Renderer.start(windowTitle, thing.system.ICanvas.PIXEL_FORMAT_R8G8B8A8, self._App__rendererReadyAtom, self.QuitOnRendererShutdown)
return self._App__exitCode
def __cleanup(self) -> None:
global Instance
if not __final__:
for i in range(5):
if self._App__pagerThread.wait(1):
break
else:
(LOG_DEBUG if i <= 2 else LOG_WARNING)('Pager 스레드 종료 대기중 (%d초)', i + 1)
else:
self._App__pagerThread.wait(5)
del self._App__pagerThread
self.JobQueue.shutdown()
self._App__clientLoaderRegisterTokens.clear()
for apartment in self._App__clientLoaderApartments.values():
apartment.shutdown()
self._App__shutdownTableManagers()
self._App__cleanupResourceManager()
if self._App__chMan is not None:
self._App__chMan.shutdown()
VERIFY(self._App__chManThread.wait(5))
del self._App__chManThread
del self._App__mainApartment
self.RPCManager.shutdown()
Instance = None
[USER=186209]Thing[/USER].overrides(natuum.app.App)
def run(self) -> 'int, exit code':
self._App__setup()
ret = self._App__run()
self._App__cleanup()
return ret
[USER=186209]Thing[/USER].overrides(natuum.app.App)
def quit(self, exitCode):
LOG_INFO('client quit called')
self.Renderer.shutdown()
curPage = natuum.client.pager.CurPage
if curPage is not None:
if not natuum.client.pager.command((curPage.canQuitApp), wait=True):
return
super().quit()
self._App__exitCode = exitCode
if self.RunOptions.SendCrashReport:
self.Platform.setCrashReporterClientExit(exitCode)
if natuum.client.app.Instance.nxlog is not None:
natuum.client.app.Instance.nxlog.stageLog(1010, str(exitCode))
self.Renderer.quit(True)
def isInRendererThreadGroup(self, threadID):
return threadID == self.Renderer.ThreadID
def collectZcomObjects(self, showBackrefsOfIDs=False):
if not __thing_can_get_zcom_objects__:
return
createdZcomObjects = self._App__createdZcomObjects
if createdZcomObjects is None:
self._App__createdZcomObjects = thing.ToolHelpers.CreatedObjects()
else:
self._App__createdZcomObjects = None
objs = None
try:
backrefsDir = os.path.join(natuum.getLogPath(), 'backrefs')
os.makedirs(backrefsDir, exist_ok=True)
today = datetime.datetime.today()
timestamp = '%4d%02d%02d_%02d%02d%02d' % (today.year, today.month, today.day, today.hour, today.minute, today.second)
graphFilePath = os.path.join(backrefsDir, 'graph_c{}.txt'.format(timestamp))
with open(graphFilePath, 'w', encoding='utf_8-sig') as file:
natuum.objects.Graph.collectToFile(file)
objs = list(createdZcomObjects)
objectIDsFilePath = os.path.join(backrefsDir, 'objects_c{}.txt'.format(timestamp))
with open(objectIDsFilePath, 'w') as file:
natuum.objects.saveObjectIDsToFile(file, objs)
if showBackrefsOfIDs:
multiprocessing.Process(target=(natuum.objects.showBackrefsOfIDs),
args=(
backrefsDir, graphFilePath, objectIDsFilePath)).start()
thing.system._debugBreak()
objs.clear()
finally:
if objs is not None:
objs.clear()
def checkMemory(self):
if __final__ or (self._App__memoryReclaimer is None):
return
for i in range(10):
self._App__memoryReclaimer.reclaimAll()
natuum.objects.GarbageCollector().collect(-1, True)
trendsCollector = self._App__objectCountTrendsCollector
if trendsCollector is None:
self._App__objectCountTrendsCollector = trendsCollector = natuum.objects.CountTrendsCollector()
trendsCollector.collect()
trends = [(v, trendsCollector.getCount(k), k) for k, v in trendsCollector.items()]
trends.sort(reverse=True)
tracker = self._App__memoryTracker
lines = []
lines.append('**** object count trend log start ****')
for trend, count, typeName in trends:
countList = tracker.get(typeName, None)
if countList is None:
countList = list()
tracker[typeName] = countList
else:
countList.append(count)
lines.append('{:G}\t{}\t{}'.format(trend, typeName, '\t'.join([str(i) for i in countList])))
lines.append('**** object count trend log end ****')
def getRoughServerTime(self) -> 'int. milliseconds':
passed = int(time.time() - self._App__clientTime) * 1000
return (self._App__serverTime + passed) % 2147483647
def setListener(self, flag, position) -> None:
soundManager = self.SoundManager
if soundManager is not None:
configuration = self.ControlModeParams.get('sound')
if configuration is None:
if ListenerType.ZONE == flag:
soundManager.Listener = position
elif configuration['listener'] == flag:
soundManager.Listener = thing.Dirp.Dirp_FromLocal(configuration['local'], thing.math.ROT_IDENTITY, position)
def _setServerTime(self, serverNow):
self._App__clientTime = time.time()
self._App__serverTime = int(serverNow * 1000)
class __Renderer(natuum.renderer.Renderer):
[USER=186209]Thing[/USER].overrides(natuum.renderer.Renderer)
def onRendererCloseButton(self, renderer: 'thing.system.IRenderer', private) -> None:
Instance.quit(0)
[USER=186209]Thing[/USER].overrides(natuum.renderer.Renderer)
def onRendererConfigChange(self, renderer: 'thing.system.IRenderer', private) -> None:
if isinstance(private, thing.system.IMutableMapping):
userConfig = private
natuum.client.app.Instance._saveUserConfig(userConfig)
if natuum.client.app.Instance._refreshCanvasLoadQuality(userConfig):
natuum.client.pager.command(natuum.client.app.Instance.GameLogic.onCanvasLoadQualityChange)
def _registerLayerCategories(self) -> None:
self.registerLayerCategory('UI').forget()
class __RunOptionHandler(natuum.runOptions.IHandler):
def fillDefaults(self, options):
options.Host = None
options.Quiet = False
options.InfuseActor = None
options.CrashReportURL = 'http://socorro.thingsoft.com:8882/submit'
options.ProductName = 'client'
options.ProductVersion = '0.8.1'
options.NoUsageReport = False
options.NoEffect = False
options.BatchJob = None
options.Locale = None
options.ClusterID = 'default'
options.SSOAuthToken = None
options.FullScreen = False
options.DebugLogCategories = '*,-action,-builder,-cutscene' if __final__ else ''
options.ProjectID = 'peria_dev'
options.LauncherBuildVersion = -1
options.LauncherOptionalParam = ''
options.NexonSN = 0
options.NexonSID = None
options.disableNXLog = False
crashReport = os.environ.get('NT_NO_CRASH_REPORT', '0')
options.SendCrashReport = crashReport == '0'
def buildParser(self, parser: 'optparse.OptionParser', options) -> None:
parser.add_option('-a', '--address', dest='Host', help='server address')
parser.add_option('-q', '--quiet', dest='Quiet', default=False, action='store_true', help='quiet mode')
parser.add_option('-i', '--infuseActor', dest='InfuseActor', help='auto infuse actor')
parser.add_option('-b', '--batch', dest='BatchJob', help='batch job file')
parser.add_option('-l', '--locale', dest='Locale', help='locale')
parser.add_option('-C', '--cluster', dest='ClusterID', help='cluster id')
parser.add_option('--crashreport-url', dest='CrashReportURL', help='crash report url')
parser.add_option('--product-name', dest='ProductName', help='product name')
parser.add_option('--product-version', dest='ProductVersion', help='product version')
parser.add_option('--nousagereport', dest='NoUsageReport', default=False, action='store_true', help="don't send usage report")
parser.add_option('-t', '--auth', dest='SSOAuthToken', help='auth token')
parser.add_option('-f', '--fullScreen', dest='FullScreen', default=False, action='store_true', help='full screen mode')
parser.add_option('--debugLog', type='str', dest='DebugLogCategories', help='comma seperated log categories')
parser.add_option('--projectid', dest='ProjectID', help='crash reporter project id')
parser.add_option('--launcherBuildVersion', dest='LauncherBuildVersion', help='launcher build version')
parser.add_option('--launcherParam', dest='LauncherOptionalParam', default='', help='argument from NexonGameManager')
parser.add_option('--nexonsn', dest='NexonSN', default=0, help='argument from NexonGameManager')
parser.add_option('--nexonsid', dest='NexonSID', default='', help='argument from NexonGameManager')
parser.add_option('--disableNXLog', dest='disableNXLog', default=False, action='store_true', help='disable NXLOG')
def onParsed(self, parser: 'optparse.OptionParser', options, args: tuple) -> None:
if options.BatchJob is not None:
batchJobPath = os.path.join(natuum.getRootPath(), 'settings', options.BatchJob)
options.BatchJob = natuum.util.readXDF(batchJobPath)
if options.Locale is not None:
if options.Locale in ('ko', 'ja', 'zh', 'en'):
natuum.util.DefaultLocale = options.Locale
def __createLoaderApartments(self) -> '{ str: thing.system.IApartment }':
apartments = {}
for i in range(self.LoaderThreadCount):
name = 'Loader{}'.format(i)
apartmentObject = ApartmentActiveObject(self._App__thMan, self.RPCManager)
apartmentObject.start(name, -0.13333333333333333)
apartments[name] = apartmentObject.Apartment
return apartments
if not __final__:
def __initConsoleCtrlHandler(self):
def _terminateProcess(ctrlType):
thing.system._TerminateProcess()
thing.system.setConsoleCtrlHandler(_terminateProcess)
def __setupRPCManager(self):
thMan = thing.Thread.ThreadManager()
rpcManager = thing.RPC.RPCManager(thMan)
self._App__mainApartment = natuum.apartment.Apartment()
return (
thMan, rpcManager, None, None)
def __setupResourceManager(self, rm, loaderApartments) -> '{ str : thing.system.IForgettableToken }':
tokens = {}
for name, apartment in loaderApartments.items():
token = rm.CacheManager.registerDelayedLoaderApartment(name, apartment.Inner)
tokens[name] = token
return tokens
def __cleanupResourceManager(self) -> None:
natuum.client.resource.Manager.Instance.shutdown()
@staticmethod
def __onRendererModeChangedEntry(watched, weakSelf, hint, funcName) -> None:
self = weakSelf()
if self is not None:
clientSpace = self.ClientSpace
if clientSpace is not None:
natuum.client.pager.command(clientSpace.onRendererModeChanged)
def __pagerThreadEntry(self, rendererReadyAtom: 'thing.system.IAtom') -> None:
self.Context = thing.Common.Sites()
self.EventLoop = loop = natuum._entity.apartmentEvents.EventLoop()
asyncio.set_event_loop(loop)
self.Apartment = loop.Apartment
thing.system.setSwitchIntervalForCurrentThread(1)
rendererReadyAtom.wait()
inputManager = natuum.client.input.Manager()
self._App__initFontManager()
self.showInitialSplash(True)
if self.InitialSplashLoadTask:
loop.run_until_complete(self.InitialSplashLoadTask)
_ = self.Platform.disableAccessibility()
self.GUI = guiSystem = thing.Renderer.GUISystem()
self.Renderer.GUISystem = guiSystem
self.SoundManager = soundManager = self._App__createSoundManager(parameters=(self.ControlModeParams))
try:
soundManager.setVolume('music', self.UserConfig['BGMVolume'])
soundFXVol = self.UserConfig['SoundEffectVolume']
for bus in ('effect', 'voice', 'environment', 'kiranaContract'):
soundManager.setVolume(bus, soundFXVol)
except KeyError:
pass
natuum.configuration.Configuration.initialize()
self.ClusterGuestNode = node = natuum._entity.framework.cluster.setup_guest(self.ServerConfig['GatewayServers'])
if self.ServerHostAddress is not None:
node.overrideConnectingtHost(self.ServerHostAddress)
self.AccountSession = natuum.client.app.AccountSession()
self.ZoneChanged = natuum.signal.Signal(natuum.client.zone.Zone)
self._App__initClassTables()
if self.IsPreloading:
self._App__preload()
self._App__initTableManagers()
clientSpace = natuum.client.clientSpace.ClientSpace()
clientSpace.onRendererModeChanged()
clientSpace.addDesktop()
clientSpace.addDesktop()
clientSpace.addInventory()
self.ClientSpace = clientSpace
inputManager.setEventHandler(clientSpace)
self.GameLogic = gameLogic = natuum.client.logic.GameLogic(clientSpace)
gameLogic.SyncClock.defer(App._App__LONG_TIME_PLAY_WARNING_INTERVAL, App._App__warnLongTimePlay, 1).forget()
self._App__setupIDE()
self._App__buildDummyAvatar()
self._App__processorToken = thing.Thread.Processor().addTask(0, self.MaxFPS)
self._App__memoryReclaimer = memoryReclaimer = thing.Common.MemoryReclaimer()
memoryReclaimer.clearPolicies()
memoryReclaimer.appendPolicy(memoryReclaimer.MEMORY_RECLAIMER_CRITERION_AVAILABLE_PHYSICAL_MB_LESS_THAN, 100, 209715200, 5)
memoryReclaimer.appendPolicy(memoryReclaimer.MEMORY_RECLAIMER_CRITERION_AVAILABLE_PHYSICAL_MB_LESS_THAN, 500, 104857600, 10)
memoryReclaimer.appendPolicy(memoryReclaimer.MEMORY_RECLAIMER_CRITERION_AVAILABLE_PHYSICAL_MB_LESS_THAN, 1000, 1, 15)
memoryReclaimer.appendPolicy(memoryReclaimer.MEMORY_RECLAIMER_CRITERION_PAGE_FILE_USAGE_MB_GREATER_THAN, 7168, 102400, 15)
natuum.apartment.getCurrentApartment().Alarm.postTask(self._App__reclaimMemory, 0).forget()
if not __final__:
natuum.apartment.getCurrentApartment().Alarm.postTask(self._App__logMemoryReclaimer, 60000).forget()
self._App__memoryTracker = {}
loop.call_soon(natuum.client.pager.enter)
loop.run_forever()
loop.run_until_complete(node.shutdown())
loop.close()
gameLogic.shutdown()
thing.Client.EffectManager().terminate()
soundManager.shutdown()
guiSystem.shutdown()
self.Renderer.GUISystem = None
def __initClassTables(self) -> None:
rm = natuum.client.resource.Manager.Instance
natuum.client.action.ActionTableManager.ensureInstance()
rawClassTables = rm.load(natuum.gameClass.CLASS_TABLE).lockForReading().Data
natuum.gameClass.initManager(rawClassTables)
if self.IsPreloading:
natuum.gameClass.getManagerInstance().preloadClasses()
def __initTableManagers(self) -> None:
rm = natuum.client.resource.Manager.Instance
natuum.emotionCutscene.initManager(rm)
natuum.client.craft.initManager(rm)
natuum.variation.initManager(rm)
natuum.indexBook.initManager(rm)
natuum.client.contract.initManager(rm)
natuum.reward.initManager(rm)
natuum.growth.initManager(rm)
natuum.actor.initManager(rm)
natuum.client.quest.initManager(rm)
natuum.town.initManager(rm)
natuum.client.relationship.initManager(rm)
natuum.client.synergy.initManager(rm)
natuum.gameService.wordFilter.initManager(rm)
def __initFontManager(self) -> None:
fontManager = thing.Renderer.FontManager()
rm = natuum.client.resource.Manager.Instance
rm.preload('Font', preloadList=(natuum.util.FontNames))
for fontName in natuum.util.FontNames:
fontID = natuum.builder.combineID(fontName, 'Font')
fontData = rm.ensureResource(fontID)
fontManager.registerFontData(fontData[0], fontData[1])
for info in TEXT_FORMAT_TO_PRELOAD:
(fontManager.createRasterTextFormat)(self.Renderer, *info)
def __setupIDE(self) -> None:
pass
def __buildDummyAvatar(self) -> None:
rm = natuum.client.resource.Manager.Instance
meshSet = rm.ensureResource('AP7250@MeshSet')
sceneObjectData = thing.Scene.SceneObjectData_Mesh()
sceneObjectData.ShaderFlags = thing.system.IShader.SHADER_SHADOW_MAP | thing.system.IShader.SHADER_REALISTIC
for meshName, meshAndBone in meshSet.items():
sceneObjectMeshElementData = thing.Scene.SceneObjectMeshElementData()
sceneObjectMeshElementData.Mesh = meshAndBone['mesh']
sceneObjectData.Elements[meshName] = sceneObjectMeshElementData
self.Renderer.warm(sceneObjectData, 0)
self.DummyAvatarSceneObjectData = sceneObjectData
def __shutdownTableManagers(self) -> None:
natuum.client.craft.shutdownManager()
natuum.client.action.ActionTableManager.shutdown()
natuum.gameClass.shutdownManager()
def __reclaimMemory(self) -> None:
if self.IsQuitting:
return
waitDuration = self._App__memoryReclaimer.reclaim()
natuum.apartment.getCurrentApartment().Alarm.postTask(self._App__reclaimMemory, waitDuration).forget()
if not __final__:
def __logMemoryReclaimer(self) -> None:
if self.IsQuitting:
return
memoryReclaimer = self._App__memoryReclaimer
LOG_INFO('available physical memory: {} GB'.format(memoryReclaimer.AvailablePhysicalMemoryGB))
LOG_INFO('page file usage: {} GB'.format(memoryReclaimer.PageFileUsageGB))
natuum.apartment.getCurrentApartment().Alarm.postTask(self._App__logMemoryReclaimer, 60000).forget()
def __sendUsageReport(self) -> None:
def sendReport(info: 'sequence of ( str, str )') -> str:
tokenDelim = '_TDELIM_'
emptyToken = '_EMPTY'
stream = tokenDelim.join([value if value != '' else emptyToken for value in info])
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(stream.encode('utf-8'), ('wild.thingsoft.com', 8025))
LOG_INFO('Usage report sent..')
except socket.error:
pass
sock.close()
rendererManager = thing.Renderer.RendererManager()
usageInfo = (
'{}'.format(platform.node()),
'{} {}'.format(platform.system(), platform.version()),
'{}'.format(platform.processor()),
'{}'.format(self.Platform.MemorySize),
'{}'.format(self.Platform.HardDiskSize),
'{}'.format(rendererManager.DeviceDescription.split('\x00')[0].strip()),
'{}'.format(natuum.util.getBuildVersion()))
sendReport(usageInfo)
sendReport = None
[USER=437263]clas[/USER]smethod
def __createSoundManager(cls, parameters=None, liveUpdate=False) -> 'thing.system.ISoundManager':
rm = natuum.client.resource.Manager.Instance
masterBank = rm.load(cls._App__masterBankResourceID)
masterBank = masterBank.lockForReading().Data
try:
masterBank = masterBank.SoundData
except KeyError:
LOG_WARNING('{}를 읽지 못했습니다. 이벤트 경로를 읽지 못해 소리가 나오지 ' + '않습니다.'.format(cls._App__masterBankResourceID))
return
else:
masterStringBank = rm.load(cls._App__masterStringBankResourceID)
try:
masterStringBank = masterStringBank.lockForReading().Data.SoundData
except KeyError:
LOG_WARNING('{}를 읽지 못했습니다. 이벤트 경로를 읽지 못해 소리가 나오지 ' + '않습니다.'.format(cls._App__masterStringBankResourceID))
return
else:
busGroups = cls._App__getBusGroups(parameters)
return thing.Sound.SoundManager(masterBank, masterStringBank, liveUpdate, natuum.getRootPath(), busGroups)
def __closeSplashZoneViewerMarker(self):
self._App__splashZoneViewerMarker.close()
self._App__splashZoneViewerMarker = None
def showInitialSplash(self, show):
self._App__splashNoticeLayer = None
self._App__splashLayer = None
if self._App__splashZoneViewerMarker:
self.Renderer.Timer.defer(0, self._App__closeSplashZoneViewerMarker).forget()
if show:
rm = natuum.client.resource.Manager.Instance
canvas = rm.load('ui_title_booting@Canvas').lockForReading().Data
self._App__splashLayer = self.Renderer.createOverlayLayer(thing.Dirp.Dirp_Static(), thing.Dirp.Dirp_Static(self.AspectRatio), canvas)
self.Renderer.updateLayers()
@staticmethod
def __onSplashZoneLoaded(fut_) -> None:
app = natuum.client.app.Instance
canvas = app._App__splashZoneViewerMarker.getViewCanvas()
app._App__splashLayer = app.Renderer.createOverlayLayer(thing.Dirp.Dirp_Static(), thing.Dirp.Dirp_Static(app.AspectRatio), canvas)
text = natuum.client.text.Text('로딩 중입니다. 기다리는 동안 지형 편집을 연습해 보세요.', 22, 'NanumSquare', thing.system.vec(xyzw=1), thing.system.vec(a=1), 'bold', 0.0)
app._App__splashNoticeLayer = app.Renderer.createOverlayLayer(thing.Dirp.Dirp_Static(thing.system.vec(0.5, 0.8)), thing.Dirp.Dirp_Static(thing.system.vec(text.getWidth(), text.getHeight()) / text.getHeight() * 0.04), text.
getCanvas())
app.Renderer.updateLayers()
def showWindowsMessageBox(self, text, title='Peria Chronicles', uType=0, quit=False):
import ctypes
MessageBox = ctypes.windll.user32.MessageBoxW
ret = None
if natuum.client.app.Instance.Renderer.NativeWindowHandle:
ret = MessageBox(natuum.client.app.Instance.Renderer.NativeWindowHandle, text, 'Peria Chronicles', uType)
if quit:
self.GameLogic.turnOffGame()
return ret
@staticmethod
def __warnLongTimePlay(count):
app = Instance
if app is None:
return
gameLogic = app.GameLogic
if gameLogic is None:
return
getLocalString = natuum.action.ActionTableManager.getInstance().getLocalString
author = getLocalString('NoticeAuthor')
longTimePlayWarning = getLocalString('LongTimePlayWarning').format(N=count)
ageRatingInformation = getLocalString('AgeRatingInformation')
gameLogic.createMarker('message', ('(색상:빨강)(크기:크게){}(/크기)(/색상)'.format(longTimePlayWarning)), forced=True)
gameLogic.SyncClock.addWork(5000, (gameLogic.createMarker), 'message', ('(색상:빨강)(크기:크게){}(/크기)(/색상)'.format(ageRatingInformation)), forced=True).forget()
gameLogic.vueUiController.ChattingView.addChatText('notice', author, longTimePlayWarning)
gameLogic.vueUiController.ChattingView.addChatText('notice', author, ageRatingInformation)
gameLogic.SyncClock.defer(App._App__LONG_TIME_PLAY_WARNING_INTERVAL, App._App__warnLongTimePlay, count + 1).forget()
@staticmethod
def __getBusGroups(parameters) -> '{ str : var }':
if parameters is None:
return {}
try:
return parameters['sound']['bus']['groups']
except KeyError:
return {}
@staticmethod
def __onHangDetected(detected: 'thing.system.IHangDetector') -> None:
if not __final__:
import thing.debugger
if thing.debugger.checkAttached():
LOG_WARNING('hang detected')
thing.debugger.breakIfAttached()
return
try:
raise RuntimeError('hang detected')
except Exception as e:
try:
sys.excepthook(type(e), e, e.__traceback__)
finally:
e = None
del e
_App__thMan = None
_App__chMan = None
_App__clientLoaderApartments = None
_App__clientLoaderRegisterTokens = None
_App__chManThread = None
_App__pagerThread = None
_App__rendererReadyAtom = None
_App__exitCode = 0
_App__serverPort = 9999
_App__server = None
_App__memoryReclaimer = None
_App__memoryChecker = None
if not __final__:
_App__objectCountTrendsCollector = None
if __thing_can_get_zcom_objects__:
_App__createdZcomObjects = None
_App__actionTableManager = None
_App__masterBankResourceID = natuum.builder.combineID('MasterBank', 'Sound')
_App__masterStringBankResourceID = natuum.builder.combineID('MasterBankstrings', 'Sound')
_App__splashLayer = None
_App__splashNoticeLayer = None
_App__splashZoneViewerMarker = None
_App__PRELOAD_EFFECTS = ('EF7000', 'EF7000_lumi', 'EF7001', 'EF7002', 'EF7003',
'EF7004', 'EF7006', 'EF7007', 'EF7010', 'EF7012', 'EF7013',
'EF7016', 'EF7019', 'EF7020', 'EF7022', 'EF7024', 'EF7033',
'EF7050', 'EF7051', 'EF7052', 'EF7053', 'EF7054', 'EF7058',
'EF7074', 'EF7075', 'EF7080', 'EF7081', 'EF7082', 'EF7083',
'EF7084', 'EF7093', 'EF7094', 'EF7095', 'EF7096', 'EF7098',
'EF7099', 'EF8000', 'EF8001', 'EF8002', 'EF8003', 'EF8003',
'EF8004', 'EF8008', 'EF8010', 'EF8011', 'EF8012', 'EF8013',
'EF8015', 'EF8016', 'EF8017', 'EF8020', 'EF8021', 'EF8022',
'EF8030', 'EF8031', 'EF8040', 'EF8041', 'EF8050', 'EF8051',
'EF8100', 'EF8100a', 'EF8100b', 'EF8100d', 'EF8107',
'EF8130', 'EF8131', 'EF8132', 'EF8133', 'EF8134', 'EF8135',
'EF8136', 'EF8137', 'EF8139', 'EF8142', 'EF8142', 'EF8143',
'EF8144', 'EF8145', 'EF8146', 'EF8147', 'EF8148', 'EF8149',
'EF8149', 'EF8149', 'EF8150', 'EF8151', 'EF8152', 'EF8153',
'EF8154', 'EF8156', 'EF8159', 'EF8160', 'EF8162', 'EF8165',
'EF8167', 'EF8168', 'EF8170', 'EF8171', 'EF8172', 'EF8173',
'EF8174', 'EF8175', 'EF8176', 'EF8179', 'EF8182', 'EF8184',
'EF8186', 'EF8187', 'EF8188', 'EF8189', 'EF8191', 'EF8192',
'EF8194', 'EF8196', 'EF8197', 'EF8198', 'EF8199', 'EF8200',
'EF8201', 'EF8205', 'EF8207', 'EF8210', 'EF8211', 'EF8212',
'EF8213', 'EF8216', 'EF8217', 'EF8218', 'EF8219', 'EF8220',
'EF8158a', 'EF8158b', 'EF8158c', 'EF8224', 'EF8233',
'EF8234', 'EF8236', 'EF8237', 'SEF(warning_01)', 'SEF1018(world_map)',
'SEF1020(marker_open)', 'SEF1023(guardian_qattack_ready)',
'SEF1025(guardian_qattack_fire)', 'SEF1026(guardian_qattack_targeting)',
'SEF1028(actionmaker_click)', 'SEF1029(actionmaker_hover)',
'SEF1030(actionmaker_open)', 'SEF1031(actionmaker_release)',
'SEF1032(conversation_click)', 'SEF1033(conversation_hover)',
'SEF1034(f_key_to_continue_conversation)', 'SEF1035(f_key_to_start_conversation)',
'SEF1036(general_button_click)', 'SEF1037(general_button_release)',
'SEF1038(changing_tab)', 'SEF1043(list_open)', 'SEF1044(list_close)',
'SEF1045(Xbutton)', 'SEF1046(popup_window)', 'SEF1047(conversation_release)',
'SEF1048(f_key_hover)', 'SEF1049(general_button_hover)',
'SEF1050(tab_hover)', 'SEF1051(small_button_click)',
'SEF1052(small_button_hover)', 'SEF1053(small_button_release)',
'SEF1054(kirana_listup_hover)', 'SEF1055(kirana_listup_click)',
'SEF1057(kirana_listup_release)', 'SEF1058(kirana_listup_release_cancel)',
'SEF1063(f_key_click)', 'SEF1065(battle_book_use)',
'SEF1066(inventory_hover)', 'SEF1067(inventory_click)',
'SEF1068(inventory_block)', 'SEF1069(inventory_release)',
'SEF1070(tab_release)', 'SEF1071(battle_book_hover)',
'SEF1075(battle_book_appearance)', 'SEF1076(battle_book_disappearance)',
'UI_deliveryRangeSphere', 'balloon_marker', 'button_marker',
'caption_marker', 'close_marker', 'coordinates_marker',
'gauge_marker', 'label', 'list_marker', 'list_marker3',
'text_balloon_marker', 'text_edit_marker', 'tooltip_marker',
'window', 'window2')
_App__PRELOAD_PROPPARTS = ('PP6954', 'PP6366(blue)', 'PP6366(green)', 'PP6366(purple)',
'PP6366(red)', 'PP6366(white)', 'PP6366(yellow)',
'PP6851', 'PP8200', 'PP8201', 'PP8202', 'PP8203',
'PP8204', 'PP8205', 'PP8206', 'PP8207', 'PP8208',
'PP8209', 'PP8210', 'PP8211', 'PP8212', 'PP8213',
'PP8214')
_App__DUMMY_AVATAR_MESHSETS = ('AP7250', )
class AccountSession(natuum._entity.IEntitySubscriber, IGatewaySubscriber):
def __init__(self):
self._AccountSession__connected = False
self._AccountSession__gatewaySubscription = None
self._AccountSession__NGSClient = None
self._AccountSession__JYPClient = None
self._AccountSession__accountID = None
self._AccountSession__kickoutMessage = None
self._AccountSession__weakOnConntionQueueChangedCallback = None
self._AccountSession__weakOnAccountAuthenticatedAfterWaitingQueueCallback = None
self.OnDisconnected = natuum.signal.Signal(bool, str)
self.OnBeginTransferMessage = natuum.signal.Signal(bool)
self.OnPrepareTransferMessage = natuum.signal.Signal(str)
self.OnFinishTransferMessage = natuum.signal.Signal(thing.system.uuid, str, bool)
async def connect(self, callback=None, maxTryCount=-1):
if self._AccountSession__connected:
return
await natuum.client.app.Instance.ClusterGuestNode.start()
apartment = asyncio.get_event_loop().Apartment
tryCount = 0
entity = None
while maxTryCount < 0 or maxTryCount > tryCount:
try:
entity = await apartment.EntityManager.findEntity(natuum.client.app.Instance.GatewayEntityID)
break
except natuum._entity.error.RemoteEntityServerNotFound:
LOG_WARNING('RemoteEntityServer not found')
return
except natuum._entity.error.EntityNotExist:
LOG_WARNING('GatewayEntity not exist')
return
except natuum._entity.error.EntityNotRestored:
LOG_WARNING('GatewayEntity not restored. try after 5 seconds. try count : {}'.format(tryCount))
tryCount += 1
await asyncio.sleep(5)
except natuum._entity.error.SubscriptionChannelClosed:
tryCount += 1
await asyncio.sleep(5)
except asyncio.TimeoutError:
return
except asyncio.CancelledError:
return
if entity is None:
return
try:
subscription = await natuum._entity.subscribeEntity(entity, 'hello', None, self)
except natuum._entity.error.SubscribeFailed:
return
else:
self._AccountSession__gatewaySubscription = subscription
self._AccountSession__connected = True
LOG_INFO('Connection to game server established')
async def disconnect(self, forced=True):
if not self._AccountSession__connected:
return
LOG_INFO('Connection to game server closed')
self._AccountSession__connected = False
self._AccountSession__gatewaySubscription = None
self._AccountSession__NGSClient = None
self._AccountSession__JYPClient = None
await natuum.client.app.Instance.ClusterGuestNode.shutdown()
self.OnDisconnected.emit(forced, self.KickOutMessage)
self.KickOutMessage = None
def setAuthenticationWaitingCallback(self, onConntionQueueChanged, onAccountAuthenticatedAfterWaitingQueue):
self._AccountSession__weakOnConntionQueueChangedCallback = weakref.WeakMethod(onConntionQueueChanged) if onConntionQueueChanged is not None else None
self._AccountSession__weakOnAccountAuthenticatedAfterWaitingQueueCallback = weakref.WeakMethod(onAccountAuthenticatedAfterWaitingQueue) if onAccountAuthenticatedAfterWaitingQueue is not None else None
[USER=1333341624]Property[/USER]
def Connected(self) -> 'bool':
return self._AccountSession__connected
[USER=1333341624]Property[/USER]
def AccountID(self) -> 'str':
return self._AccountSession__accountID
[USER=162874]account[/USER]ID.setter
def AccountID(self, accountID: 'str'):
self._AccountSession__accountID = accountID
[USER=1333341624]Property[/USER]
def KickOutMessage(self) -> 'str':
return self._AccountSession__kickoutMessage
[USER=2000007488]KickOut[/USER]Message.setter
def KickOutMessage(self, msg: 'str'):
self._AccountSession__kickoutMessage = msg
[USER=1333341624]Property[/USER]
def GatewaySubscription(self):
return self._AccountSession__gatewaySubscription
def setupNGS(self):
LOG_INFO('NGS:setupNGS')
if self._AccountSession__NGSClient is not None:
return
natuum.client.app.Instance.nxlog.stageLog(510, 'setupNGS')
def _sendMessage(weakSubscription, data):
subscription = weakSubscription()
if subscription is not None:
_data = data.tobytes()
subscription.MessageProxy.onNGSMessageReceived(_data, nowait=True)
def _callSendMessage(loop, weakSelf, data):
loop.call_soon_threadsafe(_sendMessage, weakSelf, data)
callableFactory = thing.Common.CallableFactory()
args = thing.Collection.Array()
args.append(asyncio.get_event_loop())
args.append(weakref.ref(self._AccountSession__gatewaySubscription))
args.append(callableFactory.PlaceHolder[1])
sendNGSMessage = callableFactory.bind(_callSendMessage, '__call__', args.iterate())
self._AccountSession__NGSClient = thing.NGSClient.NGSClient(sendNGSMessage)
if not self._AccountSession__NGSClient.isInitialized():
natuum.client.app.Instance.showWindowsMessageBox('NGS 초기화에 실패하여 프로그램을 종료합니다.')
natuum.client.app.Instance.GameLogic.turnOffGame()
natuum.client.app.Instance.nxlog.stageLog(520, 'setupNGS')
def setupJYP(self, nexonID):
LOG_INFO('NGS:setupJYP')
if self._AccountSession__JYPClient is not None:
return
self._AccountSession__JYPClient = thing.JYP.JYPClient(nexonID)
self._AccountSession__JYPClient.collectThisThread()
def onFrameRenderForJYP(self):
if self._AccountSession__JYPClient is not None:
self._AccountSession__JYPClient.onFrameRender()
def onZoneEnterForJYP(self, zoneID):
if self._AccountSession__JYPClient is not None:
self._AccountSession__JYPClient.onSetZone(zoneID)
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
def doAnything(self, *args, **kwds):
pass
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
def onBeginTransfer(self, targetZoneName: str):
self.OnBeginTransferMessage.emit(targetZoneName)
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
def onPrepareTransfer(self, zoneStyle: str):
self.OnPrepareTransferMessage.emit(zoneStyle)
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
async def onFinishTransfer(self, zoneEntityID: 'thing.system.uuid or None', reason: str, isTimeout: bool):
self.OnFinishTransferMessage.emit(zoneEntityID, reason, isTimeout)
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
def onNGSMessageReceivedFromServer(self, data):
if self._AccountSession__NGSClient is not None:
self._AccountSession__NGSClient.onReceive(data)
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
async def notifyKickOut(self, type, errorCode):
LOG_INFO('서버에 의해 게임을 강제 종료:{},{}.'.format(type, errorCode))
text = '서버에 의해 프로그램이 종료됩니다.\n\n사유 : {}\n에러 코드 :{}'.format(type, errorCode)
self._AccountSession__kickoutMessage = text
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
async def notifyServerClock(self, now):
Instance._setServerTime(now)
[USER=186209]Thing[/USER].overrides(natuum._entity.IEntitySubscriber)
def onMessage(self, serial: 'int', message: 'var'):
pass
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
async def checkAlive(self, channelID=None):
pass
[USER=186209]Thing[/USER].overrides(natuum._entity.IEntitySubscriber)
def onChannelStatusChanged(self, status: 'int', detailedStatus: 'str'):
asyncio.ensure_future_and_forget(self.disconnect())
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
def onConnectionQueueChanged(self, left: 'int'):
callback = self._AccountSession__weakOnConntionQueueChangedCallback()
if callback is not None:
callback(left)
[USER=215285]mess[/USER]ageRPC.impl(IGatewaySubscriber)
def onAccountAuthenticatedAfterWaitingQueue(self, userID: 'str', actors: 'collections.Sequence'):
callback = self._AccountSession__weakOnAccountAuthenticatedAfterWaitingQueueCallback()
if callback is not None:
callback(userID, actors)
_AccountSession__connected = None
class EngineConfig:
def __init__(self, id: 'str', config: 'collisions.Mapping'):
self._EngineConfig__id = id
self._EngineConfig__config = config
[USER=1333341624]Property[/USER]
def ID(self):
return self._EngineConfig__id
[USER=1333341624]Property[/USER]
def Config(self):
return self._EngineConfig__config
def apply(self):
pass
def onReload(self, newFactory):
self._EngineConfig__config = newFactory._EngineConfig__config
self.apply()
_EngineConfig__id = None
_EngineConfig__config = None
# okay decompiling app.pyc
def __collectMarkerResources(self):
def collectResourceIDs(value, resourceIDs_):
if isinstance(value, str) and natuum.builder.isResourceID(value):
name, typeName, _ = natuum.builder.splitID(value)
resourceIDs_[typeName].add(name)
elif not isinstance(value, str) or isinstance(value, collections.Sequence):
for value_ in value:
collectResourceIDs(value_, resourceIDs_)
elif isinstance(value, collections.Mapping):
for value_ in value.values():
collectResourceIDs(value_, resourceIDs_)