Jump to content

Some Useful Python Scripts for Mappers and Server Admins


Recommended Posts

  • Premium

As we work with maps we accumulate a large number of unused textures which end up making the client / pack downloads for our server bigger. For this reason I made this little python 2.7 script.

It will read all the textureset files and the texture paths on it and copy to textureset_release/ only the textures that are actually being used by your maps, as listed in Settings.txt

The folder where the script looks for Settings.txt files recursively is "maps/", change it at the start of the code if yours is different. Likewise, it will look for "textureset/" and "terrainmaps/", and create "textureset_release/". No files will be deleted.

Disclaimer: The code is very ugly, I actually have no idea of python, I made this script looking at docs and based on my knowledge of other languages. If you actually know python I suggest you don't look at it to avoid hurting your eyes.

 

import os
import re
import string
import shutil
import sys

ct = 0
usedimg = []
usedsets = []
list = []
mapfolder = 'maps/'

class cd:
    """Context manager for changing the current working directory"""
    def __init__(self, newPath):
        self.newPath = os.path.expanduser(newPath)

    def __enter__(self):
        self.savedPath = os.getcwd()
        os.chdir(self.newPath)

    def __exit__(self, etype, value, traceback):
        os.chdir(self.savedPath)

def cleanValue(val):
	val = val.replace('\\', '/')
	val = val.strip(' \t\n"')
	val = val.lower()
	return val

def copyFile(src, dest):
    try:
        shutil.copy(src, dest)
    # eg. src and dest are the same file
    except shutil.Error as e:
        print('Error: %s' % e)
    # eg. source or destination doesn't exist
    except IOError as e:
        print('Error: %s' % e.strerror)

# Read the tab-separated value of a parameter "param" in all files named "fname" (can be an extension) in folder "folder"

def SaveParams(param,fname,folder,list):
	for path, subdirs, files in os.walk(folder):
		for filename in files:
			if filename.lower() == fname.lower() or (fname.startswith('.') and filename.endswith (fname)):
				f = os.path.join(path, filename)
				with open(f, "rt") as current:
					for line in current:
						lcline = line.lower() 
						lcparam = param.lower()
						if lcparam in lcline:
							# strip tabs and split values
							value = line.rstrip('\t\n')
							# get parameter value
							list.append(value)

# Read a value with the order number "order" within a parameter block "block" in all files named "fname" (can be an extension) in folder "folder" which are also in list "compare"

def SaveParamsFromBlock(block,order,fname,folder,list,compare):
	for path, subdirs, files in os.walk(folder):
		for filename in files:
			if filename in compare and (filename.lower() == fname.lower() or (fname.startswith('.') and filename.endswith (fname))):
				countblock = -1
				f = os.path.join(path, filename)
				with open(f, "rt") as current:
					for line in current:
						lcline = line.lower() 
						lcblock = block.lower()
						if countblock == order:
							list.append(line)							
							countblock = -1
						elif lcline.startswith(lcblock):
							countblock = 0
						elif countblock >= 0:
							countblock = countblock + 1

# move to the client data folder

with cd('..\client\data'):

	try:
		os.makedirs('terrainmaps_release')
	except:
		shutil.rmtree('terrainmaps_release')
		os.makedirs('terrainmaps_release')

	print "This script copies to terrainmaps_release only the textures which are actually listed in textureset files."
	print "The folder is emptied on each run. make_archive.py uses this folder as source for making the terrainmaps pack."
	print "This script is written to be run from the tools repo copy and assumes the client repo copy to be in the same base directory as tools"
	print ""
	select = raw_input("Press any key to start, e to exit")
	if str(select) == "e":
		sys.exit()
	
	# Get all the texturesets used in our maps

	SaveParams('TextureSet','Setting.txt','maps',usedsets)

	# Extract the filename part of the used TextureSet paths and write it back to the list
 
	for idx,val in enumerate(usedsets):
		val = cleanValue(val)
		parts = re.split('/', val.lower())
		# check its actually a terrainmaps path
		usedsets[idx] = parts[-1]

	# Fetch a list of the textures used in the sets used

	SaveParamsFromBlock('Start Texture',0,'.txt','textureset',usedimg,usedsets)

	# Copy the textures used in textureset_release

	for idx,val in enumerate(usedimg):
		# check its actually a terrainmaps path
		if  "terrainmaps" in val:
			val = cleanValue(val)
			val = val[len('d:/ymir work/terrainmaps/'):]
			usedimg[idx] = val.lower()
			srcPath = 'terrainmaps/' + usedimg[idx]
			destPath = 'terrainmaps_release/' + usedimg[idx]
			print "Copy " + srcPath + " to " + destPath
			if not os.path.isdir(os.path.dirname(destPath)):
				os.makedirs(os.path.dirname(destPath))
			copyFile(srcPath, destPath)
			ct = ct + 1
	print "Total " + str(ct) + " textures copied in terrainmaps_release"
	raw_input("Press any key to exit")

As a bonus another python 2.7 script used to create the property/list file with all your prb, pre. Assumes a property/ folder at the location where you run it.

 

import os
import math

count = 0
extensions = ('prb','prt','prd','pre','pra')
with open("property/list", "w") as a:
    for path, subdirs, files in os.walk(r'property'):
       	for filename in files:
        	f = os.path.join(path, filename)
        	if filename != "list" and filename !="reserve":
         		extension = filename.split ('.')[-1]
         		if (extension in extensions): 
            			a.write(str(f) + '\n')
         		else:
         			Print ("Strange file: " + f)
         		count = count + 1
print 'Total: ' + str(count) + ' files listed on property/list!'

raw_input("Press any key to exit")

 

And finally another script to copy all your msa and motlist.txt files to a server/data folder that you can upload later to your server. It will only copy when files are different or not existing at the destination. It assumes a ../client/data/npc (and so on) and ../server/data/monster etc. structure, feel free to edit the paths in the scripts to your needs.

 

import os
import shutil
from itertools import chain
import filecmp

pathList = []
count = 0

def copyFile(src, dest):
    try:
        shutil.copy(src, dest)
        return True
    # eg. src and dest are the same file
    except shutil.Error as e:
        print('Error: %s' % e)
    # eg. source or destination doesn't exist
    except IOError as e:
        print('Error: %s' % e.strerror)

print "This script moves all the .msa and motlist.txt files from pc monster and npc client folders to the appropiate server folders, creating them if necessary."
paths = ('../client/data/monster/', '../client/data/monster2/', '../client/data/npc/', '../client/data/npc2/', '../client/data/pc/', '../client/data/pc2/')
for path, dirs, files in chain.from_iterable(os.walk(path) for path in paths):
	for filename in files:
		if filename.endswith('.msa') or filename.endswith('.txt'):
			realpath = path.replace('\\', '/')
			cfolder = os.path.split(realpath)[1]
			gfolder = 'monster'
			if ('/pc/' in realpath):
				gfolder = 'pc/' + realpath.split('/')[4]
			elif ('/pc2/' in realpath):
				gfolder = 'pc2/' + realpath.split('/')[4]
			else:
				# Check for duplicated non-pc folders
				existingpath = next((s for s in pathList if ('/' + cfolder) in s), None)
				if existingpath and existingpath.endswith(cfolder):
					if realpath != existingpath:
						print("Warning: duplicate folders " + realpath + " and " + existingpath + "!")
						pathList.remove(existingpath)
						break
					elif path not in pathList:
						pathList.append(realpath)
				else:
					pathList.append(realpath)
				
			spath = realpath  + '/' + filename

			dpath = '../server/data/' + gfolder + '/' + cfolder
			# Create destination folder if not existing
			if not os.path.isdir(dpath):
				os.makedirs(dpath)
			dpath = dpath + '/' + filename
			# Copy file if destination is not existing or different
			if not os.path.exists(dpath) or not filecmp.cmp(spath,dpath):
				if copyFile(spath, dpath):
					print "Copied " + spath + " to " + dpath
					count = count + 1

print "Finished copying " + str(count) + " files!"
raw_input("Press any key to exit")

How to use: install python 2.7 anywhere on your hd (C:\Python27 for example), add this path to the system path, and save this code in a file named something.py, then run it by doubleclick

Remember to change directory to wherever you have your client files.

  • Love 7
Link to comment
Share on other sites

  • Management

Thanks for sharing!

The second I can't use, it doesn't do anything...

The second, I managed to get it to work on Python 3:

import os
import math

count = 0
extensions = ('prb','prt','prd','pre','pra')
with open("property/list", "w", encoding='utf-8') as a:
	for path, subdirs, files in os.walk(r'property'):
		for filename in files:
			f = os.path.join(path, filename)
			if filename != "list" and filename !="reserve":
				extension = filename.split ('.')[-1]
				if (extension in extensions): 
					a.write(str(f) + '\n')
				else:
					print ("Strange file: " + f)
				count = count + 1
print ('Total: ' + str(count) + ' files listed on property/list!')

input("Press any key to exit")

raw_input doesn't exist anymore, it's now knows as input.

print needs parenthesis.

I also added the encoding for the file, otherwise I would be getting a encoding message while it wrote the file and couldn't complete it.

raw

raw

Link to comment
Share on other sites

Announcements



  • Similar Content

  • Similar Content

  • Similar Content

  • Tags

  • Activity

    1. 3

      Crystal Metinstone

    2. 3

      Feeding game source to LLM

    3. 113

      Ulthar SF V2 (TMP4 Base)

    4. 3

      Feeding game source to LLM

    5. 0

      Target Information System

    6. 3

      Feeding game source to LLM

    7. 2

      anti exp explanation pls

  • Recently Browsing

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.