Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
00aa302229 | |||
c720b66818 | |||
f9ec811b10 | |||
d25ee09155 |
24
LICENSE
24
LICENSE
@ -1,11 +1,21 @@
|
||||
“Commons Clause” License Condition v1.0
|
||||
MIT License
|
||||
|
||||
The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition.
|
||||
Copyright (c) 2025 bdnugget
|
||||
|
||||
Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, right to Sell the Software.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Cause License Condition notice.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
Software: GoonServer (for Goonscape)
|
||||
License: Commons Clause v1.0
|
||||
Licensor: bdnugget
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.3
|
||||
// protoc v5.29.2
|
||||
// source: actions.proto
|
||||
// protoc-gen-go v1.36.6
|
||||
// protoc v6.30.1
|
||||
// source: actions/actions.proto
|
||||
|
||||
package actions
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -59,11 +60,11 @@ func (x Action_ActionType) String() string {
|
||||
}
|
||||
|
||||
func (Action_ActionType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_actions_proto_enumTypes[0].Descriptor()
|
||||
return file_actions_actions_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (Action_ActionType) Type() protoreflect.EnumType {
|
||||
return &file_actions_proto_enumTypes[0]
|
||||
return &file_actions_actions_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x Action_ActionType) Number() protoreflect.EnumNumber {
|
||||
@ -72,7 +73,7 @@ func (x Action_ActionType) Number() protoreflect.EnumNumber {
|
||||
|
||||
// Deprecated: Use Action_ActionType.Descriptor instead.
|
||||
func (Action_ActionType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_actions_proto_rawDescGZIP(), []int{0, 0}
|
||||
return file_actions_actions_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
type Action struct {
|
||||
@ -90,7 +91,7 @@ type Action struct {
|
||||
|
||||
func (x *Action) Reset() {
|
||||
*x = Action{}
|
||||
mi := &file_actions_proto_msgTypes[0]
|
||||
mi := &file_actions_actions_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -102,7 +103,7 @@ func (x *Action) String() string {
|
||||
func (*Action) ProtoMessage() {}
|
||||
|
||||
func (x *Action) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_actions_proto_msgTypes[0]
|
||||
mi := &file_actions_actions_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -115,7 +116,7 @@ func (x *Action) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Action.ProtoReflect.Descriptor instead.
|
||||
func (*Action) Descriptor() ([]byte, []int) {
|
||||
return file_actions_proto_rawDescGZIP(), []int{0}
|
||||
return file_actions_actions_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Action) GetType() Action_ActionType {
|
||||
@ -168,18 +169,19 @@ func (x *Action) GetPassword() string {
|
||||
}
|
||||
|
||||
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"`
|
||||
ProtocolVersion int32 `protobuf:"varint,4,opt,name=protocol_version,json=protocolVersion,proto3" json:"protocol_version,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"`
|
||||
LastSeenMessageTimestamp int64 `protobuf:"varint,5,opt,name=last_seen_message_timestamp,json=lastSeenMessageTimestamp,proto3" json:"last_seen_message_timestamp,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ActionBatch) Reset() {
|
||||
*x = ActionBatch{}
|
||||
mi := &file_actions_proto_msgTypes[1]
|
||||
mi := &file_actions_actions_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -191,7 +193,7 @@ func (x *ActionBatch) String() string {
|
||||
func (*ActionBatch) ProtoMessage() {}
|
||||
|
||||
func (x *ActionBatch) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_actions_proto_msgTypes[1]
|
||||
mi := &file_actions_actions_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -204,7 +206,7 @@ func (x *ActionBatch) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ActionBatch.ProtoReflect.Descriptor instead.
|
||||
func (*ActionBatch) Descriptor() ([]byte, []int) {
|
||||
return file_actions_proto_rawDescGZIP(), []int{1}
|
||||
return file_actions_actions_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *ActionBatch) GetPlayerId() int32 {
|
||||
@ -235,6 +237,13 @@ func (x *ActionBatch) GetProtocolVersion() int32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ActionBatch) GetLastSeenMessageTimestamp() int64 {
|
||||
if x != nil {
|
||||
return x.LastSeenMessageTimestamp
|
||||
}
|
||||
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"`
|
||||
@ -247,7 +256,7 @@ type PlayerState struct {
|
||||
|
||||
func (x *PlayerState) Reset() {
|
||||
*x = PlayerState{}
|
||||
mi := &file_actions_proto_msgTypes[2]
|
||||
mi := &file_actions_actions_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -259,7 +268,7 @@ func (x *PlayerState) String() string {
|
||||
func (*PlayerState) ProtoMessage() {}
|
||||
|
||||
func (x *PlayerState) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_actions_proto_msgTypes[2]
|
||||
mi := &file_actions_actions_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -272,7 +281,7 @@ func (x *PlayerState) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use PlayerState.ProtoReflect.Descriptor instead.
|
||||
func (*PlayerState) Descriptor() ([]byte, []int) {
|
||||
return file_actions_proto_rawDescGZIP(), []int{2}
|
||||
return file_actions_actions_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *PlayerState) GetPlayerId() int32 {
|
||||
@ -315,7 +324,7 @@ type ChatMessage struct {
|
||||
|
||||
func (x *ChatMessage) Reset() {
|
||||
*x = ChatMessage{}
|
||||
mi := &file_actions_proto_msgTypes[3]
|
||||
mi := &file_actions_actions_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -327,7 +336,7 @@ func (x *ChatMessage) String() string {
|
||||
func (*ChatMessage) ProtoMessage() {}
|
||||
|
||||
func (x *ChatMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_actions_proto_msgTypes[3]
|
||||
mi := &file_actions_actions_proto_msgTypes[3]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -340,7 +349,7 @@ func (x *ChatMessage) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ChatMessage.ProtoReflect.Descriptor instead.
|
||||
func (*ChatMessage) Descriptor() ([]byte, []int) {
|
||||
return file_actions_proto_rawDescGZIP(), []int{3}
|
||||
return file_actions_actions_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *ChatMessage) GetPlayerId() int32 {
|
||||
@ -386,7 +395,7 @@ type ServerMessage struct {
|
||||
|
||||
func (x *ServerMessage) Reset() {
|
||||
*x = ServerMessage{}
|
||||
mi := &file_actions_proto_msgTypes[4]
|
||||
mi := &file_actions_actions_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -398,7 +407,7 @@ func (x *ServerMessage) String() string {
|
||||
func (*ServerMessage) ProtoMessage() {}
|
||||
|
||||
func (x *ServerMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_actions_proto_msgTypes[4]
|
||||
mi := &file_actions_actions_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -411,7 +420,7 @@ func (x *ServerMessage) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ServerMessage.ProtoReflect.Descriptor instead.
|
||||
func (*ServerMessage) Descriptor() ([]byte, []int) {
|
||||
return file_actions_proto_rawDescGZIP(), []int{4}
|
||||
return file_actions_actions_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *ServerMessage) GetPlayerId() int32 {
|
||||
@ -463,92 +472,67 @@ func (x *ServerMessage) GetProtocolVersion() int32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_actions_proto protoreflect.FileDescriptor
|
||||
var File_actions_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, 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,
|
||||
0x79, 0x70, 0x65, 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,
|
||||
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, 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,
|
||||
}
|
||||
const file_actions_actions_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x15actions/actions.proto\x12\aactions\"\x97\x02\n" +
|
||||
"\x06Action\x12.\n" +
|
||||
"\x04type\x18\x01 \x01(\x0e2\x1a.actions.Action.ActionTypeR\x04type\x12\f\n" +
|
||||
"\x01x\x18\x02 \x01(\x05R\x01x\x12\f\n" +
|
||||
"\x01y\x18\x03 \x01(\x05R\x01y\x12\x1b\n" +
|
||||
"\tplayer_id\x18\x04 \x01(\x05R\bplayerId\x12!\n" +
|
||||
"\fchat_message\x18\x05 \x01(\tR\vchatMessage\x12\x1a\n" +
|
||||
"\busername\x18\x06 \x01(\tR\busername\x12\x1a\n" +
|
||||
"\bpassword\x18\a \x01(\tR\bpassword\"I\n" +
|
||||
"\n" +
|
||||
"ActionType\x12\b\n" +
|
||||
"\x04MOVE\x10\x00\x12\b\n" +
|
||||
"\x04CHAT\x10\x01\x12\x0e\n" +
|
||||
"\n" +
|
||||
"DISCONNECT\x10\x02\x12\t\n" +
|
||||
"\x05LOGIN\x10\x03\x12\f\n" +
|
||||
"\bREGISTER\x10\x04\"\xd3\x01\n" +
|
||||
"\vActionBatch\x12\x1b\n" +
|
||||
"\tplayer_id\x18\x01 \x01(\x05R\bplayerId\x12)\n" +
|
||||
"\aactions\x18\x02 \x03(\v2\x0f.actions.ActionR\aactions\x12\x12\n" +
|
||||
"\x04tick\x18\x03 \x01(\x03R\x04tick\x12)\n" +
|
||||
"\x10protocol_version\x18\x04 \x01(\x05R\x0fprotocolVersion\x12=\n" +
|
||||
"\x1blast_seen_message_timestamp\x18\x05 \x01(\x03R\x18lastSeenMessageTimestamp\"b\n" +
|
||||
"\vPlayerState\x12\x1b\n" +
|
||||
"\tplayer_id\x18\x01 \x01(\x05R\bplayerId\x12\f\n" +
|
||||
"\x01x\x18\x02 \x01(\x05R\x01x\x12\f\n" +
|
||||
"\x01y\x18\x03 \x01(\x05R\x01y\x12\x1a\n" +
|
||||
"\busername\x18\x04 \x01(\tR\busername\"~\n" +
|
||||
"\vChatMessage\x12\x1b\n" +
|
||||
"\tplayer_id\x18\x01 \x01(\x05R\bplayerId\x12\x1a\n" +
|
||||
"\busername\x18\x02 \x01(\tR\busername\x12\x18\n" +
|
||||
"\acontent\x18\x03 \x01(\tR\acontent\x12\x1c\n" +
|
||||
"\ttimestamp\x18\x04 \x01(\x03R\ttimestamp\"\xad\x02\n" +
|
||||
"\rServerMessage\x12\x1b\n" +
|
||||
"\tplayer_id\x18\x01 \x01(\x05R\bplayerId\x12.\n" +
|
||||
"\aplayers\x18\x02 \x03(\v2\x14.actions.PlayerStateR\aplayers\x12!\n" +
|
||||
"\fcurrent_tick\x18\x03 \x01(\x03R\vcurrentTick\x129\n" +
|
||||
"\rchat_messages\x18\x04 \x03(\v2\x14.actions.ChatMessageR\fchatMessages\x12!\n" +
|
||||
"\fauth_success\x18\x05 \x01(\bR\vauthSuccess\x12#\n" +
|
||||
"\rerror_message\x18\x06 \x01(\tR\ferrorMessage\x12)\n" +
|
||||
"\x10protocol_version\x18\a \x01(\x05R\x0fprotocolVersionB,Z*gitea.boner.be/bdnugget/goonserver/actionsb\x06proto3"
|
||||
|
||||
var (
|
||||
file_actions_proto_rawDescOnce sync.Once
|
||||
file_actions_proto_rawDescData = file_actions_proto_rawDesc
|
||||
file_actions_actions_proto_rawDescOnce sync.Once
|
||||
file_actions_actions_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_actions_proto_rawDescGZIP() []byte {
|
||||
file_actions_proto_rawDescOnce.Do(func() {
|
||||
file_actions_proto_rawDescData = protoimpl.X.CompressGZIP(file_actions_proto_rawDescData)
|
||||
func file_actions_actions_proto_rawDescGZIP() []byte {
|
||||
file_actions_actions_proto_rawDescOnce.Do(func() {
|
||||
file_actions_actions_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_actions_actions_proto_rawDesc), len(file_actions_actions_proto_rawDesc)))
|
||||
})
|
||||
return file_actions_proto_rawDescData
|
||||
return file_actions_actions_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_actions_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_actions_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_actions_proto_goTypes = []any{
|
||||
var file_actions_actions_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_actions_actions_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_actions_actions_proto_goTypes = []any{
|
||||
(Action_ActionType)(0), // 0: actions.Action.ActionType
|
||||
(*Action)(nil), // 1: actions.Action
|
||||
(*ActionBatch)(nil), // 2: actions.ActionBatch
|
||||
@ -556,7 +540,7 @@ var file_actions_proto_goTypes = []any{
|
||||
(*ChatMessage)(nil), // 4: actions.ChatMessage
|
||||
(*ServerMessage)(nil), // 5: actions.ServerMessage
|
||||
}
|
||||
var file_actions_proto_depIdxs = []int32{
|
||||
var file_actions_actions_proto_depIdxs = []int32{
|
||||
0, // 0: actions.Action.type:type_name -> actions.Action.ActionType
|
||||
1, // 1: actions.ActionBatch.actions:type_name -> actions.Action
|
||||
3, // 2: actions.ServerMessage.players:type_name -> actions.PlayerState
|
||||
@ -568,28 +552,27 @@ var file_actions_proto_depIdxs = []int32{
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_actions_proto_init() }
|
||||
func file_actions_proto_init() {
|
||||
if File_actions_proto != nil {
|
||||
func init() { file_actions_actions_proto_init() }
|
||||
func file_actions_actions_proto_init() {
|
||||
if File_actions_actions_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_actions_proto_rawDesc,
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_actions_actions_proto_rawDesc), len(file_actions_actions_proto_rawDesc)),
|
||||
NumEnums: 1,
|
||||
NumMessages: 5,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_actions_proto_goTypes,
|
||||
DependencyIndexes: file_actions_proto_depIdxs,
|
||||
EnumInfos: file_actions_proto_enumTypes,
|
||||
MessageInfos: file_actions_proto_msgTypes,
|
||||
GoTypes: file_actions_actions_proto_goTypes,
|
||||
DependencyIndexes: file_actions_actions_proto_depIdxs,
|
||||
EnumInfos: file_actions_actions_proto_enumTypes,
|
||||
MessageInfos: file_actions_actions_proto_msgTypes,
|
||||
}.Build()
|
||||
File_actions_proto = out.File
|
||||
file_actions_proto_rawDesc = nil
|
||||
file_actions_proto_goTypes = nil
|
||||
file_actions_proto_depIdxs = nil
|
||||
File_actions_actions_proto = out.File
|
||||
file_actions_actions_proto_goTypes = nil
|
||||
file_actions_actions_proto_depIdxs = nil
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ message ActionBatch {
|
||||
repeated Action actions = 2;
|
||||
int64 tick = 3;
|
||||
int32 protocol_version = 4;
|
||||
int64 last_seen_message_timestamp = 5;
|
||||
}
|
||||
|
||||
message PlayerState {
|
||||
|
BIN
goonserver
Executable file
BIN
goonserver
Executable file
Binary file not shown.
231
main.go
231
main.go
@ -24,9 +24,10 @@ const (
|
||||
|
||||
type Player struct {
|
||||
sync.Mutex
|
||||
ID int
|
||||
X, Y int
|
||||
Username string
|
||||
ID int
|
||||
X, Y int
|
||||
Username string
|
||||
LastSeenMsgTimestamp int64 // Track the last message timestamp this player has seen
|
||||
}
|
||||
|
||||
var (
|
||||
@ -82,7 +83,10 @@ func main() {
|
||||
}
|
||||
|
||||
func handleConnection(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
defer func() {
|
||||
conn.Close()
|
||||
log.Printf("Connection closed and cleanup complete")
|
||||
}()
|
||||
|
||||
// Get client IP
|
||||
remoteAddr := conn.RemoteAddr().String()
|
||||
@ -188,29 +192,57 @@ func handleConnection(conn net.Conn) {
|
||||
return
|
||||
}
|
||||
|
||||
player := &Player{
|
||||
ID: playerID,
|
||||
X: x,
|
||||
Y: y,
|
||||
Username: username,
|
||||
log.Printf("Player %d (%s) authenticated successfully, checking for existing session", playerID, username)
|
||||
|
||||
// Check for existing session and force disconnect if needed
|
||||
mu.Lock()
|
||||
existingPlayer, alreadyLoggedIn := players[playerID]
|
||||
if alreadyLoggedIn {
|
||||
log.Printf("Player %d (%s) is already logged in, forcing disconnect of old session", playerID, username)
|
||||
// An existing session is found - clean it up
|
||||
if oldConn, exists := playerConns[playerID]; exists {
|
||||
// Try to close the old connection
|
||||
oldConn.Close()
|
||||
delete(playerConns, playerID)
|
||||
}
|
||||
// Keep the player object but update its connection
|
||||
existingPlayer.X = x
|
||||
existingPlayer.Y = y
|
||||
playerConns[playerID] = conn
|
||||
mu.Unlock()
|
||||
} else {
|
||||
// Create a new player
|
||||
player := &Player{
|
||||
ID: playerID,
|
||||
X: x,
|
||||
Y: y,
|
||||
Username: username,
|
||||
LastSeenMsgTimestamp: 0, // Initialize to 0 to receive all messages initially
|
||||
}
|
||||
players[playerID] = player
|
||||
playerConns[playerID] = conn
|
||||
mu.Unlock()
|
||||
existingPlayer = player
|
||||
|
||||
// Announce connection
|
||||
addSystemMessage(fmt.Sprintf("%s connected", 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",
|
||||
// Ensure player state is saved on any kind of disconnect
|
||||
defer func() {
|
||||
if p, exists := players[playerID]; exists {
|
||||
if err := db.SavePlayerState(playerID, p.X, p.Y); err != nil {
|
||||
log.Printf("Error saving state for player %d: %v", playerID, err)
|
||||
}
|
||||
writeMessage(conn, response)
|
||||
return
|
||||
}
|
||||
}
|
||||
players[playerID] = player
|
||||
playerConns[playerID] = conn
|
||||
mu.Unlock()
|
||||
addSystemMessage(fmt.Sprintf("%s disconnected", username))
|
||||
mu.Lock()
|
||||
delete(players, playerID)
|
||||
delete(playerConns, playerID)
|
||||
delete(actionQueue, playerID)
|
||||
mu.Unlock()
|
||||
log.Printf("Player %d (%s) disconnected", playerID, username)
|
||||
}()
|
||||
|
||||
// Send initial state with correct position
|
||||
response = &pb.ServerMessage{
|
||||
@ -225,26 +257,13 @@ func handleConnection(conn net.Conn) {
|
||||
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)
|
||||
log.Printf("Player %d (%s) connected successfully", playerID, username)
|
||||
|
||||
// Listen for incoming actions from this player
|
||||
for {
|
||||
@ -273,6 +292,11 @@ func handleConnection(conn net.Conn) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Update the last seen message timestamp
|
||||
if batch.LastSeenMessageTimestamp > 0 {
|
||||
existingPlayer.LastSeenMsgTimestamp = batch.LastSeenMessageTimestamp
|
||||
}
|
||||
|
||||
// Queue the actions for processing
|
||||
if batch.PlayerId == int32(playerID) {
|
||||
for _, action := range batch.Actions {
|
||||
@ -281,7 +305,9 @@ func handleConnection(conn net.Conn) {
|
||||
return
|
||||
}
|
||||
}
|
||||
mu.Lock()
|
||||
actionQueue[playerID] = append(actionQueue[playerID], batch.Actions...)
|
||||
mu.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -308,13 +334,49 @@ func addChatMessage(playerID int32, content string) {
|
||||
chatHistory = append(chatHistory, msg)
|
||||
}
|
||||
|
||||
func addSystemMessage(content string) {
|
||||
chatMutex.Lock()
|
||||
defer chatMutex.Unlock()
|
||||
|
||||
msg := &pb.ChatMessage{
|
||||
PlayerId: 0, // System messages use ID 0
|
||||
Username: "System",
|
||||
Content: content,
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
}
|
||||
|
||||
if len(chatHistory) >= 100 {
|
||||
chatHistory = chatHistory[1:]
|
||||
}
|
||||
chatHistory = append(chatHistory, msg)
|
||||
}
|
||||
|
||||
func processActions() {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
// Make a list of players to process first, to avoid lock contention
|
||||
activePlayers := make(map[int]*Player)
|
||||
for id, p := range players {
|
||||
activePlayers[id] = p
|
||||
}
|
||||
activeConns := make(map[int]net.Conn)
|
||||
for id, conn := range playerConns {
|
||||
activeConns[id] = conn
|
||||
}
|
||||
activeQueues := make(map[int][]*pb.Action)
|
||||
for id, actions := range actionQueue {
|
||||
if len(actions) > 0 {
|
||||
activeQueues[id] = actions
|
||||
actionQueue[id] = nil // Clear the queue early to avoid double processing
|
||||
}
|
||||
}
|
||||
mu.Unlock()
|
||||
|
||||
// Update players based on queued actions
|
||||
for playerID, actions := range actionQueue {
|
||||
player := players[playerID]
|
||||
// Process actions without holding the global lock
|
||||
for playerID, actions := range activeQueues {
|
||||
player, exists := activePlayers[playerID]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
player.Lock()
|
||||
for _, action := range actions {
|
||||
switch action.Type {
|
||||
@ -328,20 +390,21 @@ func processActions() {
|
||||
}
|
||||
}
|
||||
player.Unlock()
|
||||
actionQueue[playerID] = nil // Clear the action queue after processing
|
||||
}
|
||||
|
||||
// Prepare and broadcast the current game state
|
||||
// Prepare current game state
|
||||
currentTick := time.Now().UnixNano() / int64(tickRate)
|
||||
state := &pb.ServerMessage{
|
||||
CurrentTick: currentTick,
|
||||
Players: make([]*pb.PlayerState, 0, len(players)),
|
||||
}
|
||||
|
||||
// Convert players to PlayerState
|
||||
for id, p := range players {
|
||||
// Get recent messages for new connections
|
||||
chatMutex.RLock()
|
||||
recentMessages := chatHistory[max(0, len(chatHistory)-5):] // Get last 5 for new connections
|
||||
chatMutex.RUnlock()
|
||||
|
||||
// To avoid holding locks too long, prepare player states first
|
||||
playerStates := make([]*pb.PlayerState, 0, len(activePlayers))
|
||||
for id, p := range activePlayers {
|
||||
p.Lock()
|
||||
state.Players = append(state.Players, &pb.PlayerState{
|
||||
playerStates = append(playerStates, &pb.PlayerState{
|
||||
PlayerId: int32(id),
|
||||
X: int32(p.X),
|
||||
Y: int32(p.Y),
|
||||
@ -350,15 +413,69 @@ func processActions() {
|
||||
p.Unlock()
|
||||
}
|
||||
|
||||
// Add chat messages to the state
|
||||
chatMutex.RLock()
|
||||
state.ChatMessages = chatHistory[max(0, len(chatHistory)-5):] // Only send last 5 messages
|
||||
chatMutex.RUnlock()
|
||||
// Now send updates to each player
|
||||
for playerID, conn := range activeConns {
|
||||
player, exists := activePlayers[playerID]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
// Send to each connected player
|
||||
for _, conn := range playerConns {
|
||||
state := &pb.ServerMessage{
|
||||
CurrentTick: currentTick,
|
||||
Players: playerStates,
|
||||
}
|
||||
|
||||
// Add chat messages - only send those the player hasn't seen
|
||||
player.Lock()
|
||||
lastSeen := player.LastSeenMsgTimestamp
|
||||
player.Unlock()
|
||||
|
||||
chatMutex.RLock()
|
||||
var newMessages []*pb.ChatMessage
|
||||
|
||||
// For new connections, send the 5 most recent messages
|
||||
if lastSeen == 0 && len(recentMessages) > 0 {
|
||||
newMessages = recentMessages
|
||||
if len(newMessages) > 0 {
|
||||
// Update the player's timestamp to the latest message
|
||||
player.Lock()
|
||||
player.LastSeenMsgTimestamp = newMessages[len(newMessages)-1].Timestamp
|
||||
player.Unlock()
|
||||
}
|
||||
} else {
|
||||
// For existing connections, only send new messages
|
||||
for _, msg := range chatHistory {
|
||||
if msg.Timestamp > lastSeen {
|
||||
newMessages = append(newMessages, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Update the player's timestamp if we sent them new messages
|
||||
if len(newMessages) > 0 {
|
||||
player.Lock()
|
||||
player.LastSeenMsgTimestamp = newMessages[len(newMessages)-1].Timestamp
|
||||
player.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
state.ChatMessages = newMessages
|
||||
chatMutex.RUnlock()
|
||||
|
||||
// Log the number of messages we're sending
|
||||
if len(newMessages) > 0 {
|
||||
log.Printf("Sending %d new messages to player %d", len(newMessages), playerID)
|
||||
}
|
||||
|
||||
// Send the state to the player - do this without holding any locks
|
||||
if err := writeMessage(conn, state); err != nil {
|
||||
log.Printf("Failed to send update: %v", err)
|
||||
log.Printf("Failed to send update to player %d: %v", playerID, err)
|
||||
|
||||
// Handle connection errors by removing the player
|
||||
mu.Lock()
|
||||
delete(players, playerID)
|
||||
delete(playerConns, playerID)
|
||||
delete(actionQueue, playerID)
|
||||
mu.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user