Compare commits
	
		
			4 Commits
		
	
	
		
			be32dec202
			...
			3f7205d73e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 3f7205d73e | |||
| 0731339fe8 | |||
| 71d42a8fd6 | |||
| 52ab45fe53 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| *.db | ||||
| @ -26,6 +26,8 @@ const ( | ||||
| 	Action_MOVE       Action_ActionType = 0 | ||||
| 	Action_CHAT       Action_ActionType = 1 | ||||
| 	Action_DISCONNECT Action_ActionType = 2 | ||||
| 	Action_LOGIN      Action_ActionType = 3 | ||||
| 	Action_REGISTER   Action_ActionType = 4 | ||||
| ) | ||||
|  | ||||
| // Enum value maps for Action_ActionType. | ||||
| @ -34,11 +36,15 @@ var ( | ||||
| 		0: "MOVE", | ||||
| 		1: "CHAT", | ||||
| 		2: "DISCONNECT", | ||||
| 		3: "LOGIN", | ||||
| 		4: "REGISTER", | ||||
| 	} | ||||
| 	Action_ActionType_value = map[string]int32{ | ||||
| 		"MOVE":       0, | ||||
| 		"CHAT":       1, | ||||
| 		"DISCONNECT": 2, | ||||
| 		"LOGIN":      3, | ||||
| 		"REGISTER":   4, | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| @ -76,6 +82,8 @@ type Action struct { | ||||
| 	Y             int32                  `protobuf:"varint,3,opt,name=y,proto3" json:"y,omitempty"` | ||||
| 	PlayerId      int32                  `protobuf:"varint,4,opt,name=player_id,json=playerId,proto3" json:"player_id,omitempty"` | ||||
| 	ChatMessage   string                 `protobuf:"bytes,5,opt,name=chat_message,json=chatMessage,proto3" json:"chat_message,omitempty"` | ||||
| 	Username      string                 `protobuf:"bytes,6,opt,name=username,proto3" json:"username,omitempty"` | ||||
| 	Password      string                 `protobuf:"bytes,7,opt,name=password,proto3" json:"password,omitempty"` | ||||
| 	unknownFields protoimpl.UnknownFields | ||||
| 	sizeCache     protoimpl.SizeCache | ||||
| } | ||||
| @ -145,13 +153,28 @@ func (x *Action) GetChatMessage() string { | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (x *Action) GetUsername() string { | ||||
| 	if x != nil { | ||||
| 		return x.Username | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (x *Action) GetPassword() string { | ||||
| 	if x != nil { | ||||
| 		return x.Password | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| type ActionBatch struct { | ||||
| 	state         protoimpl.MessageState `protogen:"open.v1"` | ||||
| 	PlayerId      int32                  `protobuf:"varint,1,opt,name=player_id,json=playerId,proto3" json:"player_id,omitempty"` | ||||
| 	Actions       []*Action              `protobuf:"bytes,2,rep,name=actions,proto3" json:"actions,omitempty"` | ||||
| 	Tick          int64                  `protobuf:"varint,3,opt,name=tick,proto3" json:"tick,omitempty"` | ||||
| 	unknownFields protoimpl.UnknownFields | ||||
| 	sizeCache     protoimpl.SizeCache | ||||
| 	state           protoimpl.MessageState `protogen:"open.v1"` | ||||
| 	PlayerId        int32                  `protobuf:"varint,1,opt,name=player_id,json=playerId,proto3" json:"player_id,omitempty"` | ||||
| 	Actions         []*Action              `protobuf:"bytes,2,rep,name=actions,proto3" json:"actions,omitempty"` | ||||
| 	Tick            int64                  `protobuf:"varint,3,opt,name=tick,proto3" json:"tick,omitempty"` | ||||
| 	ProtocolVersion int32                  `protobuf:"varint,4,opt,name=protocol_version,json=protocolVersion,proto3" json:"protocol_version,omitempty"` | ||||
| 	unknownFields   protoimpl.UnknownFields | ||||
| 	sizeCache       protoimpl.SizeCache | ||||
| } | ||||
|  | ||||
| func (x *ActionBatch) Reset() { | ||||
| @ -205,11 +228,19 @@ func (x *ActionBatch) GetTick() int64 { | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (x *ActionBatch) GetProtocolVersion() int32 { | ||||
| 	if x != nil { | ||||
| 		return x.ProtocolVersion | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type PlayerState struct { | ||||
| 	state         protoimpl.MessageState `protogen:"open.v1"` | ||||
| 	PlayerId      int32                  `protobuf:"varint,1,opt,name=player_id,json=playerId,proto3" json:"player_id,omitempty"` | ||||
| 	X             int32                  `protobuf:"varint,2,opt,name=x,proto3" json:"x,omitempty"` | ||||
| 	Y             int32                  `protobuf:"varint,3,opt,name=y,proto3" json:"y,omitempty"` | ||||
| 	Username      string                 `protobuf:"bytes,4,opt,name=username,proto3" json:"username,omitempty"` | ||||
| 	unknownFields protoimpl.UnknownFields | ||||
| 	sizeCache     protoimpl.SizeCache | ||||
| } | ||||
| @ -265,11 +296,19 @@ func (x *PlayerState) GetY() int32 { | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (x *PlayerState) GetUsername() string { | ||||
| 	if x != nil { | ||||
| 		return x.Username | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| type ChatMessage struct { | ||||
| 	state         protoimpl.MessageState `protogen:"open.v1"` | ||||
| 	PlayerId      int32                  `protobuf:"varint,1,opt,name=player_id,json=playerId,proto3" json:"player_id,omitempty"` | ||||
| 	Content       string                 `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` | ||||
| 	Timestamp     int64                  `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` | ||||
| 	Username      string                 `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` | ||||
| 	Content       string                 `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` | ||||
| 	Timestamp     int64                  `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` | ||||
| 	unknownFields protoimpl.UnknownFields | ||||
| 	sizeCache     protoimpl.SizeCache | ||||
| } | ||||
| @ -311,6 +350,13 @@ func (x *ChatMessage) GetPlayerId() int32 { | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (x *ChatMessage) GetUsername() string { | ||||
| 	if x != nil { | ||||
| 		return x.Username | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (x *ChatMessage) GetContent() string { | ||||
| 	if x != nil { | ||||
| 		return x.Content | ||||
| @ -326,13 +372,16 @@ func (x *ChatMessage) GetTimestamp() int64 { | ||||
| } | ||||
|  | ||||
| type ServerMessage struct { | ||||
| 	state         protoimpl.MessageState `protogen:"open.v1"` | ||||
| 	PlayerId      int32                  `protobuf:"varint,1,opt,name=player_id,json=playerId,proto3" json:"player_id,omitempty"` | ||||
| 	Players       []*PlayerState         `protobuf:"bytes,2,rep,name=players,proto3" json:"players,omitempty"` | ||||
| 	CurrentTick   int64                  `protobuf:"varint,3,opt,name=current_tick,json=currentTick,proto3" json:"current_tick,omitempty"` | ||||
| 	ChatMessages  []*ChatMessage         `protobuf:"bytes,4,rep,name=chat_messages,json=chatMessages,proto3" json:"chat_messages,omitempty"` | ||||
| 	unknownFields protoimpl.UnknownFields | ||||
| 	sizeCache     protoimpl.SizeCache | ||||
| 	state           protoimpl.MessageState `protogen:"open.v1"` | ||||
| 	PlayerId        int32                  `protobuf:"varint,1,opt,name=player_id,json=playerId,proto3" json:"player_id,omitempty"` | ||||
| 	Players         []*PlayerState         `protobuf:"bytes,2,rep,name=players,proto3" json:"players,omitempty"` | ||||
| 	CurrentTick     int64                  `protobuf:"varint,3,opt,name=current_tick,json=currentTick,proto3" json:"current_tick,omitempty"` | ||||
| 	ChatMessages    []*ChatMessage         `protobuf:"bytes,4,rep,name=chat_messages,json=chatMessages,proto3" json:"chat_messages,omitempty"` | ||||
| 	AuthSuccess     bool                   `protobuf:"varint,5,opt,name=auth_success,json=authSuccess,proto3" json:"auth_success,omitempty"` | ||||
| 	ErrorMessage    string                 `protobuf:"bytes,6,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` | ||||
| 	ProtocolVersion int32                  `protobuf:"varint,7,opt,name=protocol_version,json=protocolVersion,proto3" json:"protocol_version,omitempty"` | ||||
| 	unknownFields   protoimpl.UnknownFields | ||||
| 	sizeCache       protoimpl.SizeCache | ||||
| } | ||||
|  | ||||
| func (x *ServerMessage) Reset() { | ||||
| @ -393,11 +442,32 @@ func (x *ServerMessage) GetChatMessages() []*ChatMessage { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (x *ServerMessage) GetAuthSuccess() bool { | ||||
| 	if x != nil { | ||||
| 		return x.AuthSuccess | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (x *ServerMessage) GetErrorMessage() string { | ||||
| 	if x != nil { | ||||
| 		return x.ErrorMessage | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (x *ServerMessage) GetProtocolVersion() int32 { | ||||
| 	if x != nil { | ||||
| 		return x.ProtocolVersion | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| var File_actions_proto protoreflect.FileDescriptor | ||||
|  | ||||
| var file_actions_proto_rawDesc = []byte{ | ||||
| 	0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, | ||||
| 	0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xc6, 0x01, 0x0a, 0x06, 0x41, 0x63, 0x74, | ||||
| 	0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x97, 0x02, 0x0a, 0x06, 0x41, 0x63, 0x74, | ||||
| 	0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, | ||||
| 	0x0e, 0x32, 0x1a, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, | ||||
| 	0x6f, 0x6e, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, | ||||
| @ -406,43 +476,62 @@ var file_actions_proto_rawDesc = []byte{ | ||||
| 	0x1b, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, | ||||
| 	0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, | ||||
| 	0x63, 0x68, 0x61, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, | ||||
| 	0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, | ||||
| 	0x30, 0x0a, 0x0a, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, | ||||
| 	0x04, 0x4d, 0x4f, 0x56, 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x43, 0x48, 0x41, 0x54, 0x10, | ||||
| 	0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x10, | ||||
| 	0x02, 0x22, 0x69, 0x0a, 0x0b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x61, 0x74, 0x63, 0x68, | ||||
| 	0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, | ||||
| 	0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x29, 0x0a, | ||||
| 	0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, | ||||
| 	0x2e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, | ||||
| 	0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x63, 0x6b, | ||||
| 	0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x63, 0x6b, 0x22, 0x46, 0x0a, 0x0b, | ||||
| 	0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, | ||||
| 	0x6c, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, | ||||
| 	0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x0c, 0x0a, 0x01, 0x78, 0x18, 0x02, 0x20, | ||||
| 	0x01, 0x28, 0x05, 0x52, 0x01, 0x78, 0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, | ||||
| 	0x05, 0x52, 0x01, 0x79, 0x22, 0x62, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x74, 0x4d, 0x65, 0x73, 0x73, | ||||
| 	0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x69, 0x64, | ||||
| 	0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, | ||||
| 	0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, | ||||
| 	0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, | ||||
| 	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, | ||||
| 	0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xba, 0x01, 0x0a, 0x0d, 0x53, 0x65, 0x72, | ||||
| 	0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6c, | ||||
| 	0x61, 0x79, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, | ||||
| 	0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, | ||||
| 	0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x6f, | ||||
| 	0x6e, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x07, | ||||
| 	0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, | ||||
| 	0x6e, 0x74, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, | ||||
| 	0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x12, 0x39, 0x0a, 0x0d, 0x63, 0x68, | ||||
| 	0x61, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, | ||||
| 	0x0b, 0x32, 0x14, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x68, 0x61, 0x74, | ||||
| 	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x74, 0x4d, 0x65, 0x73, | ||||
| 	0x73, 0x61, 0x67, 0x65, 0x73, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x65, 0x61, 0x2e, 0x62, | ||||
| 	0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x62, 0x65, 0x2f, 0x62, 0x64, 0x6e, 0x75, 0x67, 0x67, 0x65, 0x74, | ||||
| 	0x2f, 0x67, 0x6f, 0x6f, 0x6e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x61, 0x63, 0x74, 0x69, | ||||
| 	0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, | ||||
| 	0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, | ||||
| 	0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, | ||||
| 	0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, | ||||
| 	0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, | ||||
| 	0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x49, 0x0a, 0x0a, 0x41, 0x63, 0x74, 0x69, 0x6f, | ||||
| 	0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x4f, 0x56, 0x45, 0x10, 0x00, 0x12, | ||||
| 	0x08, 0x0a, 0x04, 0x43, 0x48, 0x41, 0x54, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x49, 0x53, | ||||
| 	0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x4f, 0x47, | ||||
| 	0x49, 0x4e, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, | ||||
| 	0x10, 0x04, 0x22, 0x94, 0x01, 0x0a, 0x0b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x61, 0x74, | ||||
| 	0x63, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, | ||||
| 	0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x12, | ||||
| 	0x29, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, | ||||
| 	0x32, 0x0f, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, | ||||
| 	0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, | ||||
| 	0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x63, 0x6b, 0x12, 0x29, | ||||
| 	0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, | ||||
| 	0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, | ||||
| 	0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x62, 0x0a, 0x0b, 0x50, 0x6c, 0x61, | ||||
| 	0x79, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x79, | ||||
| 	0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, | ||||
| 	0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x0c, 0x0a, 0x01, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, | ||||
| 	0x52, 0x01, 0x78, 0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, | ||||
| 	0x79, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, | ||||
| 	0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x7e, 0x0a, | ||||
| 	0x0b, 0x43, 0x68, 0x61, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, | ||||
| 	0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, | ||||
| 	0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, | ||||
| 	0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, | ||||
| 	0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, | ||||
| 	0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, | ||||
| 	0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, | ||||
| 	0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xad, 0x02, | ||||
| 	0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, | ||||
| 	0x1b, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, | ||||
| 	0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x07, | ||||
| 	0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, | ||||
| 	0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x53, 0x74, | ||||
| 	0x61, 0x74, 0x65, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, | ||||
| 	0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, | ||||
| 	0x28, 0x03, 0x52, 0x0b, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x12, | ||||
| 	0x39, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, | ||||
| 	0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, | ||||
| 	0x2e, 0x43, 0x68, 0x61, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x63, 0x68, | ||||
| 	0x61, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x75, | ||||
| 	0x74, 0x68, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, | ||||
| 	0x52, 0x0b, 0x61, 0x75, 0x74, 0x68, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, | ||||
| 	0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x06, | ||||
| 	0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, | ||||
| 	0x67, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, | ||||
| 	0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x70, 0x72, | ||||
| 	0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x2c, 0x5a, | ||||
| 	0x2a, 0x67, 0x69, 0x74, 0x65, 0x61, 0x2e, 0x62, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x62, 0x65, 0x2f, | ||||
| 	0x62, 0x64, 0x6e, 0x75, 0x67, 0x67, 0x65, 0x74, 0x2f, 0x67, 0x6f, 0x6f, 0x6e, 0x73, 0x65, 0x72, | ||||
| 	0x76, 0x65, 0x72, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, | ||||
| 	0x74, 0x6f, 0x33, | ||||
| } | ||||
|  | ||||
| var ( | ||||
|  | ||||
| @ -9,6 +9,8 @@ message Action { | ||||
|         MOVE = 0; | ||||
|         CHAT = 1; | ||||
|         DISCONNECT = 2; | ||||
|         LOGIN = 3; | ||||
|         REGISTER = 4; | ||||
|     } | ||||
|  | ||||
|     ActionType type = 1; | ||||
| @ -16,24 +18,29 @@ message Action { | ||||
|     int32 y = 3; | ||||
|     int32 player_id = 4; | ||||
|     string chat_message = 5; | ||||
|     string username = 6; | ||||
|     string password = 7; | ||||
| } | ||||
|  | ||||
| message ActionBatch { | ||||
|     int32 player_id = 1; | ||||
|     repeated Action actions = 2; | ||||
|     int64 tick = 3; | ||||
|     int32 protocol_version = 4; | ||||
| } | ||||
|  | ||||
| message PlayerState { | ||||
|     int32 player_id = 1; | ||||
|     int32 x = 2; | ||||
|     int32 y = 3; | ||||
|     string username = 4; | ||||
| } | ||||
|  | ||||
| message ChatMessage { | ||||
|     int32 player_id = 1; | ||||
|     string content = 2; | ||||
|     int64 timestamp = 3; | ||||
|     string username = 2; | ||||
|     string content = 3; | ||||
|     int64 timestamp = 4; | ||||
| } | ||||
|  | ||||
| message ServerMessage { | ||||
| @ -41,4 +48,7 @@ message ServerMessage { | ||||
|     repeated PlayerState players = 2; | ||||
|     int64 current_tick = 3; | ||||
|     repeated ChatMessage chat_messages = 4; | ||||
|     bool auth_success = 5; | ||||
|     string error_message = 6; | ||||
|     int32 protocol_version = 7; | ||||
| } | ||||
|  | ||||
							
								
								
									
										128
									
								
								db/db.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								db/db.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,128 @@ | ||||
| package db | ||||
|  | ||||
| import ( | ||||
| 	"crypto/sha256" | ||||
| 	"database/sql" | ||||
| 	"encoding/hex" | ||||
| 	"errors" | ||||
| 	"time" | ||||
|  | ||||
| 	_ "github.com/mattn/go-sqlite3" | ||||
| ) | ||||
|  | ||||
| var db *sql.DB | ||||
|  | ||||
| var ( | ||||
| 	ErrUserExists         = errors.New("username already exists") | ||||
| 	ErrInvalidCredentials = errors.New("invalid username or password") | ||||
| ) | ||||
|  | ||||
| func InitDB(dbPath string) error { | ||||
| 	var err error | ||||
| 	db, err = sql.Open("sqlite3", dbPath) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Create tables if they don't exist | ||||
| 	_, err = db.Exec(` | ||||
| 		CREATE TABLE IF NOT EXISTS players ( | ||||
| 			id INTEGER PRIMARY KEY AUTOINCREMENT, | ||||
| 			username TEXT UNIQUE NOT NULL, | ||||
| 			password_hash TEXT NOT NULL, | ||||
| 			created_at DATETIME NOT NULL | ||||
| 		); | ||||
|  | ||||
| 		CREATE TABLE IF NOT EXISTS player_states ( | ||||
| 			player_id INTEGER PRIMARY KEY, | ||||
| 			x INTEGER NOT NULL, | ||||
| 			y INTEGER NOT NULL, | ||||
| 			last_seen DATETIME NOT NULL, | ||||
| 			FOREIGN KEY(player_id) REFERENCES players(id) | ||||
| 		); | ||||
| 	`) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func hashPassword(password string) string { | ||||
| 	hash := sha256.Sum256([]byte(password)) | ||||
| 	return hex.EncodeToString(hash[:]) | ||||
| } | ||||
|  | ||||
| func RegisterPlayer(username, password string) (int, error) { | ||||
| 	// Check if username exists | ||||
| 	var exists bool | ||||
| 	err := db.QueryRow("SELECT EXISTS(SELECT 1 FROM players WHERE username = ?)", username).Scan(&exists) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	if exists { | ||||
| 		return 0, ErrUserExists | ||||
| 	} | ||||
|  | ||||
| 	// Create new player | ||||
| 	result, err := db.Exec(` | ||||
| 		INSERT INTO players (username, password_hash, created_at) | ||||
| 		VALUES (?, ?, ?)`, | ||||
| 		username, hashPassword(password), time.Now().UTC(), | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
|  | ||||
| 	id, err := result.LastInsertId() | ||||
| 	return int(id), err | ||||
| } | ||||
|  | ||||
| func AuthenticatePlayer(username, password string) (int, error) { | ||||
| 	var id int | ||||
| 	var storedHash string | ||||
| 	err := db.QueryRow(` | ||||
| 		SELECT id, password_hash  | ||||
| 		FROM players  | ||||
| 		WHERE username = ?`, | ||||
| 		username, | ||||
| 	).Scan(&id, &storedHash) | ||||
|  | ||||
| 	if err == sql.ErrNoRows { | ||||
| 		return 0, ErrInvalidCredentials | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
|  | ||||
| 	if storedHash != hashPassword(password) { | ||||
| 		return 0, ErrInvalidCredentials | ||||
| 	} | ||||
|  | ||||
| 	return id, nil | ||||
| } | ||||
|  | ||||
| func SavePlayerState(playerID int, x, y int) error { | ||||
| 	_, err := db.Exec(` | ||||
| 		INSERT OR REPLACE INTO player_states ( | ||||
| 			player_id, x, y, last_seen | ||||
| 		) VALUES (?, ?, ?, ?)`, | ||||
| 		playerID, x, y, time.Now().UTC(), | ||||
| 	) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func LoadPlayerState(playerID int) (x, y int, err error) { | ||||
| 	err = db.QueryRow(` | ||||
| 		SELECT x, y FROM player_states  | ||||
| 		WHERE player_id = ?`, | ||||
| 		playerID, | ||||
| 	).Scan(&x, &y) | ||||
| 	if err == sql.ErrNoRows { | ||||
| 		// Return default position for new players | ||||
| 		return 5, 5, nil | ||||
| 	} | ||||
| 	return x, y, err | ||||
| } | ||||
|  | ||||
| func GetUsername(playerID int) (string, error) { | ||||
| 	var username string | ||||
| 	err := db.QueryRow("SELECT username FROM players WHERE id = ?", playerID).Scan(&username) | ||||
| 	return username, err | ||||
| } | ||||
							
								
								
									
										5
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								go.mod
									
									
									
									
									
								
							| @ -2,4 +2,7 @@ module gitea.boner.be/bdnugget/goonserver | ||||
|  | ||||
| go 1.23.0 | ||||
|  | ||||
| require google.golang.org/protobuf v1.36.3 | ||||
| require ( | ||||
| 	github.com/mattn/go-sqlite3 v1.14.24 | ||||
| 	google.golang.org/protobuf v1.36.3 | ||||
| ) | ||||
|  | ||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @ -1,5 +1,7 @@ | ||||
| github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= | ||||
| github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= | ||||
| github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= | ||||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= | ||||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= | ||||
|  | ||||
							
								
								
									
										207
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										207
									
								
								main.go
									
									
									
									
									
								
							| @ -11,31 +11,39 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	pb "gitea.boner.be/bdnugget/goonserver/actions" | ||||
| 	"gitea.boner.be/bdnugget/goonserver/db" | ||||
|  | ||||
| 	"google.golang.org/protobuf/proto" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	port     = ":6969" // Port to listen on | ||||
| 	tickRate = 600 * time.Millisecond | ||||
| 	port         = ":6969" // Port to listen on | ||||
| 	tickRate     = 600 * time.Millisecond | ||||
| 	protoVersion = 1 | ||||
| ) | ||||
|  | ||||
| type Player struct { | ||||
| 	sync.Mutex | ||||
| 	ID   int | ||||
| 	X, Y int // Position on the game grid | ||||
| 	ID       int | ||||
| 	X, Y     int | ||||
| 	Username string | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	players     = make(map[int]*Player) | ||||
| 	actionQueue = make(map[int][]*pb.Action) // Queue to store actions for each player | ||||
| 	playerConns = make(map[int]net.Conn)     // Map to store player connections | ||||
| 	mu          sync.RWMutex                 // Add mutex for protecting shared maps | ||||
| 	chatHistory = make([]*pb.ChatMessage, 0, 100) | ||||
| 	chatMutex   sync.RWMutex | ||||
| 	players      = make(map[int]*Player) | ||||
| 	actionQueue  = make(map[int][]*pb.Action) // Queue to store actions for each player | ||||
| 	playerConns  = make(map[int]net.Conn)     // Map to store player connections | ||||
| 	mu           sync.RWMutex                 // Add mutex for protecting shared maps | ||||
| 	chatHistory  = make([]*pb.ChatMessage, 0, 100) | ||||
| 	chatMutex    sync.RWMutex | ||||
| 	nextPlayerID = 1 // Assuming player IDs start from 1 | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	if err := db.InitDB("goonserver.db"); err != nil { | ||||
| 		log.Fatalf("Failed to initialize database: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	ln, err := net.Listen("tcp", port) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Failed to listen on port %s: %v", port, err) | ||||
| @ -68,34 +76,162 @@ func main() { | ||||
| func handleConnection(conn net.Conn) { | ||||
| 	defer conn.Close() | ||||
|  | ||||
| 	mu.Lock() | ||||
| 	playerID := len(players) + 1 | ||||
| 	newPlayer := &Player{ID: playerID, X: 5, Y: 5} | ||||
| 	players[playerID] = newPlayer | ||||
| 	playerConns[playerID] = conn | ||||
| 	mu.Unlock() | ||||
| 	fmt.Printf("Player %d connected\n", playerID) | ||||
| 	// Read initial message for player ID | ||||
| 	reader := bufio.NewReader(conn) | ||||
|  | ||||
| 	// Send player ID to the client | ||||
| 	serverMsg := &pb.ServerMessage{ | ||||
| 		PlayerId:    int32(playerID), | ||||
| 		CurrentTick: 0, | ||||
| 	// Wait for authentication | ||||
| 	lengthBuf := make([]byte, 4) | ||||
| 	if _, err := io.ReadFull(reader, lengthBuf); err != nil { | ||||
| 		log.Printf("Failed to read auth message length: %v", err) | ||||
| 		return | ||||
| 	} | ||||
| 	if err := writeMessage(conn, serverMsg); err != nil { | ||||
| 		log.Printf("Failed to send player ID to player %d: %v", playerID, err) | ||||
| 	messageLength := binary.BigEndian.Uint32(lengthBuf) | ||||
|  | ||||
| 	messageBuf := make([]byte, messageLength) | ||||
| 	if _, err := io.ReadFull(reader, messageBuf); err != nil { | ||||
| 		log.Printf("Failed to read auth message: %v", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	batch := &pb.ActionBatch{} | ||||
| 	if err := proto.Unmarshal(messageBuf, batch); err != nil { | ||||
| 		log.Printf("Failed to unmarshal auth message: %v", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if len(batch.Actions) == 0 { | ||||
| 		log.Printf("No auth action received") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	action := batch.Actions[0] | ||||
| 	var playerID int | ||||
| 	var authErr error | ||||
|  | ||||
| 	if batch.ProtocolVersion == 0 { | ||||
| 		response := &pb.ServerMessage{ | ||||
| 			AuthSuccess:     false, | ||||
| 			ErrorMessage:    "Client using outdated protocol (pre-versioning)", | ||||
| 			ProtocolVersion: protoVersion, | ||||
| 		} | ||||
| 		writeMessage(conn, response) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if batch.ProtocolVersion < protoVersion { | ||||
| 		response := &pb.ServerMessage{ | ||||
| 			AuthSuccess:     false, | ||||
| 			ErrorMessage:    fmt.Sprintf("Client protocol version too old (client: %d, required: %d)", batch.ProtocolVersion, protoVersion), | ||||
| 			ProtocolVersion: protoVersion, | ||||
| 		} | ||||
| 		writeMessage(conn, response) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	switch action.Type { | ||||
| 	case pb.Action_REGISTER: | ||||
| 		playerID, authErr = db.RegisterPlayer(action.Username, action.Password) | ||||
| 	case pb.Action_LOGIN: | ||||
| 		playerID, authErr = db.AuthenticatePlayer(action.Username, action.Password) | ||||
| 	default: | ||||
| 		log.Printf("Invalid initial action type: %v", action.Type) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Send auth response | ||||
| 	response := &pb.ServerMessage{ | ||||
| 		PlayerId:    int32(playerID), | ||||
| 		AuthSuccess: authErr == nil, | ||||
| 	} | ||||
| 	if authErr != nil { | ||||
| 		response.ErrorMessage = authErr.Error() | ||||
| 		if err := writeMessage(conn, response); err != nil { | ||||
| 			log.Printf("Failed to send auth response: %v", err) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Load last known position | ||||
| 	x, y, err := db.LoadPlayerState(playerID) | ||||
| 	if err != nil { | ||||
| 		log.Printf("Error loading state for player %d: %v", playerID, err) | ||||
| 		x, y = 5, 5 // Default position | ||||
| 	} | ||||
|  | ||||
| 	username, err := db.GetUsername(playerID) | ||||
| 	if err != nil { | ||||
| 		log.Printf("Error getting username for player %d: %v", playerID, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	player := &Player{ | ||||
| 		ID:       playerID, | ||||
| 		X:        x, | ||||
| 		Y:        y, | ||||
| 		Username: username, | ||||
| 	} | ||||
|  | ||||
| 	// Prevent multiple logins | ||||
| 	mu.Lock() | ||||
| 	for _, p := range players { | ||||
| 		if p.Username == username { | ||||
| 			mu.Unlock() | ||||
| 			response := &pb.ServerMessage{ | ||||
| 				AuthSuccess:  false, | ||||
| 				ErrorMessage: "Account already logged in", | ||||
| 			} | ||||
| 			writeMessage(conn, response) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	players[playerID] = player | ||||
| 	playerConns[playerID] = conn | ||||
| 	mu.Unlock() | ||||
|  | ||||
| 	// Send initial state with correct position | ||||
| 	response = &pb.ServerMessage{ | ||||
| 		PlayerId:    int32(playerID), | ||||
| 		AuthSuccess: true, | ||||
| 		Players: []*pb.PlayerState{{ | ||||
| 			PlayerId: int32(playerID), | ||||
| 			X:        int32(x), | ||||
| 			Y:        int32(y), | ||||
| 			Username: username, | ||||
| 		}}, | ||||
| 		ProtocolVersion: protoVersion, | ||||
| 	} | ||||
|  | ||||
| 	// Ensure player state is saved on any kind of disconnect | ||||
| 	defer func() { | ||||
| 		if err := db.SavePlayerState(playerID, player.X, player.Y); err != nil { | ||||
| 			log.Printf("Error saving state for player %d: %v", playerID, err) | ||||
| 		} | ||||
| 		mu.Lock() | ||||
| 		delete(players, playerID) | ||||
| 		delete(playerConns, playerID) | ||||
| 		delete(actionQueue, playerID) | ||||
| 		mu.Unlock() | ||||
| 		log.Printf("Player %d disconnected", playerID) | ||||
| 	}() | ||||
|  | ||||
| 	// Send player ID to client | ||||
| 	if err := writeMessage(conn, response); err != nil { | ||||
| 		log.Printf("Failed to send player ID: %v", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	fmt.Printf("Player %d connected\n", playerID) | ||||
|  | ||||
| 	// Listen for incoming actions from this player | ||||
| 	reader := bufio.NewReader(conn) | ||||
| 	for { | ||||
| 		// Read message length | ||||
| 		lengthBuf := make([]byte, 4) | ||||
| 		if _, err := io.ReadFull(reader, lengthBuf); err != nil { | ||||
| 			log.Printf("Error reading message length from player %d: %v", playerID, err) | ||||
| 			delete(players, playerID) | ||||
| 			delete(playerConns, playerID) | ||||
| 			delete(actionQueue, playerID) | ||||
| 			if err == io.EOF { | ||||
| 				log.Printf("Player %d disconnected gracefully", playerID) | ||||
| 			} else { | ||||
| 				log.Printf("Error reading message length from player %d: %v", playerID, err) | ||||
| 			} | ||||
| 			return | ||||
| 		} | ||||
| 		messageLength := binary.BigEndian.Uint32(lengthBuf) | ||||
| @ -104,9 +240,6 @@ func handleConnection(conn net.Conn) { | ||||
| 		messageBuf := make([]byte, messageLength) | ||||
| 		if _, err := io.ReadFull(reader, messageBuf); err != nil { | ||||
| 			log.Printf("Error reading message from player %d: %v", playerID, err) | ||||
| 			delete(players, playerID) | ||||
| 			delete(playerConns, playerID) | ||||
| 			delete(actionQueue, playerID) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| @ -120,10 +253,7 @@ func handleConnection(conn net.Conn) { | ||||
| 		if batch.PlayerId == int32(playerID) { | ||||
| 			for _, action := range batch.Actions { | ||||
| 				if action.Type == pb.Action_DISCONNECT { | ||||
| 					log.Printf("Player %d disconnected gracefully", playerID) | ||||
| 					delete(players, playerID) | ||||
| 					delete(playerConns, playerID) | ||||
| 					delete(actionQueue, playerID) | ||||
| 					log.Printf("Player %d requested disconnect", playerID) | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| @ -133,11 +263,17 @@ func handleConnection(conn net.Conn) { | ||||
| } | ||||
|  | ||||
| func addChatMessage(playerID int32, content string) { | ||||
| 	player, exists := players[int(playerID)] | ||||
| 	if !exists { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	chatMutex.Lock() | ||||
| 	defer chatMutex.Unlock() | ||||
|  | ||||
| 	msg := &pb.ChatMessage{ | ||||
| 		PlayerId:  playerID, | ||||
| 		Username:  player.Username, | ||||
| 		Content:   content, | ||||
| 		Timestamp: time.Now().UnixNano(), | ||||
| 	} | ||||
| @ -185,6 +321,7 @@ func processActions() { | ||||
| 			PlayerId: int32(id), | ||||
| 			X:        int32(p.X), | ||||
| 			Y:        int32(p.Y), | ||||
| 			Username: p.Username, | ||||
| 		}) | ||||
| 		p.Unlock() | ||||
| 	} | ||||
|  | ||||
		Reference in New Issue
	
	Block a user