EverQuest Project 1999

12 May 2012

Project 1999

I started playing the amazing MMORPG computer game, EverQuest (often abbreviated as “EQ”), almost a year after it was released in 1999. What followed was five or more years of pure gaming bliss, consisting of fun friendships and even an authentic sense of [digital] accomplishment. While the game still lives on successfully even as of my writing this post, numerous expansions and changes have altered the game from its originally challenging and people-dependent playing style. Ever since, players have longed for a way to go back to the glory days of EverQuest, and thankfully, Project 1999 provides that exact opportunity!

As quoted from its home page at project1999.org, “Project 1999 is a free to play Emulated EverQuest Server giving players the opportunity to experience Classic EQ Once again, starting with the original 3 continents and a max level of 50 [increased to 60 with the subsequent release of Kunark and Velious], with the look and feel of the old interface and several modifications making game mechanics similar to how the game used to be. Project 1999 is the best and most popular classic EverQuest experience.” Even though it is free to play, the server is supported by player donations and professionally maintained and monitored by developers and in-game GMs. Although it is a progression server, Velious will be its final expansion, at least as of now.

Soon after I learned of the Project 1999 (P99), I acquired the appropriate software (EverQuest Titanium edition client), made the necessary changes and started playing. If you have already legally purchased EverQuest software in the past, the appropriate version is available via download through BitTorrent or similar sources. You can also purchase it from Amazon or eBay. The P99 web site details the steps necessary to get the game working correctly, and a custom EQEmu patcher is available to make the necessary modifications easier. Furthermore, if the pre-Luclin look of the game is just too dated for you, you can download the Luclin enhanced texture versions of all the game zones from the P99 forums.

So far I have loving playing P99 just as much as I did over a decade ago. The quality of this game really shines even against current MMOs. So whether you are a veteran EQ player or have only just learned of it, be sure to give Project 1999 a try and relive EverQuest the way it was meant to be played!


Simple Python Chat Client & Server

15 March 2012

Provided below is the source code for a relatively simply Python chat client and server program solution which serves as a functional example of socket programming. I apologize for the squished formatting and lack of white space in the source viewer, but viewing the source directly from the text box button should make it a little more readable.

The first file is the server which should run fine on any modern Linux operating system. The client should also be run on Linux, and can connect to the server from any networked computer on the same subnet. I have had some success connecting this client/server to a similar program written in Java, though you may need to play around with the buffer sizes in each.

I also included a few custom commands for the client to execute. The comments in the source should be sufficient to explain what is going on to experienced Python programmers. I know I am terrible for this, but I cannot remember from where I took the original source code before modifying it. Enjoy!

Client.py

import socket
import sys
import time
# Default connection parameters
client_host = "localhost" #Address of server
client_port = int(9020) #Port used by server
time = time.strftime('%l:%M %p %Z on %b %d, %Y') # Client start time
login_time = str(time) #Convert client start time to string
print "Client initiated at: " + login_time
# Override default parameters (optional command line arguments)
if(len(sys.argv) > 1): #One parameter argument provided by client
 client_host = sys.argv[1] #Override host server IP default "localhost" w/ first argument
if(len(sys.argv) > 2): #Two parameter arguments provided by client
 client_port = int(sys.argv[2]) #Override host port number w/ second argument
# Set up client socket connection
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((client_host, client_port))
# Loop indefinitely while client running
while 1:
 server_data = client_socket.recv(2048) #Receive server data into buffer
 client_data = server_data.lower() #Lowercase received data for processing

 # Process received data
 if (client_data == 'adios'):
 client_socket.close() #Close socket connection
 break;
 else:
 print "(SERVER REPLY)",server_data #Feedback from server
 server_data = raw_input("SEND TO SERVER>> ") #Get client input from keyboard
 client_data = server_data.lower() #Lowercase client input

 # Sent commands
 if (client_data != 'adios'):
 client_socket.send(server_data + "\r\n") #Send data to server if not "adios"
 else:
 client_socket.send(server_data + "\r\n")
 client_socket.close #Otherwise close the socket connection
 break;

Server.py

import os
import re
import socket
import sys
import time
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Create socket
server_socket.bind(("", 9020)) #Bind server to this socket
server_socket.listen(4) #Max number of queued connections
# Welcome message
print "TCP chat server now awaiting client connection on port 9020..."
chat_log = [] #Contains chat log
time = time.strftime('%l:%M %p %Z on %b %d, %Y') #Server start time formatted nicely
start_time = str(time) #Convert server start time to string
username = "ChatUser" #Default server username if user does not provide one
# Support ~2^x client connections, where x is the number of process forks
os.fork()
os.fork()
os.fork()
# This variable contains the help documentation for the "help" command
chatHelp = ("The chat server accepts the following commands:\n"
+ "adios Closes the program\n"
+ "connection Shows client connection info (IP, port)\n"
+ "get Returns complete chat log\n"
+ "getrange <#> <#> Get chat log entries from <#> to <#> (starts at 1)\n"
+ "help Lists valid commands\n"
+ "name: <text> Sets your username to <text>\n"
+ "test: <text> Echo data back to you <text>\n"
+ "time Shows time when server was initiated\n"
+ "push: <text> Add <text> to chat log\n"
+ "save Save chat log to file\n")
while 1:
 # Accept connection
 client_socket, address = server_socket.accept()

 # Print connection info from client for server log
 print "Received connection from client at", address
# Used in the connection command function (client request) below
 connection = str(address)
# Send welcome string to client
 client_socket.send("Welcome to Nigel's chat room! You are logged in as ChatUser.\n Type help for a list of valid commands.\n")
# Loop indefinitely while server running
 while 1:
 data = client_socket.recv(2048) #Receive client data into buffer
 process_data = data.lower() #Lowercase received data for processing
 print "Data received from client>>", process_data #Print data received from client for log reference

 # Functions for the received commands (I use the find library to reduce compatibility errors with other languages)
 # ---"adios" command function---
 if (process_data.find("adios") == 0):
 client_socket.close() #Close socket connection
 print "<Ctrl+C to exit.>>"
 break;

 # ---"connection:" command function---
 elif(process_data.find("connection") == 0):
 client_socket.send("Client connection info: " + connection + "\n")
 print "User requested connection information"

 # ---"getrange" command function w/ regular expression filtering (must be BEFORE "get" command function)---
 elif(re.match(r'getrange\s+(\d+)\s+(\d+)',process_data)): # Regex to find correct match with dynamic numbers input
 match = re.match(r'getrange\s+(\d+)\s+(\d+)',process_data)
 getValue = "Chat log from range "+ match.group(1) + " and " + match.group(2) + ":\n" # Grab first and second range number provided by client
 if(len(chat_log) >= int(match.group(1)) and len(chat_log) >= int(match.group(2))): # Check to see if chat log extends to given range
 count = int(match.group(1)) - 1
 while(count < int(match.group(2))):
 getValue += chat_log[count] + "\n"
 count += 1
 else:
 getValue += "<>\n" #No data in range provided by client
 client_socket.send(getValue) #Send results to client
# ---"get" command function---
 elif(process_data.find("get") == 0):
 log = "Chat log: \n"
 for item in chat_log:
 log += item+" \n"
 client_socket.send(log)

 # ---"help:" command function---
 elif(process_data.find("help") == 0):
 client_socket.send(chatHelp + "\n")
 print "User requested help"

 # ---"name:" command function---
 elif(process_data.find("name:") == 0):
 username = data[5:].strip() #Only grab the value client set (not "name:")
 client_socket.send("Username set to: " + data[5:] + "\n")

 # ---"test:" command function---
 elif(process_data.find("test:") == 0):
 client_socket.send(data[5:]+"\n") #Echo last 5 elements to client
 print data

 # ---"time" command function---
 elif(process_data.find("time") == 0):
 client_socket.send("Chat server was started at: " + start_time + "\n")
 print "User requested server start time"

 # ---"save" command function---
 elif(process_data.find("save") == 0):
 print "(Saving chat log to file)"
 client_socket.send("Saving chat log to file..." + "\n")
 filename = "chat.log"
 file = open(filename,"w") #Create file
 for item in chat_log: #Loop through elements in chat_log
 file.write("%s\n" % item) #Write elements one by one on a new line
 file.close() #Close/write file

 # ---"push" command function---
 elif(process_data.find("push:") == 0):
 print "(Pushing data to chat log)"
 if(username != ""):
 chat_log.append(username + ": " + data[5:].strip()) #Save actual chat text to log (not "push:")
 else:
 chat_log.append(data[5:].strip())
 client_socket.send("OK\n")
 else:
 print "<<Unknown Data Received>>",data #Server log
 try:
 client_socket.send("Unrecognized command: " + data + "") #Advise client of invalid command
 except socket.error, e:
 print "<<Ctrl+C to exit>>" #Server log
 break;


File System Wars

7 December 2011

For a class presentation I edited a fun little video depicting a humorous battle between Unix File System (UFS), hierarchical file system (HFS), and extensible file system (ext). UFS is depicted by Darth Vader, HFS by Emperor Palpatine/Steve Jobs, and ext by Luke Skywalker.

Unless you’re a computer person familiar with file systems it might not make a whole lot of sense or seem funny at all, but at the very least Emperor Steve is pretty hilarious.

Click on the “Vimeo” button on the bottom right of the player to view a larger version of the video. Otherwise click play and enjoy!


Follow

Get every new post delivered to your Inbox.