OK - I've updated the cruise script example. I found a bug with the UDP connection when using InSim and pushed a fix onto the
CodePlex repository. You may need to get the latest source revision if you want to use a separate port for position updates at the moment. I have removed the UDPPort setting from the cruise example until I can get round to creating a proper release.
Anyway here is the cruise script updated for pyinsim 2.0. I also made a couple of tweaks to the way commands work to make them simpler. You will need to create a subdirectory called 'users' in the script folder, which is where it stores user info.
# Make sure correct version of pyinsim is imported.
VERSION = '2.0.0'
try:
import pyinsim
if not pyinsim.version(VERSION):
raise ImportError
except ImportError:
print 'You must install pyinsim %s or better' % VERSION
import sys
sys.exit(1)
# Dependencies.
import cPickle
import os
import threading
# Constants.
HOST = '127.0.0.1'
PORT = 29999
ADMIN = ''
PREFIX = '!'
UDPPORT = 30000
INTERVAL = 1000 # Milliseconds
PROG_NAME = 'PyCruise'
CASH_MULTIPLIER = 2 # Dollars per second
STARTING_CARS = ['UF1',]
STARTING_CASH = 10000 # Dollars
HEARTBEAT_INTERVAL = 1 # Seconds
USER_DIR = 'users'
HOST_ID = 0
SPEED_DEADZONE = 10
CAR_PRICES = {'XFG': 4500, 'XRG': 6000, 'FBM': 150000, 'XRT': 14000, 'RB4': 12000,
'FXO': 12000, 'LX4': 15000, 'LX6': 25000, 'MRT': 30000,'UF1': 3000,
'RAC': 30000, 'FZ5': 38000, 'XFR': 50000, 'UFR': 45000, 'FOX': 150000,
'FO8': 165000, 'BF1': 350000, 'FXR': 120000, 'XRR': 120000, 'FZR': 130000}
WELCOME_MSG = '''Welcome to %s
For help type ^3!help
Website: www.pyinsim.codeplex.com
Good luck and behave yourself!''' % PROG_NAME
ADMIN_USERNAMES = ('DarkTimes',) # Set list of admins LFSWorld usernames.
# Global variables.
connections = {}
players = {}
# Class to store user info.
class UserVars:
def __init__(self):
self.dist = 0
self.cash = STARTING_CASH
self.cars = STARTING_CARS
# Draw on-screen display.
def draw_osd(insim, ncn):
insim.send(pyinsim.ISP_BTN, ReqI=1, UCID=ncn.UCID, ClickID=1,
BStyle=pyinsim.ISB_DARK | 3, T=4, L=85, W=30, H=6,
Text='Cash: $%d | Distance: %.2f Km' % (ncn.vars.cash, ncn.vars.dist))
# Called every second to update cash and OSD.
def heartbeat(insim):
for ncn in connections.values():
if ncn.UCID != HOST_ID:
if ncn.speed > SPEED_DEADZONE:
ncn.vars.cash += CASH_MULTIPLIER
draw_osd(insim, ncn)
if insim.connected:
threading.Timer(HEARTBEAT_INTERVAL, heartbeat, [insim]).start()
# Load user info from file.
def load_user_vars(uname):
path = os.path.join(USER_DIR, uname)
if os.path.exists(path):
try:
with open(path, 'r') as f:
return cPickle.load(f)
except IOError as err:
print 'Load Error:', err
return UserVars() # Default
# Save user info to file.
def save_user_vars(uname, vars):
path = os.path.join(USER_DIR, uname)
try:
with open(path, 'w') as f:
cPickle.dump(vars, f)
except IOError as err:
print 'Save Error:', err
# Request all connections and players to be sent.
def req_conns(insim):
insim.send(pyinsim.ISP_TINY, ReqI=1, SubT=pyinsim.TINY_NCN)
insim.send(pyinsim.ISP_TINY, ReqI=1, SubT=pyinsim.TINY_NPL)
# New connection joined host
def new_conn(insim, ncn):
if ncn.UCID != HOST_ID:
ncn.vars = load_user_vars(ncn.UName)
ncn.speed = 0.0
ncn.last_pos = [0,0,0]
ncn.current_car = None
connections[ncn.UCID] = ncn
if ncn.UCID != HOST_ID:
for line in WELCOME_MSG.splitlines():
insim.sendm('^3| ^7%s' % line, ucid=ncn.UCID)
# Connection left host.
def conn_left(insim, cnl):
if cnl.UCID != HOST_ID:
ncn = connections[cnl.UCID]
save_user_vars(ncn.UName, ncn.vars)
del connections[cnl.UCID]
# Player tries to join track.
def new_ply(insim, npl):
players[npl.PLID] = npl
ncn = connections[npl.UCID]
if npl.CName in ncn.vars.cars:
ncn.current_car = npl.CName
else:
insim.sendm('/spec %s' % ncn.UName)
insim.sendm('^3| ^7You do not own the %s' % npl.CName, ncn.UCID)
insim.sendm('^3| ^7Type ^3!cars ^7to see which cars you own', ncn.UCID)
# Player leaves track.
def ply_left(insim, pll):
npl = players[pll.PLID]
ncn = connections[npl.UCID]
ncn.vars.current_car = None
del players[pll.PLID]
# Print out car prices ordered by price.
def cmd_prices(insim, ncn, args):
cars = CAR_PRICES.items()
cars.sort(key=lambda c: c[1])
insim.sendm('^3| ^7Car Prices:', ncn.UCID)
for car, price in cars:
insim.sendm('^3| ^7%s: $%d' % (car, price), ncn.UCID)
# Buy a new car.
def cmd_buy(insim, ncn, args):
if args:
car = args[0].upper()
if car in ncn.vars.cars:
insim.sendm('^3| ^7You already own the %s' % car, ncn.UCID)
elif car not in CAR_PRICES:
insim.sendm('^3| ^7The car %s does not exist' % car, ncn.UCID)
elif CAR_PRICES[car] > ncn.vars.cash:
insim.sendm('^3| ^7You need $%d more cash to afford the %s' % (CAR_PRICES[car] - ncn.vars.cash, car), ncn.UCID)
else:
ncn.vars.cash -= CAR_PRICES[car]
ncn.vars.cars.append(car)
insim.sendm('^3| ^7You bought the %s for $%d' % (car, CAR_PRICES[car]), ncn.UCID)
insim.sendm('^3| ^8%s ^7bought the %s!' % (ncn.PName, car))
else:
insim.sendm('^3| ^7Usage: !buy <car>', ncn.UCID)
# Sell an owned car.
def cmd_sell(insim, ncn, args):
if args:
car = args[0].upper()
if car not in CAR_PRICES:
insim.sendm('^3| ^7The car %s does not exist' % car, ncn.UCID)
elif car not in ncn.vars.cars:
insim.sendm('^3| ^7You do not own the %s' % car, ncn.UCID)
else:
ncn.vars.cash += CAR_PRICES[car]
ncn.vars.cars.remove(car)
insim.sendm('^3| ^7You have sold the %s for $%d' % (car, CAR_PRICES[car]), ncn.UCID)
insim.sendm('^3| ^8%s ^7sold the %s' % (ncn.PName, car))
if car == ncn.current_car:
insim.sendm('/spec %s' % ncn.UName)
insim.sendm('^3| ^7You no longer own the %s' % car, ncn.UCID)
else:
insim.sendm('^3| ^7Usage: !sell <car>', ncn.UCID)
# Print list of owned cars ordered by price.
def cmd_cars(insim, ncn, args):
cars = [(c, CAR_PRICES[c]) for c in ncn.vars.cars]
cars.sort(key=lambda c: c[1])
insim.sendm('^3| ^7Currently Owned Cars:', ncn.UCID)
for car, price in cars:
insim.sendm('^3| ^7%s: $%d' %(car, price), ncn.UCID)
def cmd_location(insim, ncn, args):
if ncn.current_car:
x = pyinsim.length(ncn.last_pos[0])
y = pyinsim.length(ncn.last_pos[1])
z = pyinsim.length(ncn.last_pos[2])
insim.sendm('^3| ^7X: %d Y: %d Z: %d' % (x, y, z), ncn.UCID)
else:
insim.sendm('^3| ^7You are not currently in a car', ncn.UCID)
def cmd_save(insim, ncn, args):
if ncn.UName in ADMIN_USERNAMES:
[save_user_vars(n.UName, n.vars) for n in connections.values() if n.UCID]
insim.sendm('^3| ^7The users have been saved', ncn.UCID)
else:
insim.sendm('^3| ^7You are not an admin', ncn.UCID)
# Print usage info.
def cmd_help(insim, ncn, args):
insim.sendm('^3| ^7Usage Info:', ncn.UCID)
insim.sendm('^3| !help ^7- Show this message', ncn.UCID)
insim.sendm('^3| !prices ^7- View car prices', ncn.UCID)
insim.sendm('^3| !cars ^7- See what cars you currently own', ncn.UCID)
insim.sendm('^3| !buy <car> ^7- Buy a new car', ncn.UCID)
insim.sendm('^3| !sell <car> ^7- Sell an owned car', ncn.UCID)
insim.sendm('^3| !location ^7- See your coordinates')
CMD_LOOKUP = {'!prices': cmd_prices, '!buy': cmd_buy, '!sell': cmd_sell,
'!cars': cmd_cars, '!help': cmd_help, '!loc': cmd_location,
'!save': cmd_save}
# Handle command message from LFS.
def message_out(insim, mso):
if mso.UserType == pyinsim.MSO_PREFIX:
args = mso.Msg[mso.TextStart:].split()
if args:
cmd = args[0].lower()
if cmd in CMD_LOOKUP:
ncn = connections[mso.UCID]
CMD_LOOKUP[cmd](insim, ncn, args[1:])
else:
insim.sendm('^3| ^7Unknown command \'^3%s^7\'' % cmd, mso.UCID)
# Calculate distance travelled.
def add_distance(ncn, car):
curr_pos = (car.X, car.Y, car.Z)
if ncn.last_pos and car.Speed > SPEED_DEADZONE:
dist = pyinsim.dist(ncn.last_pos, curr_pos)
ncn.vars.dist += pyinsim.length(dist) / 1000 # Km
ncn.last_pos = curr_pos
# Player MCI updates.
def car_info(insim, mci):
for car in mci.Info:
npl = players.get(car.PLID)
if npl:
ncn = connections[npl.UCID]
ncn.speed = car.Speed
add_distance(ncn, car)
# Save user vars if connection is lost.
def closed(insim):
for ncn in connections.values():
if ncn.UCID != HOST_ID:
save_user_vars(ncn.UName, ncn)
def init(insim):
print '%s is running!' % PROG_NAME
insim.sendm('/canreset no')
insim.sendm('/cruise yes')
insim.sendm('/laps 0')
if __name__ == '__main__':
print '%s' % PROG_NAME
print ''.rjust(len(PROG_NAME), '-')
print
print 'Starting cruise server...'
# Initialize InSim and bind events.
insim = pyinsim.insim(HOST, PORT, IName='^7%s' % PROG_NAME, Prefix=PREFIX,
Flags=pyinsim.ISF_MCI, Interval=INTERVAL, Admin=ADMIN, UDPPort=UDPPORT)
insim.bind(pyinsim.ISP_NCN, new_conn)
insim.bind(pyinsim.ISP_CNL, conn_left)
insim.bind(pyinsim.ISP_NPL, new_ply)
insim.bind(pyinsim.ISP_PLL, ply_left)
insim.bind(pyinsim.ISP_MSO, message_out)
insim.bind(pyinsim.ISP_MCI, car_info)
insim.bind(pyinsim.EVT_INIT, init)
insim.bind(pyinsim.EVT_CLOSE, closed)
# Request players and connections.
req_conns(insim)
# Start heartbeat timer.
threading.Timer(HEARTBEAT_INTERVAL, heartbeat, [insim]).start()
# Run pyinsim!
pyinsim.run()
print 'Server exiting as no hosts connected'