Recently, I was programming a Python MMORPG using repl.it's database system. However, I ran into an error that I have no idea how to fix. I am trying to make a key in the database that lists all the humanoids in a certain area, so that different screens can see the same humanoids. But it is erroring and giving the same error no matter what I do: ValueError: Circular reference detected
. (My code will only work on replit, because it uses replit's database system.)
Error Message:
Traceback (most recent call last):
File "main.py", line 156, in <module>
db["humanoids_in_"+background[1]] = humanoids
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/replit/database/database.py", line 491, in __setitem__
self.set(key, value)
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/replit/database/database.py", line 500, in set
self.set_raw(key, _dumps(value))
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/replit/database/database.py", line 56, in dumps
return json.dumps(val, separators=(",", ":"), cls=DBJSONEncoder)
File "/usr/lib/python3.8/json/__init__.py", line 234, in dumps
return cls(
File "/usr/lib/python3.8/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.8/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
ValueError: Circular reference detected
Main File Code:
import pygame
from pygame.locals import *
from replit import db
from config import *
import replit
# STATS FORMAT: 0: Password, 1: Level, 2: Abilities
# IF: you can't see the full screen THEN: put your zoom to 80/70%
# IF: the program is loading infinitely THEN: reload
# IF: click is not being detected THEN: try a lighter click (usually works) or harder click (or just try again until it works)
screen = pygame.display.set_mode((700, 800))
pygame.display.set_caption("Alterpolis")
clock = pygame.time.Clock()
pygame.init()
Player = Humanoid(20, ["Punch", "Rock Throw"], (325, 375))
humanoids.append(Player)
# Bandit = Humanoid(15, ["Punch", "Rock Throw"], ai=True) MAKE BANDIT BODY PARTS
#enemies = [Bandit]
replit.clear()
while True:
clock.tick(1000)
screen.fill(BLACK)
for event in pygame.event.get():
if event.type == QUIT:
quit()
if event.type == MOUSEBUTTONDOWN:
mousepos = event.pos
if stage == "main_menu":
if touching(mousepos[0], mousepos[1], 225, 400, 180, 120) == True:
stage = "account"
box_selected = "login_button"
if stage == "account":
if touching(mousepos[0], mousepos[1], 650, 350, 20, 20) == True:
if "username" not in selected:
selected = "username_typing_box"
else:
seleted = ""
if touching(mousepos[0], mousepos[1], 650, 385, 20, 20) == True:
if selected != "password_typing_box":
selected = "password_typing_box"
else:
selected = ""
if touching(mousepos[0], mousepos[1], 210, 425, 100, 150) == True:
# Login button
box_selected = "login_button"
if touching(mousepos[0], mousepos[1], 20, 425, 100, 150) == True:
# Create account button
box_selected = "create_account_button"
if touching(mousepos[0], mousepos[1], 20, 550, 200, 200) == True:
# submit button
if box_selected == "login_button":
try:
if typing_password in db["UserStats="+typing_username]:
print("Successfully signed in!")
user_stats = db["UserStats="+typing_username]
Player.stats = user_stats
stage = "actual_game"
selected = ""
except:
print("Incorrect password/username.")
if box_selected == "create_account_button":
try:
if db["UserStats="+typing_username]:
print("Username already used.")
except:
db["UserStats="+typing_username] = [typing_password, 1, []]
user_stats = db["UserStats="+typing_username]
Player.stats = user_stats
print("Account created successfully!")
stage = "actual_game"
selected = ""
if event.type == KEYDOWN:
if selected == "username_typing_box":
if event.key == K_LSHIFT or event.key == K_RSHIFT:
event.key = 1
char = chr(event.key)
if event.key == K_BACKSPACE:
typing_username = typing_username.rstrip(typing_username[-1])
else:
typing_username = typing_username + char
if selected == "password_typing_box":
char = chr(event.key)
if event.key == K_BACKSPACE:
typing_password = typing_password.rstrip(typing_password[-1])
typing_password_shown = typing_password_shown.rstrip(typing_password_shown[-1])
else:
typing_password = typing_password + char
typing_password_shown = typing_password_shown + "*"
if stage == "actual_game":
if event.key == K_UP:
Player.up = True
if event.key == K_DOWN:
Player.down = True
if event.key == K_LEFT:
Player.left = True
if event.key == K_RIGHT:
Player.right = True
try:
Player.process(chr(event.key))
except:
pass
if event.type == KEYUP:
if stage == "actual_game":
if event.key == K_UP:
Player.up = False
if event.key == K_DOWN:
Player.down = False
if event.key == K_LEFT:
Player.left = False
if event.key == K_RIGHT:
Player.right = False
if stage == "main_menu":
screen.blit(title_screen, (0,0))
screen.blit(play_button, (225, 400))
elif stage == "account":
screen.blit(title_screen, (0,0))
show_text("Username: "+typing_username, 20, 350, WHITE, 20, screen)
show_text("Password: "+typing_password_shown, 20, 380, WHITE, 20, screen)
# Username Interaction Button
screen.blit(white_box, (650, 355))
# Password Interaction Button
screen.blit(white_box, (650, 385))
if box_selected == "login_button":
screen.blit(login_box_selected, (210, 425))
else:
screen.blit(login_box_unselected, (210, 425))
if box_selected == "create_account_button":
screen.blit(create_account_box_selected, (20, 425))
else:
screen.blit(create_account_box_unselected, (20, 425))
screen.blit(submit_button, (20, 550))
elif stage == "actual_game":
Player.name = typing_username
Player.tick(screen)
screen.blit(background[0], (0,0))
screen.blit(player_char, (Player.headpos))
show_text(background[1], 10, 10, BLACK, 25, screen)
for i in humanoids:
show_text(i.name, i.headpos[0] - (len(i.name) * 3.5), i.headpos[1] - 25, BLACK, 25, screen)
show_text("Level: "+str(i.stats[1]), i.headpos[0] - (len("Level: "+str(i.stats[1])) * 3.5), i.headpos[1] - 50, BLACK, 25, screen)
show_text(str(i.health) + "/" + str(i.maxhealth), i.headpos[0] - (len(str(i.health) + "/" + str(i.maxhealth)) * 3.5), i.headpos[1] - 75, GREEN, 25, screen)
v = 0
for i in humanoids:
if i.name == typing_username:
humanoids[v] = Player
v = v + 1
db["humanoids_in_"+background[1]] = humanoids
for i in humanoids:
if i.ticks > 0:
i.ticks = i.ticks - 1
if i.ticktype == "PUNCH":
screen.blit(impact_circle, i.tickpos)
i.canmove = False
else:
i.canmove = True
pygame.display.update()
Config File Code:
import pygame
from pygame.event import *
from pygame.locals import *
import random
ticks = 0
ticktype = 'NONE'
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
WHITE = (255,255,255)
BLACK = (0,0,0)
PURPLE = (102, 0, 204)
BROWN = (139,69,19)
COLORS = [RED, GREEN, BLUE, PURPLE, BROWN]
GOLD = (255,215,0)
pygame.init()
humanoids = []
screen = pygame.display.set_mode((1,1))
stage = "main_menu"
play_button = pygame.image.load("assets/play_button.png")
play_button = pygame.transform.scale(play_button, (180, 120)).convert()
title_screen = pygame.image.load("assets/title_screen.png").convert()
account_screen = pygame.image.load("assets/account_screen.png").convert()
white_box = pygame.image.load("assets/white_box.png").convert()
login_box_selected = pygame.image.load("assets/login-account-selected.png").convert()
login_box_unselected = pygame.image.load("assets/login-account-unselected.png").convert()
create_account_box_selected = pygame.image.load("assets/create-account-selected.png").convert()
create_account_box_unselected = pygame.image.load("assets/create-account-unselected.png").convert()
impact_circle = pygame.transform.scale(pygame.image.load("assets/impact_circle.png"), (60, 60))
submit_button = pygame.image.load("assets/submit-button.png").convert()
error_notification = pygame.image.load("assets/error.png").convert()
ai_unselected = pygame.image.load("assets/ai-unselected.png").convert()
ai_selected = pygame.image.load("assets/ai-selected.png").convert()
player_unselected = pygame.image.load("assets/player-unselected.png").convert()
player_selected = pygame.image.load("assets/player-selected.png").convert()
battle_arena = pygame.image.load("assets/battle-arena.png").convert()
player_char = pygame.image.load("assets/characters/main_char.png")
test_place = pygame.image.load("assets/locations/test_place.png")
events = {"Punch":impact_circle}
typing_username = ""
typing_password = ""
typing_password_shown = ""
selected = ""
box_selected = ""
user_stats = []
attacks_database = {"Punch" : 2, "Rock Throw" : 4, "Pheonix Strike" : 100000000000000000}
background = [test_place, "Test Place"]
class Humanoid():
def __init__(self, maxhealth, moves, headpos, ai = False, health=1, speed = 0.4, name = "none"):
self.maxhealth = maxhealth
self.headpos = headpos
self.up = False
self.down = False
self.right = False
self.left = False
self.speed = speed
self.name = name
self.stats = []
self.ticks = 0
self.ticktype = "NONE"
self.tickpos = (0,0)
self.canmove = True
if health == 1:
self.health = maxhealth
else:
self.health = health
self.moves = moves
self.ai = ai
def tick(self, window):
if self.health <= 0:
self.delete()
if self.canmove == True:
if self.up == True:
self.headpos = (self.headpos[0], self.headpos[1] - self.speed)
elif self.down == True:
self.headpos = (self.headpos[0], self.headpos[1] + self.speed)
if self.left == True:
self.headpos = (self.headpos[0] - self.speed, self.headpos[1])
elif self.right == True:
self.headpos = (self.headpos[0] + self.speed, self.headpos[1])
if self.ai == True:
self.move = random.choice(moves)
# execute the move in target direction if target in range. if not in range then move towards target.
show_text(self.name, self.headpos[0] - (len(self.name) / 2), self.headpos[1] + 20, BLACK, 25, window)
def process(self, key):
key = key.lower()
if key == "q":
screen.blit(trigger_server_event(self.moves[0]), self.headpos)
self.ticktype = "PUNCH"
self.ticks = 175
self.tickpos = (self.headpos[0] - 17, self.headpos[1] - 17)
enemies = []
#touching - checks for touch
def touching(obj1x,obj1y,obj2x,obj2y,obj2length, obj2width):
if obj1x in range(obj2x, obj2x + obj2length - 1) and obj1y in range(obj2y, obj2y + obj2length - 1):
return True
else:
return False
if obj1x in range(obj2x, obj2x + obj2width - 1) and obj1y in range(obj2y, obj2y + obj2width + 1):
return True
else:
return False
#show_text - displays pygame text
def show_text(msg, x, y, color, size, screen):
fontobj= pygame.font.SysFont("freesans", size)
msgobj = fontobj.render(msg,False,color)
screen.blit(msgobj,(x, y))
def trigger_server_event(event):
return events[event]