mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-07-15 10:17:39 +07:00
Replaced ArrayLists with Arrays, overhauled requesting of logs from the server, improved rollback command and added log resetting.
This commit is contained in:
@ -4,6 +4,7 @@ import com.badlogic.gdx.Application.ApplicationType;
|
|||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.files.FileHandle;
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
import com.badlogic.gdx.utils.IntMap;
|
import com.badlogic.gdx.utils.IntMap;
|
||||||
import io.anuke.mindustry.core.*;
|
import io.anuke.mindustry.core.*;
|
||||||
import io.anuke.mindustry.entities.Bullet;
|
import io.anuke.mindustry.entities.Bullet;
|
||||||
@ -20,7 +21,6 @@ import io.anuke.ucore.entities.EffectEntity;
|
|||||||
import io.anuke.ucore.entities.Entities;
|
import io.anuke.ucore.entities.Entities;
|
||||||
import io.anuke.ucore.entities.EntityGroup;
|
import io.anuke.ucore.entities.EntityGroup;
|
||||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class Vars{
|
public class Vars{
|
||||||
@ -81,8 +81,6 @@ public class Vars{
|
|||||||
public static boolean showUI = true;
|
public static boolean showUI = true;
|
||||||
//whether to show block debug
|
//whether to show block debug
|
||||||
public static boolean showBlockDebug = false;
|
public static boolean showBlockDebug = false;
|
||||||
|
|
||||||
public static IntMap<ArrayList<EditLog>> editLogs = new IntMap<>();
|
|
||||||
|
|
||||||
public static boolean headless = false;
|
public static boolean headless = false;
|
||||||
|
|
||||||
@ -94,6 +92,8 @@ public class Vars{
|
|||||||
//amount of drops that are left when breaking a block
|
//amount of drops that are left when breaking a block
|
||||||
public static final float breakDropAmount = 0.5f;
|
public static final float breakDropAmount = 0.5f;
|
||||||
|
|
||||||
|
public static Array<EditLog> currentEditLogs = new Array<>();
|
||||||
|
|
||||||
//only if smoothCamera
|
//only if smoothCamera
|
||||||
public static boolean snapCamera = true;
|
public static boolean snapCamera = true;
|
||||||
|
|
||||||
|
@ -169,9 +169,9 @@ public class NetClient extends Module {
|
|||||||
ui.hudfrag.updateItems();
|
ui.hudfrag.updateItems();
|
||||||
});
|
});
|
||||||
|
|
||||||
Net.handleClient(BlockLogSyncPacket.class, packet -> {
|
Net.handleClient(BlockLogRequestPacket.class, packet -> {
|
||||||
Vars.editLogs = packet.editlogs;
|
currentEditLogs = packet.editlogs;
|
||||||
});
|
});
|
||||||
|
|
||||||
Net.handleClient(PlacePacket.class, (packet) -> {
|
Net.handleClient(PlacePacket.class, (packet) -> {
|
||||||
Placement.placeBlock(packet.x, packet.y, Block.getByID(packet.block), packet.rotation, true, Timers.get("placeblocksound", 10));
|
Placement.placeBlock(packet.x, packet.y, Block.getByID(packet.block), packet.rotation, true, Timers.get("placeblocksound", 10));
|
||||||
@ -256,6 +256,7 @@ public class NetClient extends Module {
|
|||||||
world.getCore().entity != null){
|
world.getCore().entity != null){
|
||||||
world.getCore().entity.onDeath(true);
|
world.getCore().entity.onDeath(true);
|
||||||
}
|
}
|
||||||
|
netServer.admins.getEditLogs().clear();
|
||||||
kicked = true;
|
kicked = true;
|
||||||
ui.restart.show();
|
ui.restart.show();
|
||||||
});
|
});
|
||||||
|
@ -33,7 +33,6 @@ public class NetServer extends Module{
|
|||||||
|
|
||||||
private final static int timerEntitySync = 0;
|
private final static int timerEntitySync = 0;
|
||||||
private final static int timerStateSync = 1;
|
private final static int timerStateSync = 1;
|
||||||
private final static int timerBlockLogSync = 2;
|
|
||||||
|
|
||||||
public final Administration admins = new Administration();
|
public final Administration admins = new Administration();
|
||||||
|
|
||||||
@ -348,6 +347,11 @@ public class NetServer extends Module{
|
|||||||
Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name);
|
Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Net.handleServer(BlockLogRequestPacket.class, (id, packet) -> {
|
||||||
|
packet.editlogs = EditLog.logsFromTile(packet.x, packet.y);
|
||||||
|
Net.sendTo(id, packet, SendMode.udp);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(){
|
public void update(){
|
||||||
@ -480,12 +484,5 @@ public class NetServer extends Module{
|
|||||||
|
|
||||||
Net.send(packet, SendMode.udp);
|
Net.send(packet, SendMode.udp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(timer.get(timerBlockLogSync, serverSyncTime)) {
|
|
||||||
BlockLogSyncPacket packet = new BlockLogSyncPacket();
|
|
||||||
packet.editlogs = admins.getEditLogs();
|
|
||||||
|
|
||||||
Net.send(packet, SendMode.udp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
if(recipe == null && !ui.hasMouse() && Inputs.keyDown("block_logs")) {
|
if(recipe == null && !ui.hasMouse() && Inputs.keyDown("block_logs")) {
|
||||||
showCursor = true;
|
showCursor = true;
|
||||||
if(Inputs.keyTap("select")){
|
if(Inputs.keyTap("select")){
|
||||||
|
NetEvents.handleBlockLogRequest(getBlockX(), getBlockY());
|
||||||
Timers.runTask(20f, () -> {
|
Timers.runTask(20f, () -> {
|
||||||
ui.hudfrag.blockfrag.showBlockLogs(getBlockX(), getBlockY());
|
ui.hudfrag.blockfrag.showBlockLogs(getBlockX(), getBlockY());
|
||||||
Cursors.restoreCursor();
|
Cursors.restoreCursor();
|
||||||
|
@ -12,7 +12,6 @@ import io.anuke.mindustry.world.blocks.types.Floor;
|
|||||||
import io.anuke.mindustry.world.blocks.types.Rock;
|
import io.anuke.mindustry.world.blocks.types.Rock;
|
||||||
import io.anuke.mindustry.world.blocks.types.StaticBlock;
|
import io.anuke.mindustry.world.blocks.types.StaticBlock;
|
||||||
import io.anuke.ucore.core.Settings;
|
import io.anuke.ucore.core.Settings;
|
||||||
import java.util.ArrayList;
|
|
||||||
import static io.anuke.mindustry.Vars.world;
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
public class Administration {
|
public class Administration {
|
||||||
@ -25,7 +24,7 @@ public class Administration {
|
|||||||
/**Maps UUIDs to trace infos. This is wiped when a player logs off.*/
|
/**Maps UUIDs to trace infos. This is wiped when a player logs off.*/
|
||||||
private ObjectMap<String, TraceInfo> traceInfo = new ObjectMap<>();
|
private ObjectMap<String, TraceInfo> traceInfo = new ObjectMap<>();
|
||||||
/**Maps packed coordinates to logs for that coordinate */
|
/**Maps packed coordinates to logs for that coordinate */
|
||||||
private IntMap<ArrayList<EditLog>> editLogs = new IntMap<>();
|
private IntMap<Array<EditLog>> editLogs = new IntMap<>();
|
||||||
|
|
||||||
private Array<String> bannedIPs = new Array<>();
|
private Array<String> bannedIPs = new Array<>();
|
||||||
|
|
||||||
@ -60,17 +59,21 @@ public class Administration {
|
|||||||
Settings.save();
|
Settings.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntMap<ArrayList<EditLog>> getEditLogs() {
|
public IntMap<Array<EditLog>> getEditLogs() {
|
||||||
return editLogs;
|
return editLogs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setEditLogs(IntMap<Array<EditLog>> editLogs) {
|
||||||
|
this.editLogs = editLogs;
|
||||||
|
}
|
||||||
|
|
||||||
public void logEdit(int x, int y, Player player, Block block, int rotation, EditLog.EditAction action) {
|
public void logEdit(int x, int y, Player player, Block block, int rotation, EditLog.EditAction action) {
|
||||||
if(block instanceof BlockPart || block instanceof Rock || block instanceof Floor || block instanceof StaticBlock) return;
|
if(block instanceof BlockPart || block instanceof Rock || block instanceof Floor || block instanceof StaticBlock) return;
|
||||||
if(editLogs.containsKey(x + y * world.width())) {
|
if(editLogs.containsKey(x + y * world.width())) {
|
||||||
editLogs.get(x + y * world.width()).add(new EditLog(player, block, rotation, action));
|
editLogs.get(x + y * world.width()).add(new EditLog(player, block, rotation, action));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ArrayList<EditLog> logs = new ArrayList<>();
|
Array<EditLog> logs = new Array<>();
|
||||||
logs.add(new EditLog(player, block, rotation, action));
|
logs.add(new EditLog(player, block, rotation, action));
|
||||||
editLogs.put(x + y * world.width(), logs);
|
editLogs.put(x + y * world.width(), logs);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package io.anuke.mindustry.net;
|
package io.anuke.mindustry.net;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.badlogic.gdx.utils.IntMap;
|
||||||
import io.anuke.mindustry.entities.Player;
|
import io.anuke.mindustry.entities.Player;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
|
import static io.anuke.mindustry.Vars.netServer;
|
||||||
import static io.anuke.mindustry.Vars.playerGroup;
|
import static io.anuke.mindustry.Vars.playerGroup;
|
||||||
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
public class EditLog {
|
public class EditLog {
|
||||||
|
|
||||||
@ -30,6 +34,15 @@ public class EditLog {
|
|||||||
EditAction.valueOf(parts[3]));
|
EditAction.valueOf(parts[3]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Array<EditLog> logsFromTile(int x, int y) {
|
||||||
|
for(IntMap.Entry<Array<EditLog>> editLog : netServer.admins.getEditLogs().entries()) {
|
||||||
|
if(editLog.key == (x + y * world.width())) {
|
||||||
|
return editLog.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Array<>();
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("%s:%s:%s:%s", player.id, block.id, rotation, action.toString());
|
return String.format("%s:%s:%s:%s", player.id, block.id, rotation, action.toString());
|
||||||
}
|
}
|
||||||
|
@ -177,4 +177,13 @@ public class NetEvents {
|
|||||||
ui.traces.show(target, netServer.admins.getTrace(Net.getConnection(target.clientid).address));
|
ui.traces.show(target, netServer.admins.getTrace(Net.getConnection(target.clientid).address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void handleBlockLogRequest(int x, int y) {
|
||||||
|
BlockLogRequestPacket packet = new BlockLogRequestPacket();
|
||||||
|
packet.x = x;
|
||||||
|
packet.y = y;
|
||||||
|
packet.editlogs = Vars.currentEditLogs;
|
||||||
|
|
||||||
|
Net.send(packet, SendMode.udp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.anuke.mindustry.net;
|
package io.anuke.mindustry.net;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
import com.badlogic.gdx.utils.Base64Coder;
|
import com.badlogic.gdx.utils.Base64Coder;
|
||||||
import com.badlogic.gdx.utils.IntMap;
|
import com.badlogic.gdx.utils.IntMap;
|
||||||
import com.badlogic.gdx.utils.reflect.ClassReflection;
|
import com.badlogic.gdx.utils.reflect.ClassReflection;
|
||||||
@ -14,7 +15,6 @@ import io.anuke.mindustry.world.Block;
|
|||||||
import io.anuke.ucore.entities.Entities;
|
import io.anuke.ucore.entities.Entities;
|
||||||
import io.anuke.ucore.entities.EntityGroup;
|
import io.anuke.ucore.entities.EntityGroup;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**Class for storing all packets.*/
|
/**Class for storing all packets.*/
|
||||||
public class Packets {
|
public class Packets {
|
||||||
@ -140,51 +140,36 @@ public class Packets {
|
|||||||
timestamp = buffer.getLong();
|
timestamp = buffer.getLong();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class BlockLogSyncPacket implements Packet {
|
|
||||||
public IntMap<ArrayList<EditLog>> editlogs;
|
|
||||||
|
|
||||||
|
public static class BlockLogRequestPacket implements Packet {
|
||||||
|
public int x;
|
||||||
|
public int y;
|
||||||
|
public Array<EditLog> editlogs;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(ByteBuffer buffer) {
|
public void write(ByteBuffer buffer) {
|
||||||
int size = editlogs.size;
|
buffer.putInt(x);
|
||||||
buffer.putInt(size);
|
buffer.putInt(y);
|
||||||
for(IntMap.Entry<ArrayList<EditLog>> editlog :editlogs.entries()) {
|
buffer.putInt(editlogs.size);
|
||||||
|
for(EditLog value : editlogs) {
|
||||||
|
|
||||||
String key = String.valueOf(editlog.key);
|
String rawValue = value.toString();
|
||||||
buffer.put((byte) key.getBytes().length);
|
buffer.put((byte) rawValue.getBytes().length);
|
||||||
buffer.put(key.getBytes());
|
buffer.put(rawValue.getBytes());
|
||||||
|
|
||||||
ArrayList<EditLog> values = editlog.value;
|
|
||||||
buffer.putInt(values.size());
|
|
||||||
for(EditLog value : values) {
|
|
||||||
|
|
||||||
String rawValue = value.toString();
|
|
||||||
buffer.put((byte) rawValue.getBytes().length);
|
|
||||||
buffer.put(rawValue.getBytes());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(ByteBuffer buffer) {
|
public void read(ByteBuffer buffer) {
|
||||||
editlogs = new IntMap<>();
|
x = buffer.getInt();
|
||||||
int logssize = buffer.getInt();
|
y = buffer.getInt();
|
||||||
for(int i = 0; i < logssize; i ++){
|
editlogs = new Array<>();
|
||||||
|
int arraySize = buffer.getInt();
|
||||||
byte length = buffer.get();
|
for(int a = 0; a < arraySize; a ++) {
|
||||||
byte[] bytes = new byte[length];
|
|
||||||
buffer.get(bytes);
|
|
||||||
Integer key = Integer.valueOf(new String(bytes));
|
|
||||||
|
|
||||||
ArrayList<EditLog> list = new ArrayList<>();
|
|
||||||
int arraySize = buffer.getInt();
|
|
||||||
for(int a = 0; a < arraySize; a ++) {
|
|
||||||
|
|
||||||
byte[] arraybytes = new byte[buffer.get()];
|
byte[] arraybytes = new byte[buffer.get()];
|
||||||
buffer.get(arraybytes);
|
buffer.get(arraybytes);
|
||||||
list.add(EditLog.valueOf(new String(arraybytes)));
|
editlogs.add(EditLog.valueOf(new String(arraybytes)));
|
||||||
}
|
|
||||||
editlogs.put(key, list);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ public class Registrator {
|
|||||||
PlacePacket.class,
|
PlacePacket.class,
|
||||||
BreakPacket.class,
|
BreakPacket.class,
|
||||||
StateSyncPacket.class,
|
StateSyncPacket.class,
|
||||||
BlockLogSyncPacket.class,
|
BlockLogRequestPacket.class,
|
||||||
BlockSyncPacket.class,
|
BlockSyncPacket.class,
|
||||||
BulletPacket.class,
|
BulletPacket.class,
|
||||||
EnemyDeathPacket.class,
|
EnemyDeathPacket.class,
|
||||||
|
@ -9,6 +9,7 @@ import io.anuke.mindustry.Vars;
|
|||||||
import io.anuke.mindustry.core.GameState.State;
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.input.InputHandler;
|
import io.anuke.mindustry.input.InputHandler;
|
||||||
import io.anuke.mindustry.net.EditLog;
|
import io.anuke.mindustry.net.EditLog;
|
||||||
|
import io.anuke.mindustry.net.NetEvents;
|
||||||
import io.anuke.mindustry.resource.*;
|
import io.anuke.mindustry.resource.*;
|
||||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
@ -26,7 +27,6 @@ import io.anuke.ucore.scene.ui.layout.Table;
|
|||||||
import io.anuke.ucore.util.Bundles;
|
import io.anuke.ucore.util.Bundles;
|
||||||
import io.anuke.ucore.util.Mathf;
|
import io.anuke.ucore.util.Mathf;
|
||||||
import io.anuke.ucore.util.Strings;
|
import io.anuke.ucore.util.Strings;
|
||||||
import java.util.ArrayList;
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class BlocksFragment implements Fragment{
|
public class BlocksFragment implements Fragment{
|
||||||
@ -364,13 +364,13 @@ public class BlocksFragment implements Fragment{
|
|||||||
|
|
||||||
d.content().add(pane).grow();
|
d.content().add(pane).grow();
|
||||||
|
|
||||||
ArrayList<EditLog> logs = Vars.editLogs.get(x + y * world.width());
|
Array<EditLog> logs = Vars.currentEditLogs;
|
||||||
if(logs == null || logs.isEmpty()) {
|
if(logs == null || logs.size == 0) {
|
||||||
table.add("$text.block.editlogsnotfound").left();
|
table.add("$text.block.editlogsnotfound").left();
|
||||||
table.row();
|
table.row();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for(int i = 0; i < logs.size(); i++) {
|
for(int i = 0; i < logs.size; i++) {
|
||||||
EditLog log = logs.get(i);
|
EditLog log = logs.get(i);
|
||||||
table.add("[gold]" + (i + 1) + ". [white]" + log.info()).left();
|
table.add("[gold]" + (i + 1) + ". [white]" + log.info()).left();
|
||||||
table.row();
|
table.row();
|
||||||
|
@ -30,15 +30,11 @@ import io.anuke.ucore.util.Log;
|
|||||||
import io.anuke.ucore.util.Strings;
|
import io.anuke.ucore.util.Strings;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
import static io.anuke.ucore.util.Log.*;
|
import static io.anuke.ucore.util.Log.*;
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
public class ServerControl extends Module {
|
public class ServerControl extends Module {
|
||||||
private final CommandHandler handler = new CommandHandler("");
|
private final CommandHandler handler = new CommandHandler("");
|
||||||
private ShuffleMode mode;
|
private ShuffleMode mode;
|
||||||
@ -734,25 +730,26 @@ public class ServerControl extends Module {
|
|||||||
err("Open the server first.");
|
err("Open the server first.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(arg[0] == null) {
|
|
||||||
err("Please specify the amount of block edit cycles to rollback");
|
if(!Strings.canParsePostiveInt(arg[0])) {
|
||||||
|
err("Please input a valid, positive, number of times to rollback");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rollbackTimes = Integer.valueOf(arg[0]);
|
int rollbackTimes = Integer.valueOf(arg[0]);
|
||||||
IntMap<ArrayList<EditLog>> editLogs = netServer.admins.getEditLogs();
|
IntMap<Array<EditLog>> editLogs = netServer.admins.getEditLogs();
|
||||||
if(editLogs.size == 0){
|
if(editLogs.size == 0){
|
||||||
err("Nothing to rollback!");
|
err("Nothing to rollback!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(IntMap.Entry<ArrayList<EditLog>> editLog : editLogs.entries()) {
|
for(IntMap.Entry<Array<EditLog>> editLog : editLogs.entries()) {
|
||||||
int coords = editLog.key;
|
int coords = editLog.key;
|
||||||
ArrayList<EditLog> logs = editLog.value;
|
Array<EditLog> logs = editLog.value;
|
||||||
|
|
||||||
for(int i = 0; i < rollbackTimes; i++) {
|
for(int i = 0; i < rollbackTimes; i++) {
|
||||||
|
|
||||||
EditLog log = logs.get(logs.size() - 1);
|
EditLog log = logs.get(logs.size - 1);
|
||||||
|
|
||||||
int x = coords % world.width();
|
int x = coords % world.width();
|
||||||
int y = coords / world.width();
|
int y = coords / world.width();
|
||||||
@ -782,8 +779,8 @@ public class ServerControl extends Module {
|
|||||||
Net.send(packet, Net.SendMode.tcp);
|
Net.send(packet, Net.SendMode.tcp);
|
||||||
}
|
}
|
||||||
|
|
||||||
logs.remove(logs.size() - 1);
|
logs.removeIndex(logs.size - 1);
|
||||||
if(logs.isEmpty()) {
|
if(logs.size == 0) {
|
||||||
editLogs.remove(coords);
|
editLogs.remove(coords);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user