// File: main.go
package main

import (
	"ROBLOX-GO/remote"
	"fmt"
	"time"
)

func main() {
	// Start the remote server
	remote.StartServer()

	// Register remote events
	remote.RegisterRemoteEvent("Name1")
	remote.RegisterRemoteEvent("Name1Response")

	// Set up server-side event handler for "Name1"
	remote.OnServerEvent("Name1", func(args []interface{}) {
		fmt.Println("Received Name1 event from client with args:", args)

		// Fire a response event to the client
		remote.FireClient("Name1Response", "Acknowledged by server", 200)
	})

	// Periodically fire an event to clients
	go func() {
		for {
			time.Sleep(1 * time.Second)
			remote.FireServer("Name1", "Hello from server", 42)
		}
	}()

	// Keep the main goroutine alive
	select {}
}



// File: client.go
package main

import (
	"ROBLOX-GO/remote"
	"fmt"
	"time"
)

func main() {
	// Connect to the remote server
	remote.ConnectToServer()

	// Set up client-side event handler for "Name1Response"
	remote.OnClientEvent("Name1Response", func(args []interface{}) {
		fmt.Println("Received Name1Response event with args:", args)
		remote.FireServer("Name1", "Hello from client", 100)
	})

	// Optionally, set up handler for "Name1" if clients need to handle server-initiated events
	remote.OnClientEvent("Name1", func(args []interface{}) {
		fmt.Println("Received Name1 event from server with args:", args)
		// You can choose to respond back or perform other actions here
	})

	// Optionally, fire an initial event to the server after a short delay
	go func() {
		time.Sleep(2 * time.Second)
		remote.FireServer("Name1", "Initial hello from client", 101)
	}()

	// Keep the main goroutine alive
	select {}
}



// File: remote/remote.go
package remote

import (
	"ROBLOX-GO/errors"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"sync"
)

// Server address and port
const (
	address = "localhost:9999"
)

// Message represents the structure of messages exchanged between server and clients
type Message struct {
	Sender string        `json:"sender"`
	Event  string        `json:"event"`
	Args   []interface{} `json:"args"`
}

// HandlerFunc defines the signature for event handler functions
type HandlerFunc func(args []interface{})

// RemoteServer manages server-side operations
type RemoteServer struct {
	listener      net.Listener
	clients       map[net.Conn]struct{}
	clientsMutex  sync.RWMutex
	eventHandlers map[string]HandlerFunc
	eventsMutex   sync.RWMutex
}

// RemoteClient manages client-side operations
type RemoteClient struct {
	conn          net.Conn
	eventHandlers map[string]HandlerFunc
	eventsMutex   sync.RWMutex
}

// Singleton instances
var (
	serverInstance  *RemoteServer
	serverOnce      sync.Once
	clientInstances []*RemoteClient
	clientMutex     sync.Mutex
)

// StartServer initializes and starts the TCP server
func StartServer() {
	serverOnce.Do(func() {
		serverInstance = &RemoteServer{
			clients:       make(map[net.Conn]struct{}),
			eventHandlers: make(map[string]HandlerFunc),
		}
		ln, err := net.Listen("tcp", address)
		if err != nil {
			errors.HandleError(errors.WrapError("Failed to start server", 1001, err))
			return
		}
		serverInstance.listener = ln
		fmt.Printf("Server started on %s\n", address)

		go serverInstance.acceptConnections()
	})
}

// acceptConnections handles incoming client connections
func (s *RemoteServer) acceptConnections() {
	for {
		conn, err := s.listener.Accept()
		if err != nil {
			errors.HandleError(errors.WrapError("Failed to accept connection", 1002, err))
			continue
		}
		s.clientsMutex.Lock()
		s.clients[conn] = struct{}{}
		s.clientsMutex.Unlock()
		fmt.Printf("Client connected: %s\n", conn.RemoteAddr())

		go s.handleConnection(conn)
	}
}

// handleConnection manages communication with a single client
func (s *RemoteServer) handleConnection(conn net.Conn) {
	defer func() {
		s.clientsMutex.Lock()
		delete(s.clients, conn)
		s.clientsMutex.Unlock()
		conn.Close()
		fmt.Printf("Client disconnected: %s\n", conn.RemoteAddr())
	}()

	decoder := json.NewDecoder(conn)
	for {
		var msg Message
		if err := decoder.Decode(&msg); err != nil {
			if err == io.EOF {
				return
			}
			errors.HandleError(errors.WrapError("Failed to decode message", 1003, err))
			return
		}
		s.dispatchEvent(conn, msg)
	}
}

// dispatchEvent triggers the appropriate handler based on the event name
func (s *RemoteServer) dispatchEvent(conn net.Conn, msg Message) {
	s.eventsMutex.RLock()
	handler, exists := s.eventHandlers[msg.Event]
	s.eventsMutex.RUnlock()

	if exists && handler != nil {
		go handler(msg.Args)
	} else {
		fmt.Printf("No handler registered for event: %s\n", msg.Event)
	}
}

// RegisterRemoteEvent registers an event name on the server
func RegisterRemoteEvent(name string) {
	// Registration is implicit by adding a handler
	fmt.Printf("Registered remote event: %s\n", name)
}

// OnServerEvent registers a handler for a specific server event
func OnServerEvent(name string, handler HandlerFunc) {
	serverInstance.eventsMutex.Lock()
	defer serverInstance.eventsMutex.Unlock()
	serverInstance.eventHandlers[name] = handler
	fmt.Printf("Handler registered for server event: %s\n", name)
}

// FireClient sends an event to all connected clients
func FireClient(event string, args ...interface{}) {
	server := serverInstance
	msg := Message{
		Sender: "Server",
		Event:  event,
		Args:   args,
	}
	data, err := json.Marshal(msg)
	if err != nil {
		errors.HandleError(errors.WrapError("Failed to marshal message", 1004, err))
		return
	}

	server.clientsMutex.RLock()
	defer server.clientsMutex.RUnlock()
	for conn := range server.clients {
		_, err := conn.Write(append(data, '\n'))
		if err != nil {
			errors.HandleError(errors.WrapError("Failed to send message to client", 1005, err))
		}
	}
}

// ConnectToServer initializes the client connection to the server
func ConnectToServer() {
	client := &RemoteClient{
		eventHandlers: make(map[string]HandlerFunc),
	}

	conn, err := net.Dial("tcp", address)
	if err != nil {
		errors.HandleError(errors.WrapError("Failed to connect to server", 2001, err))
		return
	}
	client.conn = conn

	clientMutex.Lock()
	clientInstances = append(clientInstances, client)
	clientMutex.Unlock()
	fmt.Printf("Connected to server at %s\n", address)

	go client.listen()
}

// listen handles incoming messages from the server
func (c *RemoteClient) listen() {
	decoder := json.NewDecoder(c.conn)
	for {
		var msg Message
		if err := decoder.Decode(&msg); err != nil {
			if err == io.EOF {
				return
			}
			errors.HandleError(errors.WrapError("Failed to decode message", 2002, err))
			return
		}
		c.dispatchEvent(msg)
	}
}

// dispatchEvent triggers the appropriate handler based on the event name
func (c *RemoteClient) dispatchEvent(msg Message) {
	c.eventsMutex.RLock()
	handler, exists := c.eventHandlers[msg.Event]
	c.eventsMutex.RUnlock()

	if exists && handler != nil {
		go handler(msg.Args)
	} else {
		fmt.Printf("No handler registered for event: %s\n", msg.Event)
	}
}

// OnClientEvent registers a handler for a specific client event
func OnClientEvent(name string, handler HandlerFunc) {
	clientMutex.Lock()
	defer clientMutex.Unlock()
	for _, client := range clientInstances {
		client.eventsMutex.Lock()
		client.eventHandlers[name] = handler
		client.eventsMutex.Unlock()
	}
	fmt.Printf("Handler registered for client event: %s\n", name)
}

// FireServer sends an event to the server and triggers the server's event handler
func FireServer(event string, args ...interface{}) {
	// Create the message as if sent by a client
	msg := Message{
		Sender: "Client",
		Event:  event,
		Args:   args,
	}

	// Marshal the message
	data, err := json.Marshal(msg)
	if err != nil {
		errors.HandleError(errors.WrapError("Failed to marshal message", 2003, err))
		return
	}

	// Send the message to all clients as FireServer is supposed to do
	server := serverInstance
	server.clientsMutex.RLock()
	defer server.clientsMutex.RUnlock()
	for conn := range server.clients {
		_, err := conn.Write(append(data, '\n'))
		if err != nil {
			errors.HandleError(errors.WrapError("Failed to send message to server", 2004, err))
		}
	}

	// Additionally, dispatch the event internally to trigger OnServerEvent
	server.dispatchEvent(nil, msg)
}


PS D:\JBProjects\GOLAND\ROBLOX-GO> go run client.go
Connected to server at localhost:9999
Handler registered for client event: Name1Response
Handler registered for client event: Name1
Received Name1 event from server with args: [Hello from server 42]
Received Name1Response event with args: [Acknowledged by server 200]
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x1 addr=0x28 pc=0x3877b8]

goroutine 38 [running]:
ROBLOX-GO/remote.FireServer({0x3bf177?, 0xc00008c028?}, {0xc00006e160?, 0x2?, 0x2?})
        D:/JBProjects/GOLAND/ROBLOX-GO/remote/remote_event.go:243 +0xf8
main.main.func1({0xc0001880a0?, 0x0?, 0x0?})
        D:/JBProjects/GOLAND/ROBLOX-GO/client.go:17 +0xcc
created by ROBLOX-GO/remote.(*RemoteClient).dispatchEvent in goroutine 35
        D:/JBProjects/GOLAND/ROBLOX-GO/remote/remote_event.go:207 +0x175
exit status 2