diff --git a/fortran/client/README.md b/fortran/client/README.md index 1a1661f..31c4cea 100644 --- a/fortran/client/README.md +++ b/fortran/client/README.md @@ -1,3 +1,5 @@ # fortran mmo-project client pipes suck and dont work, try wrapping the libdill library instead. + +libdill library from https://github.com/modern-fortran/tcp-client-server diff --git a/fortran/client/main.f90 b/fortran/client/app/main.f90 similarity index 62% rename from fortran/client/main.f90 rename to fortran/client/app/main.f90 index a95191a..ac996b7 100644 --- a/fortran/client/main.f90 +++ b/fortran/client/app/main.f90 @@ -13,7 +13,7 @@ program main type(player), dimension(:), allocatable :: players character(len=24):: username character(len=24):: password - integer :: i, status, in_pipe, out_pipe + integer :: i, status logical :: player_updated, exist inquire (file="debug.log", exist=exist) @@ -23,28 +23,11 @@ program main open (12, file="debug.log", status="new", action="write") end if - call execute_command_line('rm fortran-mmo-in.pipe') - write(12, *) 'removed fortran-mmo-in.pipe' - call execute_command_line('rm fortran-mmo-out.pipe') - write(12, *) 'removed fortran-mmo-out.pipe' - call execute_command_line('mkfifo fortran-mmo-in.pipe && mkfifo fortran-mmo-out.pipe') - write(12, *) 'created new pipes' - call execute_command_line('nc localhost 35565 < fortran-mmo-in.pipe > fortran-mmo-out.pipe', wait=.false.) - write(12, *) 'started coms' - - in_pipe = 13 - open (unit=in_pipe, file="fortran-mmo-in.pipe", form='formatted', access='stream', iostat=status) - write(12, *) 'fortran-mmo-in.pipe open success', status - - out_pipe = 14 - open (unit=out_pipe, file="fortran-mmo-out.pipe", form='formatted', access='stream', iostat=status) - write(12, *) 'fortran-mmo-out.pipe open success', status - call getarg(1, username) call getarg(2, password) - me = player(username, vector3( 0.0_c_float, 1.0_c_float, 2.0_c_float ), PURPLE, in_pipe, out_pipe) - players = me%login(password) + me = player(username, vector3( 0.0_c_float, 1.0_c_float, 2.0_c_float ), PURPLE) + !players = me%login(password) camera%position = vector3(0.0_c_float, 10.0_c_float, 10.0_c_float) !Camera position camera%target = vector3(0.0_c_float, 0.0_c_float, 0.0_c_float) !Camera looking at point @@ -75,9 +58,9 @@ program main call me%sync_camera(camera) if (player_updated) then - players = me%move() + !players = me%move() else - players = me%ping() + !players = me%ping() end if call begin_drawing() @@ -87,21 +70,20 @@ program main ! Draw floor call draw_grid(30_c_int, 1.0_c_float) - do i=1,size(players) - call draw_cube(players(i)%position, 0.5_c_float, 0.5_c_float, 0.5_c_float, players(i)%apperance) - end do + call draw_cube(me%position, 0.5_c_float, 0.5_c_float, 0.5_c_float, me%apperance) + !do i=1,size(players) + ! call draw_cube(players(i)%position, 0.5_c_float, 0.5_c_float, 0.5_c_float, players(i)%apperance) + !end do call end_mode_3d() call end_drawing() end do - players = me%logout() - deallocate(players) + !players = me%logout() + if (allocated(players)) then + deallocate(players) + end if call close_window() !Close window and OpenGL context - close(in_pipe) - close(out_pipe) close(12) - call execute_command_line('rm fortran-mmo-in.pipe') - call execute_command_line('rm fortran-mmo-out.pipe') end program main diff --git a/fortran/client/build.sh b/fortran/client/build.sh index 144470e..fb8cd21 100755 --- a/fortran/client/build.sh +++ b/fortran/client/build.sh @@ -1,2 +1 @@ -#!/bin/sh -gfortran -fno-range-check main.f90 raylib.f90 $(pkg-config --libs --cflags raylib) player.f90 -o client \ No newline at end of file +fpm build --flag '-fno-range-check' \ No newline at end of file diff --git a/fortran/client/fpm.toml b/fortran/client/fpm.toml new file mode 100644 index 0000000..c7e5650 --- /dev/null +++ b/fortran/client/fpm.toml @@ -0,0 +1,18 @@ +name = "fortran-mmo-client" +version = "0.1.0" +license = "license" +author = "zongor" +maintainer = "admin@alfrescocavern.com" +copyright = "Copyright 2023, zongor" +[build] +link = ["libdill", "raylib"] +auto-executables = true +auto-tests = true +auto-examples = true +module-naming = false +[install] +library = false +[fortran] +implicit-typing = false +implicit-external = false +source-form = "free" diff --git a/fortran/client/src/mod_dill.f90 b/fortran/client/src/mod_dill.f90 new file mode 100644 index 0000000..ca27b4e --- /dev/null +++ b/fortran/client/src/mod_dill.f90 @@ -0,0 +1,118 @@ +module mod_dill + + use iso_c_binding, only: c_char, c_int, c_int64_t, c_size_t + implicit none + + private + public :: ipaddr, ipaddr_local, ipaddr_port, ipaddr_remote, ipaddr_str, & + IPADDR_MAXSTRLEN, IPADDR_IPV4, IPADDR_IPV6, mrecv, msend, & + suffix_attach, suffix_detach, tcp_accept, tcp_close, tcp_connect, & + tcp_listen + + integer(c_int), parameter :: IPADDR_IPV4 = 1 + integer(c_int), parameter :: IPADDR_IPV6 = 2 + integer(c_int), parameter :: IPADDR_MAXSTRLEN = 46 + + type, bind(c) :: ipaddr + character(c_char) :: address(32) + end type ipaddr + + interface + + integer(c_int) function ipaddr_local(addr, name, port, mode) & + bind(c, name='dill_ipaddr_local') + import :: c_char, c_int, ipaddr + type(ipaddr), intent(out) :: addr + character(c_char), intent(in) :: name(*) + integer(c_int), value, intent(in) :: port + integer(c_int), value, intent(in) :: mode + end function ipaddr_local + + integer(c_int) function ipaddr_port(addr) & + bind(c, name='dill_ipaddr_port') + import :: c_int, ipaddr + type(ipaddr), intent(in) :: addr + end function ipaddr_port + + integer(c_int) function ipaddr_remote(addr, name, port, mode, deadline) & + bind(c, name='dill_ipaddr_remote') + import :: c_char, c_int, c_int64_t, ipaddr + type(ipaddr), intent(out) :: addr + character(c_char), intent(in) :: name(*) + integer(c_int), value, intent(in) :: port + integer(c_int), value, intent(in) :: mode + integer(c_int64_t), value, intent(in) :: deadline + end function ipaddr_remote + + subroutine ipaddr_str(addr, buf) & + bind(c, name='dill_ipaddr_str') + import :: c_char, ipaddr + type(ipaddr), intent(in) :: addr + character(c_char), intent(in out) :: buf(*) + end subroutine ipaddr_str + + integer(c_size_t) function mrecv(s, buf, len, deadline) & + bind(c, name='dill_mrecv') + import :: c_char, c_int, c_int64_t, c_size_t + integer(c_int), value, intent(in) :: s + character(c_char), intent(in out) :: buf(*) + integer(c_size_t), value, intent(in) :: len + integer(c_int64_t), value, intent(in) :: deadline + end function mrecv + + integer(c_int) function msend(s, buf, len, deadline) & + bind(c, name='dill_msend') + import :: c_char, c_int, c_int64_t, c_size_t + integer(c_int), value, intent(in) :: s + character(c_char), intent(in) :: buf(*) + integer(c_size_t), value, intent(in) :: len + integer(c_int64_t), value, intent(in) :: deadline + end function msend + + integer(c_int) function suffix_attach(s, suffix, suffixlen) & + bind(c, name='dill_suffix_attach') + import :: c_char, c_int, c_size_t + integer(c_int), value, intent(in) :: s + character(c_char), intent(in) :: suffix(*) + integer(c_size_t), value, intent(in) :: suffixlen + end function suffix_attach + + integer(c_int) function suffix_detach(s, deadline) & + bind(c, name='dill_suffix_detach') + import :: c_int, c_int64_t + integer(c_int), value, intent(in) :: s + integer(c_int64_t), value, intent(in) :: deadline + end function suffix_detach + + integer(c_int) function tcp_accept(s, addr, deadline) & + bind(c, name='dill_tcp_accept') + import :: c_int, c_int64_t, ipaddr + integer(c_int), value, intent(in) :: s + type(ipaddr), intent(out) :: addr + integer(c_int64_t), value, intent(in) :: deadline + end function tcp_accept + + integer(c_int) function tcp_close(s, deadline) & + bind(c, name='dill_tcp_close') + import :: c_int, c_int64_t + integer(c_int), value, intent(in) :: s + integer(c_int64_t), value, intent(in) :: deadline + end function tcp_close + + integer(c_int) function tcp_connect(addr, deadline) & + bind(c, name='dill_tcp_connect') + import :: c_int, c_int64_t, ipaddr + type(ipaddr), intent(in) :: addr + integer(c_int64_t), value, intent(in) :: deadline + end function tcp_connect + + integer(c_int) function tcp_listen(addr, backlog) & + bind(c, name='dill_tcp_listen') + import :: c_int, ipaddr + type(ipaddr), intent(in) :: addr + integer(c_int), value, intent(in) :: backlog + end function tcp_listen + + end interface + +end module mod_dill diff --git a/fortran/client/player.f90 b/fortran/client/src/player.f90 similarity index 59% rename from fortran/client/player.f90 rename to fortran/client/src/player.f90 index a7100e3..05fb28d 100644 --- a/fortran/client/player.f90 +++ b/fortran/client/src/player.f90 @@ -2,14 +2,14 @@ module player_mod use iso_fortran_env use iso_c_binding use raylib + use mod_dill, only: ipaddr, ipaddr_remote, IPADDR_IPV4, mrecv, msend, tcp_connect, & + suffix_attach implicit none type player character(len=24):: username type(vector3) :: position type(color) :: apperance - integer :: fifo_write - integer :: fifo_read contains procedure, public :: login procedure, public :: logout @@ -30,8 +30,6 @@ contains this%username = username this%position = position this%apperance = apperance - this%fifo_write = fifo_write - this%fifo_read = fifo_read end function function login(this, password) result(players) @@ -83,26 +81,37 @@ contains integer :: apperance_r, apperance_g, apperance_b, i, count real(c_float) :: x_pos, y_pos - write(this%fifo_write, "(i3, 1x, a24, 1x, f8.2, 1x, f8.2)") request_type, & - this%username, this%position%x, this%position%y - call flush(this%fifo_write) + integer(c_int) :: rc, connection + integer(c_size_t) :: message_size, msglen = 256 + type(ipaddr) :: addr + character(c_char) :: message(256) = '' + character(len=*), parameter :: TCP_SUFFIX = c_carriage_return // c_new_line // c_null_char - write(12, "(i3, 1x, a24, 1x, f8.2, 1x, f8.2)") request_type, & - this%username, this%position%x, this%position%y + rc = ipaddr_remote(addr, '127.0.0.1' // c_null_char, 35565_c_int, IPADDR_IPV4, -1_c_int64_t) + connection = tcp_connect(addr, -1_c_int64_t) + connection = suffix_attach(connection, TCP_SUFFIX, 2_c_size_t) - read (this%fifo_read, '(i3)') count - do i=0, count, 1 - read(this%fifo_read, "(a, i3, i3, i3, f8.2, f8.2)") username, & - apperance_r, apperance_g, apperance_b, x_pos, y_pos + write(message, "(i3, 1x, a24, 1x, f8.2, 1x, f8.2)") request_type, & + this%username, this%position%x, this%position%y - if (allocated(players)) then - players = [players, player(username, vector3( x_pos, 1.0_c_float, y_pos ), & - color(apperance_r, apperance_g, apperance_b, 255), -1, -1)] - else - players = [player(username, vector3( x_pos, 1.0_c_float, y_pos ), & - color(apperance_r, apperance_g, apperance_b, 255), -1, -1)] - end if - end do + rc = msend(connection, message(Len_Trim(message)), transfer(Len_Trim(message), 0_c_size_t), -1_c_int64_t) + + message_size = mrecv(connection, message, msglen, -1_c_int64_t) + read (message(:message_size), '(i3)') count + do i=0, count, 1 + message_size = mrecv(connection, message, msglen, -1_c_int64_t) + + read(message, "(a, i3, i3, i3, f8.2, f8.2)") username, & + apperance_r, apperance_g, apperance_b, x_pos, y_pos + + if (allocated(players)) then + players = [players, player(username, vector3( x_pos, 1.0_c_float, y_pos ), & + color(apperance_r, apperance_g, apperance_b, 255))] + else + players = [player(username, vector3( x_pos, 1.0_c_float, y_pos ), & + color(apperance_r, apperance_g, apperance_b, 255))] + end if + end do end function send_packet end module player_mod diff --git a/fortran/client/raylib.f90 b/fortran/client/src/raylib.f90 similarity index 100% rename from fortran/client/raylib.f90 rename to fortran/client/src/raylib.f90 diff --git a/fortran/client/test/check.f90 b/fortran/client/test/check.f90 new file mode 100644 index 0000000..d7e3cba --- /dev/null +++ b/fortran/client/test/check.f90 @@ -0,0 +1,5 @@ +program check +implicit none + +print *, "Put some tests in here!" +end program check diff --git a/fortran/server/app/main.f90 b/fortran/server/app/main.f90 index 462696d..8e7ba81 100644 --- a/fortran/server/app/main.f90 +++ b/fortran/server/app/main.f90 @@ -31,7 +31,7 @@ program main server_loop: do ! read message from stdin - read(input_unit, "(i3, 1x, a24, 1x, f8.2, 1x, f8.2)") command, username, x_pos, y_pos + read(input_unit, "(i3, 1x, a24, 1x, f8.2, 1x, f8.2)") command, username, x_pos, y_pos write(12, "(i3, 1x, a24, 1x, f8.2, 1x, f8.2)") command, username, x_pos, y_pos call flush(12) diff --git a/fortran/server/fpm.toml b/fortran/server/fpm.toml index 9d2c8bb..0fbb4e6 100644 --- a/fortran/server/fpm.toml +++ b/fortran/server/fpm.toml @@ -5,6 +5,7 @@ author = "zongor" maintainer = "admin@alfrescocavern.com" copyright = "Copyright 2023, zongor" [build] +link = ["libdill"] auto-executables = true auto-tests = true auto-examples = true diff --git a/fortran/server/src/mod_dill.f90 b/fortran/server/src/mod_dill.f90 new file mode 100644 index 0000000..ca27b4e --- /dev/null +++ b/fortran/server/src/mod_dill.f90 @@ -0,0 +1,118 @@ +module mod_dill + + use iso_c_binding, only: c_char, c_int, c_int64_t, c_size_t + implicit none + + private + public :: ipaddr, ipaddr_local, ipaddr_port, ipaddr_remote, ipaddr_str, & + IPADDR_MAXSTRLEN, IPADDR_IPV4, IPADDR_IPV6, mrecv, msend, & + suffix_attach, suffix_detach, tcp_accept, tcp_close, tcp_connect, & + tcp_listen + + integer(c_int), parameter :: IPADDR_IPV4 = 1 + integer(c_int), parameter :: IPADDR_IPV6 = 2 + integer(c_int), parameter :: IPADDR_MAXSTRLEN = 46 + + type, bind(c) :: ipaddr + character(c_char) :: address(32) + end type ipaddr + + interface + + integer(c_int) function ipaddr_local(addr, name, port, mode) & + bind(c, name='dill_ipaddr_local') + import :: c_char, c_int, ipaddr + type(ipaddr), intent(out) :: addr + character(c_char), intent(in) :: name(*) + integer(c_int), value, intent(in) :: port + integer(c_int), value, intent(in) :: mode + end function ipaddr_local + + integer(c_int) function ipaddr_port(addr) & + bind(c, name='dill_ipaddr_port') + import :: c_int, ipaddr + type(ipaddr), intent(in) :: addr + end function ipaddr_port + + integer(c_int) function ipaddr_remote(addr, name, port, mode, deadline) & + bind(c, name='dill_ipaddr_remote') + import :: c_char, c_int, c_int64_t, ipaddr + type(ipaddr), intent(out) :: addr + character(c_char), intent(in) :: name(*) + integer(c_int), value, intent(in) :: port + integer(c_int), value, intent(in) :: mode + integer(c_int64_t), value, intent(in) :: deadline + end function ipaddr_remote + + subroutine ipaddr_str(addr, buf) & + bind(c, name='dill_ipaddr_str') + import :: c_char, ipaddr + type(ipaddr), intent(in) :: addr + character(c_char), intent(in out) :: buf(*) + end subroutine ipaddr_str + + integer(c_size_t) function mrecv(s, buf, len, deadline) & + bind(c, name='dill_mrecv') + import :: c_char, c_int, c_int64_t, c_size_t + integer(c_int), value, intent(in) :: s + character(c_char), intent(in out) :: buf(*) + integer(c_size_t), value, intent(in) :: len + integer(c_int64_t), value, intent(in) :: deadline + end function mrecv + + integer(c_int) function msend(s, buf, len, deadline) & + bind(c, name='dill_msend') + import :: c_char, c_int, c_int64_t, c_size_t + integer(c_int), value, intent(in) :: s + character(c_char), intent(in) :: buf(*) + integer(c_size_t), value, intent(in) :: len + integer(c_int64_t), value, intent(in) :: deadline + end function msend + + integer(c_int) function suffix_attach(s, suffix, suffixlen) & + bind(c, name='dill_suffix_attach') + import :: c_char, c_int, c_size_t + integer(c_int), value, intent(in) :: s + character(c_char), intent(in) :: suffix(*) + integer(c_size_t), value, intent(in) :: suffixlen + end function suffix_attach + + integer(c_int) function suffix_detach(s, deadline) & + bind(c, name='dill_suffix_detach') + import :: c_int, c_int64_t + integer(c_int), value, intent(in) :: s + integer(c_int64_t), value, intent(in) :: deadline + end function suffix_detach + + integer(c_int) function tcp_accept(s, addr, deadline) & + bind(c, name='dill_tcp_accept') + import :: c_int, c_int64_t, ipaddr + integer(c_int), value, intent(in) :: s + type(ipaddr), intent(out) :: addr + integer(c_int64_t), value, intent(in) :: deadline + end function tcp_accept + + integer(c_int) function tcp_close(s, deadline) & + bind(c, name='dill_tcp_close') + import :: c_int, c_int64_t + integer(c_int), value, intent(in) :: s + integer(c_int64_t), value, intent(in) :: deadline + end function tcp_close + + integer(c_int) function tcp_connect(addr, deadline) & + bind(c, name='dill_tcp_connect') + import :: c_int, c_int64_t, ipaddr + type(ipaddr), intent(in) :: addr + integer(c_int64_t), value, intent(in) :: deadline + end function tcp_connect + + integer(c_int) function tcp_listen(addr, backlog) & + bind(c, name='dill_tcp_listen') + import :: c_int, ipaddr + type(ipaddr), intent(in) :: addr + integer(c_int), value, intent(in) :: backlog + end function tcp_listen + + end interface + +end module mod_dill