chichilku3 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/chichilku3 +3 -0
- data/bin/chichilku3-server +3 -0
- data/client.json +6 -0
- data/lib/client/chichilku3.rb +18 -0
- data/lib/client/client.rb +289 -0
- data/lib/client/client_cfg.rb +15 -0
- data/lib/client/gui.rb +492 -0
- data/lib/client/img/background1024x512.png +0 -0
- data/lib/client/img/battle1024x576.png +0 -0
- data/lib/client/img/connecting1024x512.png +0 -0
- data/lib/client/img/grass1024x512.png +0 -0
- data/lib/client/img/grey128.png +0 -0
- data/lib/client/img/menu1920x1080.png +0 -0
- data/lib/client/img/stick128/stick0.png +0 -0
- data/lib/client/img/stick128/stick1.png +0 -0
- data/lib/client/img/stick128/stick2.png +0 -0
- data/lib/client/img/stick128/stick3.png +0 -0
- data/lib/client/img/stick128/stick4.png +0 -0
- data/lib/client/img/stick128/stick5.png +0 -0
- data/lib/client/img/stick128/stick_crouching0.png +0 -0
- data/lib/client/img/stick128/stick_crouching1.png +0 -0
- data/lib/client/img/stick128/stick_crouching2.png +0 -0
- data/lib/client/img/stick128/stick_crouching3.png +0 -0
- data/lib/client/img/stick128/stick_crouching4.png +0 -0
- data/lib/client/img/stick128/stick_crouching5.png +0 -0
- data/lib/client/scoreboard.rb +25 -0
- data/lib/client/test.rb +39 -0
- data/lib/client/text.rb +86 -0
- data/lib/server/chichilku3_server.rb +293 -0
- data/lib/server/gamelogic.rb +121 -0
- data/lib/server/server_cfg.rb +6 -0
- data/lib/share/config.rb +53 -0
- data/lib/share/console.rb +18 -0
- data/lib/share/network.rb +145 -0
- data/lib/share/player.rb +286 -0
- data/server.json +4 -0
- metadata +81 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e90a2851bf8d4a37c61c581919708cd7fc75c8592291755c0281e090e03e5d84
|
4
|
+
data.tar.gz: 10e3825729ef2c5a0f17543a8c4519cbbf61f021805d624b54a8f79e314db898
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2452e5c7f2764142ea99f151828994b6c163d301370835558a464c8215c6f1689036a2de9ed681b7d937d90787a8f1d124c241848e63a7d79e3f0fc3c40937be
|
7
|
+
data.tar.gz: 610086071507b30d4acdaaefdb029f485d1c2696c3df1a36369e224f14a9afe67dbc7454affbb3c0d968d47bbd3eeef323223e7f9530924cea85c0e14ecc6399
|
data/bin/chichilku3
ADDED
data/client.json
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'gosu'
|
2
|
+
require_relative 'client'
|
3
|
+
require_relative '../share/console'
|
4
|
+
require_relative '../share/player'
|
5
|
+
require_relative 'gui'
|
6
|
+
require_relative 'client_cfg'
|
7
|
+
|
8
|
+
# The project root is the game
|
9
|
+
class Game
|
10
|
+
def initialize
|
11
|
+
console = Console.new
|
12
|
+
cfg = ClientCfg.new(console, "client.json")
|
13
|
+
gui = Gui.new(cfg)
|
14
|
+
gui.show
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Game.new
|
@@ -0,0 +1,289 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require_relative '../share/network'
|
3
|
+
require_relative '../share/player'
|
4
|
+
|
5
|
+
STATE_ERROR = -2
|
6
|
+
STATE_MENU = -1
|
7
|
+
STATE_OFFLINE = 0
|
8
|
+
STATE_CONNECTING = 1
|
9
|
+
STATE_INGAME = 2
|
10
|
+
|
11
|
+
# Networking part of the game clientside
|
12
|
+
class Client
|
13
|
+
attr_reader :id, :state
|
14
|
+
def initialize(console, cfg)
|
15
|
+
@id = nil
|
16
|
+
@tick = 0
|
17
|
+
@state = STATE_MENU
|
18
|
+
@cfg = cfg
|
19
|
+
|
20
|
+
@console = console
|
21
|
+
@console.log "LOAD #{@s}"
|
22
|
+
|
23
|
+
@s = nil # network socket (set in connect() method)
|
24
|
+
|
25
|
+
# state variables
|
26
|
+
@req_playerlist = Time.now - 8
|
27
|
+
|
28
|
+
# return values
|
29
|
+
@players = []
|
30
|
+
@flags = { skip: false, state: @state, gamestate: 'g',id: nil }
|
31
|
+
end
|
32
|
+
|
33
|
+
def reset()
|
34
|
+
@id = nil
|
35
|
+
@tick = 0
|
36
|
+
@state = STATE_MENU
|
37
|
+
@players = []
|
38
|
+
@flags = { skip: false, state: @state, gamestate: 'g',id: nil }
|
39
|
+
end
|
40
|
+
|
41
|
+
def connect(ip, port)
|
42
|
+
reset
|
43
|
+
@s = TCPSocket.open(ip, port)
|
44
|
+
@s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) # nagle's algorithm-
|
45
|
+
@state = STATE_CONNECTING
|
46
|
+
end
|
47
|
+
|
48
|
+
def disconnect()
|
49
|
+
return if @state == STATE_MENU
|
50
|
+
@console.log "disconnecting from server."
|
51
|
+
@s.close
|
52
|
+
@s = nil
|
53
|
+
reset
|
54
|
+
end
|
55
|
+
|
56
|
+
def tick(client_data, protocol, tick)
|
57
|
+
return nil if @state == STATE_MENU
|
58
|
+
|
59
|
+
# sleep(1)
|
60
|
+
@tick = tick
|
61
|
+
@flags[:skip] = false
|
62
|
+
|
63
|
+
# send data to the server
|
64
|
+
send_data(client_data, protocol)
|
65
|
+
|
66
|
+
# get data from the server + implicit return
|
67
|
+
data = fetch_server_data
|
68
|
+
return nil if data.nil?
|
69
|
+
|
70
|
+
# only process the long packages and ignore ip packages here
|
71
|
+
return nil if data.length != SERVER_PACKAGE_LEN
|
72
|
+
|
73
|
+
# save protocol and cut it off
|
74
|
+
msg = handle_protocol(data[0].to_i, data[1], data[2..-1])
|
75
|
+
[@players, @flags, msg]
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def update_state(state)
|
81
|
+
@flags[:state] = state
|
82
|
+
@state = state
|
83
|
+
end
|
84
|
+
|
85
|
+
def handle_protocol(protocol, p_status, data)
|
86
|
+
@console.dbg "HANDLE PROTOCOL=#{protocol} status=#{p_status}"
|
87
|
+
if protocol == 0 # error packet
|
88
|
+
code = data[0..2]
|
89
|
+
error_msg = data[3..-1]
|
90
|
+
if code == NET_ERR_FULL
|
91
|
+
@console.log "server is full."
|
92
|
+
elsif code == NET_ERR_DISCONNECT
|
93
|
+
@console.log "disconnected by server."
|
94
|
+
elsif code == NET_ERR_KICK
|
95
|
+
@console.log "kicked by server."
|
96
|
+
elsif code == NET_ERR_BAN
|
97
|
+
@console.log "banned by server."
|
98
|
+
elsif code == NET_ERR_SERVER_OUTDATED
|
99
|
+
@console.log "failed to connect to server: server is outdated."
|
100
|
+
@console.log error_msg
|
101
|
+
elsif code == NET_ERR_CLIENT_OUTDATED
|
102
|
+
@console.log "failed to connect to server: your client is outdated."
|
103
|
+
else
|
104
|
+
@console.log "ERROR unkown error code code=#{code} data=#{data}"
|
105
|
+
return
|
106
|
+
end
|
107
|
+
@state = STATE_ERROR
|
108
|
+
return [0, code, error_msg]
|
109
|
+
elsif protocol == 1 # update package
|
110
|
+
server_package_to_player_array(data)
|
111
|
+
elsif protocol == 2 # id packet
|
112
|
+
if @id.nil?
|
113
|
+
id_packet(data)
|
114
|
+
else
|
115
|
+
@console.log "WARNING got unexpected id packet=#{data}"
|
116
|
+
end
|
117
|
+
elsif protocol == 3 # name packet
|
118
|
+
protocol_names(data)
|
119
|
+
elsif protocol == 4 # command respond
|
120
|
+
@console.log "server respond: #{data}"
|
121
|
+
return [1, data]
|
122
|
+
else
|
123
|
+
@console.log "ERROR unkown protocol=#{protocol} data=#{data}"
|
124
|
+
end
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
|
128
|
+
def send_data(data, protocol)
|
129
|
+
if @id.nil?
|
130
|
+
# request id has priority
|
131
|
+
# resend after 100 ticks if no respond
|
132
|
+
name = @cfg.data['username'].ljust(5, '-')
|
133
|
+
net_write("1l#{name}") if (@tick % 200).zero?
|
134
|
+
return
|
135
|
+
end
|
136
|
+
|
137
|
+
# if no playerlist yet -> request one
|
138
|
+
if @players == [] && @req_playerlist < Time.now - 4
|
139
|
+
net_write("3l#{id}#{GAME_VERSION}")
|
140
|
+
@console.log('requesting a playerlist')
|
141
|
+
@req_playerlist = Time.now
|
142
|
+
return
|
143
|
+
end
|
144
|
+
|
145
|
+
# prefix data with id
|
146
|
+
# prot 2 = update pck
|
147
|
+
# prot updated to dynamic becuase we now also send cmds
|
148
|
+
# data = format("#{protocol}l%02d#{data.join('')}", @id) # old 2byte id
|
149
|
+
data = "#{protocol}l#{@id}#{data.join('')}" # new 1byte id
|
150
|
+
net_write(data)
|
151
|
+
end
|
152
|
+
|
153
|
+
def set_id(id)
|
154
|
+
if id > MAX_CLIENTS || id < 1
|
155
|
+
@console.log "Errornous id=#{id}"
|
156
|
+
return false
|
157
|
+
end
|
158
|
+
@id = id
|
159
|
+
@console.log "Set ID=#{@id}"
|
160
|
+
@flags[:id] = @id
|
161
|
+
true
|
162
|
+
end
|
163
|
+
|
164
|
+
def grab_id(data)
|
165
|
+
@console.log 'Trying to read id...'
|
166
|
+
@playercount = data[0..1]
|
167
|
+
id = data[2..3].to_i
|
168
|
+
set_id(id)
|
169
|
+
update_state(STATE_INGAME)
|
170
|
+
end
|
171
|
+
|
172
|
+
def id_packet(data)
|
173
|
+
# protocol 2
|
174
|
+
# the id protocol contains fresh client id
|
175
|
+
# and server version
|
176
|
+
grab_id(data)
|
177
|
+
get_server_version(data)
|
178
|
+
end
|
179
|
+
|
180
|
+
def get_server_version(data)
|
181
|
+
server_version = data[4..8]
|
182
|
+
@console.log "server version='#{server_version}'"
|
183
|
+
end
|
184
|
+
|
185
|
+
def fetch_server_data
|
186
|
+
server_data = save_read(@s, SERVER_PACKAGE_LEN)
|
187
|
+
return nil if server_data == ''
|
188
|
+
|
189
|
+
@console.dbg "recived data: #{server_data}"
|
190
|
+
server_data
|
191
|
+
end
|
192
|
+
|
193
|
+
def net_write(data)
|
194
|
+
if data.length != CLIENT_PACKAGE_LEN
|
195
|
+
@console.log "ERROR wrong pack len: #{data.length}/#{CLIENT_PACKAGE_LEN} pck: #{data}"
|
196
|
+
exit
|
197
|
+
end
|
198
|
+
@s.write(data)
|
199
|
+
@console.dbg "sent: #{data}"
|
200
|
+
end
|
201
|
+
|
202
|
+
# TODO: add protocol class for this
|
203
|
+
# TODO: protocol_names should create the player objects
|
204
|
+
# AND: server_package_to_player_array should update the objs
|
205
|
+
|
206
|
+
# playername package
|
207
|
+
# And its dependencies:
|
208
|
+
def protocol_names(data)
|
209
|
+
# 3 0 00 00000 00 00000 00 00000 000
|
210
|
+
playercount = data[0].to_i
|
211
|
+
@flags[:gamestate] = data[1]
|
212
|
+
data = data[2..-1]
|
213
|
+
p_strs = protocol_names_to_player_strs(playercount, data)
|
214
|
+
protocol_names_strs_to_objs(p_strs)
|
215
|
+
end
|
216
|
+
|
217
|
+
def protocol_names_to_player_strs(slots, data)
|
218
|
+
players = []
|
219
|
+
slots.times do |index|
|
220
|
+
players[index] = data[index * 7..index * 7 + 6]
|
221
|
+
end
|
222
|
+
players
|
223
|
+
end
|
224
|
+
|
225
|
+
def protocol_names_strs_to_objs(player_strs)
|
226
|
+
players = []
|
227
|
+
player_strs.each do |player_str|
|
228
|
+
id = player_str[0].to_i
|
229
|
+
score = net_unpack_int(player_str[1])
|
230
|
+
name = player_str[2..-1]
|
231
|
+
players << Player.new(id, 0, 0, score, name) unless id.zero?
|
232
|
+
end
|
233
|
+
# debug
|
234
|
+
players.each { |p| @console.dbg "player=#{p.id} score=#{p.score} name='#{p.name}'" }
|
235
|
+
@flags[:skip] = true # dont redner players at position zer0
|
236
|
+
@players = players
|
237
|
+
end
|
238
|
+
|
239
|
+
# server_package_to_player_array
|
240
|
+
# And its dependencies:
|
241
|
+
def server_package_to_player_array(data)
|
242
|
+
# /(?<count>\d{2})(?<player>(?<id>\d{2})(?<x>\d{3})(?<y>\d{3}))/
|
243
|
+
# @console.log "data: #{data}"
|
244
|
+
slots = data[0].to_i # save occupado slots
|
245
|
+
# gamestate = data[1].to_i # save gamestate
|
246
|
+
@flags[:gamestate] = data[1]
|
247
|
+
# @console.log "gamestate: " + @flags[:gamestate]
|
248
|
+
data = data[2..-1] # cut slots and gamestate off
|
249
|
+
players = server_package_to_player_strs(slots, data)
|
250
|
+
# @console.log "players: \n#{players}"
|
251
|
+
player_strs_to_objects(players)
|
252
|
+
end
|
253
|
+
|
254
|
+
def server_package_to_player_strs(slots, data)
|
255
|
+
players = []
|
256
|
+
slots.times do |index|
|
257
|
+
players[index] = data[index * 8..index * 8 + 7]
|
258
|
+
end
|
259
|
+
players
|
260
|
+
end
|
261
|
+
|
262
|
+
def player_strs_to_objects(player_strs)
|
263
|
+
players = []
|
264
|
+
player_strs.each do |player_str|
|
265
|
+
id = player_str[0].to_i
|
266
|
+
score = net_unpack_int(player_str[1])
|
267
|
+
unused = player_str[2]
|
268
|
+
net_state = player_str[3]
|
269
|
+
x = net_unpack_bigint(player_str[4..5])
|
270
|
+
y = net_unpack_bigint(player_str[6..7])
|
271
|
+
# puts "id: #{id} x: #{x} y: #{y}"
|
272
|
+
# players << Player.new(id, x, y) unless id.zero?
|
273
|
+
|
274
|
+
@console.dbg "-- updt player id=#{id} score=#{score}--"
|
275
|
+
p_index = Player.get_player_index_by_id(@players, id)
|
276
|
+
@console.dbg "@players index=#{p_index}"
|
277
|
+
@console.dbg "players: \n #{@players}"
|
278
|
+
next if p_index.nil?
|
279
|
+
|
280
|
+
@console.dbg "got player: #{@players[p_index]}"
|
281
|
+
new_player = Player.update_player(@players, id, x, y, score)
|
282
|
+
new_player.net_to_state(net_state)
|
283
|
+
@players[Player.get_player_index_by_id(@players, id)] = new_player
|
284
|
+
end
|
285
|
+
# debug
|
286
|
+
players.each { |p| @console.dbg "player=#{p.id} pos=#{p.x}/#{p.y}" }
|
287
|
+
players
|
288
|
+
end
|
289
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'json'
|
2
|
+
require_relative '../share/network'
|
3
|
+
require_relative '../share/config'
|
4
|
+
|
5
|
+
# The client side repository usign JSON
|
6
|
+
class ClientCfg < Config
|
7
|
+
def sanitize_data(data)
|
8
|
+
data = JSON.parse(File.read(@file))
|
9
|
+
if data['username'].length > NAME_LEN
|
10
|
+
data['username'] = data['username'][0..NAME_LEN - 1]
|
11
|
+
@console.log "username to long chopped to '#{data['username']}'"
|
12
|
+
end
|
13
|
+
data
|
14
|
+
end
|
15
|
+
end
|